int get_password(struct passwd_ctx *ctx) { char buf[MAX_STRING_LEN + 1]; if (ctx->passwd_src == PW_STDIN) { apr_file_t *file_stdin; apr_size_t nread; if (apr_file_open_stdin(&file_stdin, ctx->pool) != APR_SUCCESS) { ctx->errstr = "Unable to read from stdin."; return ERR_GENERAL; } if (apr_file_read_full(file_stdin, buf, sizeof(buf) - 1, &nread) != APR_EOF || nread == sizeof(buf) - 1) { goto err_too_long; } buf[nread] = '\0'; if (nread >= 1 && buf[nread-1] == '\n') { buf[nread-1] = '\0'; if (nread >= 2 && buf[nread-2] == '\r') buf[nread-2] = '\0'; } apr_file_close(file_stdin); ctx->passwd = apr_pstrdup(ctx->pool, buf); } else if (ctx->passwd_src == PW_PROMPT_VERIFY) { apr_size_t bufsize = sizeof(buf); if (apr_password_get("Enter password: "******"New password: "******"Re-type new password: "******"password verification error"; memset(ctx->passwd, '\0', strlen(ctx->passwd)); memset(buf, '\0', sizeof(buf)); return ERR_PWMISMATCH; } } memset(buf, '\0', sizeof(buf)); return 0; err_too_long: ctx->errstr = apr_psprintf(ctx->pool, "password too long (>%" APR_SIZE_T_FMT ")", ctx->out_len - 1); return ERR_OVERFLOW; }
static void add_password(const char *user, const char *realm, apr_file_t *f) { char *pw; apr_md5_ctx_t context; unsigned char digest[16]; char string[MAX_STRING_LEN]; char pwin[MAX_STRING_LEN]; char pwv[MAX_STRING_LEN]; unsigned int i; apr_size_t len = sizeof(pwin); if (apr_password_get("New password: "******"password too long"); cleanup_tempfile_and_exit(5); } len = sizeof(pwin); apr_password_get("Re-type new password: "******"They don't match, sorry.\n"); cleanup_tempfile_and_exit(1); } pw = pwin; apr_file_printf(f, "%s:%s:", user, realm); /* Do MD5 stuff */ sprintf(string, "%s:%s:%s", user, realm, pw); apr_md5_init(&context); #if APR_CHARSET_EBCDIC apr_md5_set_xlate(&context, to_ascii); #endif apr_md5_update(&context, (unsigned char *) string, strlen(string)); apr_md5_final(digest, &context); for (i = 0; i < 16; i++) apr_file_printf(f, "%02x", digest[i]); apr_file_printf(f, "\n"); }
/* * Make a password record from the given information. A zero return * indicates success; failure means that the output buffer contains an * error message instead. */ static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd, int alg) { char *pw; char cpw[120]; char pwin[MAX_STRING_LEN]; char pwv[MAX_STRING_LEN]; char salt[9]; apr_size_t bufsize; if (passwd != NULL) { pw = passwd; } else { bufsize = sizeof(pwin); if (apr_password_get("New password: "******"password too long (>%" APR_SIZE_T_FMT ")", sizeof(pwin) - 1); return ERR_OVERFLOW; } bufsize = sizeof(pwv); apr_password_get("Re-type new password: "******"password verification error", (rlen - 1)); return ERR_PWMISMATCH; } pw = pwin; memset(pwv, '\0', sizeof(pwin)); } switch (alg) { case ALG_APSHA: /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */ apr_sha1_base64(pw,strlen(pw),cpw); break; case ALG_APMD5: if (seed_rand()) { break; } generate_salt(&salt[0], 8); salt[8] = '\0'; apr_md5_encode((const char *)pw, (const char *)salt, cpw, sizeof(cpw)); break; case ALG_PLAIN: /* XXX this len limitation is not in sync with any HTTPd len. */ apr_cpystrn(cpw,pw,sizeof(cpw)); break; #if (!(defined(WIN32) || defined(NETWARE))) case ALG_CRYPT: default: if (seed_rand()) { break; } to64(&salt[0], rand(), 8); salt[8] = '\0'; apr_cpystrn(cpw, crypt(pw, salt), sizeof(cpw) - 1); if (strlen(pw) > 8) { char *truncpw = strdup(pw); truncpw[8] = '\0'; if (!strcmp(cpw, crypt(truncpw, salt))) { apr_file_printf(errfile, "Warning: Password truncated to 8 characters " "by CRYPT algorithm." NL); } free(truncpw); } break; #endif } memset(pw, '\0', strlen(pw)); /* * Check to see if the buffer is large enough to hold the username, * hash, and delimiters. */ if ((strlen(user) + 1 + strlen(cpw)) > (rlen - 1)) { apr_cpystrn(record, "resultant record too long", (rlen - 1)); return ERR_OVERFLOW; } strcpy(record, user); strcat(record, ":"); strcat(record, cpw); strcat(record, "\n"); return 0; }
int main(int argc, const char * const argv[]) { apr_pool_t *pool; apr_status_t rv; apr_size_t l; char pwi[MAX_STRING_LEN]; char pwc[MAX_STRING_LEN]; char errbuf[MAX_STRING_LEN]; const char *arg; int need_file = 1; int need_user = 1; int need_pwd = 1; int need_cmnt = 0; int pwd_supplied = 0; int changed = 0; int cmd = HTDBM_MAKE; int i; int args_left = 2; apr_app_initialize(&argc, &argv, NULL); atexit(terminate); if ((rv = htdbm_init(&pool, &h)) != APR_SUCCESS) { fprintf(stderr, "Unable to initialize htdbm terminating!\n"); apr_strerror(rv, errbuf, sizeof(errbuf)); exit(1); } /* * Preliminary check to make sure they provided at least * three arguments, we'll do better argument checking as * we parse the command line. */ if (argc < 3) htdbm_usage(); /* * Go through the argument list and pick out any options. They * have to precede any other arguments. */ for (i = 1; i < argc; i++) { arg = argv[i]; if (*arg != '-') break; while (*++arg != '\0') { switch (*arg) { case 'b': pwd_supplied = 1; need_pwd = 0; args_left++; break; case 'c': h->create = 1; break; case 'n': need_file = 0; cmd = HTDBM_NOFILE; args_left--; break; case 'l': need_pwd = 0; need_user = 0; cmd = HTDBM_LIST; h->rdonly = 1; args_left--; break; case 't': need_cmnt = 1; args_left++; break; case 'T': h->type = apr_pstrdup(h->pool, ++arg); while (*arg != '\0') ++arg; --arg; /* so incrementing this in the loop with find a null */ break; case 'v': h->rdonly = 1; cmd = HTDBM_VERIFY; break; case 'x': need_pwd = 0; cmd = HTDBM_DELETE; break; case 'm': h->alg = ALG_APMD5; break; case 'p': h->alg = ALG_PLAIN; break; case 's': h->alg = ALG_APSHA; break; #if (!(defined(WIN32) || defined(TPF) || defined(NETWARE))) case 'd': h->alg = ALG_CRYPT; break; #endif default: htdbm_usage(); break; } } } /* * Make sure we still have exactly the right number of arguments left * (the filename, the username, and possibly the password if -b was * specified). */ if ((argc - i) != args_left) htdbm_usage(); if (!need_file) i--; else { h->filename = apr_pstrdup(h->pool, argv[i]); if ((rv = htdbm_open(h)) != APR_SUCCESS) { fprintf(stderr, "Error opening database %s\n", argv[i]); apr_strerror(rv, errbuf, sizeof(errbuf)); fprintf(stderr,"%s\n",errbuf); exit(ERR_FILEPERM); } } if (need_user) { h->username = apr_pstrdup(pool, argv[i+1]); if (htdbm_valid_username(h) != APR_SUCCESS) exit(ERR_BADUSER); } if (pwd_supplied) h->userpass = apr_pstrdup(pool, argv[i+2]); if (need_pwd) { l = sizeof(pwc); if (apr_password_get("Enter password : "******"Password too long\n"); exit(ERR_OVERFLOW); } l = sizeof(pwc); if (apr_password_get("Re-type password : "******"Password too long\n"); exit(ERR_OVERFLOW); } if (strcmp(pwi, pwc) != 0) { fprintf(stderr, "Password verification error\n"); exit(ERR_PWMISMATCH); } h->userpass = apr_pstrdup(pool, pwi); } if (need_cmnt && pwd_supplied) h->comment = apr_pstrdup(pool, argv[i+3]); else if (need_cmnt) h->comment = apr_pstrdup(pool, argv[i+2]); switch (cmd) { case HTDBM_VERIFY: if ((rv = htdbm_verify(h)) != APR_SUCCESS) { if(rv == APR_ENOENT) { fprintf(stderr, "The user '%s' could not be found in database\n", h->username); exit(ERR_BADUSER); } else { fprintf(stderr, "Password mismatch for user '%s'\n", h->username); exit(ERR_PWMISMATCH); } } else fprintf(stderr, "Password validated for user '%s'\n", h->username); break; case HTDBM_DELETE: if (htdbm_del(h) != APR_SUCCESS) { fprintf(stderr, "Cannot find user '%s' in database\n", h->username); exit(ERR_BADUSER); } h->username = NULL; changed = 1; break; case HTDBM_LIST: htdbm_list(h); break; default: htdbm_make(h); break; } if (need_file && !h->rdonly) { if ((rv = htdbm_save(h, &changed)) != APR_SUCCESS) { apr_strerror(rv, errbuf, sizeof(errbuf)); exit(ERR_FILEPERM); } fprintf(stdout, "Database %s %s.\n", h->filename, h->create ? "created" : (changed ? "modified" : "updated")); } if (cmd == HTDBM_NOFILE) { if (!need_cmnt) { fprintf(stderr, "%s:%s\n", h->username, h->userpass); } else { fprintf(stderr, "%s:%s:%s\n", h->username, h->userpass, h->comment); } } htdbm_terminate(h); return 0; /* Suppress compiler warning. */ }