static char* netepi_crypt(request_rec *r, char *password, char *encrypted_password_with_salt) { /* We do this ourselves, because platform crypt() implementations vary too * much, and we'd like our data to be portable. * * We need to extract the salt from the encrypted_password_with_salt string * prefixed by $S$xxxxxxxx$. * We know it starts with '$' at this point. */ char *saltcopy; char *salt; char *saveptr; char *salted_password; char sha1hash[APR_SHA1PW_IDLEN + APR_SHA1_DIGESTSIZE + 1]; char *final_hash; saltcopy = apr_pstrdup(r->pool, encrypted_password_with_salt); if (saltcopy == NULL) return NULL; salt = apr_strtok(saltcopy, "$", &saveptr); if (salt == NULL || strcmp(salt, "S")) return NULL; /* Wrong hash method */ salt = apr_strtok(NULL, "$", &saveptr); if (salt == NULL) return NULL; /* No salt! */ salted_password = apr_pstrcat(r->pool, salt, password, NULL); if (salted_password == NULL) return NULL; apr_sha1_base64(salted_password, strlen(salted_password), sha1hash); /* We want to skip over the "{SHA1}" in the hash and allow room for $S$...$...\0 */ final_hash = apr_pstrcat(r->pool, "$S$", salt, "$", &sha1hash[APR_SHA1PW_IDLEN], NULL); return final_hash; }
static void test_shapass(abts_case *tc, void *data) { const char *pass = "******"; char hash[100]; apr_sha1_base64(pass, strlen(pass), hash); APR_ASSERT_SUCCESS(tc, "SHA1 password validated", apr_password_validate(pass, hash)); }
// Returns the base64 hash of the temp file's name and PorterSharedSecret. char *porter_sign_filename(porter_upload_request_t *ur, apr_finfo_t *finfo) { PORTER_LOG("Signing Filename"); const char *value_to_hash = apr_pstrcat(ur->pool, finfo->fname, ur->secret, NULL); char *hash = apr_palloc(ur->pool, 100 * sizeof(char)); apr_sha1_base64(value_to_hash, strlen(value_to_hash), hash); PORTER_LOG(hash); return hash + APR_SHA1PW_IDLEN; }
static void test_shapass(abts_case *tc, void *data) { const char *pass = "******"; const char *pass2 = "hellojed2"; char hash[100]; apr_sha1_base64(pass, strlen(pass), hash); apr_assert_success(tc, "SHA1 password validated", apr_password_validate(pass, hash)); APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate", apr_password_validate(pass2, hash)); }
static apr_status_t htdbm_make(htdbm_t *htdbm) { char cpw[MAX_STRING_LEN]; char salt[9]; #if (!(defined(WIN32) || defined(NETWARE))) char *cbuf; #endif switch (htdbm->alg) { case ALG_APSHA: /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */ apr_sha1_base64(htdbm->userpass,strlen(htdbm->userpass),cpw); break; case ALG_APMD5: (void) srand((int) time((time_t *) NULL)); to64(&salt[0], rand(), 8); salt[8] = '\0'; apr_md5_encode((const char *)htdbm->userpass, (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,htdbm->userpass,sizeof(cpw)); #if (!(defined(WIN32) || defined(TPF) || defined(NETWARE))) fprintf(stderr, "Warning: Plain text passwords aren't supported by the " "server on this platform!\n"); #endif break; #if (!(defined(WIN32) || defined(TPF) || defined(NETWARE))) case ALG_CRYPT: (void) srand((int) time((time_t *) NULL)); to64(&salt[0], rand(), 8); salt[8] = '\0'; cbuf = crypt(htdbm->userpass, salt); if (cbuf == NULL) { char errbuf[128]; fprintf(stderr, "crypt() failed: %s\n", apr_strerror(errno, errbuf, sizeof errbuf)); exit(ERR_PWMISMATCH); } apr_cpystrn(cpw, cbuf, sizeof(cpw) - 1); fprintf(stderr, "CRYPT is now deprecated, use MD5 instead!\n"); #endif default: break; } htdbm->userpass = apr_pstrdup(htdbm->pool, cpw); return APR_SUCCESS; }
/* Mod_authn_socache wants us to pass it the username and the encrypted * password from the user database to cache. But we have no access to the * actual user database - only the external authenticator can see that - * and chances are, the passwords there aren't encrypted in any way that * mod_authn_socache would understand anyway. So instead, after successful * authentications only, we take the user's plain text password, encrypt * that using an algorithm mod_authn_socache will understand, and cache that * as if we'd actually gotten it from a password database. */ void mock_turtle_cache(request_rec *r, const char *plainpw) { char cryptpw[120]; /* Authn_cache_store will be null if mod_authn_socache does not exist. * If it does exist, but is not set up to cache us, then * authn_cache_store() will do nothing, which is why we turn this off * with "AuthExternalProvideCache Off" to avoid doing the encryption * for no reason. */ if (authn_cache_store != NULL) { apr_sha1_base64(plainpw,strlen(plainpw),cryptpw); authn_cache_store(r, "external", r->user, NULL, cryptpw); } }
/* * Validate a plaintext password against a smashed one. Uses either * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending * upon the format of the smashed input password. Returns APR_SUCCESS if * they match, or APR_EMISMATCH if they don't. If the platform doesn't * support crypt, then the default check is against a clear text string. */ APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, const char *hash) { char sample[200]; #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char *crypt_pw; #endif if (hash[0] == '$' && hash[1] == '2' && (hash[2] == 'a' || hash[2] == 'y') && hash[3] == '$') { if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) return APR_FROM_OS_ERROR(errno); } else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { /* * The hash was created using our custom algorithm. */ apr_md5_encode(passwd, hash, sample, sizeof(sample)); } else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { apr_sha1_base64(passwd, (int)strlen(passwd), sample); } else { /* * It's not our algorithm, so feed it to crypt() if possible. */ #if defined(WIN32) || defined(BEOS) || defined(NETWARE) return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_CRYPTD) apr_status_t rv; CRYPTD *buffer = malloc(sizeof(*buffer)); if (buffer == NULL) return APR_ENOMEM; crypt_pw = crypt_r(passwd, hash, buffer); if (!crypt_pw) rv = APR_EMISMATCH; else rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; free(buffer); return rv; #elif defined(CRYPT_R_STRUCT_CRYPT_DATA) apr_status_t rv; struct crypt_data *buffer = malloc(sizeof(*buffer)); if (buffer == NULL) return APR_ENOMEM; #ifdef __GLIBC_PREREQ /* * For not too old glibc (>= 2.3.2), it's enough to set * buffer.initialized = 0. For < 2.3.2 and for other platforms, * we need to zero the whole struct. */ #if __GLIBC_PREREQ(2,4) #define USE_CRYPT_DATA_INITALIZED #endif #endif #ifdef USE_CRYPT_DATA_INITALIZED buffer->initialized = 0; #else memset(buffer, 0, sizeof(*buffer)); #endif crypt_pw = crypt_r(passwd, hash, buffer); if (!crypt_pw) rv = APR_EMISMATCH; else rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; free(buffer); return rv; #else /* Do a bit of sanity checking since we know that crypt_r() * should always be used for threaded builds on AIX, and * problems in configure logic can result in the wrong * choice being made. */ #if defined(_AIX) && APR_HAS_THREADS #error Configuration error! crypt_r() should have been selected! #endif { apr_status_t rv; /* Handle thread safety issues by holding a mutex around the * call to crypt(). */ crypt_mutex_lock(); crypt_pw = crypt(passwd, hash); if (!crypt_pw) { rv = APR_EMISMATCH; } else { rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; } crypt_mutex_unlock(); return rv; } #endif } return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; }
/* * Validate a plaintext password against a smashed one. Uses either * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending * upon the format of the smashed input password. Returns APR_SUCCESS if * they match, or APR_EMISMATCH if they don't. If the platform doesn't * support crypt, then the default check is against a clear text string. */ APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd, const char *hash) { char sample[200]; #if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char *crypt_pw; #endif if (hash[0] == '$') { if (hash[1] == '2' && (hash[2] == 'a' || hash[2] == 'y') && hash[3] == '$') { if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL) return APR_FROM_OS_ERROR(errno); } else if (!strncmp(hash, apr1_id, strlen(apr1_id))) { /* * The hash was created using our custom algorithm. */ apr_md5_encode(passwd, hash, sample, sizeof(sample)); } } else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) { apr_sha1_base64(passwd, (int)strlen(passwd), sample); } else { /* * It's not our algorithm, so feed it to crypt() if possible. */ #if defined(WIN32) || defined(BEOS) || defined(NETWARE) return (strcmp(passwd, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_CRYPTD) CRYPTD buffer; crypt_pw = crypt_r(passwd, hash, &buffer); if (!crypt_pw) { return APR_EMISMATCH; } return (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #elif defined(CRYPT_R_STRUCT_CRYPT_DATA) struct crypt_data buffer; #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,4) buffer.initialized = 0; #else /* * glibc before 2.3.2 had a bug that required clearing the * whole struct */ memset(&buffer, 0, sizeof(buffer)); #endif crypt_pw = crypt_r(passwd, hash, &buffer); if (!crypt_pw) { return APR_EMISMATCH; } return (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; #else /* Do a bit of sanity checking since we know that crypt_r() * should always be used for threaded builds on AIX, and * problems in configure logic can result in the wrong * choice being made. */ #if defined(_AIX) && APR_HAS_THREADS #error Configuration error! crypt_r() should have been selected! #endif { apr_status_t rv; /* Handle thread safety issues by holding a mutex around the * call to crypt(). */ crypt_mutex_lock(); crypt_pw = crypt(passwd, hash); if (!crypt_pw) { rv = APR_EMISMATCH; } else { rv = (strcmp(crypt_pw, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; } crypt_mutex_unlock(); return rv; } #endif } return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH; }
/* * Make a password record from the given information. A zero return * indicates success; on failure, ctx->errstr points to the error message. */ int mkhash(struct passwd_ctx *ctx) { char *pw; char pwin[MAX_STRING_LEN]; char salt[16]; apr_status_t rv; int ret = 0; #if CRYPT_ALGO_SUPPORTED char *cbuf; #endif if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { apr_file_printf(errfile, "Warning: Ignoring -C argument for this algorithm." NL); } if (ctx->passwd != NULL) { pw = ctx->passwd; } else { if ((ret = get_password(ctx)) != 0) return ret; pw = pwin; } switch (ctx->alg) { case ALG_APSHA: /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */ apr_sha1_base64(pw, strlen(pw), ctx->out); break; case ALG_APMD5: ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); if (ret != 0) break; rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "could not encode password: %pm", &rv); ret = ERR_GENERAL; } break; case ALG_PLAIN: /* XXX this len limitation is not in sync with any HTTPd len. */ apr_cpystrn(ctx->out, pw, ctx->out_len); break; #if CRYPT_ALGO_SUPPORTED case ALG_CRYPT: ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); if (ret != 0) break; cbuf = crypt(pw, salt); if (cbuf == NULL) { rv = APR_FROM_OS_ERROR(errno); ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); ret = ERR_PWMISMATCH; break; } apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); if (strlen(pw) > 8) { char *truncpw = strdup(pw); truncpw[8] = '\0'; if (!strcmp(ctx->out, crypt(truncpw, salt))) { apr_file_printf(errfile, "Warning: Password truncated to 8 " "characters by CRYPT algorithm." NL); } memset(truncpw, '\0', strlen(pw)); free(truncpw); } break; #endif /* CRYPT_ALGO_SUPPORTED */ #if BCRYPT_ALGO_SUPPORTED case ALG_BCRYPT: rv = apr_generate_random_bytes((unsigned char*)salt, 16); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random " "bytes: %pm", &rv); ret = ERR_RANDOM; break; } if (ctx->cost == 0) ctx->cost = BCRYPT_DEFAULT_COST; rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16, ctx->out, ctx->out_len); if (rv != APR_SUCCESS) { ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with " "bcrypt: %pm", &rv); ret = ERR_PWMISMATCH; break; } break; #endif /* BCRYPT_ALGO_SUPPORTED */ default: apr_file_printf(errfile, "mkhash(): BUG: invalid algorithm %d", ctx->alg); abort(); } memset(pw, '\0', strlen(pw)); return ret; }
/* * 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; }