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

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

Webmaster