00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "apr.h"
00026 #include "apr_lib.h"
00027 #include "apr_strings.h"
00028 #include "apr_file_io.h"
00029 #include "apr_file_info.h"
00030 #include "apr_pools.h"
00031 #include "apr_signal.h"
00032 #include "apr_md5.h"
00033 #include "apr_sha1.h"
00034 #include "apr_dbm.h"
00035
00036 #if APR_HAVE_STDLIB_H
00037 #include <stdlib.h>
00038 #endif
00039 #if APR_HAVE_STRING_H
00040 #include <string.h>
00041 #endif
00042 #if APR_HAVE_STRINGS_H
00043 #include <strings.h>
00044 #endif
00045 #include <time.h>
00046
00047 #if APR_CHARSET_EBCDIC
00048 #include "apr_xlate.h"
00049 #endif
00050
00051 #if APR_HAVE_CRYPT_H
00052 #include <crypt.h>
00053 #endif
00054
00055
00056 #if !APR_CHARSET_EBCDIC
00057 #define LF 10
00058 #define CR 13
00059 #else
00060 #define LF '\n'
00061 #define CR '\r'
00062 #endif
00063
00064 #define MAX_STRING_LEN 256
00065 #define ALG_PLAIN 0
00066 #define ALG_APMD5 1
00067 #define ALG_APSHA 2
00068
00069 #if APR_HAVE_CRYPT_H
00070 #define ALG_CRYPT 3
00071 #endif
00072
00073
00074 #define ERR_FILEPERM 1
00075 #define ERR_SYNTAX 2
00076 #define ERR_PWMISMATCH 3
00077 #define ERR_INTERRUPTED 4
00078 #define ERR_OVERFLOW 5
00079 #define ERR_BADUSER 6
00080 #define ERR_EMPTY 7
00081
00082
00083 typedef struct htdbm_t htdbm_t;
00084
00085 struct htdbm_t {
00086 apr_dbm_t *dbm;
00087 apr_pool_t *pool;
00088 #if APR_CHARSET_EBCDIC
00089 apr_xlate_t *to_ascii;
00090 #endif
00091 char *filename;
00092 char *username;
00093 char *userpass;
00094 char *comment;
00095 char *type;
00096 int create;
00097 int rdonly;
00098 int alg;
00099 };
00100
00101
00102 #define HTDBM_MAKE 0
00103 #define HTDBM_DELETE 1
00104 #define HTDBM_VERIFY 2
00105 #define HTDBM_LIST 3
00106 #define HTDBM_NOFILE 4
00107 #define HTDBM_STDIN 5
00108
00109 static void terminate(void)
00110 {
00111 apr_terminate();
00112 #ifdef NETWARE
00113 pressanykey();
00114 #endif
00115 }
00116
00117 static void htdbm_terminate(htdbm_t *htdbm)
00118 {
00119 if (htdbm->dbm)
00120 apr_dbm_close(htdbm->dbm);
00121 htdbm->dbm = NULL;
00122 }
00123
00124 static htdbm_t *h;
00125
00126 static void htdbm_interrupted(void)
00127 {
00128 htdbm_terminate(h);
00129 fprintf(stderr, "htdbm Interrupted !\n");
00130 exit(ERR_INTERRUPTED);
00131 }
00132
00133 static apr_status_t htdbm_init(apr_pool_t **pool, htdbm_t **hdbm)
00134 {
00135
00136 #if APR_CHARSET_EBCDIC
00137 apr_status_t rv;
00138 #endif
00139
00140 apr_pool_create( pool, NULL);
00141 apr_signal(SIGINT, (void (*)(int)) htdbm_interrupted);
00142
00143 (*hdbm) = (htdbm_t *)apr_pcalloc(*pool, sizeof(htdbm_t));
00144 (*hdbm)->pool = *pool;
00145
00146 #if APR_CHARSET_EBCDIC
00147 rv = apr_xlate_open(&((*hdbm)->to_ascii), "ISO8859-1", APR_DEFAULT_CHARSET, (*hdbm)->pool);
00148 if (rv) {
00149 fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv);
00150 return APR_EGENERAL;
00151 }
00152 rv = apr_SHA1InitEBCDIC((*hdbm)->to_ascii);
00153 if (rv) {
00154 fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv);
00155 return APR_EGENERAL;
00156 }
00157 rv = apr_MD5InitEBCDIC((*hdbm)->to_ascii);
00158 if (rv) {
00159 fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv);
00160 return APR_EGENERAL;
00161 }
00162 #endif
00163
00164
00165 (*hdbm)->alg = ALG_APMD5;
00166 (*hdbm)->type = "default";
00167 return APR_SUCCESS;
00168 }
00169
00170 static apr_status_t htdbm_open(htdbm_t *htdbm)
00171 {
00172 if (htdbm->create)
00173 return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, APR_DBM_RWCREATE,
00174 APR_OS_DEFAULT, htdbm->pool);
00175 else
00176 return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename,
00177 htdbm->rdonly ? APR_DBM_READONLY : APR_DBM_READWRITE,
00178 APR_OS_DEFAULT, htdbm->pool);
00179 }
00180
00181 static apr_status_t htdbm_save(htdbm_t *htdbm, int *changed)
00182 {
00183 apr_datum_t key, val;
00184
00185 if (!htdbm->username)
00186 return APR_SUCCESS;
00187
00188 key.dptr = htdbm->username;
00189 key.dsize = strlen(htdbm->username);
00190 if (apr_dbm_exists(htdbm->dbm, key))
00191 *changed = 1;
00192
00193 val.dsize = strlen(htdbm->userpass);
00194 if (!htdbm->comment)
00195 val.dptr = htdbm->userpass;
00196 else {
00197 val.dptr = apr_pstrcat(htdbm->pool, htdbm->userpass, ":",
00198 htdbm->comment, NULL);
00199 val.dsize += (strlen(htdbm->comment) + 1);
00200 }
00201 return apr_dbm_store(htdbm->dbm, key, val);
00202 }
00203
00204 static apr_status_t htdbm_del(htdbm_t *htdbm)
00205 {
00206 apr_datum_t key;
00207
00208 key.dptr = htdbm->username;
00209 key.dsize = strlen(htdbm->username);
00210 if (!apr_dbm_exists(htdbm->dbm, key))
00211 return APR_ENOENT;
00212
00213 return apr_dbm_delete(htdbm->dbm, key);
00214 }
00215
00216 static apr_status_t htdbm_verify(htdbm_t *htdbm)
00217 {
00218 apr_datum_t key, val;
00219 char pwd[MAX_STRING_LEN] = {0};
00220 char *rec, *cmnt;
00221
00222 key.dptr = htdbm->username;
00223 key.dsize = strlen(htdbm->username);
00224 if (!apr_dbm_exists(htdbm->dbm, key))
00225 return APR_ENOENT;
00226 if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS)
00227 return APR_ENOENT;
00228 rec = apr_pstrndup(htdbm->pool, val.dptr, val.dsize);
00229 cmnt = strchr(rec, ';');
00230 if (cmnt)
00231 strncpy(pwd, rec, cmnt - rec);
00232 else
00233 strcpy(pwd, rec);
00234 return apr_password_validate(htdbm->userpass, pwd);
00235 }
00236
00237 static apr_status_t htdbm_list(htdbm_t *htdbm)
00238 {
00239 apr_status_t rv;
00240 apr_datum_t key, val;
00241 char *rec, *cmnt;
00242 char kb[MAX_STRING_LEN];
00243 int i = 0;
00244
00245 rv = apr_dbm_firstkey(htdbm->dbm, &key);
00246 if (rv != APR_SUCCESS) {
00247 fprintf(stderr, "Empty database -- %s\n", htdbm->filename);
00248 return APR_ENOENT;
00249 }
00250 rec = apr_pcalloc(htdbm->pool, HUGE_STRING_LEN);
00251
00252 fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename);
00253 fprintf(stderr, " %-32sComment\n", "Username");
00254 while (key.dptr != NULL) {
00255 rv = apr_dbm_fetch(htdbm->dbm, key, &val);
00256 if (rv != APR_SUCCESS) {
00257 fprintf(stderr, "Failed getting data from %s\n", htdbm->filename);
00258 return APR_EGENERAL;
00259 }
00260 strncpy(kb, key.dptr, key.dsize);
00261 kb[key.dsize] = '\0';
00262 fprintf(stderr, " %-32s", kb);
00263 strncpy(rec, val.dptr, val.dsize);
00264 rec[val.dsize] = '\0';
00265 cmnt = strchr(rec, ':');
00266 if (cmnt)
00267 fprintf(stderr, cmnt + 1);
00268 fprintf(stderr, "\n");
00269 rv = apr_dbm_nextkey(htdbm->dbm, &key);
00270 if (rv != APR_SUCCESS)
00271 fprintf(stderr, "Failed getting NextKey\n");
00272 ++i;
00273 }
00274
00275 fprintf(stderr, "Total #records : %d\n", i);
00276 return APR_SUCCESS;
00277 }
00278
00279 static void to64(char *s, unsigned long v, int n)
00280 {
00281 static unsigned char itoa64[] =
00282 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00283
00284 while (--n >= 0) {
00285 *s++ = itoa64[v&0x3f];
00286 v >>= 6;
00287 }
00288 }
00289
00290 static apr_status_t htdbm_make(htdbm_t *htdbm)
00291 {
00292 char cpw[MAX_STRING_LEN];
00293 char salt[9];
00294
00295 switch (htdbm->alg) {
00296 case ALG_APSHA:
00297
00298 apr_sha1_base64(htdbm->userpass,strlen(htdbm->userpass),cpw);
00299 break;
00300
00301 case ALG_APMD5:
00302 (void) srand((int) time((time_t *) NULL));
00303 to64(&salt[0], rand(), 8);
00304 salt[8] = '\0';
00305 apr_md5_encode((const char *)htdbm->userpass, (const char *)salt,
00306 cpw, sizeof(cpw));
00307 break;
00308 case ALG_PLAIN:
00309
00310 apr_cpystrn(cpw,htdbm->userpass,sizeof(cpw));
00311 break;
00312 #if APR_HAVE_CRYPT_H
00313 case ALG_CRYPT:
00314 (void) srand((int) time((time_t *) NULL));
00315 to64(&salt[0], rand(), 8);
00316 salt[8] = '\0';
00317 apr_cpystrn(cpw, (char *)crypt(htdbm->userpass, salt), sizeof(cpw) - 1);
00318 fprintf(stderr, "CRYPT is now deprecated, use MD5 instead!\n");
00319 #endif
00320 default:
00321 break;
00322 }
00323 htdbm->userpass = apr_pstrdup(htdbm->pool, cpw);
00324 return APR_SUCCESS;
00325 }
00326
00327 static apr_status_t htdbm_valid_username(htdbm_t *htdbm)
00328 {
00329 if (!htdbm->username || (strlen(htdbm->username) > 64) || (strlen(htdbm->username) < 1)) {
00330 fprintf(stderr, "Invalid username length\n");
00331 return APR_EINVAL;
00332 }
00333 if (strchr(htdbm->username, ':')) {
00334 fprintf(stderr, "Username contains invalid characters\n");
00335 return APR_EINVAL;
00336 }
00337 return APR_SUCCESS;
00338 }
00339
00340 static void htdbm_usage(void)
00341 {
00342
00343 #if APR_HAVE_CRYPT_H
00344 #define CRYPT_OPTION "d"
00345 #else
00346 #define CRYPT_OPTION ""
00347 #endif
00348 fprintf(stderr, "htdbm -- program for manipulating DBM password databases.\n\n");
00349 fprintf(stderr, "Usage: htdbm [-cm"CRYPT_OPTION"pstvx] [-TDBTYPE] database username\n");
00350 fprintf(stderr, " -b[cm"CRYPT_OPTION"ptsv] [-TDBTYPE] database username password\n");
00351 fprintf(stderr, " -n[m"CRYPT_OPTION"pst] username\n");
00352 fprintf(stderr, " -nb[m"CRYPT_OPTION"pst] username password\n");
00353 fprintf(stderr, " -v[m"CRYPT_OPTION"ps] [-TDBTYPE] database username\n");
00354 fprintf(stderr, " -vb[m"CRYPT_OPTION"ps] [-TDBTYPE] database username password\n");
00355 fprintf(stderr, " -x[m"CRYPT_OPTION"ps] [-TDBTYPE] database username\n");
00356 fprintf(stderr, " -l [-TDBTYPE] database\n");
00357 fprintf(stderr, "Options:\n");
00358 fprintf(stderr, " -b Use the password from the command line rather "
00359 "than prompting for it.\n");
00360 fprintf(stderr, " -c Create a new database.\n");
00361 fprintf(stderr, " -n Don't update database; display results on stdout.\n");
00362 fprintf(stderr, " -m Force MD5 encryption of the password (default).\n");
00363 #if APR_HAVE_CRYPT_H
00364 fprintf(stderr, " -d Force CRYPT encryption of the password (now deprecated).\n");
00365 #endif
00366 fprintf(stderr, " -p Do not encrypt the password (plaintext).\n");
00367 fprintf(stderr, " -s Force SHA encryption of the password.\n");
00368 fprintf(stderr, " -T DBM Type (SDBM|GDBM|DB|default).\n");
00369 fprintf(stderr, " -l Display usernames from database on stdout.\n");
00370 fprintf(stderr, " -t The last param is username comment.\n");
00371 fprintf(stderr, " -v Verify the username/password.\n");
00372 fprintf(stderr, " -x Remove the username record from database.\n");
00373 exit(ERR_SYNTAX);
00374
00375 }
00376
00377
00378 int main(int argc, const char * const argv[])
00379 {
00380 apr_pool_t *pool;
00381 apr_status_t rv;
00382 apr_size_t l;
00383 char pwi[MAX_STRING_LEN];
00384 char pwc[MAX_STRING_LEN];
00385 char errbuf[MAX_STRING_LEN];
00386 const char *arg;
00387 int need_file = 1;
00388 int need_user = 1;
00389 int need_pwd = 1;
00390 int need_cmnt = 0;
00391 int pwd_supplied = 0;
00392 int changed;
00393 int cmd = HTDBM_MAKE;
00394 int i;
00395 int args_left = 2;
00396
00397 apr_app_initialize(&argc, &argv, NULL);
00398 atexit(terminate);
00399
00400 if ((rv = htdbm_init(&pool, &h)) != APR_SUCCESS) {
00401 fprintf(stderr, "Unable to initialize htdbm terminating!\n");
00402 apr_strerror(rv, errbuf, sizeof(errbuf));
00403 exit(1);
00404 }
00405
00406
00407
00408
00409
00410 if (argc < 3)
00411 htdbm_usage();
00412
00413
00414
00415
00416 for (i = 1; i < argc; i++) {
00417 arg = argv[i];
00418 if (*arg != '-')
00419 break;
00420
00421 while (*++arg != '\0') {
00422 switch (*arg) {
00423 case 'b':
00424 pwd_supplied = 1;
00425 need_pwd = 0;
00426 args_left++;
00427 break;
00428 case 'c':
00429 h->create = 1;
00430 break;
00431 case 'n':
00432 need_file = 0;
00433 cmd = HTDBM_NOFILE;
00434 args_left--;
00435 break;
00436 case 'l':
00437 need_pwd = 0;
00438 need_user = 0;
00439 cmd = HTDBM_LIST;
00440 h->rdonly = 1;
00441 args_left--;
00442 break;
00443 case 't':
00444 need_cmnt = 1;
00445 args_left++;
00446 break;
00447 case 'T':
00448 h->type = apr_pstrdup(h->pool, ++arg);
00449 while (*arg != '\0')
00450 ++arg;
00451 --arg;
00452 break;
00453 case 'v':
00454 h->rdonly = 1;
00455 cmd = HTDBM_VERIFY;
00456 break;
00457 case 'x':
00458 need_pwd = 0;
00459 cmd = HTDBM_DELETE;
00460 break;
00461 case 'm':
00462 h->alg = ALG_APMD5;
00463 break;
00464 case 'p':
00465 h->alg = ALG_PLAIN;
00466 break;
00467 case 's':
00468 h->alg = ALG_APSHA;
00469 break;
00470 #if APR_HAVE_CRYPT_H
00471 case 'd':
00472 h->alg = ALG_CRYPT;
00473 break;
00474 #endif
00475 default:
00476 htdbm_usage();
00477 break;
00478 }
00479 }
00480 }
00481
00482
00483
00484
00485
00486 if ((argc - i) != args_left)
00487 htdbm_usage();
00488
00489 if (!need_file)
00490 i--;
00491 else {
00492 h->filename = apr_pstrdup(h->pool, argv[i]);
00493 if ((rv = htdbm_open(h)) != APR_SUCCESS) {
00494 fprintf(stderr, "Error opening database %s\n", argv[i]);
00495 apr_strerror(rv, errbuf, sizeof(errbuf));
00496 fprintf(stderr,"%s\n",errbuf);
00497 exit(ERR_FILEPERM);
00498 }
00499 }
00500 if (need_user) {
00501 h->username = apr_pstrdup(pool, argv[i+1]);
00502 if (htdbm_valid_username(h) != APR_SUCCESS)
00503 exit(ERR_BADUSER);
00504 }
00505 if (pwd_supplied)
00506 h->userpass = apr_pstrdup(pool, argv[i+2]);
00507
00508 if (need_pwd) {
00509 l = sizeof(pwc);
00510 if (apr_password_get("Enter password : ", pwi, &l) != APR_SUCCESS) {
00511 fprintf(stderr, "Password too long\n");
00512 exit(ERR_OVERFLOW);
00513 }
00514 l = sizeof(pwc);
00515 if (apr_password_get("Re-type password : ", pwc, &l) != APR_SUCCESS) {
00516 fprintf(stderr, "Password too long\n");
00517 exit(ERR_OVERFLOW);
00518 }
00519 if (strcmp(pwi, pwc) != 0) {
00520 fprintf(stderr, "Password verification error\n");
00521 exit(ERR_PWMISMATCH);
00522 }
00523
00524 h->userpass = apr_pstrdup(pool, pwi);
00525 }
00526 if (need_cmnt && pwd_supplied)
00527 h->comment = apr_pstrdup(pool, argv[i+3]);
00528 else if (need_cmnt)
00529 h->comment = apr_pstrdup(pool, argv[i+2]);
00530
00531 switch (cmd) {
00532 case HTDBM_VERIFY:
00533 if ((rv = htdbm_verify(h)) != APR_SUCCESS) {
00534 if(rv == APR_ENOENT) {
00535 fprintf(stderr, "The user '%s' could not be found in database\n", h->username);
00536 exit(ERR_BADUSER);
00537 }
00538 else {
00539 fprintf(stderr, "Password mismatch for user '%s'\n", h->username);
00540 exit(ERR_PWMISMATCH);
00541 }
00542 }
00543 else
00544 fprintf(stderr, "Password validated for user '%s'\n", h->username);
00545 break;
00546 case HTDBM_DELETE:
00547 if (htdbm_del(h) != APR_SUCCESS) {
00548 fprintf(stderr, "Cannot find user '%s' in database\n", h->username);
00549 exit(ERR_BADUSER);
00550 }
00551 h->username = NULL;
00552 changed = 1;
00553 break;
00554 case HTDBM_LIST:
00555 htdbm_list(h);
00556 break;
00557 default:
00558 htdbm_make(h);
00559 break;
00560
00561 }
00562 if (need_file && !h->rdonly) {
00563 if ((rv = htdbm_save(h, &changed)) != APR_SUCCESS) {
00564 apr_strerror(rv, errbuf, sizeof(errbuf));
00565 exit(ERR_FILEPERM);
00566 }
00567 fprintf(stdout, "Database %s %s.\n", h->filename,
00568 h->create ? "created" : (changed ? "modified" : "updated"));
00569 }
00570 if (cmd == HTDBM_NOFILE) {
00571 if (!need_cmnt) {
00572 fprintf(stderr, "%s:%s\n", h->username, h->userpass);
00573 }
00574 else {
00575 fprintf(stderr, "%s:%s:%s\n", h->username, h->userpass,
00576 h->comment);
00577 }
00578 }
00579 htdbm_terminate(h);
00580
00581 return 0;
00582 }