Annotation of libwww/Library/src/HTAABrow.c, revision 2.1
2.1 ! luotonen 1:
! 2: /* MODULE HTAABrow.c
! 3: ** BROWSER SIDE ACCESS AUTHORIZATION MODULE
! 4: **
! 5: ** Containts the code for keeping track on server hostnames,
! 6: ** port numbers, scheme names, usernames, passwords
! 7: ** (and servers' public keys).
! 8: **
! 9: ** IMPORTANT:
! 10: ** Routines in this module use dynamic allocation, but free
! 11: ** automatically all the memory reserved by them.
! 12: **
! 13: ** Therefore the caller never has to (and never should)
! 14: ** free() any object returned by these functions.
! 15: **
! 16: ** Therefore also all the strings returned by this package
! 17: ** are only valid until the next call to the same function
! 18: ** is made. This approach is selected, because of the nature
! 19: ** of access authorization: no string returned by the package
! 20: ** needs to be valid longer than until the next call.
! 21: **
! 22: ** This also makes it easy to plug the AA package in:
! 23: ** you don't have to ponder whether to free() something
! 24: ** here or is it done somewhere else (because it is always
! 25: ** done somewhere else).
! 26: **
! 27: ** The strings that the package needs to store are copied
! 28: ** so the original strings given as parameters to AA
! 29: ** functions may be freed or modified with no side effects.
! 30: **
! 31: ** The AA package does not free() anything else than what
! 32: ** it has itself allocated.
! 33: **
! 34: ** AUTHORS:
! 35: ** AL Ari Luotonen luotonen@dxcern.cern.ch
! 36: **
! 37: ** HISTORY:
! 38: **
! 39: **
! 40: ** BUGS:
! 41: **
! 42: **
! 43: */
! 44:
! 45: #include <string.h> /* strchr() */
! 46:
! 47: #include "HTUtils.h"
! 48: #include "HTString.h"
! 49: #include "HTParse.h" /* URL parsing function */
! 50: #include "HTList.h" /* HTList object */
! 51: #include "HTAlert.h" /* HTConfirm(), HTPrompt() */
! 52: #include "HTAAUtil.h" /* AA common to both sides */
! 53: #include "HTAABrow.h" /* Implemented here */
! 54: #include "HTUU.h" /* Uuencoding and uudecoding */
! 55:
! 56:
! 57:
! 58: /*
! 59: ** Local datatype definitions
! 60: **
! 61: ** HTAAServer contains all the information about one server.
! 62: */
! 63: typedef struct {
! 64:
! 65: char * hostname; /* Host's name */
! 66: int portnumber; /* Port number */
! 67: HTList * setups; /* List of protection setups */
! 68: /* on this server; i.e. valid */
! 69: /* authentication schemes and */
! 70: /* templates when to use them. */
! 71: /* This is actually a list of */
! 72: /* HTAASetup objects. */
! 73: } HTAAServer;
! 74:
! 75:
! 76: /*
! 77: ** HTAASetup contains information about one server's one
! 78: ** protected tree of documents.
! 79: */
! 80: typedef struct {
! 81: HTAAServer *server; /* Which server serves this tree */
! 82: char * template; /* Template for this tree */
! 83: BOOL valid_schemes[MAX_SCHEMES]; /* Valid authentic.schemes */
! 84: HTAA_Arg * scheme_specifics[MAX_SCHEMES]; /* Scheme specific params */
! 85: BOOL retry; /* Failed last time -- reprompt (or whatever)*/
! 86: } HTAASetup;
! 87:
! 88:
! 89: /*
! 90: ** Information about usernames and passwords in
! 91: ** Basic and Pubkey authentication schemes;
! 92: */
! 93: typedef struct {
! 94: char * realmname; /* Password domain name */
! 95: char * username; /* Username in that domain */
! 96: char * password; /* Corresponding password */
! 97: } HTAARealm;
! 98:
! 99:
! 100:
! 101: /*
! 102: ** Module-wide global variables
! 103: */
! 104:
! 105: PRIVATE HTList *server_table = NULL; /* Browser's info about servers */
! 106: PRIVATE HTList *realm_table = NULL; /* Information about passwords */
! 107: PRIVATE char *secret_key = NULL; /* Browser's latest secret key */
! 108: PRIVATE HTAASetup *current_setup= NULL; /* The server setup we are currently */
! 109: /* talking to */
! 110: PRIVATE char *current_hostname = NULL; /* The server's name and portnumber */
! 111: PRIVATE int current_portnumber = 80; /* where we are currently trying to */
! 112: /* connect. */
! 113: PRIVATE char *current_docname = NULL; /* The document's name we are */
! 114: /* trying to access. */
! 115:
! 116:
! 117:
! 118:
! 119:
! 120: /**************************** HTAAServer ***********************************/
! 121:
! 122:
! 123: /* PRIVATE HTAAServer_new()
! 124: ** ALLOCATE A NEW NODE TO HOLD SERVER INFO
! 125: ** AND ADD IT TO THE LIST OF SERVERS
! 126: ** ON ENTRY:
! 127: ** hostname is the name of the host that the server
! 128: ** is running in.
! 129: ** portnumber is the portnumber which the server listens.
! 130: **
! 131: ** ON EXIT:
! 132: ** returns the newly-allocated node with all the strings
! 133: ** duplicated.
! 134: ** Strings will be automatically freed by
! 135: ** the function HTAAServer_delete(), which also
! 136: ** frees the node itself.
! 137: */
! 138: PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*, hostname,
! 139: int, portnumber)
! 140: {
! 141: HTAAServer *server;
! 142:
! 143: if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
! 144: outofmem(__FILE__, "HTAAServer_new");
! 145:
! 146: server->hostname = NULL;
! 147: server->portnumber = (portnumber > 0 ? portnumber : 80);
! 148: server->setups = HTList_new();
! 149:
! 150: if (hostname) StrAllocCopy(server->hostname, hostname);
! 151:
! 152: if (!server_table) server_table = HTList_new();
! 153:
! 154: HTList_addObject(server_table, (void*)server);
! 155:
! 156: return server;
! 157: }
! 158:
! 159:
! 160: /* PRIVATE HTAAServer_delete()
! 161: **
! 162: ** DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
! 163: ** AND FREE THE MEMORY USED BY IT.
! 164: **
! 165: ** ON ENTRY:
! 166: ** killme points to the HTAAServer to be freed.
! 167: **
! 168: ** ON EXIT:
! 169: ** returns nothing.
! 170: */
! 171: #ifdef NOT_NEEDED_IT_SEEMS
! 172: PRIVATE void HTAASetup_delete(); /* Forward */
! 173: PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
! 174: {
! 175: if (killme) {
! 176: HTList *cur = killme->setups;
! 177: HTAASetup *setup;
! 178:
! 179: while (NULL != (setup = HTList_nextObject(cur)))
! 180: HTAASetup_delete(setup);
! 181: HTList_delete(killme->setups);
! 182:
! 183: FREE(killme->hostname);
! 184:
! 185: HTList_removeObject(server_table, (void*)killme);
! 186:
! 187: free(killme);
! 188: }
! 189: }
! 190: #endif /*NOT_NEEDED_IT_SEEMS*/
! 191:
! 192:
! 193: /* PRIVATE HTAAServer_lookup()
! 194: ** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
! 195: ** ON ENTRY:
! 196: ** hostname obvious.
! 197: ** portnumber if non-positive defaults to 80.
! 198: **
! 199: ** Looks up the server in the module-global server_table.
! 200: **
! 201: ** ON EXIT:
! 202: ** returns pointer to a HTAAServer structure
! 203: ** representing the looked-up server.
! 204: ** NULL, if not found.
! 205: */
! 206: PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
! 207: int, portnumber)
! 208: {
! 209: if (hostname) {
! 210: HTList *cur = server_table;
! 211: HTAAServer *server;
! 212:
! 213: if (portnumber <= 0) portnumber = 80;
! 214:
! 215: while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
! 216: if (server->portnumber == portnumber &&
! 217: 0==strcmp(server->hostname, hostname))
! 218: return server;
! 219: }
! 220: }
! 221: return NULL; /* NULL parameter, or not found */
! 222: }
! 223:
! 224:
! 225:
! 226:
! 227: /*************************** HTAASetup *******************************/
! 228:
! 229:
! 230: /* PRIVATE HTAASetup_lookup()
! 231: ** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
! 232: ** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
! 233: **
! 234: ** ON ENTRY:
! 235: ** hostname is the name of the server host machine.
! 236: ** portnumber is the port that the server is running in.
! 237: ** docname is the (URL-)pathname of the document we
! 238: ** are trying to access.
! 239: **
! 240: ** This function goes through the information known about
! 241: ** all the setups of the server, and finds out if the given
! 242: ** filename resides in one of the protected directories.
! 243: **
! 244: ** ON EXIT:
! 245: ** returns NULL if no match.
! 246: ** Otherwise, a HTAASetup structure representing
! 247: ** the protected server setup on the corresponding
! 248: ** document tree.
! 249: **
! 250: */
! 251: PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
! 252: int, portnumber,
! 253: CONST char *, docname)
! 254: {
! 255: HTAAServer *server;
! 256: HTAASetup *setup;
! 257:
! 258: if (portnumber <= 0) portnumber = 80;
! 259:
! 260: if (hostname && docname && *hostname && *docname &&
! 261: NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
! 262:
! 263: HTList *cur = server->setups;
! 264:
! 265: if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
! 266: "HTAASetup_lookup: resolving setup for",
! 267: hostname, portnumber, docname);
! 268:
! 269: while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
! 270: if (HTAA_templateMatch(setup->template, docname)) {
! 271: if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
! 272: "HTAASetup_lookup:", docname,
! 273: "matched template", setup->template);
! 274: return setup;
! 275: }
! 276: else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
! 277: "HTAASetup_lookup:", docname,
! 278: "did NOT match template", setup->template);
! 279: } /* while setups remain */
! 280: } /* if valid parameters and server found */
! 281:
! 282: if (TRACE) fprintf(stderr, "%s `%s' %s\n",
! 283: "HTAASetup_lookup: No template matched",
! 284: (docname ? docname : "(null)"),
! 285: "(so probably not protected)");
! 286:
! 287: return NULL; /* NULL in parameters, or not found */
! 288: }
! 289:
! 290:
! 291:
! 292:
! 293: /* PRIVATE HTAASetup_new()
! 294: ** CREATE A NEW SETUP NODE
! 295: ** ON ENTRY:
! 296: ** server is a pointer to a HTAAServer structure
! 297: ** to which this setup belongs.
! 298: ** template documents matching this template
! 299: ** are protected according to this setup.
! 300: ** valid_schemes a boolean array indicating which
! 301: ** authentication schemes are valid for
! 302: ** this setup.
! 303: ** If NULL, all schemes are disallowed.
! 304: ** scheme_specifics is an array of strings, that are the
! 305: ** scheme specific parameters given by
! 306: ** server in Authenticate: fields.
! 307: ** If NULL, all scheme specifics are
! 308: ** set to NULL.
! 309: ** ON EXIT:
! 310: ** returns a new HTAASetup node, and also adds it as
! 311: ** part of the HTAAServer given as parameter.
! 312: */
! 313: PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *, server,
! 314: char *, template,
! 315: BOOL *, valid_schemes,
! 316: HTAA_Arg **, scheme_specifics)
! 317: {
! 318: HTAASetup *setup;
! 319: HTAAScheme scheme;
! 320:
! 321: if (!server || !template || !*template) return NULL;
! 322:
! 323: if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
! 324: outofmem(__FILE__, "HTAASetup_new");
! 325:
! 326: setup->retry = NO;
! 327:
! 328: setup->server = server;
! 329: HTList_addObject(server->setups, (void*)setup);
! 330:
! 331: setup->template = NULL;
! 332: StrAllocCopy(setup->template, template);
! 333:
! 334: if (valid_schemes)
! 335: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 336: setup->valid_schemes[scheme] = valid_schemes[scheme];
! 337: else
! 338: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 339: setup->valid_schemes[scheme] = NO;
! 340:
! 341: if (scheme_specifics)
! 342: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 343: setup->scheme_specifics[scheme] = scheme_specifics[scheme];
! 344: else
! 345: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 346: setup->scheme_specifics[scheme] = NULL;
! 347:
! 348: return setup;
! 349: }
! 350:
! 351:
! 352:
! 353: /* PRIVATE HTAASetup_delete()
! 354: ** FREE A HTAASetup STRUCTURE
! 355: ** ON ENTRY:
! 356: ** killme is a pointer to the structure to free().
! 357: **
! 358: ** ON EXIT:
! 359: ** returns nothing.
! 360: */
! 361: #ifdef NOT_NEEDED_IT_SEEMS
! 362: PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
! 363: {
! 364: HTAAScheme scheme;
! 365:
! 366: if (killme) {
! 367: FREE(killme->template);
! 368: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 369: HTAA_Arg_delete(killme->scheme_specifics[scheme]);
! 370: free(killme);
! 371: }
! 372: }
! 373: #endif /*NOT_NEEDED_IT_SEEMS*/
! 374:
! 375:
! 376:
! 377: /* PRIVATE HTAASetup_updateSpecifics()
! 378: * COPY SCHEME SPECIFIC PARAMETERS
! 379: ** TO HTAASetup STRUCTURE
! 380: ** ON ENTRY:
! 381: ** setup destination setup structure.
! 382: ** specifics string array containing scheme
! 383: ** specific parameters for each scheme.
! 384: ** If NULL, all the scheme specific
! 385: ** parameters are set to NULL.
! 386: **
! 387: ** ON EXIT:
! 388: ** returns nothing.
! 389: */
! 390: PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *, setup,
! 391: HTAA_Arg **, specifics)
! 392: {
! 393: HTAAScheme scheme;
! 394:
! 395: for (scheme=0; scheme < MAX_SCHEMES; scheme++) {
! 396: HTAA_Arg_delete(setup->scheme_specifics[scheme]);
! 397: setup->scheme_specifics[scheme] = NULL;
! 398: }
! 399:
! 400: if (setup)
! 401: for (scheme=0; scheme < MAX_SCHEMES; scheme++)
! 402: setup->scheme_specifics[scheme] = specifics[scheme];
! 403: }
! 404:
! 405:
! 406:
! 407:
! 408: /*************************** HTAARealm **********************************/
! 409:
! 410: /* PRIVATE HTAARealm_lookup()
! 411: ** LOOKUP HTAARealm STRUCTURE BY REALM NAME
! 412: ** ON ENTRY:
! 413: ** realmname is the name of realm to look for.
! 414: **
! 415: ** ON EXIT:
! 416: ** returns the realm. NULL, if not found.
! 417: */
! 418: PRIVATE HTAARealm *HTAARealm_lookup ARGS1(CONST char *, realmname)
! 419: {
! 420: if (realm_table && realmname) {
! 421: HTList *cur = realm_table;
! 422: HTAARealm *realm;
! 423:
! 424: while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
! 425: if (0==strcmp(realm->realmname, realmname))
! 426: return realm;
! 427: }
! 428: }
! 429: return NULL; /* No table, NULL param, or not found */
! 430: }
! 431:
! 432:
! 433:
! 434: /* PRIVATE HTAARealm_new()
! 435: ** CREATE A NODE CONTAINING USERNAME AND
! 436: ** PASSWORD USED FOR THE GIVEN REALM.
! 437: ** IF REALM ALREADY EXISTS, CHANGE
! 438: ** USERNAME/PASSWORD.
! 439: ** ON ENTRY:
! 440: ** realmname is the name of the password domain.
! 441: ** username and
! 442: ** password are what you can expect them to be.
! 443: **
! 444: ** ON EXIT:
! 445: ** returns the created realm.
! 446: */
! 447: PRIVATE HTAARealm *HTAARealm_new ARGS3(CONST char *, realmname,
! 448: CONST char *, username,
! 449: CONST char *, password)
! 450: {
! 451: HTAARealm *realm;
! 452:
! 453: if (!realm_table) {
! 454: realm_table = HTList_new();
! 455: realm = NULL;
! 456: }
! 457: else {
! 458: realm = HTAARealm_lookup(realmname);
! 459: }
! 460:
! 461: if (!realm) {
! 462: if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
! 463: outofmem(__FILE__, "HTAARealm_new");
! 464: realm->realmname = NULL;
! 465: realm->username = NULL;
! 466: realm->password = NULL;
! 467: StrAllocCopy(realm->realmname, realmname);
! 468: HTList_addObject(realm_table, (void*)realm);
! 469: }
! 470: if (username) StrAllocCopy(realm->username, username);
! 471: if (password) StrAllocCopy(realm->password, password);
! 472:
! 473: return realm;
! 474: }
! 475:
! 476:
! 477:
! 478:
! 479: /***************** Basic and Pubkey Authentication ************************/
! 480:
! 481: /* PRIVATE compose_auth_string()
! 482: **
! 483: ** COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
! 484: ** PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
! 485: **
! 486: ** ON ENTRY:
! 487: ** scheme is either HTAA_BASIC or HTAA_PUBKEY.
! 488: ** realmname is the password domain name.
! 489: **
! 490: ** ON EXIT:
! 491: ** returns a newly composed authorization string,
! 492: ** (with, of course, a newly generated secret
! 493: ** key and fresh timestamp, if Pubkey-scheme
! 494: ** is being used).
! 495: ** NOTE:
! 496: ** Like throughout the entire AA package, no string or structure
! 497: ** returned by AA package needs to (or should) be freed.
! 498: **
! 499: */
! 500: PRIVATE char *compose_auth_string ARGS2(HTAAScheme, scheme,
! 501: HTAASetup *, setup)
! 502: {
! 503: static char *result = NULL; /* Uuencoded presentation, the result */
! 504: char *cleartext = NULL; /* Cleartext presentation */
! 505: char *ciphertext = NULL; /* Encrypted presentation */
! 506: int len;
! 507: char *username;
! 508: char *password;
! 509: char *realmname;
! 510: HTAARealm *realm;
! 511: char *inet_addr = "0.0.0.0"; /* Change... @@@@ */
! 512: char *timestamp = "42"; /* ... these @@@@ */
! 513:
! 514:
! 515: FREE(result); /* From previous call */
! 516:
! 517: if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup)
! 518: return "";
! 519:
! 520: realmname = HTAA_Arg_lookupValue(setup->scheme_specifics[scheme], "realm");
! 521: if (!realmname) return "";
! 522:
! 523: realm = HTAARealm_lookup(realmname);
! 524: if (!realm || setup->retry) {
! 525: if (!realm) {
! 526: if (TRACE) fprintf(stderr, "%s `%s' %s\n",
! 527: "compose_auth_string: realm:", realmname,
! 528: "not found -- creating");
! 529: realm = HTAARealm_new(realmname, NULL, NULL);
! 530: realm->username =
! 531: HTPrompt("Document is protected. Enter username: ",
! 532: realm->username);
! 533: }
! 534: else {
! 535: username = HTPrompt("Enter username: ", realm->username);
! 536: FREE(realm->username);
! 537: realm->username = username;
! 538: }
! 539:
! 540: password = HTPromptPassword("Enter password: ");
! 541: FREE(realm->password);
! 542: realm->password = password;
! 543: }
! 544:
! 545: len = strlen(realm->username ? realm->username : "") +
! 546: strlen(realm->password ? realm->password : "") + 3;
! 547:
! 548: if (scheme == HTAA_PUBKEY) {
! 549: #ifdef PUBKEY
! 550: /* Generate new secret key */
! 551: StrAllocCopy(secret_key, HTAA_generateRandomKey());
! 552: #endif
! 553: /* Room for secret key, timestamp and inet address */
! 554: len += strlen(secret_key ? secret_key : "") + 30;
! 555: }
! 556: else
! 557: FREE(secret_key);
! 558:
! 559: if (!(cleartext = (char*)malloc(len)))
! 560: outofmem(__FILE__, "compose_auth_string");
! 561:
! 562: if (realm->username) strcpy(cleartext, realm->username);
! 563: else *cleartext = NULL;
! 564:
! 565: strcat(cleartext, ":");
! 566:
! 567: if (realm->password) strcat(cleartext, realm->password);
! 568:
! 569: if (scheme == HTAA_PUBKEY) {
! 570: strcat(cleartext, ":");
! 571: strcat(cleartext, inet_addr);
! 572: strcat(cleartext, ":");
! 573: strcat(cleartext, timestamp);
! 574: strcat(cleartext, ":");
! 575: if (secret_key) strcat(cleartext, secret_key);
! 576:
! 577: if (!((ciphertext = (char*)malloc(2*len)) &&
! 578: (result = (char*)malloc(3*len))))
! 579: outofmem(__FILE__, "compose_auth_string");
! 580: #ifdef PUBKEY
! 581: HTPK_encrypt(cleartext, ciphertext, server->public_key);
! 582: HTUU_encode(ciphertext, strlen(ciphertext), result);
! 583: #endif
! 584: free(cleartext);
! 585: free(ciphertext);
! 586: }
! 587: else { /* scheme == HTAA_BASIC */
! 588: if (!(result = (char*)malloc(len + len/2)))
! 589: outofmem(__FILE__, "compose_auth_string");
! 590: HTUU_encode(cleartext, strlen(cleartext), result);
! 591: free(cleartext);
! 592: }
! 593: return result;
! 594: }
! 595:
! 596:
! 597:
! 598: /* BROWSER PRIVATE HTAA_selectScheme()
! 599: ** SELECT THE AUTHENTICATION SCHEME TO USE
! 600: ** ON ENTRY:
! 601: ** setup is the server setup structure which can
! 602: ** be used to make the decision about the
! 603: ** used scheme.
! 604: **
! 605: ** When new authentication methods are added to library
! 606: ** this function makes the decision about which one to
! 607: ** use at a given time. This can be done by inspecting
! 608: ** environment variables etc.
! 609: **
! 610: ** ON EXIT:
! 611: ** returns the authentication scheme to use.
! 612: */
! 613: PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
! 614: {
! 615: return HTAA_BASIC;
! 616: }
! 617:
! 618:
! 619:
! 620:
! 621: /* BROWSER PUBLIC HTAA_composeAuth()
! 622: **
! 623: ** SELECT THE AUTHENTICATION SCHEME AND
! 624: ** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
! 625: ** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
! 626: **
! 627: ** ON ENTRY:
! 628: ** hostname is the hostname of the server.
! 629: ** portnumber is the portnumber in which the server runs.
! 630: ** docname is the pathname of the document (as in URL)
! 631: **
! 632: ** ON EXIT:
! 633: ** returns NULL, if no authorization seems to be needed, or
! 634: ** if it is the entire Authorization: line, e.g.
! 635: **
! 636: ** "Authorization: Basic username:password"
! 637: **
! 638: ** As usual, this string is automatically freed.
! 639: */
! 640: PUBLIC char *HTAA_composeAuth ARGS3(CONST char *, hostname,
! 641: CONST int, portnumber,
! 642: CONST char *, docname)
! 643: {
! 644: static char *result = NULL;
! 645: char *auth_string;
! 646: BOOL retry;
! 647: HTAAScheme scheme;
! 648:
! 649: FREE(result); /* From previous call */
! 650:
! 651: if (TRACE)
! 652: fprintf(stderr,
! 653: "Composing Authorization for %s:%d/%s\n",
! 654: hostname, portnumber, docname);
! 655:
! 656: if (current_portnumber != portnumber ||
! 657: !current_hostname || !current_docname ||
! 658: !hostname || !docname ||
! 659: 0 != strcmp(current_hostname, hostname) ||
! 660: 0 != strcmp(current_docname, docname)) {
! 661:
! 662: retry = NO;
! 663:
! 664: current_portnumber = portnumber;
! 665:
! 666: if (hostname) StrAllocCopy(current_hostname, hostname);
! 667: else FREE(current_hostname);
! 668:
! 669: if (docname) StrAllocCopy(current_docname, docname);
! 670: else FREE(current_docname);
! 671: }
! 672: else retry = YES;
! 673:
! 674: if (!current_setup || !retry)
! 675: current_setup = HTAASetup_lookup(hostname, portnumber, docname);
! 676:
! 677: if (!current_setup)
! 678: return NULL;
! 679:
! 680:
! 681: switch (scheme = HTAA_selectScheme(current_setup)) {
! 682: case HTAA_BASIC:
! 683: case HTAA_PUBKEY:
! 684: auth_string = compose_auth_string(scheme, current_setup);
! 685: break;
! 686: case HTAA_KERBEROS_V4:
! 687: /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
! 688: default:
! 689: {
! 690: char msg[100];
! 691: sprintf(msg, "%s %s `%s'",
! 692: "This client doesn't know how to compose authentication",
! 693: "information for scheme", HTAAScheme_name(scheme));
! 694: HTAlert(msg);
! 695: auth_string = "";
! 696: }
! 697: } /* switch scheme */
! 698:
! 699: current_setup->retry = NO;
! 700:
! 701: if (!(result = (char*)malloc(sizeof(char) * (strlen(auth_string)+40))))
! 702: outofmem(__FILE__, "HTAA_composeAuth");
! 703: strcpy(result, "Authorization: ");
! 704: strcat(result, HTAAScheme_name(scheme));
! 705: strcat(result, " ");
! 706: strcat(result, auth_string);
! 707: return result;
! 708: }
! 709:
! 710:
! 711:
! 712:
! 713: /* BROWSER PUBLIC HTAA_shouldRetryWithAuth()
! 714: **
! 715: ** DETERMINES IF WE SHOULD RETRY THE SERVER
! 716: ** WITH AUTHORIZATION
! 717: ** (OR IF ALREADY RETRIED, WITH A DIFFERENT
! 718: ** USERNAME AND/OR PASSWORD (IF MISSPELLED))
! 719: ** ON ENTRY:
! 720: ** start_of_headers is the first block already read from socket,
! 721: ** but status line skipped; i.e. points to the
! 722: ** start of the header section.
! 723: ** length is the remaining length of the first block.
! 724: ** soc is the socket to read the rest of server reply.
! 725: **
! 726: ** This function should only be called when
! 727: ** server has replied with a 401 (Unauthorized)
! 728: ** status code.
! 729: ** ON EXIT:
! 730: ** returns YES, if connection should be retried.
! 731: ** The node containing all the necessary
! 732: ** information is
! 733: ** * either constructed if it does not exist
! 734: ** * or password is reset to NULL to indicate
! 735: ** that username and password should be
! 736: ** reprompted when composing Authorization:
! 737: ** field (in function HTAA_composeAuth()).
! 738: ** NO, otherwise.
! 739: */
! 740: PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS3(char *, start_of_headers,
! 741: int, length,
! 742: int, soc)
! 743: {
! 744: HTAAScheme scheme;
! 745: char *line;
! 746: int num_schemes = 0;
! 747: BOOL valid_schemes[MAX_SCHEMES];
! 748: HTAA_Arg *scheme_specifics[MAX_SCHEMES];
! 749: char *template = NULL;
! 750:
! 751:
! 752: for (scheme=0; scheme < MAX_SCHEMES; scheme++) {
! 753: valid_schemes[scheme] = NO;
! 754: scheme_specifics[scheme] = NULL;
! 755: }
! 756:
! 757:
! 758: /* Read server reply header lines */
! 759:
! 760: if (TRACE)
! 761: fprintf(stderr, "Server reply header lines:\n");
! 762:
! 763: HTAA_setupReader(start_of_headers, length, soc);
! 764: while (NULL != (line = HTAA_getUnfoldedLine()) && NULL != *line ) {
! 765:
! 766: if (TRACE) fprintf(stderr, "%s\n", line);
! 767:
! 768: if (strchr(line, ':')) { /* Valid header line */
! 769:
! 770: char *p = line;
! 771: char *fieldname = HTNextField(&p);
! 772: char *arg1 = HTNextField(&p);
! 773: char *args = p;
! 774:
! 775: if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
! 776: if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
! 777: valid_schemes[scheme] = YES;
! 778: scheme_specifics[scheme] = HTAA_parseArgList(args);
! 779: num_schemes++;
! 780: }
! 781: else if (TRACE) {
! 782: fprintf(stderr, "Unknown scheme `%s' %s\n",
! 783: (arg1 ? arg1 : "(null)"),
! 784: "in WWW-Authenticate: field");
! 785: }
! 786: }
! 787:
! 788: else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
! 789: if (TRACE)
! 790: fprintf(stderr, "Protection template set to `%s'\n", arg1);
! 791: StrAllocCopy(template, arg1);
! 792: }
! 793:
! 794: } /* if a valid header line */
! 795: else if (TRACE) {
! 796: fprintf(stderr, "Invalid header line `%s' ignored\n", line);
! 797: } /* else invalid header line */
! 798: } /* while header lines remain */
! 799:
! 800:
! 801: /* So should we retry with authorization */
! 802:
! 803: if (num_schemes == 0) { /* No authentication valid */
! 804: current_setup = NULL;
! 805: return NO;
! 806: }
! 807:
! 808: if (current_setup && current_setup->server) {
! 809: /* So we have already tried with authorization. */
! 810: /* Either we don't have access or username or */
! 811: /* password was misspelled. */
! 812:
! 813: /* Update scheme-specific parameters */
! 814: /* (in case they have expired by chance). */
! 815: HTAASetup_updateSpecifics(current_setup, scheme_specifics);
! 816:
! 817: if (NO == HTConfirm("Authorization failed. Retry?")) {
! 818: current_setup = NULL;
! 819: return NO;
! 820: } /* HTConfirm(...) == NO */
! 821: else { /* re-ask username+password (if misspelled) */
! 822: current_setup->retry = YES;
! 823: return YES;
! 824: } /* HTConfirm(...) == YES */
! 825: } /* if current_setup != NULL */
! 826:
! 827: else { /* current_setup == NULL, i.e. we have a */
! 828: /* first connection to a protected server or */
! 829: /* the server serves a wider set of documents */
! 830: /* than we expected so far. */
! 831:
! 832: HTAAServer *server = HTAAServer_lookup(current_hostname,
! 833: current_portnumber);
! 834: if (!server) {
! 835: server = HTAAServer_new(current_hostname,
! 836: current_portnumber);
! 837: }
! 838: if (!template)
! 839: template = HTAA_makeProtectionTemplate(current_docname);
! 840: current_setup = HTAASetup_new(server,
! 841: template,
! 842: valid_schemes,
! 843: scheme_specifics);
! 844:
! 845: HTAlert("Access without authorization denied -- retrying");
! 846: return YES;
! 847: } /* else current_setup == NULL */
! 848:
! 849: /* Never reached */
! 850: }
! 851:
Webmaster