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

📄 mod_auth_digest.c

📁 apache服务器源代码(版本号:2.2.2)
💻 C
📖 第 1 页 / 共 5 页
字号:
    }}/* * configuration code */static void *create_digest_dir_config(apr_pool_t *p, char *dir){    digest_config_rec *conf;    if (dir == NULL) {        return NULL;    }    conf = (digest_config_rec *) apr_pcalloc(p, sizeof(digest_config_rec));    if (conf) {        conf->qop_list       = apr_palloc(p, sizeof(char*));        conf->qop_list[0]    = NULL;        conf->nonce_lifetime = DFLT_NONCE_LIFE;        conf->dir_name       = apr_pstrdup(p, dir);        conf->algorithm      = DFLT_ALGORITHM;    }    return conf;}static const char *set_realm(cmd_parms *cmd, void *config, const char *realm){    digest_config_rec *conf = (digest_config_rec *) config;    /* The core already handles the realm, but it's just too convenient to     * grab it ourselves too and cache some setups. However, we need to     * let the core get at it too, which is why we decline at the end -     * this relies on the fact that http_core is last in the list.     */    conf->realm = realm;    /* we precompute the part of the nonce hash that is constant (well,     * the host:port would be too, but that varies for .htaccess files     * and directives outside a virtual host section)     */    apr_sha1_init(&conf->nonce_ctx);    apr_sha1_update_binary(&conf->nonce_ctx, secret, sizeof(secret));    apr_sha1_update_binary(&conf->nonce_ctx, (const unsigned char *) realm,                           strlen(realm));    return DECLINE_CMD;}static const char *add_authn_provider(cmd_parms *cmd, void *config,                                      const char *arg){    digest_config_rec *conf = (digest_config_rec*)config;    authn_provider_list *newp;    newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));    newp->provider_name = apr_pstrdup(cmd->pool, arg);    /* lookup and cache the actual provider now */    newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,                                        newp->provider_name, "0");    if (newp->provider == NULL) {       /* by the time they use it, the provider should be loaded and           registered with us. */        return apr_psprintf(cmd->pool,                            "Unknown Authn provider: %s",                            newp->provider_name);    }    if (!newp->provider->get_realm_hash) {        /* if it doesn't provide the appropriate function, reject it */        return apr_psprintf(cmd->pool,                            "The '%s' Authn provider doesn't support "                            "Digest Authentication", newp->provider_name);    }    /* Add it to the list now. */    if (!conf->providers) {        conf->providers = newp;    }    else {        authn_provider_list *last = conf->providers;        while (last->next) {            last = last->next;        }        last->next = newp;    }    return NULL;}static const char *set_qop(cmd_parms *cmd, void *config, const char *op){    digest_config_rec *conf = (digest_config_rec *) config;    char **tmp;    int cnt;    if (!strcasecmp(op, "none")) {        if (conf->qop_list[0] == NULL) {            conf->qop_list = apr_palloc(cmd->pool, 2 * sizeof(char*));            conf->qop_list[1] = NULL;        }        conf->qop_list[0] = "none";        return NULL;    }    if (!strcasecmp(op, "auth-int")) {        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,                     "Digest: WARNING: qop `auth-int' currently only works "                     "correctly for responses with no entity");    }    else if (strcasecmp(op, "auth")) {        return apr_pstrcat(cmd->pool, "Unrecognized qop: ", op, NULL);    }    for (cnt = 0; conf->qop_list[cnt] != NULL; cnt++)        ;    tmp = apr_palloc(cmd->pool, (cnt + 2) * sizeof(char*));    memcpy(tmp, conf->qop_list, cnt*sizeof(char*));    tmp[cnt]   = apr_pstrdup(cmd->pool, op);    tmp[cnt+1] = NULL;    conf->qop_list = tmp;    return NULL;}static const char *set_nonce_lifetime(cmd_parms *cmd, void *config,                                      const char *t){    char *endptr;    long  lifetime;    lifetime = strtol(t, &endptr, 10);    if (endptr < (t+strlen(t)) && !apr_isspace(*endptr)) {        return apr_pstrcat(cmd->pool,                           "Invalid time in AuthDigestNonceLifetime: ",                           t, NULL);    }    ((digest_config_rec *) config)->nonce_lifetime = apr_time_from_sec(lifetime);    return NULL;}static const char *set_nonce_format(cmd_parms *cmd, void *config,                                    const char *fmt){    ((digest_config_rec *) config)->nonce_format = fmt;    return "AuthDigestNonceFormat is not implemented (yet)";}static const char *set_nc_check(cmd_parms *cmd, void *config, int flag){    if (flag && !client_shm)        ap_log_error(APLOG_MARK, APLOG_WARNING, 0,                     cmd->server, "Digest: WARNING: nonce-count checking "                     "is not supported on platforms without shared-memory "                     "support - disabling check");    ((digest_config_rec *) config)->check_nc = flag;    return NULL;}static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg){    if (!strcasecmp(alg, "MD5-sess")) {        if (!client_shm) {            ap_log_error(APLOG_MARK, APLOG_WARNING, 0,                         cmd->server, "Digest: WARNING: algorithm `MD5-sess' "                         "is not supported on platforms without shared-memory "                         "support - reverting to MD5");            alg = "MD5";        }    }    else if (strcasecmp(alg, "MD5")) {        return apr_pstrcat(cmd->pool, "Invalid algorithm in AuthDigestAlgorithm: ", alg, NULL);    }    ((digest_config_rec *) config)->algorithm = alg;    return NULL;}static const char *set_uri_list(cmd_parms *cmd, void *config, const char *uri){    digest_config_rec *c = (digest_config_rec *) config;    if (c->uri_list) {        c->uri_list[strlen(c->uri_list)-1] = '\0';        c->uri_list = apr_pstrcat(cmd->pool, c->uri_list, " ", uri, "\"", NULL);    }    else {        c->uri_list = apr_pstrcat(cmd->pool, ", domain=\"", uri, "\"", NULL);    }    return NULL;}static const char *set_shmem_size(cmd_parms *cmd, void *config,                                  const char *size_str){    char *endptr;    long  size, min;    size = strtol(size_str, &endptr, 10);    while (apr_isspace(*endptr)) endptr++;    if (*endptr == '\0' || *endptr == 'b' || *endptr == 'B') {        ;    }    else if (*endptr == 'k' || *endptr == 'K') {        size *= 1024;    }    else if (*endptr == 'm' || *endptr == 'M') {        size *= 1048576;    }    else {        return apr_pstrcat(cmd->pool, "Invalid size in AuthDigestShmemSize: ",                          size_str, NULL);    }    min = sizeof(*client_list) + sizeof(client_entry*) + sizeof(client_entry);    if (size < min) {        return apr_psprintf(cmd->pool, "size in AuthDigestShmemSize too small: "                           "%ld < %ld", size, min);    }    shmem_size  = size;    num_buckets = (size - sizeof(*client_list)) /                  (sizeof(client_entry*) + HASH_DEPTH * sizeof(client_entry));    if (num_buckets == 0) {        num_buckets = 1;    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,                 "Digest: Set shmem-size: %ld, num-buckets: %ld", shmem_size,                 num_buckets);    return NULL;}static const command_rec digest_cmds[] ={    AP_INIT_TAKE1("AuthName", set_realm, NULL, OR_AUTHCFG,     "The authentication realm (e.g. \"Members Only\")"),    AP_INIT_ITERATE("AuthDigestProvider", add_authn_provider, NULL, OR_AUTHCFG,                     "specify the auth providers for a directory or location"),    AP_INIT_ITERATE("AuthDigestQop", set_qop, NULL, OR_AUTHCFG,     "A list of quality-of-protection options"),    AP_INIT_TAKE1("AuthDigestNonceLifetime", set_nonce_lifetime, NULL, OR_AUTHCFG,     "Maximum lifetime of the server nonce (seconds)"),    AP_INIT_TAKE1("AuthDigestNonceFormat", set_nonce_format, NULL, OR_AUTHCFG,     "The format to use when generating the server nonce"),    AP_INIT_FLAG("AuthDigestNcCheck", set_nc_check, NULL, OR_AUTHCFG,     "Whether or not to check the nonce-count sent by the client"),    AP_INIT_TAKE1("AuthDigestAlgorithm", set_algorithm, NULL, OR_AUTHCFG,     "The algorithm used for the hash calculation"),    AP_INIT_ITERATE("AuthDigestDomain", set_uri_list, NULL, OR_AUTHCFG,     "A list of URI's which belong to the same protection space as the current URI"),    AP_INIT_TAKE1("AuthDigestShmemSize", set_shmem_size, NULL, RSRC_CONF,     "The amount of shared memory to allocate for keeping track of clients"),    {NULL}};/* * client list code * * Each client is assigned a number, which is transferred in the opaque * field of the WWW-Authenticate and Authorization headers. The number * is just a simple counter which is incremented for each new client. * Clients can't forge this number because it is hashed up into the * server nonce, and that is checked. * * The clients are kept in a simple hash table, which consists of an * array of client_entry's, each with a linked list of entries hanging * off it. The client's number modulo the size of the array gives the * bucket number. * * The clients are garbage collected whenever a new client is allocated * but there is not enough space left in the shared memory segment. A * simple semi-LRU is used for this: whenever a client entry is accessed * it is moved to the beginning of the linked list in its bucket (this * also makes for faster lookups for current clients). The garbage * collecter then just removes the oldest entry (i.e. the one at the * end of the list) in each bucket. * * The main advantages of the above scheme are that it's easy to implement * and it keeps the hash table evenly balanced (i.e. same number of entries * in each bucket). The major disadvantage is that you may be throwing * entries out which are in active use. This is not tragic, as these * clients will just be sent a new client id (opaque field) and nonce * with a stale=true (i.e. it will just look like the nonce expired, * thereby forcing an extra round trip). If the shared memory segment * has enough headroom over the current client set size then this should * not occur too often. * * To help tune the size of the shared memory segment (and see if the * above algorithm is really sufficient) a set of counters is kept * indicating the number of clients held, the number of garbage collected * clients, and the number of erroneously purged clients. These are printed * out at each garbage collection run. Note that access to the counters is * not synchronized because they are just indicaters, and whether they are * off by a few doesn't matter; and for the same reason no attempt is made * to guarantee the num_renewed is correct in the face of clients spoofing * the opaque field. *//* * Get the client given its client number (the key). Returns the entry, * or NULL if it's not found. * * Access to the list itself is synchronized via locks. However, access * to the entry returned by get_client() is NOT synchronized. This means * that there are potentially problems if a client uses multiple, * simultaneous connections to access url's within the same protection * space. However, these problems are not new: when using multiple * connections you have no guarantee of the order the requests are * processed anyway, so you have problems with the nonce-count and * one-time nonces anyway. */static client_entry *get_client(unsigned long key, const request_rec *r){    int bucket;    client_entry *entry, *prev = NULL;    if (!key || !client_shm)  return NULL;    bucket = key % client_list->tbl_len;    entry  = client_list->table[bucket];    apr_global_mutex_lock(client_lock);    while (entry && key != entry->key) {        prev  = entry;        entry = entry->next;    }    if (entry && prev) {                /* move entry to front of list */        prev->next  = entry->next;        entry->next = client_list->table[bucket];        client_list->table[bucket] = entry;    }    apr_global_mutex_unlock(client_lock);    if (entry) {        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                      "get_client(): client %lu found", key);    }    else {        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,                      "get_client(): client %lu not found", key);    }    return entry;}/* A simple garbage-collecter to remove unused clients. It removes the * last entry in each bucket and updates the counters. Returns the * number of removed entries. */static long gc(void){    client_entry *entry, *prev;    unsigned long num_removed = 0, idx;    /* garbage collect all last entries */    for (idx = 0; idx < client_list->tbl_len; idx++) {        entry = client_list->table[idx];        prev  = NULL;        while (entry->next) {   /* find last entry */            prev  = entry;            entry = entry->next;        }        if (prev) {            prev->next = NULL;   /* cut list */        }        else {            client_list->table[idx] = NULL;        }        if (entry) {                    /* remove entry */            apr_rmm_free(client_rmm, (apr_rmm_off_t)entry);            num_removed++;        }    }    /* update counters and log */    client_list->num_entries -= num_removed;    client_list->num_removed += num_removed;

⌨️ 快捷键说明

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