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

📄 httpauth.c

📁 站点映像程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    HTTP Authentication routines   Copyright (C) 1999, Joe Orton <joe@orton.demon.co.uk>                                                                        This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.     This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.     You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   $Id: httpauth.c,v 1.10.2.8 1999/07/26 10:49:12 joe Exp $*/#include <config.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#include <stdio.h>#ifdef HAVE_STRING_H#include <string.h>#endif#include <time.h>#include "dates.h"#include "base64.h"#include "md5.h"#include "strsplit.h"#include "common.h"#include "httpdav.h"#include "httpauth.h"/* HTTP Authentication, as per RFC2617. *//* The challenge parameters */typedef struct {    http_auth_scheme_t scheme;    char *realm;    char *domain;    char *nonce;    char *opaque;    bool stale;    http_auth_algorithm_t alg;    bool got_qop; /* we were given a qop directive */    bool qop_auth; /* "auth" token in qop attrib */    bool qop_auth_int; /* "auth-int" token in qop attrib */} http_auth_chall_t;const char *http_auth_qop_values[] = {    NULL,    "auth",    "auth-int"};const char *http_auth_alg_names[] = {    "MD5",    "MD5-sess",    NULL};char *http_auth_get_cnonce(void);void http_auth_clean( http_auth_session_t *sess );bool http_auth_challenge_digest( http_auth_session_t *, http_auth_chall_t * );bool http_auth_challenge_basic( http_auth_session_t *, http_auth_chall_t * );char *http_auth_request_digest( http_auth_session_t * );char *http_auth_request_basic( http_auth_session_t * );/* Initialize an auth session */void http_auth_init( http_auth_session_t *sess, 		     const char *username, const char *password ) {    /* Initialize the session information */    memset( sess, 0, sizeof( http_auth_session_t ) );    /* Remember the username+password */    sess->username = username;    sess->password = password;}/* Start a new request */void http_auth_new_request( http_auth_session_t *sess,			    const char *method, const char *uri,			    const char *body_buffer, FILE *body_stream ) {    sess->uri = uri;    sess->method = method;    sess->got_body = (body_buffer!=NULL) || (body_stream!=NULL);    sess->body_buffer = body_buffer;    sess->body_stream = body_stream;    md5_init_ctx( &sess->response_body );}void http_auth_clean( http_auth_session_t *sess ) {#define DOFREE( x ) \    if( x != NULL ) {					\	DEBUG( DEBUG_HTTPAUTH, "Freeing " #x "\n" ); 	\	free( x ); x = NULL; 				\    } else {						\	DEBUG( DEBUG_HTTPAUTH, "Not freeing " #x "\n" );	\    }    DOFREE( sess->basic );    DOFREE( sess->unq_realm );    DOFREE( sess->unq_nonce );    DOFREE( sess->unq_cnonce );    DOFREE( sess->opaque );#undef DOFREE}void http_auth_finish( http_auth_session_t *sess ) {    sess->scheme = http_auth_scheme_none;    http_auth_clean( sess );}/* Returns cnonce-value. We just use base64( time ). * TODO: Could improve this? */char *http_auth_get_cnonce(void) {    char *ret, *tmp;    tmp = rfc1123_date( time(NULL) );    ret = base64( tmp );    free( tmp );    return ret;}/* Add authentication creditials to a request */char *http_auth_request( http_auth_session_t *sess) {    switch( sess->scheme ) {    case http_auth_scheme_basic:	return http_auth_request_basic( sess );	break;    case http_auth_scheme_digest:	return http_auth_request_digest( sess );	break;    default:	break;    }    return NULL;}/* Examine a Basic auth challenge */bool http_auth_challenge_basic( http_auth_session_t *sess, 				http_auth_chall_t *parms ) {    char *tmp;    /* Verify challenge... must have realm, even though we ignore it. */    if( parms->realm == NULL )	return false;    DEBUG( DEBUG_HTTPAUTH, "Got Basic challenge with realm [%s]\n", 	   parms->realm );    sess->scheme = http_auth_scheme_basic;    /* +2 = one for ':' + one for '\0' */    tmp = malloc( strlen(sess->username) + strlen(sess->password) +		  2 );    strcpy( tmp, sess->username );    strcat( tmp, ":" );    strcat( tmp, sess->password );        sess->basic = base64( tmp );    free( tmp );    return true;    }/* Add Basic authentication credentials to a request */char *http_auth_request_basic( http_auth_session_t *sess ) {    char *buf;    /* 6 for "Basic ", 2 for \r\n, 1 for \0 */    buf = malloc( 6 + strlen(sess->basic) + 2 + 1 );    strcpy( buf, "Basic " );    strcat( buf, sess->basic );    strcat( buf, "\r\n" );    return buf;}bool http_auth_challenge_digest( http_auth_session_t *sess,				 http_auth_chall_t *parms ) {    struct md5_ctx a1, tmp;    unsigned char a1_md5[16], tmp_md5[16];    char tmp_md5_ascii[33];    /* Do we understand this challenge? */    if( parms->alg == http_auth_alg_unknown ) {	DEBUG( DEBUG_HTTPAUTH, "Unknown algorithm.\n" );	return false;    }    if( (parms->alg == http_auth_alg_md5_sess) &&	!( parms->qop_auth || parms->qop_auth_int ) ) {	DEBUG( DEBUG_HTTPAUTH, "Server did not give qop with MD5-session alg.\n" );	return false;    }    if( (parms->realm==NULL) || (parms->nonce==NULL) ) {	DEBUG( DEBUG_HTTPAUTH, "Challenge missing nonce or realm.\n" );	return false;    }    DEBUG( DEBUG_HTTPAUTH, "In digest challenge.\n" );    sess->alg = parms->alg;    sess->scheme = http_auth_scheme_digest;    sess->unq_realm = strstrip(parms->realm, '"' );    sess->unq_nonce = strstrip(parms->nonce, '"' );    sess->unq_cnonce = http_auth_get_cnonce();    if( parms->opaque != NULL ) {	sess->opaque = strdup( parms->opaque ); /* don't strip the quotes */    }    if( parms->got_qop ) {	/* What type of qop are we to apply to the message? */	DEBUG( DEBUG_HTTPAUTH, "Got qop directive.\n" );	sess->nonce_count = 0;	if( parms->qop_auth_int ) {	    sess->qop = http_auth_qop_auth_int;	} else {	    sess->qop = http_auth_qop_auth;	}    } else {	/* No qop at all/ */	sess->qop = http_auth_qop_none;    }    if( sess->alg == http_auth_alg_md5_sess ) {	/* Calculate the session H(A1)	 *  tmp = H( unq(username-value) ":" unq(realm-value) ":" passwd )	 */	DEBUG( DEBUG_HTTPAUTH, "Calculating H(A1) for session.\n" );	md5_init_ctx( &a1 );	md5_init_ctx( &tmp );	md5_process_bytes( sess->username, strlen(sess->username), &tmp);	md5_process_bytes( ":", 1, &tmp );	md5_process_bytes( sess->unq_realm, strlen(sess->unq_realm), &tmp );	md5_process_bytes( ":", 1, &tmp );	md5_process_bytes( sess->password, strlen(sess->password), &tmp);	md5_finish_ctx( &tmp, tmp_md5 );	md5_hexify( tmp_md5, tmp_md5_ascii );	/* Now we calculate A1 proper:	 *    A1 = H( ...above...) ":" unq(nonce-value) ":" unq(cnonce-value) 	 */	md5_process_bytes( tmp_md5_ascii, 32, &a1 );	md5_process_bytes( ":", 1, &a1 );	md5_process_bytes( sess->unq_nonce, strlen(sess->unq_nonce), &a1 );	md5_process_bytes( ":", 1, &a1 );	md5_process_bytes( sess->unq_cnonce, strlen(sess->unq_cnonce), &a1 );	md5_finish_ctx( &a1, a1_md5 );	md5_hexify( a1_md5, sess->h_a1 );	DEBUG( DEBUG_HTTPAUTH, "Session H(A1) is [%s]\n", sess->h_a1 );    }    DEBUG( DEBUG_HTTPAUTH, "I like this Digest challenge.\n" );    return true;}/* Return Digest authentication credentials header value for the given * session. */char *http_auth_request_digest( http_auth_session_t *sess ) {    struct md5_ctx a1, a2, rdig;    unsigned char a1_md5[16], a2_md5[16], rdig_md5[16];    char a1_md5_ascii[33], a2_md5_ascii[33], rdig_md5_ascii[33];    char nc_value[9] = {0}, *ret;    const char *qop_value; /* qop-value */    size_t retlen;    /* Increase the nonce-count */    if( sess->qop != http_auth_qop_none ) {	sess->nonce_count++;	sprintf( nc_value, "%08x", sess->nonce_count );	DEBUG( DEBUG_HTTPAUTH, "Nonce count is %d, nc is [%s]\n", 	       sess->nonce_count, nc_value );    }    qop_value = http_auth_qop_values[sess->qop];    /* If we are not using MD5-session, calculate H(A1) etc */    if( sess->alg == http_auth_alg_md5 ) {	md5_init_ctx( &a1 );	md5_process_bytes( sess->username, strlen( sess->username ), &a1 );	md5_process_bytes( ":", 1, &a1 );	md5_process_bytes( sess->unq_realm, strlen( sess->unq_realm ), &a1 );	md5_process_bytes( ":", 1, &a1 );	md5_process_bytes( sess->password, strlen( sess->password ), &a1 );	md5_finish_ctx( &a1, a1_md5 );	md5_hexify( a1_md5, a1_md5_ascii );	DEBUG( DEBUG_HTTPAUTH, "New H(A1): %s\n", a1_md5_ascii );    } /* Otherwise, we reuse the session H(A1) */    /* Calculate H(A2). */    md5_init_ctx( &a2 );    md5_process_bytes( sess->method, strlen(sess->method), &a2 );    md5_process_bytes( ":", 1, &a2 );    md5_process_bytes( sess->uri, strlen(sess->uri), &a2 );    if( sess->qop == http_auth_qop_auth_int ) {	/* Calculate H(entity-body) */	if( sess->got_body ) {	    char tmp_md5_ascii[33], tmp_md5[16];	    if( sess->body_stream != NULL ) {		DEBUG( DEBUG_HTTPAUTH, "Digesting body stream.\n" );		md5_stream( sess->body_stream, tmp_md5 );		rewind( sess->body_stream ); /* leave it at the beginning */	    } else if( sess->body_buffer ) {		DEBUG( DEBUG_HTTPAUTH, "Digesting body buffer.\n" );		md5_buffer( sess->body_buffer, strlen(sess->body_buffer), 			    tmp_md5 );	    }	    md5_hexify( tmp_md5, tmp_md5_ascii );	    DEBUG( DEBUG_HTTPAUTH, "H(entity-body) is [%s]\n", tmp_md5_ascii );	    /* Append to A2 */	    md5_process_bytes( ":", 1, &a2 );	    md5_process_bytes( tmp_md5_ascii, 32, &a2 );	} else {	    /* No entity-body. */	    DEBUG( DEBUG_HTTPAUTH, "Digesting empty entity-body.\n" );	    md5_process_bytes( ":d41d8cd98f00b204e9800998ecf8427e", 33, &a2 );	}    }    md5_finish_ctx( &a2, a2_md5 );    md5_hexify( a2_md5, a2_md5_ascii );    DEBUG( DEBUG_HTTPAUTH, "H(A2): %s\n", a2_md5_ascii );    DEBUG( DEBUG_HTTPAUTH, "Calculating Request-Digest.\n" );    /* Now, calculation of the Request-Digest.     * The first section is the regardless of qop value     *     H(A1) ":" unq(nonce-value) ":" */    md5_init_ctx( &rdig );    if( sess->alg == http_auth_alg_md5 ) {	/* Use the calculated H(A1) */	md5_process_bytes( a1_md5_ascii, 32, &rdig );    } else {	/* Use the session H(A1) */	md5_process_bytes( sess->h_a1, 32, &rdig );    }    md5_process_bytes( ":", 1, &rdig );    md5_process_bytes( sess->unq_nonce, strlen(sess->unq_nonce), &rdig );    md5_process_bytes( ":", 1, &rdig );    if( sess->qop != http_auth_qop_none ) {	/* Add on:	 *    nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":"	 */	DEBUG( DEBUG_HTTPAUTH, "Have qop directive, digesting: [%s:%s:%s]\n",	       nc_value, sess->unq_cnonce, qop_value );	md5_process_bytes( nc_value, 8, &rdig );	md5_process_bytes( ":", 1, &rdig );	md5_process_bytes( sess->unq_cnonce, strlen(sess->unq_cnonce), &rdig );	md5_process_bytes( ":", 1, &rdig );	/* Store a copy of this structure */	sess->stored_rdig = rdig;	md5_process_bytes( qop_value, strlen(qop_value), &rdig );	md5_process_bytes( ":", 1, &rdig );    } else {	/* Store a copy of this structure */

⌨️ 快捷键说明

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