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

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

Webmaster