⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_auth_digest.c

📁 apache服务器源代码(版本号:2.2.2)
💻 C
📖 第 1 页 / 共 5 页
字号:
    return num_removed;}/* * Add a new client to the list. Returns the entry if successful, NULL * otherwise. This triggers the garbage collection if memory is low. */static client_entry *add_client(unsigned long key, client_entry *info,                                server_rec *s){    int bucket;    client_entry *entry;    if (!key || !client_shm) {        return NULL;    }    bucket = key % client_list->tbl_len;    entry  = client_list->table[bucket];    apr_global_mutex_lock(client_lock);    /* try to allocate a new entry */    entry = (client_entry *)apr_rmm_malloc(client_rmm, sizeof(client_entry));    if (!entry) {        long num_removed = gc();        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,                     "Digest: gc'd %ld client entries. Total new clients: "                     "%ld; Total removed clients: %ld; Total renewed clients: "                     "%ld", num_removed,                     client_list->num_created - client_list->num_renewed,                     client_list->num_removed, client_list->num_renewed);        entry = (client_entry *)apr_rmm_malloc(client_rmm, sizeof(client_entry));        if (!entry) {            return NULL;       /* give up */        }    }    /* now add the entry */    memcpy(entry, info, sizeof(client_entry));    entry->key  = key;    entry->next = client_list->table[bucket];    client_list->table[bucket] = entry;    client_list->num_created++;    client_list->num_entries++;    apr_global_mutex_unlock(client_lock);    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,                 "allocated new client %lu", key);    return entry;}/* * Authorization header parser code *//* Parse the Authorization header, if it exists */static int get_digest_rec(request_rec *r, digest_header_rec *resp){    const char *auth_line;    apr_size_t l;    int vk = 0, vv = 0;    char *key, *value;    auth_line = apr_table_get(r->headers_in,                             (PROXYREQ_PROXY == r->proxyreq)                                 ? "Proxy-Authorization"                                 : "Authorization");    if (!auth_line) {        resp->auth_hdr_sts = NO_HEADER;        return !OK;    }    resp->scheme = ap_getword_white(r->pool, &auth_line);    if (strcasecmp(resp->scheme, "Digest")) {        resp->auth_hdr_sts = NOT_DIGEST;        return !OK;    }    l = strlen(auth_line);    key   = apr_palloc(r->pool, l+1);    value = apr_palloc(r->pool, l+1);    while (auth_line[0] != '\0') {        /* find key */        while (apr_isspace(auth_line[0])) {            auth_line++;        }        vk = 0;        while (auth_line[0] != '=' && auth_line[0] != ','               && auth_line[0] != '\0' && !apr_isspace(auth_line[0])) {            key[vk++] = *auth_line++;        }        key[vk] = '\0';        while (apr_isspace(auth_line[0])) {            auth_line++;        }        /* find value */        if (auth_line[0] == '=') {            auth_line++;            while (apr_isspace(auth_line[0])) {                auth_line++;            }            vv = 0;            if (auth_line[0] == '\"') {         /* quoted string */                auth_line++;                while (auth_line[0] != '\"' && auth_line[0] != '\0') {                    if (auth_line[0] == '\\' && auth_line[1] != '\0') {                        auth_line++;            /* escaped char */                    }                    value[vv++] = *auth_line++;                }                if (auth_line[0] != '\0') {                    auth_line++;                }            }            else {                               /* token */                while (auth_line[0] != ',' && auth_line[0] != '\0'                       && !apr_isspace(auth_line[0])) {                    value[vv++] = *auth_line++;                }            }            value[vv] = '\0';        }        while (auth_line[0] != ',' && auth_line[0] != '\0') {            auth_line++;        }        if (auth_line[0] != '\0') {            auth_line++;        }        if (!strcasecmp(key, "username"))            resp->username = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "realm"))            resp->realm = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "nonce"))            resp->nonce = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "uri"))            resp->uri = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "response"))            resp->digest = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "algorithm"))            resp->algorithm = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "cnonce"))            resp->cnonce = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "opaque"))            resp->opaque = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "qop"))            resp->message_qop = apr_pstrdup(r->pool, value);        else if (!strcasecmp(key, "nc"))            resp->nonce_count = apr_pstrdup(r->pool, value);    }    if (!resp->username || !resp->realm || !resp->nonce || !resp->uri        || !resp->digest        || (resp->message_qop && (!resp->cnonce || !resp->nonce_count))) {        resp->auth_hdr_sts = INVALID;        return !OK;    }    if (resp->opaque) {        resp->opaque_num = (unsigned long) strtol(resp->opaque, NULL, 16);    }    resp->auth_hdr_sts = VALID;    return OK;}/* Because the browser may preemptively send auth info, incrementing the * nonce-count when it does, and because the client does not get notified * if the URI didn't need authentication after all, we need to be sure to * update the nonce-count each time we receive an Authorization header no * matter what the final outcome of the request. Furthermore this is a * convenient place to get the request-uri (before any subrequests etc * are initiated) and to initialize the request_config. * * Note that this must be called after mod_proxy had its go so that * r->proxyreq is set correctly. */static int parse_hdr_and_update_nc(request_rec *r){    digest_header_rec *resp;    int res;    if (!ap_is_initial_req(r)) {        return DECLINED;    }    resp = apr_pcalloc(r->pool, sizeof(digest_header_rec));    resp->raw_request_uri = r->unparsed_uri;    resp->psd_request_uri = &r->parsed_uri;    resp->needed_auth = 0;    resp->method = r->method;    ap_set_module_config(r->request_config, &auth_digest_module, resp);    res = get_digest_rec(r, resp);    resp->client = get_client(resp->opaque_num, r);    if (res == OK && resp->client) {        resp->client->nonce_count++;    }    return DECLINED;}/* * Nonce generation code *//* The hash part of the nonce is a SHA-1 hash of the time, realm, server host * and port, opaque, and our secret. */static void gen_nonce_hash(char *hash, const char *timestr, const char *opaque,                           const server_rec *server,                           const digest_config_rec *conf){    const char *hex = "0123456789abcdef";    unsigned char sha1[APR_SHA1_DIGESTSIZE];    apr_sha1_ctx_t ctx;    int idx;    memcpy(&ctx, &conf->nonce_ctx, sizeof(ctx));    /*    apr_sha1_update_binary(&ctx, (const unsigned char *) server->server_hostname,                         strlen(server->server_hostname));    apr_sha1_update_binary(&ctx, (const unsigned char *) &server->port,                         sizeof(server->port));     */    apr_sha1_update_binary(&ctx, (const unsigned char *) timestr, strlen(timestr));    if (opaque) {        apr_sha1_update_binary(&ctx, (const unsigned char *) opaque,                             strlen(opaque));    }    apr_sha1_final(sha1, &ctx);    for (idx=0; idx<APR_SHA1_DIGESTSIZE; idx++) {        *hash++ = hex[sha1[idx] >> 4];        *hash++ = hex[sha1[idx] & 0xF];    }    *hash++ = '\0';}/* The nonce has the format b64(time)+hash . */static const char *gen_nonce(apr_pool_t *p, apr_time_t now, const char *opaque,                             const server_rec *server,                             const digest_config_rec *conf){    char *nonce = apr_palloc(p, NONCE_LEN+1);    int len;    time_rec t;    if (conf->nonce_lifetime != 0) {        t.time = now;    }    else if (otn_counter) {        /* this counter is not synch'd, because it doesn't really matter         * if it counts exactly.         */        t.time = (*otn_counter)++;    }    else {        /* XXX: WHAT IS THIS CONSTANT? */        t.time = 42;    }    len = apr_base64_encode_binary(nonce, t.arr, sizeof(t.arr));    gen_nonce_hash(nonce+NONCE_TIME_LEN, nonce, opaque, server, conf);    return nonce;}/* * Opaque and hash-table management *//* * Generate a new client entry, add it to the list, and return the * entry. Returns NULL if failed. */static client_entry *gen_client(const request_rec *r){    unsigned long op;    client_entry new_entry = { 0, NULL, 0, "", "" }, *entry;    if (!opaque_cntr) {        return NULL;    }    apr_global_mutex_lock(opaque_lock);    op = (*opaque_cntr)++;    apr_global_mutex_lock(opaque_lock);    if (!(entry = add_client(op, &new_entry, r->server))) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                      "Digest: failed to allocate client entry - ignoring "                      "client");        return NULL;    }    return entry;}/* * MD5-sess code. * * If you want to use algorithm=MD5-sess you must write get_userpw_hash() * yourself (see below). The dummy provided here just uses the hash from * the auth-file, i.e. it is only useful for testing client implementations * of MD5-sess . *//* * get_userpw_hash() will be called each time a new session needs to be * generated and is expected to return the equivalent of * * h_urp = ap_md5(r->pool, *         apr_pstrcat(r->pool, username, ":", ap_auth_name(r), ":", passwd)) * ap_md5(r->pool, *         (unsigned char *) apr_pstrcat(r->pool, h_urp, ":", resp->nonce, ":", *                                      resp->cnonce, NULL)); * * or put differently, it must return * *   MD5(MD5(username ":" realm ":" password) ":" nonce ":" cnonce) * * If something goes wrong, the failure must be logged and NULL returned. * * You must implement this yourself, which will probably consist of code * contacting the password server with the necessary information (typically * the username, realm, nonce, and cnonce) and receiving the hash from it. * * TBD: This function should probably be in a seperate source file so that * people need not modify mod_auth_digest.c each time they install a new * version of apache. */static const char *get_userpw_hash(const request_rec *r,                                   const digest_header_rec *resp,                                   const digest_config_rec *conf){    return ap_md5(r->pool,             (unsigned char *) apr_pstrcat(r->pool, conf->ha1, ":", resp->nonce,                                           ":", resp->cnonce, NULL));}/* Retrieve current session H(A1). If there is none and "generate" is * true then a new session for MD5-sess is generated and stored in the * client struct; if generate is false, or a new session could not be * generated then NULL is returned (in case of failure to generate the * failure reason will have been logged already). */static const char *get_session_HA1(const request_rec *r,                                   digest_header_rec *resp,                                   const digest_config_rec *conf,                                   int generate){    const char *ha1 = NULL;    /* return the current sessions if there is one */    if (resp->opaque && resp->client && resp->client->ha1[0]) {        return resp->client->ha1;    }    else if (!generate) {        return NULL;    }    /* generate a new session */    if (!resp->client) {        resp->client = gen_client(r);    }    if (resp->client) {        ha1 = get_userpw_hash(r, resp, conf);        if (ha1) {            memcpy(resp->client->ha1, ha1, sizeof(resp->client->ha1));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -