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

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

Webmaster