Annotation of libwww/Library/src/HTAABrow.c, revision 2.3

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

Webmaster