Annotation of libwww/Library/src/HTAABrow.c, revision 2.32
2.15 frystyk 1: /* HTAABrow.c
2.32 ! frystyk 2: ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
2.15 frystyk 3: **
2.19 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.15 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.1 luotonen 6: **
2.32 ! frystyk 7: ** Contains code for parsing challenges and creating credentials for
! 8: ** basic and digest authentication schemes. See also the HTAAUtil module
! 9: ** for how to handle other authentication schemes. You don't have to use
! 10: ** this code at all.
2.1 luotonen 11: **
12: ** AUTHORS:
13: ** AL Ari Luotonen luotonen@dxcern.cern.ch
2.32 ! frystyk 14: ** HFN Henrik Frystyk
2.1 luotonen 15: **
16: ** HISTORY:
2.5 luotonen 17: ** Oct 17 AL Made corrections suggested by marca:
18: ** Added if (!realm->username) return NULL;
19: ** Changed some ""s to NULLs.
20: ** Now doing calloc() to init uuencode source;
21: ** otherwise HTUU_encode() reads uninitialized memory
22: ** every now and then (not a real bug but not pretty).
23: ** Corrected the formula for uuencode destination size.
2.32 ! frystyk 24: ** Feb 96 HFN Rewritten to make it scheme independent and based on
! 25: ** callback functions and an info structure
2.1 luotonen 26: */
27:
2.17 frystyk 28: /* Library include files */
2.27 frystyk 29: #include "WWWLib.h"
30: #include "HTAAUtil.h"
31: #include "HTAABrow.h" /* Implemented here */
2.1 luotonen 32:
2.32 ! frystyk 33: typedef struct _HTBasic { /* Basic challenge and credentials */
! 34: char * uid;
! 35: char * pw;
! 36: } HTBasic;
! 37:
! 38: typedef struct _HTDigest { /* Digest challenge and credentials */
! 39: char * nounce;
! 40: char * opaque;
! 41: BOOL stale;
! 42: char * uid;
! 43: char * pw;
! 44: } HTDigest;
2.7 luotonen 45:
2.32 ! frystyk 46: /* ------------------------------------------------------------------------- */
2.1 luotonen 47:
2.32 ! frystyk 48: /*
! 49: ** Create a protection template for the files
! 50: ** in the same directory as the given file
! 51: ** Returns a template matching docname, and other files in that directory.
! 52: **
! 53: ** E.g. /foo/bar/x.html => /foo/bar/ *
! 54: ** ^
! 55: ** Space only to prevent it from
! 56: ** being a comment marker here,
! 57: ** there really isn't any space.
2.1 luotonen 58: */
2.32 ! frystyk 59: PRIVATE char * make_template (CONST char * docname)
2.1 luotonen 60: {
2.32 ! frystyk 61: char *tmplate = NULL;
! 62: char *slash = NULL;
! 63: if (docname) {
! 64: StrAllocCopy(tmplate, docname);
! 65: slash = strrchr(tmplate, '/');
! 66: if (slash) slash++;
! 67: else slash = tmplate;
! 68: *slash = '\0';
! 69: StrAllocCat(tmplate, "*");
! 70: }
! 71: else StrAllocCopy(tmplate, "*");
! 72: if (AUTH_TRACE)
! 73: HTTrace("Template.... Made template `%s' for file `%s'\n",
! 74: tmplate, docname);
! 75: return tmplate;
2.1 luotonen 76: }
77:
2.32 ! frystyk 78: /*
! 79: ** Make basic authentication scheme credentials and register this
! 80: ** information in the request object as credentials. They will then
! 81: ** be included in the request header. An example is
! 82: **
! 83: ** "Basic AkRDIhEF8sdEgs72F73bfaS=="
! 84: **
! 85: ** Returns YES if credentials created, else NO
! 86: */
! 87: PRIVATE HTAssocList * basic_credentials (HTRequest * request, HTBasic * basic)
! 88: {
! 89: if (request && basic) {
! 90: HTAssocList * credentials = HTAssocList_new();
! 91: char * cleartext = NULL;
! 92: char * cipher = NULL;
! 93: int cl_len = strlen(basic->uid ? basic->uid : "") +
! 94: strlen(basic->pw ? basic->pw : "") + 3;
! 95: int ci_len = (4*(cl_len+2))/3;
! 96: if ((cleartext = (char *) HT_CALLOC(1, cl_len+3)) == NULL)
! 97: HT_OUTOFMEM("basic_credentials");
! 98: *cleartext = '\0';
! 99: if (basic->uid) strcpy(cleartext, basic->uid);
! 100: strcat(cleartext, ":");
! 101: if (basic->pw) strcat(cleartext, basic->pw);
! 102: if ((cipher = (char *) HT_MALLOC(ci_len+1)) == NULL)
! 103: HT_OUTOFMEM("basic_credentials");
! 104: HTUU_encode((unsigned char *) cleartext, cl_len, cipher);
2.1 luotonen 105:
2.32 ! frystyk 106: /* Create the credentials and assign them to the request object */
! 107: {
! 108: int cr_len = strlen("basic") + ci_len + 2;
! 109: char * cookie = (char *) HT_MALLOC(cr_len+1);
! 110: if (!cookie) HT_OUTOFMEM("basic_credentials");
! 111: strcpy(cookie, "Basic ");
! 112: strcat(cookie, cipher);
! 113: HTAssocList_add(credentials, "Authorization", cookie);
! 114: HT_FREE(cookie);
2.1 luotonen 115: }
2.32 ! frystyk 116: HT_FREE(cleartext);
! 117: HT_FREE(cipher);
! 118: return credentials;
2.1 luotonen 119: }
2.32 ! frystyk 120: return NULL;
2.1 luotonen 121: }
122:
2.32 ! frystyk 123: /*
! 124: ** Make digest authentication scheme credentials and register this
! 125: ** information in the request object as credentials. They will then
! 126: ** be included in the request header.
! 127: ** Returns YES if credentials created, else NO
! 128: */
! 129: PRIVATE HTAssocList *digest_credentials (HTRequest * request, HTDigest *digest)
! 130: {
! 131: if (request && digest) {
! 132: HTAssocList * credentials = HTAssocList_new();
! 133: char * cleartext = NULL;
! 134: char * cipher = NULL;
! 135:
! 136: /* Do the generation */
! 137: #if 0
! 138: HTAssocList_add(credentials, "Authorization", cookie);
! 139: #endif
! 140: HT_FREE(cleartext);
! 141: HT_FREE(cipher);
! 142: return credentials;
! 143: }
! 144: return NULL;
2.1 luotonen 145: }
146:
2.32 ! frystyk 147: /*
! 148: ** Prompt the user for username and password.
! 149: ** Returns YES if user name was typed in, else NO
2.1 luotonen 150: */
2.32 ! frystyk 151: PRIVATE BOOL prompt_user (HTRequest * request, char * realm,
! 152: char ** uid, char ** pw)
2.1 luotonen 153: {
2.32 ! frystyk 154: HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
! 155: if (request && cbf) {
! 156: HTAlertPar * reply = HTAlert_newReply();
! 157: BOOL res = (*cbf)(request, HT_A_USER_PW,HT_MSG_NULL,*uid,realm,reply);
! 158: if (res) {
! 159: HT_FREE(*uid);
! 160: HT_FREE(*pw);
! 161: *uid = HTAlert_replyMessage(reply);
! 162: *pw = HTAlert_replySecret(reply);
! 163: }
! 164: HTAlert_deleteReply(reply);
! 165: return res ? YES : NO;
2.1 luotonen 166: }
2.32 ! frystyk 167: return NO;
2.1 luotonen 168: }
169:
2.32 ! frystyk 170: /* HTBasic_generate
! 171: ** ----------------
! 172: ** This function generates "basic" credentials for the challenge found in
! 173: ** the authentication information base for this request. The result is
! 174: ** stored as an association list in the request object.
! 175: ** This is a callback function for the AA handler.
! 176: */
! 177: PUBLIC BOOL HTBasic_generate (HTRequest * request, CONST char * scheme,
! 178: char * realm, void * challenge)
! 179: {
! 180: if (request && scheme && realm && challenge) {
! 181: HTBasic * basic = (HTBasic *) challenge;
! 182: if (AUTH_TRACE) HTTrace("Auth........ Generating basic credentials\n");
! 183: /*
! 184: ** If we have a set of credentials then store it in the request object
! 185: */
! 186: if (basic->uid || prompt_user(request, realm,&basic->uid,&basic->pw)) {
! 187: HTAssocList * credentials = HTRequest_credentials(request);
! 188: if (credentials) HTAssocList_delete(credentials);
! 189: if ((credentials = basic_credentials(request, basic))) {
! 190: HTRequest_setCredentials(request, credentials);
! 191: return YES;
2.2 luotonen 192: }
193: }
2.1 luotonen 194: }
2.32 ! frystyk 195: return NO;
2.1 luotonen 196: }
197:
2.32 ! frystyk 198: /* HTBasic_parse
! 199: ** -------------
! 200: ** This function parses the contents of a "basic" challenge
! 201: ** and stores the challenge in our authentication information datebase.
! 202: ** We also store the realm in the request object which will help finding
! 203: ** the right set of credentials to generate.
! 204: ** The function is a callback function for the AA handler.
! 205: */
! 206: PUBLIC BOOL HTBasic_parse (HTRequest * request, CONST char * scheme)
! 207: {
! 208: HTAssocList * challenge;
! 209: if (request && (challenge = HTRequest_challenge(request))) {
! 210: char * p = HTAssocList_lookup(challenge, "WWW-authenticate");
! 211: char * value = HTNextField(&p);
! 212: if (AUTH_TRACE)
! 213: HTTrace("Auth........ Parsing %s challenge\n", value?value:"NULL");
! 214: if (p && (value = HTNextField(&p))) {
! 215: /*
! 216: ** If valid challenge then make a template for the resource and
! 217: ** store this information in our authentication base
! 218: */
! 219: if (!strcasecomp(value, "realm") && (value = HTNextField(&p))) {
! 220: char * url = HTAnchor_physical(HTRequest_anchor(request));
! 221: char * tmplate = make_template(url);
! 222: HTBasic * me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic));
! 223: if (!me) HT_OUTOFMEM("HTBasic_parse");
! 224: HTAuthInfo_add(scheme, tmplate, value, me);
! 225: HTRequest_setRealm(request, value);
! 226: HT_FREE(tmplate);
! 227: return YES;
! 228: }
2.1 luotonen 229: }
230: }
2.32 ! frystyk 231: if (AUTH_TRACE) HTTrace("Auth........ None basic challenge found\n");
! 232: return NO;
2.1 luotonen 233: }
234:
2.32 ! frystyk 235: /* HTBasic_delete
! 236: ** --------------
! 237: ** Deletes a "basic" information object
! 238: */
! 239: PUBLIC BOOL HTBasic_delete (CONST char * scheme, void * data)
! 240: {
! 241: HTBasic * basic = (HTBasic *) data;
! 242: if (basic) {
! 243: HTBasic * basic = (HTBasic *) data;
! 244: HT_FREE(basic->uid);
! 245: HT_FREE(basic->pw);
! 246: HT_FREE(basic);
! 247: return YES;
2.1 luotonen 248: }
2.32 ! frystyk 249: return NO;
2.1 luotonen 250: }
251:
2.32 ! frystyk 252: /* HTDigest_generate
! 253: ** -----------------
! 254: ** This function generates "basic" credentials for the challenge found in
! 255: ** the authentication information base for this request. The result is
! 256: ** stored as an association list in the request object.
! 257: ** This is a callback function for the AA handler.
! 258: */
! 259: PUBLIC BOOL HTDigest_generate (HTRequest * request, CONST char * scheme,
! 260: char * realm, void * challenge)
! 261: {
! 262: if (request && scheme && realm && challenge) {
! 263: HTDigest * digest = (HTDigest *) challenge;
! 264: if (AUTH_TRACE)HTTrace("Auth........ Generating digest credentials\n");
! 265: /*
! 266: ** If we have a set of credentials then store it in the request object
! 267: */
! 268: #if 0
! 269: if (basic->uid || prompt_user(request, realm,&basic->uid,&basic->pw)) {
! 270: HTAssocList * credentials = HTRequest_credentials(request);
! 271: if (credentials) HTAssocList_delete(credentials);
! 272: if ((credentials = basic_credentials(request, basic))) {
! 273: HTRequest_setCredentials(request, credentials);
! 274: return YES;
! 275: }
2.1 luotonen 276: }
2.32 ! frystyk 277: #endif
2.1 luotonen 278: }
2.32 ! frystyk 279: return NO;
2.1 luotonen 280: }
281:
2.32 ! frystyk 282: /* HTDigest_parse
! 283: ** --------------
! 284: ** This function parses the contents of a "digest" challenge
! 285: ** and stores the challenge in our authentication information datebase.
! 286: ** We also store the realm in the request object which will help finding
! 287: ** the right set of credentials to generate.
! 288: ** The function is a callback function for the AA handler.
2.1 luotonen 289: */
2.32 ! frystyk 290: PUBLIC BOOL HTDigest_parse (HTRequest * request, CONST char * scheme)
2.1 luotonen 291: {
2.32 ! frystyk 292: if (request) {
2.1 luotonen 293:
2.32 ! frystyk 294: /* Do the parsing */
2.1 luotonen 295:
296: }
2.32 ! frystyk 297: if (AUTH_TRACE) HTTrace("Auth........ No digest challenge found\n");
! 298: return NULL;
2.7 luotonen 299: }
2.1 luotonen 300:
2.32 ! frystyk 301: /* HTDigest_delete
! 302: ** ---------------
! 303: ** Deletes a "digest" information object
2.7 luotonen 304: */
2.32 ! frystyk 305: PUBLIC BOOL HTDigest_delete (CONST char * scheme, void * data)
2.1 luotonen 306: {
2.32 ! frystyk 307: HTDigest * digest = (HTDigest *) data;
! 308: if (digest) {
! 309: HT_FREE(digest->nounce);
! 310: HT_FREE(digest->opaque);
! 311: HT_FREE(digest->uid);
! 312: HT_FREE(digest->pw);
! 313: HT_FREE(digest);
! 314: return YES;
2.7 luotonen 315: }
2.14 frystyk 316: return NO;
2.7 luotonen 317: }
2.1 luotonen 318:
319:
Webmaster