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

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

Webmaster