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

📄 mod_auth_digest.c

📁 apache 安装教程 apache 安装教程
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 * However, it has not been extensively tested yet, and is therefore * currently marked experimental. Send problem reports to me * (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"? *//* The section for the Configure script: * MODULE-DEFINITION-START * Name: digest_auth_module * ConfigStart    RULE_DEV_RANDOM=`./helpers/CutRule DEV_RANDOM $file`    if [ "$RULE_DEV_RANDOM" = "default" ]; then	if [ -r "/dev/random" ]; then	    RULE_DEV_RANDOM="/dev/random"	elif [ -r "/dev/urandom" ]; then	    RULE_DEV_RANDOM="/dev/urandom"	else	    RULE_DEV_RANDOM="truerand"	    if helpers/TestCompile func randbyte; then		:	    elif helpers/TestCompile lib rand randbyte; then		:	    else		echo "      (mod_auth_digest) truerand library missing!"		echo "** This will most probably defeat successful compilation."		echo "** See Rule DEV_RANDOM in src/Configuration.tmpl for more information."	    fi	fi    fi    if [ "$RULE_DEV_RANDOM" = "truerand" ]; then	echo "      using truerand library (-lrand) for the random seed"	LIBS="$LIBS -L/usr/local/lib -lrand"    else	echo "      using $RULE_DEV_RANDOM for the random seed"	CFLAGS="$CFLAGS -DDEV_RANDOM=$RULE_DEV_RANDOM"    fi * ConfigEnd * MODULE-DEFINITION-END */#include "httpd.h"#include "http_config.h"#include "http_conf_globals.h"#include "http_core.h"#include "http_request.h"#include "http_log.h"#include "http_protocol.h"#include "ap_config.h"#include "ap_ctype.h"#include "util_uri.h"#include "util_md5.h"#include "ap_sha1.h"#ifdef WIN32/* Crypt APIs are available on Win95 with OSR 2 */#include <wincrypt.h>#endif#ifdef HAVE_SHMEM_MM#include "mm.h"#endif	/* HAVE_SHMEM_MM *//* struct to hold the configuration info */typedef struct digest_config_struct {    const char  *dir_name;    const char  *pwfile;    const char  *grpfile;    const char  *realm;    const char **qop_list;    AP_SHA1_CTX  nonce_ctx;    long         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	300L#define NEXTNONCE_DELTA	30#define NONCE_TIME_LEN	(((sizeof(time_t)+2)/3)*4)#define NONCE_HASH_LEN	(2*SHA_DIGESTSIZE)#define NONCE_LEN	(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           *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 */    time_t                nonce_time;    enum hdr_sts          auth_hdr_sts;    const char           *raw_request_uri;    uri_components       *psd_request_uri;    int                   needed_auth;    client_entry         *client;} digest_header_rec;/* (mostly) nonce stuff */typedef union time_union {    time_t	  time;    unsigned char arr[sizeof(time_t)];} time_rec;static unsigned char secret[SECRET_LEN];static int call_cnt = 0;#ifdef HAVE_SHMEM_MM/* opaque stuff */static MM            *opaque_mm;static unsigned long *opaque_cntr;static MM            *client_mm;static MM            *otn_count_mm;static time_t        *otn_counter;	/* one-time-nonce counter */#define	SHMEM_SIZE 	1000		/* ~ 12 entries */#define	NUM_BUCKETS	15UL#else	/* HAVE_SHMEM_MM */static void          *client_mm = NULL;#endif	/* HAVE_SHMEM_MM */module MODULE_VAR_EXPORT digest_auth_module;/* * initialization code */#ifdef HAVE_SHMEM_MMstatic void cleanup_tables(void *not_used){    fprintf(stderr, "Digest: cleaning up shared memory\n");    fflush(stderr);    if (client_mm) {	mm_destroy(client_mm);	client_mm = NULL;    }    if (opaque_mm) {	mm_destroy(opaque_mm);	opaque_mm = NULL;    }    if (otn_count_mm) {	mm_destroy(otn_count_mm);	otn_count_mm = NULL;    }}#endif	/* HAVE_SHMEM_MM */#ifdef __OpenBSD__static void initialize_secret(server_rec *s){    u_int32_t rnd = 0, i;    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s,		 "Digest: generating secret for digest authentication ...");    for (i = 0; i < sizeof(secret); i++) {	if (i % 4 == 0)	    rnd = arc4random();	secret[i] = rnd;	rnd >>= 8;    }    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s,		 "Digest: done");}#elif defined(WIN32)/* TODO: abstract out the random number generation. APR? */static void initialize_secret(server_rec *s){    HCRYPTPROV hProv;    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s,		 "Digest: generating secret for digest authentication ...");    if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,0)) {        ap_log_error(APLOG_MARK, APLOG_CRIT, s,                      "Digest: Error acquiring context. Errno = %d",                     GetLastError());        exit(EXIT_FAILURE);    }    if (!CryptGenRandom(hProv,sizeof(secret),secret)) {        ap_log_error(APLOG_MARK, APLOG_CRIT, s,                      "Digest: Error generating secret. Errno = %d",                     GetLastError());        exit(EXIT_FAILURE);    }    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, "Digest: done");}#elsestatic void initialize_secret(server_rec *s){#ifdef	DEV_RANDOM    int rnd;    ssize_t got;    size_t tot;#else    extern int randbyte(void);	/* from the truerand library */    unsigned int idx;#endif    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s,		 "Digest: generating secret for digest authentication ...");#ifdef	DEV_RANDOM#define	XSTR(x)	#x#define	STR(x)	XSTR(x)    if ((rnd = open(STR(DEV_RANDOM), O_RDONLY)) == -1) {	ap_log_error(APLOG_MARK, APLOG_CRIT, s,		     "Digest: Couldn't open " STR(DEV_RANDOM));	exit(EXIT_FAILURE);    }    for (tot=0; tot<sizeof(secret); tot += got) {	if ((got = read(rnd, secret+tot, sizeof(secret)-tot)) < 0) {	    ap_log_error(APLOG_MARK, APLOG_CRIT, s,			 "Digest: Error reading " STR(DEV_RANDOM));	    exit(EXIT_FAILURE);	}    }    close(rnd);#undef	STR#undef	XSTR#else	/* use truerand */    /* this will increase the startup time of the server, unfortunately...     * (generating 20 bytes takes about 8 seconds)     */    for (idx=0; idx<sizeof(secret); idx++)	secret[idx] = (unsigned char) randbyte();#endif	/* DEV_RANDOM */    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, "Digest: done");}#endif#ifdef HAVE_SHMEM_MMstatic void initialize_tables(server_rec *s){    unsigned long idx;    /* set up client list */    client_mm = mm_create(SHMEM_SIZE, tmpnam(NULL));    if (client_mm == NULL)	goto failed;#ifdef MPE    if (geteuid() == 1) {#else    if (geteuid() == 0) {#endif	if (mm_permission(client_mm, 0600, ap_user_id, ap_group_id))	    goto failed;    }    client_list = mm_malloc(client_mm, sizeof(*client_list) +				       sizeof(client_entry*)*NUM_BUCKETS);    if (!client_list)  goto failed;    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;    /* setup opaque */    opaque_mm = mm_create(sizeof(*opaque_cntr), tmpnam(NULL));    if (opaque_mm == NULL)	goto failed;#ifdef MPE    if (geteuid() == 1) {#else    if (geteuid() == 0) {#endif	if (mm_permission(opaque_mm, 0600, ap_user_id, ap_group_id))	    goto failed;    }    opaque_cntr = mm_malloc(opaque_mm, sizeof(*opaque_cntr));    if (opaque_cntr == NULL)	goto failed;    *opaque_cntr = 1UL;    /* setup one-time-nonce counter */    otn_count_mm = mm_create(sizeof(*otn_counter), tmpnam(NULL));    if (otn_count_mm == NULL)	goto failed;#ifdef MPE    if (geteuid() == 1) {#else    if (geteuid() == 0) {#endif	if (mm_permission(otn_count_mm, 0600, ap_user_id, ap_group_id))	    goto failed;    }    otn_counter = mm_malloc(otn_count_mm, sizeof(*otn_counter));    if (otn_counter == NULL)	goto failed;    *otn_counter = 0;    /* success */    return;failed:    if (!client_mm || (client_list && client_list->table && !opaque_mm)	|| (opaque_cntr && !otn_count_mm))	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s,		     "Digest: failed to create shared memory segments; reason "		     "was `%s' - all nonce-count checking, one-time nonces, "		     "and MD5-sess algorithm disabled", mm_error());    else	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s,		     "Digest: failed to allocate shared mem; reason was `%s' "		     "- all nonce-count checking, one-time nonces, and "		     "MD5-sess algorithm disabled", mm_error());    cleanup_tables(NULL);}#endif	/* HAVE_SHMEM_MM */static void initialize_module(server_rec *s, pool *p){    /* keep from doing the init more than once at startup, and delay     * the init until the second round     */    if (++call_cnt < 2)	return;    /* only initialize the secret on startup, not on restarts */    if (call_cnt == 2)	initialize_secret(s);#ifdef HAVE_SHMEM_MM    /* 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 mm_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);    /* atexit(cleanup_tables); */    ap_register_cleanup(p, NULL, cleanup_tables, ap_null_cleanup);#endif	/* HAVE_SHMEM_MM */}/* * configuration code */static void *create_digest_dir_config(pool *p, char *dir){    digest_config_rec *conf;    if (dir == NULL)  return NULL;    conf = (digest_config_rec *) ap_pcalloc(p, sizeof(digest_config_rec));    if (conf) {	conf->qop_list       = ap_palloc(p, sizeof(char*));	conf->qop_list[0]    = NULL;	conf->nonce_lifetime = DFLT_NONCE_LIFE;	conf->dir_name       = ap_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)     */    ap_SHA1Init(&conf->nonce_ctx);    ap_SHA1Update_binary(&conf->nonce_ctx, secret, sizeof(secret));    ap_SHA1Update_binary(&conf->nonce_ctx, (const unsigned char *) realm,			 strlen(realm));    return DECLINE_CMD;}static const char *set_digest_file(cmd_parms *cmd, void *config,				   const char *file){    ((digest_config_rec *) config)->pwfile = file;    return NULL;

⌨️ 快捷键说明

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