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;
}
예제 #2
0
파일: testpass.c 프로젝트: dtrebbien/apr
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));
}
예제 #3
0
// 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;
}
예제 #4
0
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));
}
예제 #5
0
파일: htdbm.c 프로젝트: Distrotech/httpd
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);
    }
}
예제 #7
0
/*
 * 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;
}
예제 #8
0
/*
 * 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;
}
예제 #9
0
/*
 * 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;
}
예제 #10
0
/*
 * 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;
}