Beispiel #1
0
/* Check that a nonce is one that we issued, and that the response is what is
   expected. This doesn't do any checking against the lifetime of the nonce. */
int http_digest_check_credentials(const char *username, const char *realm,
    const char *password, const char *method,
    const struct http_credentials *credentials)
{
    char response_hex[MD5_DIGEST_LENGTH * 2 + 1];
    struct timeval tv;
    char *nonce;

    if (credentials->scheme != AUTH_DIGEST
        || credentials->u.digest.username == NULL
        || credentials->u.digest.realm == NULL
        || credentials->u.digest.nonce == NULL
        || credentials->u.digest.uri == NULL
        || credentials->u.digest.response == NULL) {
        return 0;
    }
    if (credentials->u.digest.qop != QOP_NONE && credentials->u.digest.qop != QOP_AUTH)
        return 0;
    if (credentials->u.digest.qop == QOP_AUTH
        && (credentials->u.digest.nc == NULL
            || credentials->u.digest.cnonce == NULL)) {
        return 0;
    }

    if (strcmp(username, credentials->u.digest.username) != 0)
        return 0;
    if (strcmp(realm, credentials->u.digest.realm) != 0)
        return 0;

    if (http_digest_nonce_time(credentials->u.digest.nonce, &tv) == -1)
        return 0;

    nonce = make_nonce(&tv);
    if (strcmp(nonce, credentials->u.digest.nonce) != 0) {
        /* We could not have handed out this nonce. */
        free(nonce);
        return 0;
    }
    free(nonce);

    make_response(response_hex, credentials->u.digest.username, realm,
        password, method, credentials->u.digest.uri,
        credentials->u.digest.nonce, credentials->u.digest.qop,
        credentials->u.digest.nc, credentials->u.digest.cnonce);

    return strcmp(response_hex, credentials->u.digest.response) == 0;
}
/* userpass is a user:pass string (the argument to --proxy-auth). value is the
   value of the Proxy-Authorization header field. Returns 0 on authentication
   failure and nonzero on success. *stale is set to 1 if HTTP Digest credentials
   are valid but out of date. */
static int check_auth(const struct http_request *request,
    const struct http_credentials *credentials, int *stale)
{
    if (o.proxy_auth == NULL)
        return 1;

    *stale = 0;

    if (credentials->scheme == AUTH_BASIC) {
        char *expected;
        int cmp;

        if (credentials->u.basic == NULL)
            return 0;

        /* We don't decode the received password, we encode the expected
           password and compare the encoded strings. */
        expected = b64enc((unsigned char *) o.proxy_auth, strlen(o.proxy_auth));
        cmp = strcmp(expected, credentials->u.basic);
        free(expected);

        return cmp == 0;
    }
#if HAVE_HTTP_DIGEST
    else if (credentials->scheme == AUTH_DIGEST) {
        char *username, *password;
        char *proxy_auth;
        struct timeval nonce_tv, now;
        int nonce_age;
        int ret;

        /* Split up the proxy auth argument. */
        proxy_auth = Strdup(o.proxy_auth);
        username = strtok(proxy_auth, ":");
        password = strtok(NULL, ":");
        if (password == NULL) {
            free(proxy_auth);
            return 0;
        }
        ret = http_digest_check_credentials(username, "Ncat", password,
            request->method, credentials);
        free(proxy_auth);

        if (!ret)
            return 0;

        /* The nonce checks out as one we issued and it matches what we expect
           given the credentials. Now check if it's too old. */
        if (credentials->u.digest.nonce == NULL
            || http_digest_nonce_time(credentials->u.digest.nonce, &nonce_tv) == -1)
            return 0;
        gettimeofday(&now, NULL);
        if (TIMEVAL_AFTER(nonce_tv, now))
            return 0;
        nonce_age = TIMEVAL_SEC_SUBTRACT(now, nonce_tv);

        if (nonce_age > HTTP_DIGEST_NONCE_EXPIRY) {
            if (o.verbose)
                loguser("Nonce is %d seconds old; rejecting.\n", nonce_age);
            *stale = 1;
            return 0;
        }

        /* To prevent replays, here we should additionally check against a list
           of recently used nonces, where "recently used nonce" is one that has
           been used to successfully authenticate within the last
           HTTP_DIGEST_NONCE_EXPIRY seconds. (Older than that and we don't need
           to keep it in the list, because the expiry test above will catch it.
           This isn't supported because the fork-and-process architecture of the
           proxy server makes it hard for us to change state in the parent
           process from here in the child. */

        return 1;
    }
#endif
    else {
        return 0;
    }
}