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

📄 mod_auth_digest.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * mod_auth_digest: MD5 digest authentication * * Originally by Alexei Kosut <akosut@nueva.pvt.k12.ca.us> * Updated to RFC-2617 by Ronald Tschal鋜 <ronald@innovation.ch> * based on mod_auth, by Rob McCool and Robert S. Thau * * This module an updated version of modules/standard/mod_digest.c * It is still fairly new and problems may turn up - submit problem * reports to the Apache bug-database, or send them directly to me * at ronald@innovation.ch. * * Requires either /dev/random (or equivalent) or the truerand library, * available for instance from * ftp://research.att.com/dist/mab/librand.shar * * Open Issues: *   - qop=auth-int (when streams and trailer support available) *   - nonce-format configurability *   - Proxy-Authorization-Info header is set by this module, but is *     currently ignored by mod_proxy (needs patch to mod_proxy) *   - generating the secret takes a while (~ 8 seconds) if using the *     truerand library *   - The source of the secret should be run-time directive (with server *     scope: RSRC_CONF). However, that could be tricky when trying to *     choose truerand vs. file... *   - shared-mem not completely tested yet. Seems to work ok for me, *     but... (definitely won't work on Windoze) *   - Sharing a realm among multiple servers has following problems: *     o Server name and port can't be included in nonce-hash *       (we need two nonce formats, which must be configured explicitly) *     o Nonce-count check can't be for equal, or then nonce-count checking *       must be disabled. What we could do is the following: *       (expected < received) ? set expected = received : issue error *       The only problem is that it allows replay attacks when somebody *       captures a packet sent to one server and sends it to another *       one. Should we add "AuthDigestNcCheck Strict"? *   - expired nonces give amaya fits.   */#include "apr_sha1.h"#include "apr_base64.h"#include "apr_lib.h"#include "apr_time.h"#include "apr_errno.h"#include "apr_global_mutex.h"#include "apr_strings.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_core.h"#include "http_request.h"#include "http_log.h"#include "http_protocol.h"#include "apr_uri.h"#include "util_md5.h"#include "apr_shm.h"#include "apr_rmm.h"/* Disable shmem until pools/init gets sorted out  * remove following two lines when fixed  */#undef APR_HAS_SHARED_MEMORY#define APR_HAS_SHARED_MEMORY 0/* struct to hold the configuration info */typedef struct digest_config_struct {    const char  *dir_name;    const char  *pwfile;    const char  *grpfile;    const char  *realm;    char **qop_list;    apr_sha1_ctx_t  nonce_ctx;    apr_time_t    nonce_lifetime;    const char  *nonce_format;    int          check_nc;    const char  *algorithm;    char        *uri_list;    const char  *ha1;} digest_config_rec;#define DFLT_ALGORITHM  "MD5"#define DFLT_NONCE_LIFE apr_time_from_sec(300)#define NEXTNONCE_DELTA apr_time_from_sec(30)#define NONCE_TIME_LEN  (((sizeof(apr_time_t)+2)/3)*4)#define NONCE_HASH_LEN  (2*APR_SHA1_DIGESTSIZE)#define NONCE_LEN       (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)#define SECRET_LEN      20/* client list definitions */typedef struct hash_entry {    unsigned long      key;                     /* the key for this entry    */    struct hash_entry *next;                    /* next entry in the bucket  */    unsigned long      nonce_count;             /* for nonce-count checking  */    char               ha1[2*MD5_DIGESTSIZE+1]; /* for algorithm=MD5-sess    */    char               last_nonce[NONCE_LEN+1]; /* for one-time nonce's      */} client_entry;static struct hash_table {    client_entry  **table;    unsigned long   tbl_len;    unsigned long   num_entries;    unsigned long   num_created;    unsigned long   num_removed;    unsigned long   num_renewed;} *client_list;/* struct to hold a parsed Authorization header */enum hdr_sts { NO_HEADER, NOT_DIGEST, INVALID, VALID };typedef struct digest_header_struct {    const char           *scheme;    const char           *realm;    const char           *username;          char           *nonce;    const char           *uri;    const char           *method;    const char           *digest;    const char           *algorithm;    const char           *cnonce;    const char           *opaque;    unsigned long         opaque_num;    const char           *message_qop;    const char           *nonce_count;    /* the following fields are not (directly) from the header */    apr_time_t            nonce_time;    enum hdr_sts          auth_hdr_sts;    const char           *raw_request_uri;    apr_uri_t            *psd_request_uri;    int                   needed_auth;    client_entry         *client;} digest_header_rec;/* (mostly) nonce stuff */typedef union time_union {    apr_time_t    time;    unsigned char arr[sizeof(apr_time_t)];} time_rec;static unsigned char secret[SECRET_LEN];/* client-list, opaque, and one-time-nonce stuff */static apr_shm_t      *client_shm =  NULL;static apr_rmm_t      *client_rmm = NULL;static unsigned long  *opaque_cntr;static apr_time_t     *otn_counter;     /* one-time-nonce counter */static apr_global_mutex_t *client_lock = NULL;static apr_global_mutex_t *opaque_lock = NULL;static char           client_lock_name[L_tmpnam];static char           opaque_lock_name[L_tmpnam];#define DEF_SHMEM_SIZE  1000L           /* ~ 12 entries */#define DEF_NUM_BUCKETS 15L#define HASH_DEPTH      5static long shmem_size  = DEF_SHMEM_SIZE;static long num_buckets = DEF_NUM_BUCKETS;module AP_MODULE_DECLARE_DATA auth_digest_module;/* * initialization code */static apr_status_t cleanup_tables(void *not_used){    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,                   "Digest: cleaning up shared memory");    fflush(stderr);    if (client_shm) {        apr_shm_destroy(client_shm);        client_shm = NULL;    }    if (client_lock) {        apr_global_mutex_destroy(client_lock);        client_lock = NULL;    }    if (opaque_lock) {        apr_global_mutex_destroy(opaque_lock);        opaque_lock = NULL;    }    return APR_SUCCESS;}static apr_status_t initialize_secret(server_rec *s){    apr_status_t status;    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,                 "Digest: generating secret for digest authentication ...");#if APR_HAS_RANDOM    status = apr_generate_random_bytes(secret, sizeof(secret));#else#error APR random number support is missing; you probably need to install the truerand library.#endif    if (status != APR_SUCCESS) {        char buf[120];        ap_log_error(APLOG_MARK, APLOG_CRIT, status, s,                     "Digest: error generating secret: %s",                      apr_strerror(status, buf, sizeof(buf)));        return status;    }    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "Digest: done");    return APR_SUCCESS;}static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s){    ap_log_error(APLOG_MARK, APLOG_ERR, sts, s,                 "Digest: %s - all nonce-count checking, one-time nonces, and "                 "MD5-sess algorithm disabled", msg);    cleanup_tables(NULL);}#if APR_HAS_SHARED_MEMORYstatic void initialize_tables(server_rec *s, apr_pool_t *ctx){    unsigned long idx;    apr_status_t   sts;    /* set up client list */    sts = apr_shm_create(&client_shm, shmem_size, tmpnam(NULL), ctx);    if (sts != APR_SUCCESS) {        log_error_and_cleanup("failed to create shared memory segments", sts, s);        return;    }    client_list = apr_rmm_malloc(client_rmm, sizeof(*client_list) +                                            sizeof(client_entry*)*num_buckets);    if (!client_list) {        log_error_and_cleanup("failed to allocate shared memory", -1, s);        return;    }    client_list->table = (client_entry**) (client_list + 1);    for (idx = 0; idx < num_buckets; idx++) {        client_list->table[idx] = NULL;    }    client_list->tbl_len     = num_buckets;    client_list->num_entries = 0;    tmpnam(client_lock_name);    /* FIXME: get the client_lock_name from a directive so we're portable     * to non-process-inheriting operating systems, like Win32. */    sts = apr_global_mutex_create(&client_lock, client_lock_name,                                  APR_LOCK_DEFAULT, ctx);    if (sts != APR_SUCCESS) {        log_error_and_cleanup("failed to create lock (client_lock)", sts, s);        return;    }    /* setup opaque */    opaque_cntr = apr_rmm_malloc(client_rmm, sizeof(*opaque_cntr));    if (opaque_cntr == NULL) {        log_error_and_cleanup("failed to allocate shared memory", -1, s);        return;    }    *opaque_cntr = 1UL;    tmpnam(opaque_lock_name);    /* FIXME: get the opaque_lock_name from a directive so we're portable     * to non-process-inheriting operating systems, like Win32. */    sts = apr_global_mutex_create(&opaque_lock, opaque_lock_name,                                  APR_LOCK_DEFAULT, ctx);    if (sts != APR_SUCCESS) {        log_error_and_cleanup("failed to create lock (opaque_lock)", sts, s);        return;    }    /* setup one-time-nonce counter */    otn_counter = apr_rmm_malloc(client_rmm, sizeof(*otn_counter));    if (otn_counter == NULL) {        log_error_and_cleanup("failed to allocate shared memory", -1, s);        return;    }    *otn_counter = 0;    /* no lock here */    /* success */    return;}#endif /* APR_HAS_SHARED_MEMORY */static int initialize_module(apr_pool_t *p, apr_pool_t *plog,                             apr_pool_t *ptemp, server_rec *s){    void *data;    const char *userdata_key = "auth_digest_init";    /* initialize_module() will be called twice, and if it's a DSO     * then all static data from the first call will be lost. Only     * set up our static data on the second call. */    apr_pool_userdata_get(&data, userdata_key, s->process->pool);    if (!data) {        apr_pool_userdata_set((const void *)1, userdata_key,                               apr_pool_cleanup_null, s->process->pool);        return OK;    }    if (initialize_secret(s) != APR_SUCCESS) {        return !OK;    }#if APR_HAS_SHARED_MEMORY    /* Note: this stuff is currently fixed for the lifetime of the server,     * i.e. even across restarts. This means that A) any shmem-size     * configuration changes are ignored, and B) certain optimizations,     * such as only allocating the smallest necessary entry for each     * client, can't be done. However, the alternative is a nightmare:     * we can't call apr_shm_destroy on a graceful restart because there     * will be children using the tables, and we also don't know when the     * last child dies. Therefore we can never clean up the old stuff,     * creating a creeping memory leak.     */    initialize_tables(s, p);    apr_pool_cleanup_register(p, NULL, cleanup_tables, apr_pool_cleanup_null);#endif  /* APR_HAS_SHARED_MEMORY */    return OK;}static void initialize_child(apr_pool_t *p, server_rec *s){    apr_status_t sts;    if (!client_shm) {        return;    }    /* FIXME: get the client_lock_name from a directive so we're portable     * to non-process-inheriting operating systems, like Win32. */    sts = apr_global_mutex_child_init(&client_lock, client_lock_name, p);    if (sts != APR_SUCCESS) {        log_error_and_cleanup("failed to create lock (client_lock)", sts, s);        return;    }    /* FIXME: get the opaque_lock_name from a directive so we're portable     * to non-process-inheriting operating systems, like Win32. */    sts = apr_global_mutex_child_init(&opaque_lock, opaque_lock_name, p);    if (sts != APR_SUCCESS) {        log_error_and_cleanup("failed to create lock (opaque_lock)", sts, s);        return;    }}/* * configuration code */static void *create_digest_dir_config(apr_pool_t *p, char *dir){

⌨️ 快捷键说明

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