diff options
Diffstat (limited to 'gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c')
-rw-r--r-- | gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c | 1309 |
1 files changed, 1309 insertions, 0 deletions
diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c new file mode 100644 index 00000000000..0ebe5309e7d --- /dev/null +++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTAABrow.c @@ -0,0 +1,1309 @@ + +/* MODULE HTAABrow.c +** BROWSER SIDE ACCESS AUTHORIZATION MODULE +** +** Containts the code for keeping track on server hostnames, +** port numbers, scheme names, usernames, passwords +** (and servers' public keys). +** +** IMPORTANT: +** Routines in this module use dynamic allocation, but free +** automatically all the memory reserved by them. +** +** Therefore the caller never has to (and never should) +** free() any object returned by these functions. +** +** Therefore also all the strings returned by this package +** are only valid until the next call to the same function +** is made. This approach is selected, because of the nature +** of access authorization: no string returned by the package +** needs to be valid longer than until the next call. +** +** This also makes it easy to plug the AA package in: +** you don't have to ponder whether to free() something +** here or is it done somewhere else (because it is always +** done somewhere else). +** +** The strings that the package needs to store are copied +** so the original strings given as parameters to AA +** functions may be freed or modified with no side effects. +** +** The AA package does not free() anything else than what +** it has itself allocated. +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** +** HISTORY: +** Oct 17 AL Made corrections suggested by marca: +** Added if (!realm->username) return NULL; +** Changed some ""s to NULLs. +** Now doing calloc() to init uuencode source; +** otherwise HTUU_encode() reads uninitialized memory +** every now and then (not a real bug but not pretty). +** Corrected the formula for uuencode destination size. +** +** 28 Apr 1997 AJL Do Proxy Authorisation. +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" +#include <string.h> /* strchr() */ +#include "HTString.h" +#include "HTParse.h" /* URL parsing function */ +#include "HTList.h" /* HTList object */ +#include "HTAlert.h" /* HTConfirm(), HTPrompt() */ +#include "HTAAUtil.h" /* AA common to both sides */ +#include "HTAssoc.h" /* Assoc list */ +#include "HTAABrow.h" /* Implemented here */ +#include "HTUU.h" /* Uuencoding and uudecoding */ + +#include "LYLeaks.h" + +extern BOOL using_proxy; /* Are we using an HTTP gateway? */ + +/* +** Local datatype definitions +** +** HTAAServer contains all the information about one server. +*/ +typedef struct { + + char * hostname; /* Host's name */ + int portnumber; /* Port number */ + BOOL IsProxy; /* Is it a proxy? */ + HTList * setups; /* List of protection setups */ + /* on this server; i.e. valid */ + /* authentication schemes and */ + /* templates when to use them. */ + /* This is actually a list of */ + /* HTAASetup objects. */ + HTList * realms; /* Information about passwords */ +} HTAAServer; + +/* +** HTAASetup contains information about one server's one +** protected tree of documents. +*/ +typedef struct { + HTAAServer *server; /* Which server serves this tree */ + char * template; /* Template for this tree */ + HTList * valid_schemes; /* Valid authentic.schemes */ + HTAssocList**scheme_specifics;/* Scheme specific params */ + BOOL retry; /* Failed last time -- reprompt (or whatever)*/ +} HTAASetup; + +/* +** Information about usernames and passwords in +** Basic and Pubkey authentication schemes; +*/ +typedef struct { + char * realmname; /* Password domain name */ + char * username; /* Username in that domain */ + char * password; /* Corresponding password */ +} HTAARealm; + +/* +** To free off all globals. - FM +*/ +PRIVATE void free_HTAAGlobals NOPARAMS; +PRIVATE BOOL free_HTAAGlobalsSet = FALSE; +PRIVATE char *HTAA_composeAuthResult = NULL; +PRIVATE char *compose_auth_stringResult = NULL; /* Uuencoded presentation */ + +/* +** Module-wide global variables +*/ +PRIVATE HTList *server_table = NULL; /* Browser's info about servers */ +PRIVATE char *secret_key = NULL; /* Browser's latest secret key */ +PRIVATE HTAASetup *current_setup= NULL; /* The server setup we are currently */ + /* talking to */ +PRIVATE char *current_hostname = NULL; /* The server's name and portnumber */ +PRIVATE int current_portnumber = 80; /* where we are currently trying to */ + /* connect. */ +PRIVATE char *current_docname = NULL; /* The document's name we are */ + /* trying to access. */ +PRIVATE char *HTAAForwardAuth = NULL; /* Authorization: line to forward */ + /* (used by gateway httpds) */ +PRIVATE HTAASetup *proxy_setup = NULL; /* Same as above, but for Proxy -AJL */ +PRIVATE char *proxy_hostname = NULL; +PRIVATE char *proxy_docname = NULL; +PRIVATE int proxy_portnumber = 80; + + +/*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/ + +PUBLIC void HTAAForwardAuth_set ARGS2( + CONST char *, scheme_name, + CONST char *, scheme_specifics) +{ + int len = 20 + (scheme_name ? strlen(scheme_name) : 0) + + (scheme_specifics ? strlen(scheme_specifics) : 0); + + FREE(HTAAForwardAuth); + if (!(HTAAForwardAuth = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAAForwardAuth_set"); + + strcpy(HTAAForwardAuth, "Authorization: "); + if (scheme_name) { + strcat(HTAAForwardAuth, scheme_name); + strcat(HTAAForwardAuth, " "); + if (scheme_specifics) { + strcat(HTAAForwardAuth, scheme_specifics); + } + } +} + +PUBLIC void HTAAForwardAuth_reset NOARGS +{ + FREE(HTAAForwardAuth); +} + + +/**************************** HTAAServer ***********************************/ + +PRIVATE void HTAASetup_delete PARAMS((HTAASetup * killme)); /* Forward */ + +/* PRIVATE HTAAServer_new() +** ALLOCATE A NEW NODE TO HOLD SERVER INFO +** AND ADD IT TO THE LIST OF SERVERS +** ON ENTRY: +** hostname is the name of the host that the server +** is running in. +** portnumber is the portnumber which the server listens. +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns the newly-allocated node with all the strings +** duplicated. +** Strings will be automatically freed by +** the function HTAAServer_delete(), which also +** frees the node itself. +*/ +PRIVATE HTAAServer *HTAAServer_new ARGS3( + CONST char*, hostname, + int, portnumber, + BOOL, IsProxy) +{ + HTAAServer *server; + + if (!(server = (HTAAServer *)calloc(1, sizeof(HTAAServer)))) + outofmem(__FILE__, "HTAAServer_new"); + + server->hostname = NULL; + server->portnumber = (portnumber > 0 ? portnumber : 80); + server->IsProxy = IsProxy; + server->setups = HTList_new(); + server->realms = HTList_new(); + + if (hostname) + StrAllocCopy(server->hostname, hostname); + + if (!server_table) + server_table = HTList_new(); + + HTList_addObject(server_table, (void*)server); + + return server; +} + + +/* PRIVATE HTAAServer_delete() +** +** DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE, +** AND FREE THE MEMORY USED BY IT. +** +** ON ENTRY: +** killme points to the HTAAServer to be freed. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAAServer_delete ARGS1( + HTAAServer *, killme) +{ + int n, i; + HTAASetup *setup; + HTAARealm *realm; + HTList *cur; + + if (killme) { + if (killme->setups != NULL) { + n = HTList_count(killme->setups); + for (i = (n - 1); i >= 0; i--) { + if ((setup = (HTAASetup*)HTList_objectAt(killme->setups, + i)) != NULL) { + HTAASetup_delete(setup); + setup = NULL; + } + } + HTList_delete(killme->setups); + killme->setups = NULL; + } + + cur = killme->realms; + while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) { + FREE(realm->realmname); + FREE(realm->username); + FREE(realm->password); + FREE(realm); + } + HTList_delete(killme->realms); + killme->realms = NULL; + + FREE(killme->hostname); + + HTList_removeObject(server_table, (void*)killme); + FREE(killme); + } +} + +/* PRIVATE HTAAServer_lookup() +** LOOK UP SERVER BY HOSTNAME AND PORTNUMBER +** ON ENTRY: +** hostname obvious. +** portnumber if non-positive defaults to 80. +** IsProxy should be TRUE if this is a proxy. +** +** Looks up the server in the module-global server_table. +** +** ON EXIT: +** returns pointer to a HTAAServer structure +** representing the looked-up server. +** NULL, if not found. +*/ +PRIVATE HTAAServer *HTAAServer_lookup ARGS3( + CONST char *, hostname, + int, portnumber, + BOOL, IsProxy) +{ + if (hostname) { + HTList *cur = server_table; + HTAAServer *server; + + if (portnumber <= 0) + portnumber = 80; + + while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) { + if (server->portnumber == portnumber && + 0==strcmp(server->hostname, hostname) && + server->IsProxy == IsProxy) + return server; + } + } + return NULL; /* NULL parameter, or not found */ +} + + +/*************************** HTAASetup *******************************/ + +/* PRIVATE HTAASetup_lookup() +** FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER +** IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT +** +** ON ENTRY: +** hostname is the name of the server host machine. +** portnumber is the port that the server is running in. +** docname is the (URL-)pathname of the document we +** are trying to access. +** IsProxy should be TRUE if this is a proxy. +** +** This function goes through the information known about +** all the setups of the server, and finds out if the given +** filename resides in one of the protected directories. +** +** ON EXIT: +** returns NULL if no match. +** Otherwise, a HTAASetup structure representing +** the protected server setup on the corresponding +** document tree. +** +*/ +PRIVATE HTAASetup *HTAASetup_lookup ARGS4( + CONST char *, hostname, + int, portnumber, + CONST char *, docname, + BOOL, IsProxy) +{ + HTAAServer *server; + HTAASetup *setup; + + if (portnumber <= 0) + portnumber = 80; + + if (hostname && docname && *hostname && *docname && + NULL != (server = HTAAServer_lookup(hostname, + portnumber, + IsProxy))) { + + HTList *cur = server->setups; + + if (TRACE) + fprintf(stderr, "%s %s (%s:%d:%s)\n", + "HTAASetup_lookup: resolving setup for", + (IsProxy ? "proxy" : "server"), + hostname, portnumber, docname); + + while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) { + if (HTAA_templateMatch(setup->template, docname)) { + if (TRACE) + fprintf(stderr, "%s `%s' %s `%s'\n", + "HTAASetup_lookup:", docname, + "matched template", setup->template); + return setup; + } + else if (TRACE) + fprintf(stderr, "%s `%s' %s `%s'\n", + "HTAASetup_lookup:", docname, + "did NOT match template", setup->template); + } /* while setups remain */ + } /* if valid parameters and server found */ + + if (TRACE) + fprintf(stderr, "%s `%s' %s\n", + "HTAASetup_lookup: No template matched", + (docname ? docname : "(null)"), + "(so probably not protected)"); + + return NULL; /* NULL in parameters, or not found */ +} + +/* PRIVATE HTAASetup_new() +** CREATE A NEW SETUP NODE +** ON ENTRY: +** server is a pointer to a HTAAServer structure +** to which this setup belongs. +** template documents matching this template +** are protected according to this setup. +** valid_schemes a list containing all valid authentication +** schemes for this setup. +** If NULL, all schemes are disallowed. +** scheme_specifics is an array of assoc lists, which +** contain scheme specific parameters given +** by server in Authenticate: fields. +** If NULL, all scheme specifics are +** set to NULL. +** ON EXIT: +** returns a new HTAASetup node, and also adds it as +** part of the HTAAServer given as parameter. +*/ +PRIVATE HTAASetup *HTAASetup_new ARGS4( + HTAAServer *, server, + char *, template, + HTList *, valid_schemes, + HTAssocList **, scheme_specifics) +{ + HTAASetup *setup; + + if (!server || !template || !*template) + return NULL; + + if (!(setup = (HTAASetup*)calloc(1, sizeof(HTAASetup)))) + outofmem(__FILE__, "HTAASetup_new"); + + setup->retry = NO; + setup->server = server; + setup->template = NULL; + if (template) + StrAllocCopy(setup->template, template); + setup->valid_schemes = valid_schemes; + setup->scheme_specifics = scheme_specifics; + + HTList_addObject(server->setups, (void*)setup); + + return setup; +} + +/* PRIVATE HTAASetup_delete() +** FREE A HTAASetup STRUCTURE +** ON ENTRY: +** killme is a pointer to the structure to free(). +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAASetup_delete ARGS1( + HTAASetup *, killme) +{ + int scheme; + + if (killme) { + FREE(killme->template); + if (killme->valid_schemes) + HTList_delete(killme->valid_schemes); + killme->valid_schemes = NULL; + for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++) + if (killme->scheme_specifics[scheme]) + HTAssocList_delete(killme->scheme_specifics[scheme]); + FREE(killme->scheme_specifics); + FREE(killme); + } +} + +/* PRIVATE HTAASetup_updateSpecifics() +* COPY SCHEME SPECIFIC PARAMETERS +** TO HTAASetup STRUCTURE +** ON ENTRY: +** setup destination setup structure. +** specifics string array containing scheme +** specific parameters for each scheme. +** If NULL, all the scheme specific +** parameters are set to NULL. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAASetup_updateSpecifics ARGS2( + HTAASetup *, setup, + HTAssocList **, specifics) +{ + int scheme; + + if (setup) { + if (setup->scheme_specifics) { + for (scheme = 0; scheme < HTAA_MAX_SCHEMES; scheme++) { + if (setup->scheme_specifics[scheme]) + HTAssocList_delete(setup->scheme_specifics[scheme]); + } + FREE(setup->scheme_specifics); + } + setup->scheme_specifics = specifics; + } +} + + +/*************************** HTAARealm **********************************/ + +/* PRIVATE HTAARealm_lookup() +** LOOKUP HTAARealm STRUCTURE BY REALM NAME +** ON ENTRY: +** realm_table a list of realm objects. +** realmname is the name of realm to look for. +** +** ON EXIT: +** returns the realm. NULL, if not found. +*/ +PRIVATE HTAARealm *HTAARealm_lookup ARGS2( + HTList *, realm_table, + CONST char *, realmname) +{ + if (realm_table && realmname) { + HTList *cur = realm_table; + HTAARealm *realm; + + while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) { + if (0==strcmp(realm->realmname, realmname)) + return realm; + } + } + return NULL; /* No table, NULL param, or not found */ +} + +/* PRIVATE HTAARealm_new() +** CREATE A NODE CONTAINING USERNAME AND +** PASSWORD USED FOR THE GIVEN REALM. +** IF REALM ALREADY EXISTS, CHANGE +** USERNAME/PASSWORD. +** ON ENTRY: +** realm_table a list of realms to where to add +** the new one, too. +** realmname is the name of the password domain. +** username and +** password are what you can expect them to be. +** +** ON EXIT: +** returns the created realm. +*/ +PRIVATE HTAARealm *HTAARealm_new ARGS4( + HTList *, realm_table, + CONST char *, realmname, + CONST char *, username, + CONST char *, password) +{ + HTAARealm *realm; + + realm = HTAARealm_lookup(realm_table, realmname); + + if (!realm) { + if (!(realm = (HTAARealm*)calloc(1, sizeof(HTAARealm)))) + outofmem(__FILE__, "HTAARealm_new"); + realm->realmname = NULL; + realm->username = NULL; + realm->password = NULL; + StrAllocCopy(realm->realmname, realmname); + if (realm_table) + HTList_addObject(realm_table, (void*)realm); + } + if (username) + StrAllocCopy(realm->username, username); + if (password) + StrAllocCopy(realm->password, password); + + return realm; +} + + +/***************** Basic and Pubkey Authentication ************************/ + +/* PRIVATE compose_auth_string() +** +** COMPOSE Basic OR Pubkey AUTHENTICATION STRING; +** PROMPTS FOR USERNAME AND PASSWORD IF NEEDED +** +** ON ENTRY: +** scheme is either HTAA_BASIC or HTAA_PUBKEY. +** setup is the current server setup. +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns a newly composed authorization string, +** (with, of course, a newly generated secret +** key and fresh timestamp, if Pubkey-scheme +** is being used). +** NULL, if something fails. +** NOTE: +** Like throughout the entire AA package, no string or structure +** returned by AA package needs to (or should) be freed. +** +*/ +PRIVATE char *compose_auth_string ARGS3( + HTAAScheme, scheme, + HTAASetup *, setup, + BOOL, IsProxy) +{ + char *cleartext = NULL; /* Cleartext presentation */ + char *ciphertext = NULL; /* Encrypted presentation */ + int len; + char *msg = NULL; + char *username = NULL; + char *password = NULL; + char *realmname = NULL; + char *theHost = NULL; + char *proxiedHost = NULL; + char *thePort = NULL; + HTAARealm *realm; + char *i_net_addr = "0.0.0.0"; /* Change... @@@@ */ + char *timestamp = "42"; /* ... these @@@@ */ + + + FREE(compose_auth_stringResult); /* From previous call */ + + if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup || + !setup->scheme_specifics || !setup->scheme_specifics[scheme] || + !setup->server || !setup->server->realms) + return NULL; + + realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm"); + if (!realmname) + return NULL; + + realm = HTAARealm_lookup(setup->server->realms, realmname); + if (!(realm && + realm->username && *realm->username && + realm->password && *realm->password) || setup->retry) { + if (!realm) { + if (TRACE) + fprintf(stderr, "%s `%s' %s\n", + "compose_auth_string: realm:", realmname, + "not found -- creating"); + realm = HTAARealm_new(setup->server->realms, + realmname, NULL, NULL); + } + /* + * The template should be either the '*' global + * for everthing on the server (always true for + * proxy authorization setups), or a path for + * the start of a protected limb, with no host + * field, but we'll check for a host anyway in + * case a WWW-Protection-Template header set an + * absolute URL instead of a path. If we do get + * a host from this, it will include the port. - FM + */ + if ((!IsProxy) && using_proxy && setup->template) { + proxiedHost = HTParse(setup->template, "", PARSE_HOST); + if (proxiedHost && *proxiedHost != '\0') { + theHost = proxiedHost; + } + } + /* + * If we didn't get a host field from the + * template, set up the host name and port + * from the setup->server elements. - FM + */ + if (!theHost) + theHost = setup->server->hostname; + if (setup->server->portnumber > 0 && + setup->server->portnumber != 80) { + if (!(thePort = (char *)calloc(1, sizeof(char) * 40))) + outofmem(__FILE__, "compose_auth_string"); + sprintf(thePort, ":%d", setup->server->portnumber); + } + /* + * Set up the message for the username prompt, + * and then issue the prompt. The default + * username is included in the call to the + * prompting function, but the password is + * NULL-ed and always replaced. - FM + */ + len = strlen(realm->realmname) + + strlen(theHost ? + theHost : "??") + 50; + if (!(msg = (char *)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "compose_auth_string"); + sprintf(msg, "Username for '%s' at %s '%s%s':", + realm->realmname, + (IsProxy ? "proxy" : "server"), + (theHost ? theHost : "??"), + (thePort ? thePort : "")); + FREE(proxiedHost); + FREE(thePort); + username = realm->username; + password = NULL; + HTPromptUsernameAndPassword(msg, &username, &password, IsProxy); + + FREE(msg); + FREE(realm->username); + FREE(realm->password); + realm->username = username; + realm->password = password; + + if (!realm->username || !realm->password) { + /* + * Signals to retry. - FM + */ + return NULL; + } else if (*realm->username == '\0' || *realm->password == '\0') { + /* + * Signals to abort. - FM + */ + StrAllocCopy(compose_auth_stringResult, ""); + return compose_auth_stringResult; + } + } + + len = strlen(realm->username ? realm->username : "") + + strlen(realm->password ? realm->password : "") + 3; + + if (scheme == HTAA_PUBKEY) { +#ifdef PUBKEY + /* Generate new secret key */ + StrAllocCopy(secret_key, HTAA_generateRandomKey()); +#endif /* PUBKEY */ + /* Room for secret key, timestamp and inet address */ + len += strlen(secret_key ? secret_key : "") + 30; + } else { + FREE(secret_key); + } + + if (!(cleartext = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "compose_auth_string"); + + if (realm->username) + strcpy(cleartext, realm->username); + else + *cleartext = '\0'; + + strcat(cleartext, ":"); + + if (realm->password) + strcat(cleartext, realm->password); + + if (scheme == HTAA_PUBKEY) { + strcat(cleartext, ":"); + strcat(cleartext, i_net_addr); + strcat(cleartext, ":"); + strcat(cleartext, timestamp); + strcat(cleartext, ":"); + if (secret_key) + strcat(cleartext, secret_key); + + if (!((ciphertext = (char *)calloc(1, (sizeof(char) * 2) * len)) && + (compose_auth_stringResult = + (char *)calloc(1, (sizeof(char) * 3) * len)))) + outofmem(__FILE__, "compose_auth_string"); +#ifdef PUBKEY + HTPK_encrypt(cleartext, ciphertext, server->public_key); + HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), + compose_auth_stringResult); +#endif /* PUBKEY */ + FREE(cleartext); + FREE(ciphertext); + } + else { /* scheme == HTAA_BASIC */ + if (!(compose_auth_stringResult = + (char*)calloc(1, (4 * ((len+2)/3)) + 1))) + outofmem(__FILE__, "compose_auth_string"); + HTUU_encode((unsigned char *)cleartext, strlen(cleartext), + compose_auth_stringResult); + FREE(cleartext); + } + return compose_auth_stringResult; +} + +/* BROWSER PRIVATE HTAA_selectScheme() +** SELECT THE AUTHENTICATION SCHEME TO USE +** ON ENTRY: +** setup is the server setup structure which can +** be used to make the decision about the +** used scheme. +** +** When new authentication methods are added to library +** this function makes the decision about which one to +** use at a given time. This can be done by inspecting +** environment variables etc. +** +** Currently only searches for the first valid scheme, +** and if nothing found suggests Basic scheme; +** +** ON EXIT: +** returns the authentication scheme to use. +*/ +PRIVATE HTAAScheme HTAA_selectScheme ARGS1( + HTAASetup *, setup) +{ + HTAAScheme scheme; + + if (setup && setup->valid_schemes) { + for (scheme = HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++) + if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme)) + return scheme; + } + return HTAA_BASIC; +} + +/* +** Purpose: Free off all module globals. +** Arguments: void +** Return Value: void +** Remarks/Portability/Dependencies/Restrictions: +** To be used at program exit. +** Revision History: +** 06-19-96 created - FM +*/ +PRIVATE void free_HTAAGlobals NOARGS +{ + HTAAServer * server; + int n, i; + + if (server_table != NULL) { + n = HTList_count(server_table); + for (i = (n - 1); i >= 0; i--) { + if ((server = (HTAAServer*)HTList_objectAt(server_table, + i)) != NULL) { + HTAAServer_delete(server); + server = NULL; + } + } + HTList_delete(server_table); + server_table = NULL; + } + + HTAAForwardAuth_reset(); + FREE(HTAA_composeAuthResult); + FREE(current_hostname); + FREE(current_docname); + FREE(proxy_hostname); + FREE(proxy_docname); + FREE(compose_auth_stringResult); + FREE(secret_key); +} + +/* BROWSER PUBLIC HTAA_composeAuth() +** +** SELECT THE AUTHENTICATION SCHEME AND +** COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE +** IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION +** +** ON ENTRY: +** hostname is the hostname of the server. +** portnumber is the portnumber in which the server runs. +** docname is the pathname of the document (as in URL) +** IsProxy should be TRUE if this is a proxy. +** +** ON EXIT: +** returns NULL, if no authorization seems to be needed, or +** if it is the entire Authorization: line, e.g. +** +** "Authorization: Basic username:password" +** +** As usual, this string is automatically freed. +*/ +PUBLIC char *HTAA_composeAuth ARGS4( + CONST char *, hostname, + CONST int, portnumber, + CONST char *, docname, + BOOL, IsProxy) +{ + char *auth_string; + BOOL retry; + HTAAScheme scheme; + int len; + + /* + ** Setup atexit() freeing if not done already. - FM + */ + if (!free_HTAAGlobalsSet) { + atexit(free_HTAAGlobals); + free_HTAAGlobalsSet = TRUE; + } + + /* + ** Make gateway httpds pass authorization field as it was received. + ** (This still doesn't really work because Authenticate: headers + ** from remote server are not forwarded to client yet so it cannot + ** really know that it should send authorization; I will not + ** implement it yet because I feel we will soon change radically + ** the way requests are represented to allow multithreading + ** on server-side. Life is hard.) + */ + if (HTAAForwardAuth) { + if (TRACE) + fprintf(stderr, "HTAA_composeAuth: %s\n", + "Forwarding received authorization"); + StrAllocCopy(HTAA_composeAuthResult, HTAAForwardAuth); + HTAAForwardAuth_reset(); /* Just a precaution */ + return HTAA_composeAuthResult; + } + + FREE(HTAA_composeAuthResult); /* From previous call */ + + if (IsProxy) { + /* + ** Proxy Authorization required. - AJL + */ + + if (TRACE) + fprintf(stderr, + "Composing Proxy Authorization for %s:%d/%s\n", + hostname, portnumber, docname); + + if (proxy_portnumber != portnumber || + !proxy_hostname || !proxy_docname || + !hostname || !docname || + 0 != strcmp(proxy_hostname, hostname) || + 0 != strcmp(proxy_docname, docname)) { + + retry = NO; + + proxy_portnumber = portnumber; + + if (hostname) + StrAllocCopy(proxy_hostname, hostname); + else + FREE(proxy_hostname); + + if (docname) + StrAllocCopy(proxy_docname, docname); + else + FREE(proxy_docname); + } else { + retry = YES; + } + + if (!proxy_setup || !retry) + proxy_setup = HTAASetup_lookup(hostname, portnumber, + docname, IsProxy); + + if (!proxy_setup) + return NULL; + + switch (scheme = HTAA_selectScheme(proxy_setup)) { + case HTAA_BASIC: + case HTAA_PUBKEY: + auth_string = compose_auth_string(scheme, proxy_setup, IsProxy); + break; + case HTAA_KERBEROS_V4: + /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */ + default: + { + char msg[100]; + sprintf(msg, "%s %s `%s'", + "This client doesn't know how to compose proxy", + "authorization information for scheme", + HTAAScheme_name(scheme)); + HTAlert(msg); + auth_string = NULL; + } + } /* switch scheme */ + + proxy_setup->retry = NO; + + if (!auth_string) + /* + ** Signal a failure. - FM + */ + return NULL; /* Added by marca. */ + if (*auth_string == '\0') { + /* + ** Signal an abort. - FM + */ + StrAllocCopy(HTAA_composeAuthResult, ""); + return(HTAA_composeAuthResult); + } + len = strlen(auth_string) + strlen((char *)HTAAScheme_name(scheme)) + 26; + if (!(HTAA_composeAuthResult = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAA_composeAuth"); + strcpy(HTAA_composeAuthResult, "Proxy-Authorization: "); + + } else { + /* + ** Normal WWW authorization. + */ + if (TRACE) + fprintf(stderr, + "Composing Authorization for %s:%d/%s\n", + hostname, portnumber, docname); + + if (current_portnumber != portnumber || + !current_hostname || !current_docname || + !hostname || !docname || + 0 != strcmp(current_hostname, hostname) || + 0 != strcmp(current_docname, docname)) { + + retry = NO; + + current_portnumber = portnumber; + + if (hostname) + StrAllocCopy(current_hostname, hostname); + else + FREE(current_hostname); + + if (docname) + StrAllocCopy(current_docname, docname); + else + FREE(current_docname); + } else { + retry = YES; + } + + if (!current_setup || !retry) + current_setup = HTAASetup_lookup(hostname, portnumber, + docname, IsProxy); + + if (!current_setup) + return NULL; + + switch (scheme = HTAA_selectScheme(current_setup)) { + case HTAA_BASIC: + case HTAA_PUBKEY: + auth_string = compose_auth_string(scheme, current_setup, IsProxy); + break; + case HTAA_KERBEROS_V4: + /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */ + default: + { + char msg[100]; + sprintf(msg, "%s %s `%s'", + "This client doesn't know how to compose", + "authoritzation information for scheme", + HTAAScheme_name(scheme)); + HTAlert(msg); + auth_string = NULL; + } + } /* switch scheme */ + + current_setup->retry = NO; + + if (!auth_string) + /* + ** Signal a failure. - FM + */ + return NULL; /* Added by marca. */ + if (*auth_string == '\0') { + /* + ** Signal an abort. - FM + */ + StrAllocCopy(HTAA_composeAuthResult, ""); + return(HTAA_composeAuthResult); + } + + len = strlen(auth_string) + strlen((char *)HTAAScheme_name(scheme)) + 20; + if (!(HTAA_composeAuthResult = (char*)calloc(1, sizeof(char) * len))) + outofmem(__FILE__, "HTAA_composeAuth"); + strcpy(HTAA_composeAuthResult, "Authorization: "); + } + + strcat(HTAA_composeAuthResult, HTAAScheme_name(scheme)); + strcat(HTAA_composeAuthResult, " "); + strcat(HTAA_composeAuthResult, auth_string); + return HTAA_composeAuthResult; +} + +/* BROWSER PUBLIC HTAA_shouldRetryWithAuth() +** +** DETERMINES IF WE SHOULD RETRY THE SERVER +** WITH AUTHORIZATION +** (OR IF ALREADY RETRIED, WITH A DIFFERENT +** USERNAME AND/OR PASSWORD (IF MISSPELLED)) +** ON ENTRY: +** start_of_headers is the first block already read from socket, +** but status line skipped; i.e. points to the +** start of the header section. +** length is the remaining length of the first block. +** soc is the socket to read the rest of server reply. +** IsProxy should be TRUE if this is a proxy. +** +** This function should only be called when +** server has replied with a 401 (Unauthorized) +** status code. +** ON EXIT: +** returns YES, if connection should be retried. +** The node containing all the necessary +** information is +** * either constructed if it does not exist +** * or password is reset to NULL to indicate +** that username and password should be +** reprompted when composing Authorization: +** field (in function HTAA_composeAuth()). +** NO, otherwise. +*/ +PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS5( + char *, start_of_headers, + int, length, + void *, handle, + int, soc, + BOOL, IsProxy) +{ + HTAAScheme scheme; + char *line = NULL; + int num_schemes = 0; + HTList *valid_schemes = HTList_new(); + HTAssocList **scheme_specifics = NULL; + char *template = NULL; + char *temp = NULL; + + /* + ** Setup atexit() freeing if not done already. - FM + */ + if (!free_HTAAGlobalsSet) { + atexit(free_HTAAGlobals); + free_HTAAGlobalsSet = TRUE; + } + + /* + ** Read server reply header lines + */ + if (TRACE) + fprintf(stderr, "Server reply header lines:\n"); + + HTAA_setupReader(start_of_headers, length, handle, soc); + while (NULL != (line = HTAA_getUnfoldedLine()) && *line != '\0') { + if (TRACE) + fprintf(stderr, "%s\n", line); + + if (strchr(line, ':')) { /* Valid header line */ + + char *p = line; + char *fieldname = HTNextField(&p); + char *arg1 = HTNextField(&p); + char *args = p; + + if ((IsProxy && + 0==strcasecomp(fieldname, "Proxy-Authenticate:")) || + (!IsProxy && + 0==strcasecomp(fieldname, "WWW-Authenticate:"))) { + if (!(arg1 && *arg1 && args && *args)) { + temp = (char *)calloc(1, strlen(line) + + (arg1 ? strlen(arg1) : 0) + + (args ? strlen(args) : 0) + 24); + if (!temp) + outofmem(__FILE__, "HTAA_shouldRetryWithAuth"); + sprintf(temp, "Invalid header '%s%s%s%s%s'", line, + ((arg1 && *arg1) ? " " : ""), + ((arg1 && *arg1) ? arg1 : ""), + ((args && *args) ? " " : ""), + ((args && *args) ? args : "")); + HTAlert(temp); + FREE(temp); + } + else if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) { + HTList_addObject(valid_schemes, (void*)scheme); + if (!scheme_specifics) { + int i; + scheme_specifics = (HTAssocList**) + calloc(1, HTAA_MAX_SCHEMES * sizeof(HTAssocList*)); + if (!scheme_specifics) + outofmem(__FILE__, "HTAA_shouldRetryWithAuth"); + for (i=0; i < HTAA_MAX_SCHEMES; i++) + scheme_specifics[i] = NULL; + } + scheme_specifics[scheme] = HTAA_parseArgList(args); + num_schemes++; + } + else if (TRACE) { + fprintf(stderr, "Unknown scheme `%s' %s\n", + (arg1 ? arg1 : "(null)"), + (IsProxy ? + "in Proxy-Authenticate: field" : + "in WWW-Authenticate: field")); + } + } + + else if (!IsProxy && + 0==strcasecomp(fieldname, "WWW-Protection-Template:")) { + if (TRACE) + fprintf(stderr, "Protection template set to `%s'\n", arg1); + StrAllocCopy(template, arg1); + } + + } /* if a valid header line */ + else if (TRACE) { + fprintf(stderr, "Invalid header line `%s' ignored\n", line); + } /* else invalid header line */ + + FREE(line); + } /* while header lines remain */ + FREE(line); + + + /* + ** So should we retry with authorization? + */ + if (IsProxy) { + if (num_schemes == 0) { + /* + ** No proxy authorization valid + */ + proxy_setup = NULL; + return NO; + } + /* + ** Doing it for proxy. -AJL + */ + if (proxy_setup && proxy_setup->server) { + /* + ** We have already tried with proxy authorization. + ** Either we don't have access or username or + ** password was misspelled. + ** + ** Update scheme-specific parameters + ** (in case they have expired by chance). + */ + HTAASetup_updateSpecifics(proxy_setup, scheme_specifics); + + if (NO == HTConfirm("Authorization failed. Retry?")) { + proxy_setup = NULL; + return NO; + } else { + /* + ** Re-ask username+password (if misspelled). + */ + proxy_setup->retry = YES; + return YES; + } + } else { + /* + ** proxy_setup == NULL, i.e. we have a + ** first connection to a protected server or + ** the server serves a wider set of documents + ** than we expected so far. + */ + HTAAServer *server = HTAAServer_lookup(proxy_hostname, + proxy_portnumber, + IsProxy); + if (!server) { + server = HTAAServer_new(proxy_hostname, + proxy_portnumber, + IsProxy); + } + if (!template) /* Proxy matches everything -AJL */ + StrAllocCopy(template, "*"); + proxy_setup = HTAASetup_new(server, + template, + valid_schemes, + scheme_specifics); + FREE(template); + + HTAlert("Proxy authorization required -- retrying"); + return YES; + } + /* Never reached */ + } + /* + ** Normal WWW authorization. + */ + if (num_schemes == 0) { + /* + ** No authorization valid. + */ + current_setup = NULL; + return NO; + } + if (current_setup && current_setup->server) { + /* + ** So we have already tried with WWW authorization. + ** Either we don't have access or username or + ** password was misspelled. + ** + ** Update scheme-specific parameters + ** (in case they have expired by chance). + */ + HTAASetup_updateSpecifics(current_setup, scheme_specifics); + + if (NO == HTConfirm("Authorization failed. Retry?")) { + current_setup = NULL; + return NO; + } else { + /* + ** Re-ask username+password (if misspelled). + */ + current_setup->retry = YES; + return YES; + } + } else { + /* + ** current_setup == NULL, i.e. we have a + ** first connection to a protected server or + ** the server serves a wider set of documents + ** than we expected so far. + */ + HTAAServer *server = HTAAServer_lookup(current_hostname, + current_portnumber, + IsProxy); + if (!server) { + server = HTAAServer_new(current_hostname, + current_portnumber, + IsProxy); + } + if (!template) + template = HTAA_makeProtectionTemplate(current_docname); + current_setup = HTAASetup_new(server, + template, + valid_schemes, + scheme_specifics); + FREE(template); + + HTAlert("Access without authorization denied -- retrying"); + return YES; + } + /* Never reached */ +} + +/* +** This function clears all authorization information by +** invoking the free_HTAAGlobals() function, which normally +** is invoked at exit. It allows a browser command to do +** this at any time, for example, if the user is leaving +** the terminal for a period of time, but does not want +** to end the current session. - FM +*/ +PUBLIC void HTClearHTTPAuthInfo NOARGS +{ + /* + ** Need code to check cached documents against the + ** protention templates, and do something to ensure + ** that any protected documents no longer can be + ** accessed without a new retrieval. - FM + */ + + /* + ** Now free all of the authorization info, and + ** reset the free_HTAAGlobalsSet flag. - FM + */ + free_HTAAGlobals(); + free_HTAAGlobalsSet = FALSE; +} |