📄 htaabrow.c
字号:
/* HTAABrow.c** BROWSER SIDE ACCESS AUTHORIZATION MODULE**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTAABrow.c,v 2.60 2001/03/14 16:25:50 kahan Exp $**** Contains code for parsing challenges and creating credentials for ** basic authentication schemes. See also the HTAAUtil module** for how to handle other authentication schemes. You don't have to use** this code at all.**** AUTHORS:** AL Ari Luotonen luotonen@dxcern.cern.ch** HFN Henrik Frystyk** JKO Jose Kahan **** HISTORY:** Oct 17 AL Made corrections suggested by marca:** Added if (!realm->username) return NULL;** Changed some ""s to NULLs.** Now doing HT_CALLOC() to init uuencode source;** otherwise HTUU_encode() reads uninitialized memory** every now and then (not a real bug but not pretty).** Corrected the formula for uuencode destination size.** Feb 96 HFN Rewritten to make it scheme independent and based on** callback functions and an info structure** Nov 98 JKO Added support for message digest authentication** Jun 2000 JKO Changed the buffer size for HTUU_encode in order** to avoid a potential SIGSEV when calling that ** function (as advised by Heiner Kallweit).** Mar 2001 JKO When doing pipelining digest requests, the stale** nonce reply appears only for one of such requests,** all the following ones in the pipe will receive a ** 401. I added some code to take into account these cases** by trying to infer if a nonce is stale. ***//* Portions of this code (as indicated) are derived from the Internet Draft** draft-ietf-http-authentication-03 and are covered by the following** copyright:** Copyright (C) The Internet Society (1998). All Rights Reserved.** This document and translations of it may be copied and furnished to** others, and derivative works that comment on or otherwise explain it or** assist in its implmentation may be prepared, copied, published and** distributed, in whole or in part, without restriction of any kind,** provided that the above copyright notice and this paragraph are included** on all such copies and derivative works. However, this document itself** may not be modified in any way, such as by removing the copyright notice** or references to the Internet Society or other Internet organizations,** except as needed for the purpose of developing Internet standards in** which case the procedures for copyrights defined in the Internet** Standards process must be followed, or as required to translate it into** languages other than English.** The limited permissions granted above are perpetual and will not be** revoked by the Internet Society or its successors or assigns.** This document and the information contained herein is provided on an "AS** IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK** FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT** LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT** INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR** FITNESS FOR A PARTICULAR PURPOSE.**//* Library include files */#include "WWWLib.h"#include "HTAAUtil.h"#include "HTParse.h"#include "HTAABrow.h" /* Implemented here */#include "HTDigest.h"#define BASIC_AUTH "basic"#define DIGEST_AUTH "digest"#define DIGEST_AI "authentication-info"#define PROXY_DIGEST_AI "proxy-authentication-info"typedef struct _HTBasic { /* Basic challenge and credentials */ char * uid; char * pw; BOOL retry; /* Should we ask the user again? */ BOOL proxy; /* Proxy authentication */} HTBasic;typedef struct _HTDigest { /* Digest challenge and credentials */ /* digest info can be shared by one or more UT entries */ int references; /* client authentication data */ char * uid; char * pw; char * realm; char * cnonce; long nc; /* server authentication data */ char * nonce; char * opaque; /* session authentication data */ int algorithm; char * qop; BOOL stale; BOOL retry; /* Should we ask the user again? */ BOOL proxy; /* Proxy authentication */} HTDigest;#define HASHLEN 16typedef char HASH[HASHLEN+1];#define HASHHEXLEN 32typedef char HASHHEX[HASHHEXLEN+1];/* ------------------------------------------------------------------------- *//*** Create a protection template for the files** in the same directory as the given file** Returns a template matching docname, and other files in that directory.**** E.g. /foo/bar/x.html => /foo/bar/ *** ^** Space only to prevent it from** being a comment marker here,** there really isn't any space.*/PRIVATE char * make_template (const char * docname){ char * tmplate = NULL; if (docname) { char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION); char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION); char * slash = strrchr(path, '/'); if (slash) {#if 0 if (*(slash+1)) { strcpy(slash, "*"); StrAllocCat(host, path); } else StrAllocCat(host, "/*");#else if (*(slash+1)) { strcpy(slash + 1, "*"); StrAllocCat(host, path); } else { StrAllocCat(host, path); StrAllocCat(host, "*"); }#endif } HT_FREE(path); tmplate = host; } else StrAllocCopy(tmplate, "*"); HTTRACE(AUTH_TRACE, "Template.... Made template `%s' for file `%s'\n" _ tmplate _ docname ? docname : "<null>"); return tmplate;}/* ------------------------------------------------------------------------- *//* Basic Authentication *//* ------------------------------------------------------------------------- *//*** Prompt the user for username and password.** Returns YES if user name was typed in, else NO*/PRIVATE int prompt_user (HTRequest * request, const char * realm, HTBasic * basic){ HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW); /* If no method for prompting the user then we might as well give up */ if (!cbf) return HT_ERROR; /* Otherwise go ahead and ask the user */ if (request) { HTAlertPar * reply = HTAlert_newReply(); int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID; BOOL res = (*cbf)(request, HT_A_USER_PW, msg, basic->uid, (char *) realm, reply); if (res) { HT_FREE(basic->uid); HT_FREE(basic->pw); basic->uid = HTAlert_replyMessage(reply); basic->pw = HTAlert_replySecret(reply); } HTAlert_deleteReply(reply); return res ? HT_OK : HT_ERROR; } return HT_OK;}PRIVATE HTBasic * HTBasic_new(){ HTBasic * me = NULL; if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL) HT_OUTOFMEM("HTBasic_new"); me->retry = YES; /* Ask the first time through */ return me;}/* HTBasic_delete** --------------** Deletes a "basic" information object*/PUBLIC int HTBasic_delete (void * context){ HTBasic * basic = (HTBasic *) context; if (basic) { HT_FREE(basic->uid); HT_FREE(basic->pw); HT_FREE(basic); return YES; } return NO;}/*** Make basic authentication scheme credentials and register this** information in the request object as credentials. They will then** be included in the request header. An example is **** "Basic AkRDIhEF8sdEgs72F73bfaS=="**** The function can both create normal and proxy credentials** Returns HT_OK or HT_ERROR*/PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic){ if (request && basic) { char * cleartext = NULL; char * cipher = NULL; int cl_len = strlen(basic->uid ? basic->uid : "") + strlen(basic->pw ? basic->pw : "") + 5; int ci_len = 5 + 4 * (cl_len/3); if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL) HT_OUTOFMEM("basic_credentials"); *cleartext = '\0'; if (basic->uid) strcpy(cleartext, basic->uid); strcat(cleartext, ":"); if (basic->pw) strcat(cleartext, basic->pw); if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL) HT_OUTOFMEM("basic_credentials"); HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher); /* Create the credentials and assign them to the request object */ { int cr_len = strlen("basic") + ci_len + 3; char * cookie = (char *) HT_MALLOC(cr_len+1); if (!cookie) HT_OUTOFMEM("basic_credentials"); strcpy(cookie, "Basic "); strcat(cookie, cipher); HTTRACE(AUTH_TRACE, "Basic Cookie `%s\'\n" _ cookie); /* Check whether it is proxy or normal credentials */ if (basic->proxy) HTRequest_addCredentials(request, "Proxy-Authorization", cookie); else HTRequest_addCredentials(request, "Authorization", cookie); HT_FREE(cookie); } HT_FREE(cleartext); HT_FREE(cipher); return HT_OK; } return HT_ERROR;}/* HTBasic_generate** ----------------** This function generates "basic" credentials for the challenge found in** the authentication information base for this request. The result is** stored as an association list in the request object.** This is a callback function for the AA handler.*/PUBLIC int HTBasic_generate (HTRequest * request, void * context, int mode){ HTBasic * basic = (HTBasic *) context; BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO; if (request) { const char * realm = HTRequest_realm(request); /* ** If we were asked to explicitly ask the user again */ if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH) basic->retry = YES; /* ** If we don't have a basic context then add a new one to the tree. ** We use different trees for normal and proxy authentication */ if (!basic) { basic = HTBasic_new(); if (proxy) { char * url = HTRequest_proxy(request); basic->proxy = YES; HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic); } else { char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request)); HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic); HT_FREE(url); } } /* ** If we have a set of credentials (or the user provides a new set) ** then store it in the request object as the credentials */ if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) || (!basic->retry && basic->uid)) { basic->retry = NO; return basic_credentials(request, basic); } else { char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request)); HTAA_deleteNode(proxy, BASIC_AUTH, realm, url); HT_FREE(url); return HT_ERROR; } } return HT_OK;}/* HTBasic_parse** -------------** This function parses the contents of a "basic" challenge ** and stores the challenge in our authentication information datebase.** We also store the realm in the request object which will help finding** the right set of credentials to generate.** The function is a callback function for the AA handler.*/PUBLIC int HTBasic_parse (HTRequest * request, HTResponse * response, void * context, int status){ HTAssocList * challenge = HTResponse_challenge(response); HTBasic * basic = NULL; BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO; if (request && challenge) { char * p = HTAssocList_findObject(challenge, BASIC_AUTH); char * realm = HTNextField(&p); char * rm = HTNextField(&p); /* ** If valid challenge then make a template for the resource and ** store this information in our authentication URL Tree */ if (realm && !strcasecomp(realm, "realm") && rm) { HTTRACE(AUTH_TRACE, "Basic Parse. Realm `%s\' found\n" _ rm); HTRequest_setRealm(request, rm); /* ** If we are in proxy mode then add the proxy - not the final URL */ if (proxy) { char * url = HTRequest_proxy(request); HTTRACE(AUTH_TRACE, "Basic Parse. Proxy authentication\n"); basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm, url, NULL); /* if the previous authentication failed, then try again */ if (HTRequest_AAretrys (request) > 1 && status == HT_NO_ACCESS && basic) basic->retry = YES; } else { char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -