home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkaccess.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  73.3 KB  |  2,890 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  *
  20.  * Designed and Implemented by Lou Montulli '94
  21.  * Heavily modified by Judson Valeski '97
  22.  * Yada yada yada... Gagan Saksena '98
  23.  *
  24.  * This file implements HTTP access authorization
  25.  * and HTTP cookies
  26.  */
  27. #include "mkutils.h"
  28. #include "mkparse.h"
  29. #include "mkaccess.h"
  30. #include "prefapi.h"
  31. #include "shist.h"
  32. #include "jscookie.h"
  33.  
  34. #include "secnav.h"
  35. #include "libevent.h"
  36. #include "pwcacapi.h"
  37.  
  38. /* for XP_GetString() */
  39. #include "xpgetstr.h"
  40. extern int XP_CONFIRM_AUTHORIZATION_FAIL;
  41. extern int XP_ACCESS_ENTER_USERNAME;
  42. extern int XP_ACCESS_ENTER_USERNAME;
  43. extern int XP_CONFIRM_PROXYAUTHOR_FAIL;
  44. extern int XP_CONNECT_PLEASE_ENTER_PASSWORD_FOR_HOST;
  45. extern int XP_PROXY_REQUIRES_UNSUPPORTED_AUTH_SCHEME;
  46. extern int XP_LOOPING_OLD_NONCES;
  47. extern int XP_UNIDENTIFIED_PROXY_SERVER;
  48. extern int XP_PROXY_AUTH_REQUIRED_FOR;
  49. extern int XP_CONNECT_PLEASE_ENTER_PASSWORD_FOR_PROXY;
  50. extern int XP_FORTEZZA_PROXY_AUTH;
  51. extern int MK_ACCESS_COOKIES_THE_SERVER;
  52. extern int MK_ACCESS_COOKIES_WISHES; 
  53. extern int MK_ACCESS_COOKIES_TOANYSERV; 
  54. extern int MK_ACCESS_COOKIES_TOSELF;
  55. extern int MK_ACCESS_COOKIES_NAME_AND_VAL;
  56. extern int MK_ACCESS_COOKIES_COOKIE_WILL_PERSIST;
  57. extern int MK_ACCESS_COOKIES_SET_IT;
  58. extern int MK_ACCESS_YOUR_COOKIES;
  59. extern int MK_ACCESS_MAXIMUM_COOKS;
  60. extern int MK_ACCESS_COOK_COUNT;
  61. extern int MK_ACCESS_MAXIMUM_COOKS_PER_SERV;
  62. extern int MK_ACCESS_MAXIMUM_COOK_SIZE;
  63. extern int MK_ACCESS_NO_COOKIES;
  64. extern int MK_ACCESS_NAME;
  65. extern int MK_ACCESS_VALUE;
  66. extern int MK_ACCESS_HOST;
  67. extern int MK_ACCESS_SEND_TO_HOST;
  68. extern int MK_ACCESS_IS_DOMAIN;
  69. extern int MK_ACCESS_IS_NOT_DOMAIN;
  70. extern int MK_ACCESS_SEND_TO_PATH;
  71. extern int MK_ACCESS_AND_BELOW;
  72. extern int MK_ACCESS_SECURE;
  73. extern int MK_ACCESS_EXPIRES;
  74. extern int MK_ACCESS_END_OF_SESSION;
  75.  
  76. #define MAX_NUMBER_OF_COOKIES  300
  77. #define MAX_COOKIES_PER_SERVER 20
  78. #define MAX_BYTES_PER_COOKIE   4096  /* must be at least 1 */
  79.  
  80. /*
  81.  * Authentication information for servers and proxies is kept
  82.  * on separate lists, but both lists consist of net_AuthStruct's.
  83.  */
  84.  
  85. PRIVATE XP_List * net_auth_list = NULL;
  86. PRIVATE XP_List * net_proxy_auth_list = NULL;
  87.  
  88. PRIVATE Bool cookies_changed = FALSE;
  89.  
  90. PRIVATE NET_CookieBehaviorEnum net_CookieBehavior = NET_Accept;
  91. PRIVATE Bool net_WarnAboutCookies = FALSE;
  92. PRIVATE char *net_scriptName = (char *)0;
  93.  
  94. static const char *pref_cookieBehavior = "network.cookie.cookieBehavior";
  95. static const char *pref_warnAboutCookies = "network.cookie.warnAboutCookies";
  96. static const char *pref_scriptName = "network.cookie.filterName";
  97.  
  98.  
  99. /*
  100.  * Different schemes supported by the client.
  101.  * Order means the order of preference between authentication schemes.
  102.  *
  103.  */
  104. typedef enum _net_AuthType {
  105.     AUTH_INVALID   = 0,
  106.     AUTH_BASIC     = 1
  107. #ifdef SIMPLE_MD5
  108.     , AUTH_SIMPLEMD5 = 2        /* Much better than "Basic" */
  109. #endif /* SIMPLE_MD5 */
  110.     ,AUTH_FORTEZZA  = 3
  111. } net_AuthType;
  112.  
  113.  
  114. /*
  115.  * This struct describes both Basic and SimpleMD5 authentication stuff,
  116.  * for both HTTP servers and proxies.
  117.  *
  118.  */
  119. typedef struct _net_AuthStruct {
  120.     net_AuthType    auth_type;
  121.     char *            path;            /* For normal authentication only */
  122.     char *            proxy_addr;        /* For proxy authentication only */
  123.     char *            username;        /* Obvious */
  124.     char *            password;        /* Not too cryptic either */
  125.     char *            auth_string;    /* Storage for latest Authorization str */
  126.     char *            realm;            /* For all auth schemes */
  127. #ifdef SIMPLE_MD5
  128.     char *            domain;            /* SimpleMD5 only */
  129.     char *            nonce;            /* SimpleMD5 only */
  130.     char *            opaque;            /* SimpleMD5 only */
  131.     XP_Bool            oldNonce;        /* SimpleMD5 only */
  132.     int                oldNonce_retries;
  133. #endif
  134.     char *                      challenge;
  135.     char *                      certChain;
  136.     char *                      signature;
  137.     char *                      clientRan;
  138.     XP_Bool                     oldChallenge;
  139.     int                         oldChallenge_retries;
  140. } net_AuthStruct;
  141.  
  142.  
  143.  
  144. /*----------------- Normal client-server authentication ------------------ */
  145.  
  146. PRIVATE net_AuthStruct *
  147. net_CheckForAuthorization(char * address, Bool exact_match)
  148. {
  149.  
  150.     XP_List * list_ptr = net_auth_list;
  151.     net_AuthStruct * auth_s;
  152.  
  153.     TRACEMSG(("net_CheckForAuthorization: checking for auth on: %s", address));
  154.  
  155.     while((auth_s = (net_AuthStruct *) XP_ListNextObject(list_ptr))!=0)
  156.       {
  157.         if(exact_match)
  158.           {
  159.             if(!XP_STRCMP(address, auth_s->path))
  160.                 return(auth_s);
  161.           }
  162.         else
  163.           {
  164.             /* shorter strings always come last so there can be no
  165.              * ambiquity
  166.              */
  167.             if(!strncasecomp(address, auth_s->path, XP_STRLEN(auth_s->path)))
  168.                 return(auth_s);
  169.           }
  170.       }
  171.    
  172.     return(NULL);
  173. }
  174.  
  175. /* returns TRUE if authorization is required
  176.  */
  177. PUBLIC Bool
  178. NET_AuthorizationRequired(char * address)
  179. {
  180.     net_AuthStruct * rv;
  181.     char * last_slash = XP_STRRCHR(address, '/');
  182.  
  183.     if(last_slash)
  184.         *last_slash = '\0';
  185.  
  186.     rv = net_CheckForAuthorization(address, FALSE);
  187.  
  188.     if(last_slash)
  189.         *last_slash = '/';
  190.  
  191.     if(!rv)
  192.         return(FALSE);
  193.     else
  194.         return(TRUE);
  195. }
  196.  
  197. /* returns a authorization string if one is required, otherwise
  198.  * returns NULL
  199.  */
  200. PUBLIC char *
  201. NET_BuildAuthString(MWContext * context, URL_Struct *URL_s)
  202. {
  203.     char * address = URL_s->address;
  204.     net_AuthStruct * auth_s = net_CheckForAuthorization(address, FALSE);
  205.  
  206.     if(!auth_s)
  207. #if defined(XP_WIN) && defined(MOZILLA_CLIENT)
  208.         return(WFE_BuildCompuserveAuthString(URL_s));
  209. #else
  210.         return(NULL);
  211. #endif
  212.     else
  213.       {
  214.           static char * auth_header = 0;
  215.         
  216.         if(auth_header)
  217.             XP_FREE(auth_header);
  218.         auth_header = PR_smprintf("Authorization: Basic %s"CRLF, auth_s->auth_string);
  219.         return(auth_header);
  220.       }
  221. }
  222.  
  223. PRIVATE net_AuthStruct *
  224. net_ScanForHostnameRealmMatch(char * address, char * realm)
  225. {
  226.     char * proto_host = NET_ParseURL(address, GET_HOST_PART | GET_PROTOCOL_PART);
  227.     XP_List * list_ptr = net_auth_list;
  228.     net_AuthStruct * auth_s;
  229.  
  230.     while((auth_s = (net_AuthStruct *) XP_ListNextObject(list_ptr))!=0)
  231.       {
  232.         /* shorter strings always come last so there can be no
  233.          * ambiquity
  234.          */
  235.         if(!strncasecomp(proto_host, auth_s->path, XP_STRLEN(proto_host))
  236.             && !strcasecomp(realm, auth_s->realm))
  237.         {
  238.             XP_FREE(proto_host);
  239.             return(auth_s);
  240.         }
  241.       }
  242.     XP_FREE(proto_host);
  243.     return(NULL);
  244. }
  245.  
  246. PRIVATE void
  247. net_free_auth_struct(net_AuthStruct *auth)
  248. {
  249.     FREE(auth->path);
  250.     FREE(auth->proxy_addr);
  251.     FREE(auth->username);
  252.     FREE(auth->password);
  253.     FREE(auth->auth_string);
  254.     FREE(auth->realm);
  255.     /*FORTEZZA related stuff   */
  256.     FREEIF(auth->challenge);
  257.     FREEIF(auth->certChain);
  258.     FREEIF(auth->signature);
  259.     FREEIF(auth->clientRan);
  260.     /*End FORTEZZA related stuff*/
  261.     FREE(auth);
  262. }
  263.  
  264. /* blows away all authorization structs currently in the list, and the list itself.
  265.  * frees and nulls the list pointer itself (net_auth_list)
  266.  */
  267. PUBLIC void
  268. NET_RemoveAllAuthorizations()
  269. {
  270.     net_AuthStruct * victim;
  271.     if(XP_ListIsEmpty(net_auth_list)) /* XP_ListIsEmpty handles null list */
  272.         return;
  273.  
  274.     while((victim = (net_AuthStruct *) XP_ListNextObject(net_auth_list)) != 0)
  275.         net_free_auth_struct(victim);
  276.     XP_ListDestroy(net_auth_list);
  277.     net_auth_list = NULL;
  278. }
  279.  
  280. PRIVATE void
  281. net_remove_exact_auth_match_on_cancel(net_AuthStruct *prev_auth, char *cur_path)
  282. {
  283.     if(!prev_auth || !cur_path)
  284.         return;
  285.  
  286.     if(!XP_STRCMP(prev_auth->path, cur_path))
  287.       {
  288.         /* if the paths are exact and the user cancels
  289.          * remove the mapping
  290.          */
  291.         XP_ListRemoveObject(net_auth_list, prev_auth);
  292.         net_free_auth_struct(prev_auth);
  293.       }
  294. }
  295.  
  296. #define HTTP_PW_MODULE_NAME  "http_pw"
  297. #define HTTP_PW_NAME_TOKEN            "name"
  298. #define HTTP_PW_PASSWORD_TOKEN        "pass"
  299.  
  300. PRIVATE char *
  301. gen_http_key(char *address, char *realm)
  302. {
  303.     char *rv=NULL;
  304.  
  305.     StrAllocCopy(rv, address);
  306.     StrAllocCat(rv, "\t");
  307.     StrAllocCat(rv, realm);
  308.  
  309.     return rv;
  310. }
  311.  
  312. PRIVATE void
  313. separate_http_key(char *key, char **address, char **realm)
  314. {
  315.     char *tab;
  316.  
  317.     *address = NULL;
  318.     *realm = NULL;
  319.  
  320.     if(!key)
  321.         return;
  322.  
  323.     tab = XP_STRCHR(key, '\t');
  324.  
  325.     if(!tab)
  326.         return;
  327.  
  328.     *address = key;
  329.     *realm = tab+1;
  330. }
  331.  
  332. PRIVATE void
  333. net_store_http_password(char *address, char *realm, char *username, char *password)
  334. {
  335.     char *key;
  336.     PCNameValueArray *array = PC_NewNameValueArray();
  337.  
  338.     if(!array)
  339.         return;
  340.  
  341.     PC_AddToNameValueArray(array, HTTP_PW_NAME_TOKEN, username);    
  342.     PC_AddToNameValueArray(array, HTTP_PW_PASSWORD_TOKEN, password);    
  343.  
  344.     key = gen_http_key(address, realm);
  345.  
  346.     if(!key)
  347.         return;
  348.  
  349.     PC_StorePasswordNameValueArray(HTTP_PW_MODULE_NAME, key, array);
  350.  
  351.     FREE(key);
  352.  
  353. }
  354.  
  355. PRIVATE void
  356. net_remove_stored_http_password(char *url)
  357. {
  358.     PC_DeleteStoredPassword(HTTP_PW_MODULE_NAME, url);
  359. }
  360.  
  361. MODULE_PRIVATE void
  362. net_http_password_data_interp(
  363.         char *module,
  364.         char *key,
  365.         char *data, int32 data_len,
  366.         char *type_buffer, int32 type_buffer_size,
  367.         char *url_buffer, int32 url_buffer_size,
  368.         char *username_buffer, int32 username_buffer_size,
  369.         char *password_buffer, int32 password_buffer_size)
  370. {
  371.     PCNameValueArray * array;
  372.     char *username, *password;
  373.     char *address, *realm;
  374.  
  375.     array = PC_CharToNameValueArray(data, data_len);
  376.  
  377.     if(!array)
  378.         return;
  379.  
  380.     username = PC_FindInNameValueArray(array, HTTP_PW_NAME_TOKEN);
  381.     password = PC_FindInNameValueArray(array, HTTP_PW_PASSWORD_TOKEN);
  382.     
  383.     XP_STRNCPY_SAFE(type_buffer, "HTTP basic authorization", type_buffer_size);
  384.  
  385.     separate_http_key(key, &address, &realm);
  386.  
  387.     if(address)
  388.     {
  389.         XP_STRNCPY_SAFE(url_buffer, address, url_buffer_size);
  390.     }
  391.  
  392.     if(username)
  393.     {
  394.         XP_STRNCPY_SAFE(username_buffer, username, username_buffer_size);
  395.         XP_FREE(username);
  396.     }
  397.     
  398.     if(password)
  399.     {
  400.         XP_STRNCPY_SAFE(password_buffer, password, password_buffer_size);
  401.         XP_FREE(password);
  402.     }
  403. }
  404.  
  405. PRIVATE void
  406. net_initialize_http_access()
  407. {
  408.     /* register PW cache interp function */
  409.     
  410.     PC_RegisterDataInterpretFunc(HTTP_PW_MODULE_NAME,     
  411.                      net_http_password_data_interp);
  412. }
  413.  
  414. /* returns false if the user wishes to cancel authorization
  415.  * and TRUE if the user wants to continue with a new authorization
  416.  * string
  417.  */
  418. /* HARDTS: I took a whack at fixing up some of the strings leaked in this 
  419.  * function.  All the XP_FREEIF()s are new. 
  420.  */
  421. PUBLIC Bool 
  422. NET_AskForAuthString(MWContext *context,
  423.                      URL_Struct * URL_s, 
  424.                      char * authenticate, 
  425.                      char * prot_template,
  426.                      Bool   already_sent_auth)
  427. {
  428.     static XP_Bool first_time=TRUE;
  429.     net_AuthStruct *prev_auth;
  430.     char *address=URL_s->address;
  431.     char *host=NET_ParseURL(address, GET_HOST_PART);
  432.     char *new_address=NULL;
  433.     char *username=NULL,*colon=NULL,*password=NULL,*unamePwd=NULL;
  434.     char *u_pass_string=NULL;
  435.     char *auth_string=NULL;
  436.     char *realm;
  437.     char *slash;
  438.     char *authenticate_header_value;
  439.     char *buf=NULL;
  440.     int32 len=0;
  441.     int status;
  442.     XP_Bool re_authorize=FALSE;
  443.  
  444.     TRACEMSG(("Entering NET_AskForAuthString"));
  445.  
  446.     if(first_time)
  447.     {
  448.         net_initialize_http_access();
  449.         first_time = FALSE;
  450.     }
  451.  
  452.     if(authenticate)
  453.       {
  454.         /* check for the compuserve Remote-Passphrase type of
  455.           * authentication
  456.           */
  457.         authenticate_header_value = XP_StripLine(authenticate);
  458.  
  459. #define COMPUSERVE_HEADER_NAME "Remote-Passphrase"
  460.  
  461.         if(!strncasecomp(authenticate_header_value, 
  462.                      COMPUSERVE_HEADER_NAME, 
  463.                      sizeof(COMPUSERVE_HEADER_NAME) - 1))
  464.           {
  465.               /* This is a compuserv style header 
  466.                */
  467.  
  468.         XP_FREEIF(host);
  469. #if defined(XP_WIN) && defined(MOZILLA_CLIENT)
  470.         return(WFE_DoCompuserveAuthenticate(context, URL_s, authenticate_header_value));
  471. #else
  472.         return(NET_AUTH_FAILED_DISPLAY_DOCUMENT);        
  473. #endif    
  474.           }             
  475. #define HTTP_BASIC_AUTH_TOKEN "BASIC"
  476.         else if(strncasecomp(authenticate_header_value, 
  477.                      HTTP_BASIC_AUTH_TOKEN, 
  478.                      sizeof(HTTP_BASIC_AUTH_TOKEN) - 1))
  479.         {
  480.             /* unsupported auth type */
  481.             return(NET_AUTH_FAILED_DISPLAY_DOCUMENT);        
  482.         }
  483.       }
  484.  
  485.     new_address = NET_ParseURL(address,    GET_PROTOCOL_PART | GET_HOST_PART | GET_PATH_PART);
  486.     if(!new_address) {
  487.         XP_FREEIF(host);
  488.         return NET_AUTH_FAILED_DISPLAY_DOCUMENT;
  489.     }
  490.  
  491.     unamePwd=NET_ParseURL(address, GET_USERNAME_PART | GET_PASSWORD_PART);
  492.     /* get the username & password out of the combo string */
  493.     if( (colon = XP_STRCHR(unamePwd, ':')) != NULL ) {
  494.         *colon='\0';
  495.         username=XP_STRDUP(unamePwd);
  496.         password=XP_STRDUP(colon+1);
  497.         *colon=':';
  498.         XP_FREE(unamePwd);
  499.     } else {
  500.         username=unamePwd;
  501.     }
  502.  
  503.     if(username && !(*username) )
  504.         FREE_AND_CLEAR(username);
  505.     if(password && !(*password) )
  506.         FREE_AND_CLEAR(password);
  507.  
  508.     /*if last char is not a slash then */
  509.     if (new_address[XP_STRLEN(new_address)-1] != '/')
  510.     {
  511.         /* remove everything after the last slash */
  512.         slash = XP_STRRCHR(new_address, '/');
  513.         if(++slash)
  514.             *slash = '\0';
  515.     }
  516.  
  517.     if(!authenticate)
  518.       {
  519.         realm = "unknown";
  520.       }
  521.     else
  522.       {
  523.         realm = XP_STRCHR(authenticate, '"');
  524.     
  525.         if(realm)
  526.           {
  527.             realm++;
  528.  
  529.             /* terminate at next quote */
  530.             XP_STRTOK(realm, "\"");
  531.  
  532. #define MAX_REALM_SIZE 128
  533.             if(XP_STRLEN(realm) > MAX_REALM_SIZE)
  534.                 realm[MAX_REALM_SIZE] = '\0';
  535.     
  536.       }
  537.         else
  538.           {
  539.             realm = "unknown";
  540.            }
  541.         
  542.     }
  543.  
  544.     /* no hostname/realm match search for exact match */
  545.     prev_auth = net_CheckForAuthorization(new_address, FALSE);
  546.  
  547.     if(prev_auth && !already_sent_auth)
  548.       {
  549.         /* somehow the mapping changed since the time we sent
  550.          * the authorization.
  551.          * This happens sometimes because of the parrallel
  552.          * nature of the requests.
  553.          * In this case we want to just retry the connection
  554.          * since it will probably succede now.
  555.          */
  556.         XP_FREEIF(host);
  557.         XP_FREEIF(new_address);
  558.         XP_FREEIF(username);
  559.         XP_FREEIF(password);
  560.         return(NET_RETRY_WITH_AUTH);
  561.       }
  562.     else if(prev_auth)
  563.       {
  564.         /* we sent the authorization string and it was wrong
  565.          */
  566.         if(!FE_Confirm(context, XP_GetString(XP_CONFIRM_AUTHORIZATION_FAIL)))
  567.           {
  568.             TRACEMSG(("User canceled login!!!"));
  569.  
  570.             if(!XP_STRCMP(prev_auth->path, new_address))
  571.               {
  572.                 /* if the paths are exact and the user cancels
  573.                  * remove the mapping
  574.                  */
  575.                 net_remove_exact_auth_match_on_cancel(prev_auth, new_address);
  576.                 XP_FREEIF(host);
  577.                 XP_FREEIF(new_address);
  578.                 XP_FREEIF(username);
  579.                 XP_FREEIF(password);
  580.                 return(NET_AUTH_FAILED_DISPLAY_DOCUMENT);
  581.               }
  582.           }
  583.         
  584.         if (!username)
  585.             username = XP_STRDUP(prev_auth->username);
  586.         if (!password)
  587.             password = XP_STRDUP(prev_auth->password);
  588.         re_authorize = TRUE;
  589.       }
  590.     else
  591.       {
  592.         char *ptr1, *ptr2;
  593.  
  594.         /* scan all the authorization strings to see if we
  595.          * can find a hostname and realm match.  If we find
  596.          * a match then reduce the authorization path to include
  597.          * the current path as well.
  598.          */
  599.         prev_auth = net_ScanForHostnameRealmMatch(address, realm);
  600.     
  601.         if(prev_auth)
  602.           {
  603.             char *tmp;
  604.  
  605.             net_remove_stored_http_password(prev_auth->path);
  606.  
  607.             /* compare the two url paths until they deviate
  608.              * once they deviate truncate
  609.              */
  610.             for(ptr1 = prev_auth->path, ptr2 = new_address; *ptr1 && *ptr2; ptr1++, ptr2++)
  611.               {
  612.                 if(*ptr1 != *ptr2)
  613.                   {
  614.                     break;        /* end for */
  615.                   }
  616.               }
  617.             /* truncate at *ptr1 now since the new address may
  618.              * be just a subpath of the original address and
  619.              * the compare above will not handle the subpath correctly
  620.              */
  621.             *ptr1 = '\0'; /* truncate */
  622.  
  623.             if(*(ptr1-1) == '/')
  624.                 *(ptr1-1) = '\0'; /* strip a trailing slash */
  625.  
  626.             /* make sure a path always has at least a slash
  627.              * at the end.
  628.              * If the slash isn't there then
  629.              * the password will be sent to ports on the
  630.              * same host since we use a first part match
  631.              */
  632.             tmp = NET_ParseURL(prev_auth->path, GET_PATH_PART);
  633.             if(!*tmp)
  634.                 StrAllocCat(prev_auth->path, "/");
  635.             FREE(tmp);                
  636.  
  637.             TRACEMSG(("Truncated new auth path to be: %s", prev_auth->path));
  638.  
  639.             net_store_http_password(prev_auth->path, prev_auth->realm, prev_auth->username, prev_auth->password);
  640.  
  641.             FREE(host);
  642.             FREE(new_address);
  643.             return(NET_RETRY_WITH_AUTH);
  644.           }
  645.       }
  646.                      
  647.     /* Use username and/or password specified in URL_struct if exists. */
  648.     if (!username && URL_s->username && *URL_s->username) {
  649.         username = XP_STRDUP(URL_s->username);
  650.     }
  651.     if (!password && URL_s->password && *URL_s->password) {
  652.         password = XP_STRDUP(URL_s->password);
  653.     }
  654.  
  655.     if(!username && !password)
  656.     {
  657.         /* look for a previously stored password in the pw cache */
  658.         PCNameValueArray *array;
  659.  
  660.         array = PC_CheckForStoredPasswordArray(HTTP_PW_MODULE_NAME, URL_s->address);
  661.  
  662.         if(array)
  663.         {
  664.             username = PC_FindInNameValueArray(array, HTTP_PW_NAME_TOKEN);
  665.             password = PC_FindInNameValueArray(array, HTTP_PW_PASSWORD_TOKEN);
  666.  
  667.             if(!username)
  668.                 FREE_AND_CLEAR(password);
  669.         }
  670.     }
  671.  
  672.     /* if the password is filled in then the username must
  673.      * be filled in already.  
  674.      */
  675.     if(!password || re_authorize)
  676.       {
  677.         XP_Bool remember_password;
  678.            host = NET_ParseURL(address, GET_HOST_PART);
  679.  
  680.         /* malloc memory here to prevent buffer overflow */
  681.         len = XP_STRLEN(XP_GetString(XP_ACCESS_ENTER_USERNAME));
  682.         len += XP_STRLEN(realm) + XP_STRLEN(host) + 10;
  683.         
  684.         buf = (char *)XP_ALLOC(len*sizeof(char));
  685.         
  686.         if(buf)
  687.           {
  688.             PR_snprintf( buf, len*sizeof(char), 
  689.                         XP_GetString(XP_ACCESS_ENTER_USERNAME), 
  690.                         realm, host);
  691.  
  692.  
  693.             NET_Progress(context, XP_GetString( XP_CONNECT_PLEASE_ENTER_PASSWORD_FOR_HOST) );
  694.             if (username && !(*username))
  695.                 XP_FREE(username);
  696.             XP_FREEIF(password);
  697.             status = PC_PromptUsernameAndPassword(context, buf, 
  698.                                                     &username, &password, 
  699.                                                   &remember_password,
  700.                                                   NET_IsURLSecure(URL_s->address));
  701.     
  702.             FREE(buf);
  703.           }
  704.         else
  705.           {
  706.             status = 0;
  707.           }
  708.  
  709.         FREE(host);
  710.  
  711.         if(!status)
  712.           {
  713.             TRACEMSG(("User canceled login!!!"));
  714.  
  715.             /* if the paths are exact and the user cancels
  716.              * remove the mapping
  717.              */
  718.             net_remove_exact_auth_match_on_cancel(prev_auth, new_address);
  719.  
  720.             XP_FREEIF(username);
  721.             XP_FREEIF(password);
  722.             XP_FREEIF(new_address);
  723.             return(NET_AUTH_FAILED_DISPLAY_DOCUMENT);
  724.           }
  725.         else if(!username || !password)
  726.           {
  727.             XP_FREEIF(username);
  728.             XP_FREEIF(password);
  729.             XP_FREEIF(new_address);
  730.             return(NET_AUTH_FAILED_DISPLAY_DOCUMENT);
  731.           }
  732.         else if(remember_password)
  733.         {
  734.             net_store_http_password(URL_s->address, realm, username, password);
  735.         }
  736.       }
  737.  
  738.     StrAllocCopy(u_pass_string, username);
  739.     StrAllocCat(u_pass_string, ":");
  740.     StrAllocCat(u_pass_string, password);
  741.  
  742.     len = XP_STRLEN(u_pass_string);
  743.     auth_string = (char*) XP_ALLOC((((len+1)*4)/3)+10);
  744.  
  745.     if(!auth_string)
  746.       {
  747.         XP_FREEIF(username);
  748.         XP_FREEIF(password);
  749.         XP_FREEIF(u_pass_string);
  750.         FREE(new_address);
  751.         return(NET_RETRY_WITH_AUTH);
  752.       }
  753.  
  754.     NET_UUEncode((unsigned char *)u_pass_string, (unsigned char*) auth_string, len);
  755.  
  756.     FREE(u_pass_string);
  757.  
  758.     if(prev_auth)
  759.       {
  760.         XP_FREEIF(prev_auth->auth_string);
  761.         prev_auth->auth_string = auth_string;
  762.         XP_FREEIF(prev_auth->username);
  763.         prev_auth->username = username;
  764.         XP_FREEIF(prev_auth->password);
  765.         prev_auth->password = password;
  766.       }
  767.     else
  768.       {
  769.         XP_List * list_ptr = net_auth_list;
  770.         net_AuthStruct * tmp_auth_ptr;
  771.         size_t new_len;
  772.  
  773.         /* construct a new auth_struct
  774.          */
  775.         prev_auth = XP_NEW_ZAP(net_AuthStruct);
  776.         if(!prev_auth)
  777.           {
  778.             XP_FREEIF(auth_string);
  779.             XP_FREEIF(username);
  780.             XP_FREEIF(password);
  781.             FREE(new_address);
  782.             return(NET_RETRY_WITH_AUTH);
  783.           }
  784.         
  785.         prev_auth->auth_string = auth_string;
  786.         prev_auth->username = username;
  787.         prev_auth->password = password;
  788.         prev_auth->path = 0;
  789.         StrAllocCopy(prev_auth->path, new_address);
  790.         prev_auth->realm = 0;
  791.         StrAllocCopy(prev_auth->realm, realm);
  792.  
  793.         if(!net_auth_list)
  794.           {
  795.             net_auth_list = XP_ListNew();
  796.             if(!net_auth_list)
  797.               {
  798.           /* Maybe should free prev_auth here. */
  799.                    FREE(new_address);
  800.                 return(NET_RETRY_WITH_AUTH);
  801.               }
  802.           }        
  803.  
  804.         /* add it to the list so that it is before any strings of
  805.          * smaller length
  806.          */
  807.         new_len = XP_STRLEN(prev_auth->path);
  808.         while((tmp_auth_ptr = (net_AuthStruct *) XP_ListNextObject(list_ptr))!=0)
  809.           { 
  810.             if(new_len > XP_STRLEN(tmp_auth_ptr->path))
  811.               {
  812.                 XP_ListInsertObject(net_auth_list, tmp_auth_ptr, prev_auth);
  813.                    FREE(new_address);
  814.                 return(NET_RETRY_WITH_AUTH);
  815.               }
  816.           }
  817.         /* no shorter strings found in list */    
  818.         XP_ListAddObjectToEnd(net_auth_list, prev_auth);
  819.       }
  820.  
  821.     FREE(new_address);
  822.     return(NET_RETRY_WITH_AUTH);
  823. }
  824.  
  825. /*--------------------------------------------------
  826.  * The following routines support the 
  827.  * Set-Cookie: / Cookie: headers
  828.  */
  829.  
  830. PRIVATE XP_List * net_cookie_list=0;
  831.  
  832. typedef struct _net_CookieStruct {
  833.     char * path;
  834.     char * host;
  835.     char * name;
  836.     char * cookie;
  837.     time_t expires;
  838.     time_t last_accessed;
  839.     Bool   secure;      /* only send for https connections */
  840.     Bool   is_domain;   /* is it a domain instead of an absolute host? */
  841. } net_CookieStruct;
  842.  
  843. /* Routines and data to protect the cookie list so it
  844. **   can be accessed by mulitple threads
  845. */
  846.  
  847. #include "prthread.h"
  848. #include "prmon.h"
  849.  
  850. static PRMonitor * cookie_lock_monitor = NULL;
  851. static PRThread  * cookie_lock_owner = NULL;
  852. static int cookie_lock_count = 0;
  853.  
  854. PRIVATE void
  855. net_lock_cookie_list()
  856. {
  857.     if(!cookie_lock_monitor)
  858.     cookie_lock_monitor = PR_NewNamedMonitor("cookie-lock");
  859.  
  860.     PR_EnterMonitor(cookie_lock_monitor);
  861.  
  862.     while(TRUE) {
  863.  
  864.     /* no current owner or owned by this thread */
  865.     PRThread * t = PR_CurrentThread();
  866.     if(cookie_lock_owner == NULL || cookie_lock_owner == t) {
  867.         cookie_lock_owner = t;
  868.         cookie_lock_count++;
  869.  
  870.         PR_ExitMonitor(cookie_lock_monitor);
  871.         return;
  872.     }
  873.  
  874.     /* owned by someone else -- wait till we can get it */
  875.     PR_Wait(cookie_lock_monitor, PR_INTERVAL_NO_TIMEOUT);
  876.  
  877.     }
  878. }
  879.  
  880. PRIVATE void
  881. net_unlock_cookie_list()
  882. {
  883.    PR_EnterMonitor(cookie_lock_monitor);
  884.  
  885. #ifdef DEBUG
  886.     /* make sure someone doesn't try to free a lock they don't own */
  887.     XP_ASSERT(cookie_lock_owner == PR_CurrentThread());
  888. #endif
  889.  
  890.     cookie_lock_count--;
  891.  
  892.     if(cookie_lock_count == 0) {
  893.     cookie_lock_owner = NULL;
  894.     PR_Notify(cookie_lock_monitor);
  895.     }
  896.     PR_ExitMonitor(cookie_lock_monitor);
  897.  
  898. }
  899.  
  900. /* This should only get called while holding the cookie-lock
  901. **
  902. */
  903. PRIVATE void
  904. net_FreeCookie(net_CookieStruct * cookie)
  905. {
  906.  
  907.     if(!cookie)
  908.         return;
  909.  
  910.     XP_ListRemoveObject(net_cookie_list, cookie);
  911.  
  912.     XP_FREEIF(cookie->path);
  913.     XP_FREEIF(cookie->host);
  914.     XP_FREEIF(cookie->name);
  915.     XP_FREEIF(cookie->cookie);
  916.  
  917.     FREE(cookie);
  918.  
  919.     cookies_changed = TRUE;
  920. }
  921.  
  922.  
  923.  
  924. /* blows away all cookies currently in the list, then blows away the list itself
  925.  * nulling it after it's free'd
  926.  */
  927. PUBLIC void
  928. NET_RemoveAllCookies()
  929. {
  930.     net_CookieStruct * victim;
  931.     XP_List * cookieList;
  932.  
  933.     /* check for NULL or empty list */
  934.     net_lock_cookie_list();
  935.     cookieList = net_cookie_list;
  936.     if(XP_ListIsEmpty(cookieList)) {
  937.         net_unlock_cookie_list();
  938.         return;
  939.     }
  940.  
  941.     while((victim = (net_CookieStruct *) XP_ListNextObject(cookieList)) != 0) {
  942.         net_FreeCookie(victim);
  943.         cookieList=net_cookie_list;
  944.     }
  945.     XP_ListDestroy(net_cookie_list);
  946.     net_cookie_list = NULL;
  947.     net_unlock_cookie_list();
  948. }
  949.  
  950. PRIVATE void
  951. net_remove_oldest_cookie(void)
  952. {
  953.     XP_List * list_ptr;
  954.     net_CookieStruct * cookie_s;
  955.     net_CookieStruct * oldest_cookie;
  956.  
  957.     net_lock_cookie_list();
  958.     list_ptr = net_cookie_list;
  959.  
  960.     if(XP_ListIsEmpty(list_ptr)) {
  961.         net_unlock_cookie_list();
  962.         return;
  963.     }
  964.  
  965.     oldest_cookie = (net_CookieStruct*) list_ptr->next->object;
  966.     
  967.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0)
  968.       {
  969.         if(cookie_s->last_accessed < oldest_cookie->last_accessed)
  970.             oldest_cookie = cookie_s;
  971.       }
  972.  
  973.     if(oldest_cookie)
  974.       {
  975.         TRACEMSG(("Freeing cookie because global max cookies has been exceeded"));
  976.         net_FreeCookie(oldest_cookie);
  977.       }
  978.     net_unlock_cookie_list();
  979. }
  980.  
  981. /* Remove any expired cookies from memory 
  982. ** This routine should only be called while holding the cookie list lock
  983. */
  984. PRIVATE void
  985. net_remove_expired_cookies(void)
  986. {
  987.     XP_List * list_ptr = net_cookie_list;
  988.     net_CookieStruct * cookie_s;
  989.     time_t cur_time = time(NULL);
  990.  
  991.     if(XP_ListIsEmpty(list_ptr))
  992.         return;
  993.  
  994.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0)
  995.       {
  996.         /* Don't get rid of expire time 0 because these need to last for 
  997.          * the entire session. They'll get cleared on exit.
  998.          */
  999.         if( cookie_s->expires && (cookie_s->expires < cur_time) ) {
  1000.             net_FreeCookie(cookie_s);
  1001.             /* Reset the list_ptr to the beginning of the list.
  1002.              * Do this because list_ptr's object was just freed
  1003.              * by the call to net_FreeCookie struct, even
  1004.              * though it's inefficient.
  1005.              */
  1006.             list_ptr = net_cookie_list;
  1007.         }
  1008.       }
  1009. }
  1010.  
  1011. /* checks to see if the maximum number of cookies per host
  1012.  * is being exceeded and deletes the oldest one in that
  1013.  * case
  1014.  * This routine should only be called while holding the cookie lock
  1015.  */
  1016. PRIVATE void
  1017. net_CheckForMaxCookiesFromHost(const char * cur_host)
  1018. {
  1019.     XP_List * list_ptr = net_cookie_list;
  1020.     net_CookieStruct * cookie_s;
  1021.     net_CookieStruct * oldest_cookie = 0;
  1022.     int cookie_count = 0;
  1023.  
  1024.     if(XP_ListIsEmpty(list_ptr))
  1025.         return;
  1026.  
  1027.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0)
  1028.       {
  1029.         if(!strcasecomp(cookie_s->host, cur_host))
  1030.           {
  1031.             cookie_count++;
  1032.             if(!oldest_cookie 
  1033.                 || oldest_cookie->last_accessed > cookie_s->last_accessed)
  1034.                 oldest_cookie = cookie_s;
  1035.           }
  1036.       }
  1037.  
  1038.     if(cookie_count >= MAX_COOKIES_PER_SERVER && oldest_cookie)
  1039.       {
  1040.         TRACEMSG(("Freeing cookie because max cookies per server has been exceeded"));
  1041.         net_FreeCookie(oldest_cookie);
  1042.       }
  1043. }
  1044.  
  1045.  
  1046. /* search for previous exact match
  1047. ** This routine should only be called while holding the cookie lock
  1048. */
  1049. PRIVATE net_CookieStruct *
  1050. net_CheckForPrevCookie(char * path,
  1051.                    char * hostname,
  1052.                    char * name)
  1053. {
  1054.  
  1055.     XP_List * list_ptr = net_cookie_list;
  1056.     net_CookieStruct * cookie_s;
  1057.  
  1058.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0)
  1059.       {
  1060.         if(path 
  1061.             && hostname 
  1062.                 && cookie_s->path
  1063.                    && cookie_s->host
  1064.                       && cookie_s->name
  1065.                           && !XP_STRCMP(name, cookie_s->name)
  1066.                             && !XP_STRCMP(path, cookie_s->path)
  1067.                                 && !XP_STRCASECMP(hostname, cookie_s->host))
  1068.                 return(cookie_s);
  1069.             
  1070.       }
  1071.  
  1072.     return(NULL);
  1073. }
  1074.  
  1075. /* cookie utility functions */
  1076. PRIVATE void
  1077. NET_SetCookieBehaviorPref(NET_CookieBehaviorEnum x)
  1078. {
  1079.     net_CookieBehavior = x;
  1080.  
  1081.     if(net_CookieBehavior == NET_DontUse)
  1082.         XP_FileRemove("", xpHTTPCookie);
  1083. }
  1084.  
  1085. PRIVATE void
  1086. NET_SetCookieWarningPref(Bool x)
  1087. {
  1088.     net_WarnAboutCookies = x;
  1089. }
  1090.  
  1091. PRIVATE void
  1092. NET_SetCookieScriptPref(const char *name)
  1093. {
  1094.     XP_FREEIF(net_scriptName);
  1095.     if( name && *name )
  1096.         net_scriptName=XP_STRDUP(name);
  1097.     else
  1098.         net_scriptName=NULL;
  1099. }
  1100.  
  1101. PRIVATE NET_CookieBehaviorEnum
  1102. NET_GetCookieBehaviorPref(void)
  1103. {
  1104.     return net_CookieBehavior;
  1105. }
  1106.  
  1107. PRIVATE Bool
  1108. NET_GetCookieWarningPref(void)
  1109. {
  1110.     return net_WarnAboutCookies;
  1111. }
  1112.  
  1113. PRIVATE const char *
  1114. NET_GetCookieScriptPref(void)
  1115. {
  1116.     return (const char *)net_scriptName;
  1117. }
  1118.  
  1119. MODULE_PRIVATE int PR_CALLBACK
  1120. NET_CookieBehaviorPrefChanged(const char * newpref, void * data)
  1121. {
  1122.     int32    n;
  1123.     PREF_GetIntPref(pref_cookieBehavior, &n);
  1124.     NET_SetCookieBehaviorPref((NET_CookieBehaviorEnum)n);
  1125.     return PREF_NOERROR;
  1126. }
  1127.  
  1128. MODULE_PRIVATE int PR_CALLBACK
  1129. NET_CookieWarningPrefChanged(const char * newpref, void * data)
  1130. {
  1131.     Bool    x;
  1132.     PREF_GetBoolPref(pref_warnAboutCookies, &x);
  1133.     NET_SetCookieWarningPref(x);
  1134.     return PREF_NOERROR;
  1135. }
  1136.  
  1137. MODULE_PRIVATE int PR_CALLBACK
  1138. NET_CookieScriptPrefChanged(const char * newpref, void * data)
  1139. {
  1140.     char    s[64];
  1141.     int len = sizeof(s);
  1142.     PREF_GetCharPref(pref_scriptName, s, &len);
  1143.     NET_SetCookieScriptPref(s);
  1144.     return PREF_NOERROR;
  1145. }
  1146.  
  1147.  
  1148. /* called from mkgeturl.c, NET_InitNetLib(). This sets the module local cookie pref variables
  1149.    and registers the callbacks */
  1150. PUBLIC void
  1151. NET_RegisterCookiePrefCallbacks(void)
  1152. {
  1153.     int32    n;
  1154.     Bool    x;
  1155.     char    s[64];
  1156.     int len = sizeof(s);
  1157.  
  1158.     PREF_GetIntPref(pref_cookieBehavior, &n);
  1159.     NET_SetCookieBehaviorPref((NET_CookieBehaviorEnum)n);
  1160.     PREF_RegisterCallback(pref_cookieBehavior, NET_CookieBehaviorPrefChanged, NULL);
  1161.  
  1162.     PREF_GetBoolPref(pref_warnAboutCookies, &x);
  1163.     NET_SetCookieWarningPref(x);
  1164.     PREF_RegisterCallback(pref_warnAboutCookies, NET_CookieWarningPrefChanged, NULL);
  1165.  
  1166.     PREF_GetCharPref(pref_scriptName, s, &len);
  1167.     NET_SetCookieScriptPref(s);
  1168.     PREF_RegisterCallback(pref_scriptName, NET_CookieScriptPrefChanged, NULL);
  1169. }
  1170.  
  1171. /* returns TRUE if authorization is required
  1172. ** 
  1173. **
  1174. ** IMPORTANT:  Now that this routine is mutli-threaded it is up
  1175. **             to the caller to free any returned string
  1176. */
  1177. PUBLIC char *
  1178. NET_GetCookie(MWContext * context, char * address)
  1179. {
  1180.     char *name=0;
  1181.     char *host = NET_ParseURL(address, GET_HOST_PART);
  1182.     char *path = NET_ParseURL(address, GET_PATH_PART);
  1183.     XP_List * list_ptr;
  1184.     net_CookieStruct * cookie_s;
  1185.     Bool first=TRUE;
  1186.     Bool secure_path=FALSE;
  1187.     time_t cur_time = time(NULL);
  1188.     int host_length;
  1189.     int domain_length;
  1190.  
  1191.     /* return string to build */
  1192.     char * rv=0;
  1193.  
  1194.     /* disable cookie's if the user's prefs say so
  1195.      */
  1196.     if(NET_GetCookieBehaviorPref() == NET_DontUse)
  1197.         return NULL;
  1198.  
  1199.     if(!strncasecomp(address, "https", 5))
  1200.         secure_path = TRUE;
  1201.  
  1202.     /* search for all cookies
  1203.      */
  1204.     net_lock_cookie_list();
  1205.     list_ptr = net_cookie_list;
  1206.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0)
  1207.       {
  1208.         if(!cookie_s->host)
  1209.             continue;
  1210.  
  1211.         /* check the host or domain first
  1212.          */
  1213.         if(cookie_s->is_domain)
  1214.           {
  1215.             char *cp;
  1216.             domain_length = XP_STRLEN(cookie_s->host);
  1217.  
  1218.             /* calculate the host length by looking at all characters up to
  1219.              * a colon or '\0'.  That way we won't include port numbers
  1220.              * in domains
  1221.              */
  1222.             for(cp=host; *cp != '\0' && *cp != ':'; cp++)
  1223.                 ; /* null body */ 
  1224.  
  1225.             host_length = cp - host;
  1226.             if(domain_length > host_length 
  1227.                 || strncasecomp(cookie_s->host, 
  1228.                                 &host[host_length - domain_length], 
  1229.                                 domain_length))
  1230.               {
  1231.                 /* no match. FAIL 
  1232.                  */
  1233.                 continue;
  1234.               }
  1235.             
  1236.           }
  1237.         else if(strcasecomp(host, cookie_s->host))
  1238.           {
  1239.             /* hostname matchup failed. FAIL
  1240.              */
  1241.             continue;
  1242.           }
  1243.  
  1244.         /* shorter strings always come last so there can be no
  1245.          * ambiquity
  1246.          */
  1247.         if(cookie_s->path && !XP_STRNCMP(path,
  1248.                                          cookie_s->path,
  1249.                                          XP_STRLEN(cookie_s->path)))
  1250.           {
  1251.  
  1252.             /* if the cookie is secure and the path isn't
  1253.              * dont send it
  1254.              */
  1255.             if(cookie_s->secure && !secure_path)
  1256.                 continue;  /* back to top of while */
  1257.             
  1258.             /* check for expired cookies
  1259.              */
  1260.             if( cookie_s->expires && (cookie_s->expires < cur_time) )
  1261.               {
  1262.                 /* expire and remove the cookie 
  1263.                  */
  1264.                    net_FreeCookie(cookie_s);
  1265.  
  1266.                 /* start the list parsing over :(
  1267.                  * we must also start the string over
  1268.                  */
  1269.                 FREE_AND_CLEAR(rv);
  1270.                 list_ptr = net_cookie_list;
  1271.                 first = TRUE; /* reset first */
  1272.                 continue;
  1273.               }
  1274.  
  1275.             if(first)
  1276.                 first = FALSE;
  1277.             else
  1278.                 StrAllocCat(rv, "; ");
  1279.             
  1280.             if(cookie_s->name && *cookie_s->name != '\0')
  1281.               {
  1282.                 cookie_s->last_accessed = cur_time;
  1283.                 StrAllocCopy(name, cookie_s->name);
  1284.                 StrAllocCat(name, "=");
  1285.  
  1286. #ifdef PREVENT_DUPLICATE_NAMES
  1287.                 /* make sure we don't have a previous
  1288.                  * name mapping already in the string
  1289.                  */
  1290.                 if(!rv || !XP_STRSTR(rv, name))
  1291.                   {    
  1292.                     StrAllocCat(rv, name);
  1293.                     StrAllocCat(rv, cookie_s->cookie);
  1294.                   }
  1295. #else
  1296.                 StrAllocCat(rv, name);
  1297.                 StrAllocCat(rv, cookie_s->cookie);
  1298. #endif /* PREVENT_DUPLICATE_NAMES */
  1299.               }
  1300.             else
  1301.               {
  1302.                 StrAllocCat(rv, cookie_s->cookie);
  1303.               }
  1304.           }
  1305.       }
  1306.  
  1307.       net_unlock_cookie_list();
  1308.     XP_FREEIF(name);
  1309.     FREE(path);
  1310.     FREE(host);
  1311.  
  1312.     /* may be NULL */
  1313.     return(rv);
  1314. }
  1315.  
  1316. /* Java script is calling NET_SetCookieString, netlib is calling 
  1317. ** this via NET_SetCookieStringFromHttp.
  1318. */
  1319. PRIVATE void
  1320. net_IntSetCookieString(MWContext * context, 
  1321.                     char * cur_url,
  1322.                     char * set_cookie_header,
  1323.                     time_t timeToExpire)
  1324. {
  1325.     net_CookieStruct * prev_cookie;
  1326.     char *path_from_header=NULL, *host_from_header=NULL;
  1327.     char *name_from_header=NULL, *cookie_from_header=NULL;
  1328.     time_t expires=0;
  1329.     char *cur_path = NET_ParseURL(cur_url, GET_PATH_PART);
  1330.     char *cur_host = NET_ParseURL(cur_url, GET_HOST_PART);
  1331.     char *semi_colon, *ptr, *equal;
  1332.     const char *script_name;
  1333.     XP_Bool set_secure=FALSE, is_domain=FALSE, ask=FALSE, accept=FALSE;
  1334.     MWContextType type;
  1335.  
  1336.     if(!context) {
  1337.         XP_FREE(cur_path);
  1338.         XP_FREE(cur_host);
  1339.         return;
  1340.     }
  1341.  
  1342.     /* Only allow cookies to be set in the listed contexts. We
  1343.      * don't want cookies being set in html mail. 
  1344.      */
  1345.     type = context->type;
  1346.     if(!( (type == MWContextBrowser)
  1347.         || (type == MWContextHTMLHelp)
  1348.         || (type == MWContextPane) )) {
  1349.         XP_FREE(cur_path);
  1350.         XP_FREE(cur_host);
  1351.         return;
  1352.     }
  1353.     
  1354.     if(NET_GetCookieBehaviorPref() == NET_DontUse) {
  1355.         XP_FREE(cur_path);
  1356.         XP_FREE(cur_host);
  1357.         return;
  1358.     }
  1359.  
  1360.     /* terminate at any carriage return or linefeed */
  1361.     for(ptr=set_cookie_header; *ptr; ptr++)
  1362.         if(*ptr == LF || *ptr == CR) {
  1363.             *ptr = '\0';
  1364.             break;
  1365.         }
  1366.  
  1367.     /* parse path and expires attributes from header if
  1368.       * present
  1369.      */
  1370.     semi_colon = XP_STRCHR(set_cookie_header, ';');
  1371.  
  1372.     if(semi_colon)
  1373.       {
  1374.         /* truncate at semi-colon and advance 
  1375.          */
  1376.         *semi_colon++ = '\0';
  1377.  
  1378.         /* there must be some attributes. (hopefully)
  1379.          */
  1380.         if(strcasestr(semi_colon, "secure"))
  1381.             set_secure = TRUE;
  1382.  
  1383.         /* look for the path attribute
  1384.          */
  1385.         ptr = strcasestr(semi_colon, "path=");
  1386.  
  1387.         if(ptr) {
  1388.             /* allocate more than we need */
  1389.             StrAllocCopy(path_from_header, XP_StripLine(ptr+5));
  1390.             /* terminate at first space or semi-colon
  1391.              */
  1392.             for(ptr=path_from_header; *ptr != '\0'; ptr++)
  1393.                 if(XP_IS_SPACE(*ptr) || *ptr == ';' || *ptr == ',') {
  1394.                     *ptr = '\0';
  1395.                     break;
  1396.                   }
  1397.           }
  1398.  
  1399.         /* look for the URI or URL attribute
  1400.          *
  1401.          * This might be a security hole so I'm removing
  1402.          * it for now.
  1403.          */
  1404.  
  1405.         /* look for a domain */
  1406.         ptr = strcasestr(semi_colon, "domain=");
  1407.  
  1408.         if(ptr) {
  1409.             char *domain_from_header=NULL;
  1410.             char *dot, *colon;
  1411.             int domain_length, cur_host_length;
  1412.  
  1413.             /* allocate more than we need */
  1414.             StrAllocCopy(domain_from_header, XP_StripLine(ptr+7));
  1415.  
  1416.             /* terminate at first space or semi-colon
  1417.              */
  1418.             for(ptr=domain_from_header; *ptr != '\0'; ptr++)
  1419.                 if(XP_IS_SPACE(*ptr) || *ptr == ';' || *ptr == ',') {
  1420.                     *ptr = '\0';
  1421.                     break;
  1422.                   }
  1423.  
  1424.             /* verify that this host has the authority to set for
  1425.              * this domain.   We do this by making sure that the
  1426.              * host is in the domain
  1427.              * We also require that a domain have at least two
  1428.              * periods to prevent domains of the form ".com"
  1429.              * and ".edu"
  1430.              *
  1431.              * Also make sure that there is more stuff after
  1432.              * the second dot to prevent ".com."
  1433.              */
  1434.             dot = XP_STRCHR(domain_from_header, '.');
  1435.             if(dot)
  1436.                 dot = XP_STRCHR(dot+1, '.');
  1437.  
  1438.             if(!dot || *(dot+1) == '\0') {
  1439.                 /* did not pass two dot test. FAIL
  1440.                  */
  1441.                 XP_FREE(domain_from_header);
  1442.                 XP_FREE(cur_path);
  1443.                 XP_FREE(cur_host);
  1444.                 TRACEMSG(("DOMAIN failed two dot test"));
  1445.                 return;
  1446.               }
  1447.  
  1448.             /* strip port numbers from the current host
  1449.              * for the domain test
  1450.              */
  1451.             colon = XP_STRCHR(cur_host, ':');
  1452.             if(colon)
  1453.                *colon = '\0';
  1454.  
  1455.             domain_length   = XP_STRLEN(domain_from_header);
  1456.             cur_host_length = XP_STRLEN(cur_host);
  1457.  
  1458.             /* check to see if the host is in the domain
  1459.              */
  1460.             if(domain_length > cur_host_length
  1461.                 || strcasecomp(domain_from_header, 
  1462.                                &cur_host[cur_host_length-domain_length]))
  1463.               {
  1464.                 TRACEMSG(("DOMAIN failed host within domain test."
  1465.                       " Domain: %s, Host: %s", domain_from_header, cur_host));
  1466.                 XP_FREE(domain_from_header);
  1467.                 XP_FREE(cur_path);
  1468.                 XP_FREE(cur_host);
  1469.                 return;
  1470.               }
  1471.  
  1472.             /* all tests passed, copy in domain to hostname field
  1473.              */
  1474.             StrAllocCopy(host_from_header, domain_from_header);
  1475.             is_domain = TRUE;
  1476.  
  1477.             TRACEMSG(("Accepted domain: %s", host_from_header));
  1478.  
  1479.             FREE(domain_from_header);
  1480.           }
  1481.  
  1482.         /* now search for the expires header 
  1483.          * NOTE: that this part of the parsing
  1484.          * destroys the original part of the string
  1485.          */
  1486.         ptr = strcasestr(semi_colon, "expires=");
  1487.  
  1488.         if(ptr) {
  1489.             char *date =  ptr+8;
  1490.             /* terminate the string at the next semi-colon
  1491.              */
  1492.             for(ptr=date; *ptr != '\0'; ptr++)
  1493.                 if(*ptr == ';') {
  1494.                     *ptr = '\0';
  1495.                     break;
  1496.                   }
  1497.             if(timeToExpire)
  1498.                 expires = timeToExpire;
  1499.             else
  1500.                 expires = NET_ParseDate(date);
  1501.  
  1502.             TRACEMSG(("Have expires date: %ld", expires));
  1503.           }
  1504.       }
  1505.  
  1506.     if(!path_from_header) {
  1507.         /* strip down everything after the last slash
  1508.          * to get the path.
  1509.          */
  1510.         char * slash = XP_STRRCHR(cur_path, '/');
  1511.         if(slash)
  1512.             *slash = '\0';
  1513.  
  1514.         path_from_header = cur_path;
  1515.       } else {
  1516.         XP_FREE(cur_path);
  1517.       }
  1518.  
  1519.     if(!host_from_header)
  1520.         host_from_header = cur_host;
  1521.     else
  1522.         XP_FREE(cur_host);
  1523.  
  1524.     /* keep cookies under the max bytes limit */
  1525.     if(XP_STRLEN(set_cookie_header) > MAX_BYTES_PER_COOKIE)
  1526.         set_cookie_header[MAX_BYTES_PER_COOKIE-1] = '\0';
  1527.  
  1528.     /* separate the name from the cookie */
  1529.     equal = XP_STRCHR(set_cookie_header, '=');
  1530.  
  1531.     if(equal) {
  1532.         *equal = '\0';
  1533.         StrAllocCopy(name_from_header, XP_StripLine(set_cookie_header));
  1534.         StrAllocCopy(cookie_from_header, XP_StripLine(equal+1));
  1535.       } else {
  1536.         TRACEMSG(("Warning: no name found for cookie"));
  1537.         StrAllocCopy(cookie_from_header, XP_StripLine(set_cookie_header));
  1538.         StrAllocCopy(name_from_header, "");
  1539.       }
  1540.  
  1541.     /* If there's a script, call it now */
  1542.     script_name = NET_GetCookieScriptPref();
  1543.     if( (const char *)0 != script_name ) {
  1544.         JSCFCookieData *cd;
  1545.         Bool changed = FALSE;
  1546.         JSCFResult result;
  1547.  
  1548.         cd = XP_NEW_ZAP(JSCFCookieData);
  1549.         if( (JSCFCookieData *)0 == cd ) {
  1550.             XP_FREEIF(path_from_header);
  1551.             XP_FREEIF(host_from_header);
  1552.             XP_FREEIF(name_from_header);
  1553.             XP_FREEIF(cookie_from_header);
  1554.             /* FREEIF(cur_path); */
  1555.             /* FREEIF(cur_host); */
  1556.             return;
  1557.         }
  1558.  
  1559.         cd->path_from_header = path_from_header;
  1560.         cd->host_from_header = host_from_header;
  1561.         cd->name_from_header = name_from_header;
  1562.         cd->cookie_from_header = cookie_from_header;
  1563.         cd->expires = expires;
  1564.         cd->url = cur_url;
  1565.         cd->secure = set_secure;
  1566.         cd->domain = is_domain;
  1567.         cd->prompt = NET_GetCookieWarningPref();
  1568.         cd->preference = NET_GetCookieBehaviorPref();
  1569.  
  1570.     /*
  1571.      * This probably is only safe to do from the mozilla thread
  1572.      *   since it might do file I/O and uses the preferences
  1573.      *   global context + objects
  1574.      * XXX chouck
  1575.      */
  1576.         result = JSCF_Execute(context, script_name, cd, &changed);
  1577.         if( result != JSCF_error) {
  1578.             if( changed ) {
  1579.                 if( cd->path_from_header != path_from_header ) {
  1580.                     XP_FREEIF(path_from_header);
  1581.                     path_from_header = XP_STRDUP(cd->path_from_header);
  1582.                 }
  1583.                 if( cd->host_from_header != host_from_header ) {
  1584.                     XP_FREEIF(host_from_header);
  1585.                     host_from_header = XP_STRDUP(cd->host_from_header);
  1586.                 }
  1587.                 if( cd->name_from_header != name_from_header ) {
  1588.                     XP_FREEIF(name_from_header);
  1589.                     name_from_header = XP_STRDUP(cd->name_from_header);
  1590.                 }
  1591.                 if( cd->cookie_from_header != cookie_from_header ) {
  1592.                     XP_FREEIF(cookie_from_header);
  1593.                   cookie_from_header = XP_STRDUP(cd->cookie_from_header);
  1594.               }
  1595.               if( cd->expires != expires )
  1596.                   expires = cd->expires;
  1597.               if( cd->domain != is_domain )
  1598.                   /* lets hope the luser remembered to change the domain field */
  1599.                   is_domain = cd->domain;
  1600.               if( cd->secure != set_secure )
  1601.                   set_secure = cd->secure;
  1602.             }
  1603.             switch( result ) {
  1604.                 case JSCF_reject:
  1605.                     XP_FREEIF(path_from_header);
  1606.                     XP_FREEIF(host_from_header);
  1607.                     XP_FREEIF(name_from_header);
  1608.                     XP_FREEIF(cookie_from_header);
  1609.                     XP_FREE(cd);
  1610.                     /* FREEIF(cur_path); */
  1611.                     /* FREEIF(cur_host); */
  1612.                 return;
  1613.                 case JSCF_accept:
  1614.                     accept=TRUE;
  1615.                 case JSCF_error:
  1616.                 case JSCF_ask:
  1617.                     ask=TRUE;
  1618.                 case JSCF_whatever:
  1619.                 break;
  1620.             }
  1621.         }
  1622.         XP_FREE(cd);
  1623.     }
  1624.  
  1625.  
  1626.     if( (NET_GetCookieWarningPref() || ask) && !accept ) {
  1627.         /* the user wants to know about cookies so let them
  1628.          * know about every one that is set and give them
  1629.          * the choice to accept it or not
  1630.          */
  1631.         char * new_string=0;
  1632.         char * tmp_host = NET_ParseURL(cur_url, GET_HOST_PART);
  1633.  
  1634.         StrAllocCopy(new_string, XP_GetString(MK_ACCESS_COOKIES_THE_SERVER));
  1635.         StrAllocCat(new_string, tmp_host ? tmp_host : "");
  1636.         StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_WISHES));
  1637.  
  1638.         StrAllocCopy(new_string, XP_GetString(MK_ACCESS_COOKIES_THE_SERVER));
  1639.         StrAllocCat(new_string, tmp_host ? tmp_host : "");
  1640.         StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_WISHES));
  1641.  
  1642.         XP_FREE(tmp_host);
  1643.  
  1644.         if(is_domain) {
  1645.             StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_TOANYSERV));
  1646.             StrAllocCat(new_string, host_from_header);
  1647.           } else {
  1648.             StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_TOSELF));
  1649.           }
  1650.  
  1651.         StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_NAME_AND_VAL));
  1652.  
  1653.         StrAllocCat(new_string, name_from_header);
  1654.         StrAllocCat(new_string, "=");
  1655.         StrAllocCat(new_string, cookie_from_header);
  1656.         StrAllocCat(new_string, "\n");
  1657.  
  1658.         if(expires) {
  1659.             StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_COOKIE_WILL_PERSIST));
  1660.             StrAllocCat(new_string, ctime(&expires));
  1661.           }
  1662.  
  1663.         StrAllocCat(new_string, XP_GetString(MK_ACCESS_COOKIES_SET_IT));
  1664.  
  1665.         /* 
  1666.          * Who knows what thread we are on.  Only the mozilla thread
  1667.          *   is allowed to post dialogs so, if need be, go over there
  1668.          */
  1669.         if(!ET_PostMessageBox(context, new_string, TRUE)) {
  1670.             XP_FREEIF(new_string);
  1671.             return;
  1672.         }
  1673.         XP_FREEIF(new_string);
  1674.       }
  1675.  
  1676.     TRACEMSG(("mkaccess.c: Setting cookie: %s for host: %s for path: %s",
  1677.                     cookie_from_header, host_from_header, path_from_header));
  1678.  
  1679.     /* 
  1680.      * We have decided we are going to insert a cookie into the list
  1681.      *   Get the cookie lock so that we can munge on the list
  1682.      */
  1683.     net_lock_cookie_list();
  1684.  
  1685.     /* limit the number of cookies from a specific host or domain */
  1686.     net_CheckForMaxCookiesFromHost(host_from_header);
  1687.  
  1688.     if(XP_ListCount(net_cookie_list) > MAX_NUMBER_OF_COOKIES-1)
  1689.         net_remove_oldest_cookie();
  1690.  
  1691.  
  1692.     prev_cookie = net_CheckForPrevCookie(path_from_header, 
  1693.                                             host_from_header, 
  1694.                                             name_from_header);
  1695.  
  1696.     if(prev_cookie) {
  1697.         prev_cookie->expires = expires;
  1698.         XP_FREEIF(prev_cookie->cookie);
  1699.         XP_FREEIF(prev_cookie->path);
  1700.         XP_FREEIF(prev_cookie->host);
  1701.         XP_FREEIF(prev_cookie->name);
  1702.         prev_cookie->cookie = cookie_from_header;
  1703.         prev_cookie->path = path_from_header;
  1704.         prev_cookie->host = host_from_header;
  1705.         prev_cookie->name = name_from_header;
  1706.         prev_cookie->secure = set_secure;
  1707.         prev_cookie->is_domain = is_domain;
  1708.         prev_cookie->last_accessed = time(NULL);
  1709.       }    else {
  1710.         XP_List * list_ptr = net_cookie_list;
  1711.         net_CookieStruct * tmp_cookie_ptr;
  1712.         size_t new_len;
  1713.  
  1714.         /* construct a new cookie_struct
  1715.          */
  1716.         prev_cookie = XP_NEW(net_CookieStruct);
  1717.         if(!prev_cookie) {
  1718.             XP_FREEIF(path_from_header);
  1719.             XP_FREEIF(host_from_header);
  1720.             XP_FREEIF(name_from_header);
  1721.             XP_FREEIF(cookie_from_header);
  1722.             net_unlock_cookie_list();
  1723.             return;
  1724.           }
  1725.     
  1726.         /* copy
  1727.          */
  1728.         prev_cookie->cookie  = cookie_from_header;
  1729.         prev_cookie->name    = name_from_header;
  1730.         prev_cookie->path    = path_from_header;
  1731.         prev_cookie->host    = host_from_header;
  1732.         prev_cookie->expires = expires;
  1733.         prev_cookie->secure  = set_secure;
  1734.         prev_cookie->is_domain = is_domain;
  1735.         prev_cookie->last_accessed = time(NULL);
  1736.  
  1737.         if(!net_cookie_list) {
  1738.             net_cookie_list = XP_ListNew();
  1739.             if(!net_cookie_list) {
  1740.                 XP_FREEIF(path_from_header);
  1741.                 XP_FREEIF(name_from_header);
  1742.                 XP_FREEIF(host_from_header);
  1743.                 XP_FREEIF(cookie_from_header);
  1744.                 XP_FREE(prev_cookie);
  1745.                 net_unlock_cookie_list();
  1746.                 return;
  1747.               }
  1748.           }        
  1749.  
  1750.         /* add it to the list so that it is before any strings of
  1751.          * smaller length
  1752.          */
  1753.         new_len = XP_STRLEN(prev_cookie->path);
  1754.         while((tmp_cookie_ptr = (net_CookieStruct *) XP_ListNextObject(list_ptr))!=0) { 
  1755.             if(new_len > XP_STRLEN(tmp_cookie_ptr->path)) {
  1756.                 XP_ListInsertObject(net_cookie_list, tmp_cookie_ptr, prev_cookie);
  1757.                 net_unlock_cookie_list();
  1758.                 cookies_changed = TRUE;
  1759.                 return;
  1760.               }
  1761.           }
  1762.         /* no shorter strings found in list */    
  1763.         XP_ListAddObjectToEnd(net_cookie_list, prev_cookie);
  1764.       }
  1765.  
  1766.     /* At this point we know a cookie has changed. Write the cookies to file. */
  1767.     cookies_changed = TRUE;
  1768.     NET_SaveCookies(NULL);
  1769.     net_unlock_cookie_list();
  1770.     return;
  1771. }
  1772.  
  1773. PUBLIC void
  1774. NET_SetCookieString(MWContext * context, 
  1775.                     char * cur_url,
  1776.                     char * set_cookie_header) {
  1777.     net_IntSetCookieString(context, cur_url, set_cookie_header, 0);
  1778. }
  1779.  
  1780. /* Determines whether the inlineHost is in the same domain as the currentHost. For use with rfc 2109
  1781.  * compliance/non-compliance. */
  1782. PRIVATE int
  1783. NET_SameDomain(char * currentHost, char * inlineHost)
  1784. {
  1785.     char * dot = 0;
  1786.     char * currentDomain = 0;
  1787.     char * inlineDomain = 0;
  1788.  
  1789.     if(!currentHost || !inlineHost)
  1790.         return 0;
  1791.  
  1792.     /* case insensitive compare */
  1793.     if(XP_STRCASECMP(currentHost, inlineHost) == 0)
  1794.         return 1;
  1795.  
  1796.     currentDomain = XP_STRCHR(currentHost, '.');
  1797.     inlineDomain = XP_STRCHR(inlineHost, '.');
  1798.  
  1799.     if(!currentDomain || !inlineDomain)
  1800.         return 0;
  1801.     
  1802.     /* check for at least two dots before continuing, if there are
  1803.        not two dots we don't have enough information to determine
  1804.        whether or not the inlineDomain is within the currentDomain */
  1805.     dot = XP_STRCHR(inlineDomain, '.');
  1806.     if(dot)
  1807.         dot = XP_STRCHR(dot+1, '.');
  1808.     else
  1809.         return 0;
  1810.  
  1811.     /* handle .com. case */
  1812.     if(!dot || (*(dot+1) == '\0') )
  1813.         return 0;
  1814.  
  1815.     if(!XP_STRCASECMP(inlineDomain, currentDomain))
  1816.         return 1;
  1817.     return 0;
  1818. }
  1819.  
  1820. /* This function wrapper wraps NET_SetCookieString for the purposes of 
  1821. ** determining whether or not a cookie is inline (we need the URL struct, 
  1822. ** and outputFormat to do so).  this is called from NET_ParseMimeHeaders 
  1823. ** in mkhttp.c
  1824. ** This routine does not need to worry about the cookie lock since all of
  1825. **   the work is handled by sub-routines
  1826. */
  1827. PUBLIC void
  1828. NET_SetCookieStringFromHttp(FO_Present_Types outputFormat,
  1829.                             URL_Struct * URL_s,
  1830.                             MWContext * context, 
  1831.                             char * cur_url,
  1832.                             char * set_cookie_header)
  1833. {
  1834.     /* If the outputFormat is not PRESENT (the url is not going to the screen), and not
  1835.     *  SAVE AS (shift-click) then 
  1836.     *  the cookie being set is defined as inline so we need to do what the user wants us
  1837.     *  to based on his preference to deal with foreign cookies. If it's not inline, just set
  1838.     *  the cookie. */
  1839.     char *ptr=NULL, *date=NULL;
  1840.     time_t gmtCookieExpires=0, expires=0;
  1841.  
  1842.     if(CLEAR_CACHE_BIT(outputFormat) != FO_PRESENT && CLEAR_CACHE_BIT(outputFormat) != FO_SAVE_AS)
  1843.     {
  1844.         if (NET_GetCookieBehaviorPref() == NET_DontAcceptForeign)
  1845.         {
  1846.             /* the user doesn't want foreign cookies, check to see if its foreign */
  1847.             char * curSessionHistHost = 0;
  1848.             char * theColon = 0;
  1849.             char * curHost = NET_ParseURL(cur_url, GET_HOST_PART);
  1850.             History_entry * shistEntry = SHIST_GetCurrent(&context->hist);
  1851.             if (shistEntry) {
  1852.             curSessionHistHost = NET_ParseURL(shistEntry->address, GET_HOST_PART);
  1853.             }
  1854.             if(!curHost || !curSessionHistHost)
  1855.             {
  1856.                 XP_FREEIF(curHost);
  1857.                 XP_FREEIF(curSessionHistHost);
  1858.                 return;
  1859.             }
  1860.  
  1861.             /* strip ports */
  1862.             theColon = XP_STRCHR(curHost, ':');
  1863.             if(theColon)
  1864.                *theColon = '\0';
  1865.             theColon = XP_STRCHR(curSessionHistHost, ':');
  1866.             if(theColon)
  1867.                 *theColon = '\0';
  1868.  
  1869.             /* if it's foreign, get out of here after a little clean up */
  1870.             if(!NET_SameDomain(curHost, curSessionHistHost))
  1871.             {
  1872.                 XP_FREEIF(curHost);    
  1873.                 XP_FREEIF(curSessionHistHost);
  1874.                 return;
  1875.             }
  1876.             XP_FREEIF(curHost);    
  1877.             XP_FREEIF(curSessionHistHost);
  1878.         }
  1879.     }
  1880.  
  1881.     /* Determine when the cookie should expire. This is done by taking the difference between 
  1882.        the server time and the time the server wants the cookie to expire, and adding that 
  1883.        difference to the client time. This localizes the client time regardless of whether or
  1884.        not the TZ environment variable was set on the client. */
  1885.  
  1886.     /* Get the time the cookie is supposed to expire according to the attribute*/
  1887.     ptr = strcasestr(set_cookie_header, "expires=");
  1888.     if(ptr)
  1889.     {
  1890.         char *date =  ptr+8;
  1891.         char origLast = '\0';
  1892.         for(ptr=date; *ptr != '\0'; ptr++)
  1893.             if(*ptr == ';')
  1894.               {
  1895.                 origLast = ';';
  1896.                 *ptr = '\0';
  1897.                 break;
  1898.               }
  1899.         expires = NET_ParseDate(date);
  1900.         *ptr=origLast;
  1901.     }
  1902.     if( URL_s->server_date && expires )
  1903.     {
  1904.         /* If the cookie has expired, don't waste any more time. */
  1905.         if( expires < URL_s->server_date )
  1906.         {
  1907.             return;
  1908.         }
  1909.         else
  1910.         {
  1911.             gmtCookieExpires = expires - URL_s->server_date + time(NULL);
  1912.             /* if overflow */
  1913.             if( gmtCookieExpires < time(NULL) )
  1914.                 gmtCookieExpires = (((unsigned) (~0) << 1) >> 1); /* max int */
  1915.         }
  1916.     }
  1917.  
  1918.     net_IntSetCookieString(context, cur_url, set_cookie_header, gmtCookieExpires);
  1919. }
  1920.  
  1921. /* saves out the HTTP cookies to disk
  1922.  *
  1923.  * on entry pass in the name of the file to save
  1924.  *
  1925.  * returns 0 on success -1 on failure.
  1926.  *
  1927.  */
  1928. PUBLIC int
  1929. NET_SaveCookies(char * filename)
  1930. {
  1931.     XP_List * list_ptr;
  1932.     net_CookieStruct * cookie_s;
  1933.     time_t cur_date = time(NULL);
  1934.     XP_File fp;
  1935.     int32 len = 0;
  1936.     char date_string[36];
  1937.  
  1938.     if(NET_GetCookieBehaviorPref() == NET_DontUse)
  1939.       return(-1);
  1940.  
  1941.     if(!cookies_changed)
  1942.       return(-1);
  1943.  
  1944.     net_lock_cookie_list();
  1945.     list_ptr = net_cookie_list;
  1946.     if(XP_ListIsEmpty(list_ptr)) {
  1947.         net_unlock_cookie_list();
  1948.         return(-1);
  1949.     }
  1950.  
  1951.     if(!(fp = XP_FileOpen(filename, xpHTTPCookie, XP_FILE_WRITE))) {
  1952.         net_unlock_cookie_list();
  1953.         return(-1);
  1954.     }
  1955.  
  1956.     len = XP_FileWrite("# Netscape HTTP Cookie File" LINEBREAK
  1957.                  "# http://www.netscape.com/newsref/std/cookie_spec.html"
  1958.                  LINEBREAK "# This is a generated file!  Do not edit."
  1959.                  LINEBREAK LINEBREAK,
  1960.                  -1, fp);
  1961.     if (len < 0)
  1962.     {
  1963.         XP_FileClose(fp);
  1964.         net_unlock_cookie_list();
  1965.         return -1;
  1966.     }
  1967.  
  1968.     /* format shall be:
  1969.       *
  1970.      * host \t is_domain \t path \t secure \t expires \t name \t cookie
  1971.      *
  1972.      * is_domain is TRUE or FALSE
  1973.      * secure is TRUE or FALSE  
  1974.      * expires is a time_t integer
  1975.      * cookie can have tabs
  1976.      */
  1977.     while((cookie_s = (net_CookieStruct *) XP_ListNextObject(list_ptr)) != NULL)
  1978.       {
  1979.         if(cookie_s->expires < cur_date)
  1980.             continue;  /* don't write entry if cookie has expired 
  1981.                         * or has no expiration date
  1982.                         */
  1983.  
  1984.         len = XP_FileWrite(cookie_s->host, -1, fp);
  1985.         if (len < 0)
  1986.         {
  1987.             XP_FileClose(fp);
  1988.             net_unlock_cookie_list();
  1989.             return -1;
  1990.         }
  1991.         XP_FileWrite("\t", 1, fp);
  1992.         
  1993.         if(cookie_s->is_domain)
  1994.             XP_FileWrite("TRUE", -1, fp);
  1995.         else
  1996.             XP_FileWrite("FALSE", -1, fp);
  1997.         XP_FileWrite("\t", 1, fp);
  1998.  
  1999.         XP_FileWrite(cookie_s->path, -1, fp);
  2000.         XP_FileWrite("\t", 1, fp);
  2001.  
  2002.         if(cookie_s->secure)
  2003.             XP_FileWrite("TRUE", -1, fp);
  2004.         else
  2005.             XP_FileWrite("FALSE", -1, fp);
  2006.         XP_FileWrite("\t", 1, fp);
  2007.  
  2008.         PR_snprintf(date_string, sizeof(date_string), "%lu", cookie_s->expires);
  2009.         XP_FileWrite(date_string, -1, fp);
  2010.         XP_FileWrite("\t", 1, fp);
  2011.  
  2012.         XP_FileWrite(cookie_s->name, -1, fp);
  2013.         XP_FileWrite("\t", 1, fp);
  2014.  
  2015.         XP_FileWrite(cookie_s->cookie, -1, fp);
  2016.          len = XP_FileWrite(LINEBREAK, -1, fp);
  2017.         if (len < 0)
  2018.         {
  2019.             XP_FileClose(fp);
  2020.             net_unlock_cookie_list();
  2021.             return -1;
  2022.         }
  2023.       }
  2024.  
  2025.     cookies_changed = FALSE;
  2026.  
  2027.     XP_FileClose(fp);
  2028.     net_unlock_cookie_list();
  2029.     return(0);
  2030. }
  2031.  
  2032.  
  2033. /* reads HTTP cookies from disk
  2034.  *
  2035.  * on entry pass in the name of the file to read
  2036.  *
  2037.  * returns 0 on success -1 on failure.
  2038.  *
  2039.  *
  2040.  */
  2041. #define LINE_BUFFER_SIZE 4096
  2042.  
  2043. PUBLIC int
  2044. NET_ReadCookies(char * filename)
  2045. {
  2046.     XP_List * list_ptr;
  2047.     net_CookieStruct *new_cookie, *tmp_cookie_ptr;
  2048.     size_t new_len;
  2049.     XP_File fp;
  2050.     char buffer[LINE_BUFFER_SIZE];
  2051.     char *host, *is_domain, *path, *secure, *expires, *name, *cookie;
  2052.     Bool added_to_list;
  2053.  
  2054.     if(!(fp = XP_FileOpen(filename, xpHTTPCookie, XP_FILE_READ)))
  2055.         return(-1);
  2056.  
  2057.     net_lock_cookie_list();
  2058.     list_ptr = net_cookie_list;
  2059.  
  2060.     /* format is:
  2061.      *
  2062.      * host \t is_domain \t path \t secure \t expires \t name \t cookie
  2063.      *
  2064.      * if this format isn't respected we move onto the next line in the file.
  2065.      * is_domain is TRUE or FALSE    -- defaulting to FALSE
  2066.      * secure is TRUE or FALSE   -- should default to TRUE
  2067.      * expires is a time_t integer
  2068.      * cookie can have tabs
  2069.      */
  2070.     while(XP_FileReadLine(buffer, LINE_BUFFER_SIZE, fp))
  2071.       {
  2072.         added_to_list = FALSE;
  2073.  
  2074.         if (*buffer == '#' || *buffer == CR || *buffer == LF || *buffer == 0)
  2075.           continue;
  2076.  
  2077.         host = buffer;
  2078.         
  2079.         if( !(is_domain = XP_STRCHR(host, '\t')) )
  2080.             continue;
  2081.         *is_domain++ = '\0';
  2082.         if(*is_domain == CR || *is_domain == LF || *is_domain == 0)
  2083.             continue;
  2084.         
  2085.         if( !(path = XP_STRCHR(is_domain, '\t')) )
  2086.             continue;
  2087.         *path++ = '\0';
  2088.         if(*path == CR || *path == LF || *path == 0)
  2089.             continue;
  2090.  
  2091.         if( !(secure = XP_STRCHR(path, '\t')) )
  2092.             continue;
  2093.         *secure++ = '\0';
  2094.         if(*secure == CR || *secure == LF || *secure == 0)
  2095.             continue;
  2096.  
  2097.         if( !(expires = XP_STRCHR(secure, '\t')) )
  2098.             continue;
  2099.         *expires++ = '\0';
  2100.         if(*expires == CR || *expires == LF || *expires == 0)
  2101.             continue;
  2102.  
  2103.         if( !(name = XP_STRCHR(expires, '\t')) )
  2104.             continue;
  2105.         *name++ = '\0';
  2106.         if(*name == CR || *name == LF || *name == 0)
  2107.             continue;
  2108.  
  2109.         if( !(cookie = XP_STRCHR(name, '\t')) )
  2110.             continue;
  2111.         *cookie++ = '\0';
  2112.         if(*cookie == CR || *cookie == LF || *cookie == 0)
  2113.             continue;
  2114.  
  2115.         /* remove the '\n' from the end of the cookie */
  2116.         XP_StripLine(cookie);
  2117.  
  2118.         /* construct a new cookie_struct
  2119.          */
  2120.         new_cookie = XP_NEW(net_CookieStruct);
  2121.         if(!new_cookie)
  2122.           {
  2123.             net_unlock_cookie_list();
  2124.             return(-1);
  2125.           }
  2126.  
  2127.         XP_MEMSET(new_cookie, 0, sizeof(net_CookieStruct));
  2128.     
  2129.         /* copy
  2130.          */
  2131.         StrAllocCopy(new_cookie->cookie, cookie);
  2132.         StrAllocCopy(new_cookie->name, name);
  2133.         StrAllocCopy(new_cookie->path, path);
  2134.         StrAllocCopy(new_cookie->host, host);
  2135.         new_cookie->expires = atol(expires);
  2136.         if(!XP_STRCMP(secure, "FALSE"))
  2137.             new_cookie->secure = FALSE;
  2138.         else
  2139.             new_cookie->secure = TRUE;
  2140.         if(!XP_STRCMP(is_domain, "TRUE"))
  2141.             new_cookie->is_domain = TRUE;
  2142.         else
  2143.             new_cookie->is_domain = FALSE;
  2144.  
  2145.         if(!net_cookie_list)
  2146.           {
  2147.             net_cookie_list = XP_ListNew();
  2148.             if(!net_cookie_list)
  2149.               {
  2150.                 net_unlock_cookie_list();
  2151.                 return(-1);
  2152.               }
  2153.           }        
  2154.  
  2155.         /* add it to the list so that it is before any strings of
  2156.          * smaller length
  2157.          */
  2158.         new_len = XP_STRLEN(new_cookie->path);
  2159.         while((tmp_cookie_ptr = (net_CookieStruct *) XP_ListNextObject(list_ptr)) != NULL)
  2160.           { 
  2161.             if(new_len > XP_STRLEN(tmp_cookie_ptr->path))
  2162.               {
  2163.                 XP_ListInsertObject(net_cookie_list, tmp_cookie_ptr, new_cookie);
  2164.                 added_to_list = TRUE;
  2165.                 break;
  2166.               }
  2167.           }
  2168.  
  2169.         /* no shorter strings found in list */    
  2170.         if(!added_to_list)
  2171.             XP_ListAddObjectToEnd(net_cookie_list, new_cookie);
  2172.       }
  2173.  
  2174.     XP_FileClose(fp);
  2175.     net_unlock_cookie_list();
  2176.  
  2177.     cookies_changed = FALSE;
  2178.  
  2179.     return(0);
  2180. }
  2181.  
  2182.  
  2183.  
  2184. /* --- New stuff: General auth utils (currently used only by proxy auth) --- */
  2185.  
  2186. /*
  2187.  * Figure out the authentication scheme used; currently supported:
  2188.  *
  2189.  *        * Basic
  2190.  *        * SimpleMD5
  2191.  *
  2192.  */
  2193. PRIVATE net_AuthType
  2194. net_auth_type(char *name)
  2195. {
  2196.     if (name) {
  2197.         while (*name && XP_IS_SPACE(*name))
  2198.             name++;
  2199.         if (!strncasecomp(name, "basic", 5))
  2200.             return AUTH_BASIC;
  2201. #ifdef SIMPLE_MD5
  2202.         else if (!strncasecomp(name, "simplemd5", 9))
  2203.             return AUTH_SIMPLEMD5;
  2204. #endif
  2205.         /*FORTEZZA checks*/
  2206.         else if (!strncasecomp(name, "fortezzaproxy", 13))
  2207.             return AUTH_FORTEZZA;
  2208.     }
  2209.     return AUTH_INVALID;
  2210. }
  2211.  
  2212.  
  2213. /*
  2214.  * Figure out better of two {WWW,Proxy}-Authenticate headers;
  2215.  * SimpleMD5 is better than Basic.  Uses the order of AuthType
  2216.  * enum values.
  2217.  *
  2218.  */
  2219. MODULE_PRIVATE XP_Bool
  2220. net_IsBetterAuth(char *new_auth, char *old_auth)
  2221. {
  2222.     if (!old_auth || net_auth_type(new_auth) >= net_auth_type(old_auth))
  2223.         return TRUE;
  2224.     else
  2225.         return FALSE;
  2226. }
  2227.  
  2228.  
  2229. /*
  2230.  * Turns binary data of given lenght into a newly-allocated HEX string.
  2231.  *
  2232.  *
  2233.  */
  2234. PRIVATE char *
  2235. bin2hex(unsigned char *data, int len)
  2236. {
  2237.     char *buf = (char *)XP_ALLOC(2 * len + 1);
  2238.     char *p = buf;
  2239.  
  2240.     if(!buf)
  2241.         return NULL;
  2242.  
  2243.     while (len-- > 0) {
  2244.         sprintf(p, "%02x", *data);
  2245.         p += 2;
  2246.         data++;
  2247.     }
  2248.     *p = '\0';
  2249.     return buf;
  2250. }
  2251.  
  2252.  
  2253. /*
  2254.  * Parse {WWW,Proxy}-Authenticate header parameters into a net_AuthStruct
  2255.  * structure.
  2256.  *
  2257.  */
  2258. #define SKIP_WS(p) while((*(p)) && XP_IS_SPACE(*(p))) p++
  2259.  
  2260. PRIVATE XP_Bool
  2261. next_params(char **pp, char **name, char **value)
  2262. {
  2263.     char *q, *p = *pp;
  2264.  
  2265.     SKIP_WS(p);
  2266.     if (!p || !(*p) || !(q = strchr(p, '=')))
  2267.         return FALSE;
  2268.     *name = p;
  2269.     *q++ = '\0';
  2270.     if (*q == '"') {
  2271.         *value = q + 1;
  2272.         q = strchr(*value, '"');
  2273.         if (q)
  2274.           *q++ = '\0';
  2275.     }
  2276.     else {
  2277.         *value = q;
  2278.         while (*q && !XP_IS_SPACE(*q)) q++;
  2279.         if (*q)
  2280.           *q++ = '\0';
  2281.     }
  2282.  
  2283.     *pp = q;
  2284.     return TRUE;
  2285. }
  2286.  
  2287. PRIVATE net_AuthStruct *
  2288. net_parse_authenticate_line(char *auth, net_AuthStruct *ret)
  2289. {
  2290.     char *name, *value, *p = auth;
  2291.  
  2292.     if (!auth || !*auth)
  2293.         return NULL;
  2294.  
  2295.     if (!ret)
  2296.         ret = XP_NEW_ZAP(net_AuthStruct);
  2297.  
  2298.     if(!ret)
  2299.         return NULL;
  2300.  
  2301.     SKIP_WS(p);
  2302.     ret->auth_type = net_auth_type(p);
  2303.     while (*p && !XP_IS_SPACE(*p)) p++;
  2304.  
  2305.     while (next_params(&p, &name, &value)) {
  2306.         if (!strcasecomp(name, "realm"))
  2307.           {
  2308.               StrAllocCopy(ret->realm, value);
  2309.           }
  2310. #ifdef SIMPLE_MD5
  2311.         else if (!strcasecomp(name, "domain"))
  2312.           {
  2313.               StrAllocCopy(ret->domain, value);
  2314.           }
  2315.         else if (!strcasecomp(name, "nonce"))
  2316.           {
  2317.               StrAllocCopy(ret->nonce, value);
  2318.           }
  2319.         else if (!strcasecomp(name, "opaque"))
  2320.           {
  2321.               StrAllocCopy(ret->opaque, value);
  2322.           }
  2323.         else if (!strcasecomp(name, "oldnonce"))
  2324.           {
  2325.               ret->oldNonce = (!strcasecomp(value, "TRUE")) ? TRUE : FALSE;
  2326.           }
  2327. #endif /* SIMPLE_MD5 */
  2328.         /* Some FORTEZZA checks */
  2329.         else if (!strcasecomp(name, "challenge"))
  2330.           {
  2331.               StrAllocCopy(ret->challenge, value);
  2332.           }
  2333.         else if (!strcasecomp(name, "oldchallenge"))
  2334.           {
  2335.               ret->oldChallenge = (!strcasecomp(value, "TRUE")) ? TRUE : FALSE;
  2336.           }
  2337.         /* End FORTEZZA checks  */
  2338.     }
  2339.  
  2340. #ifdef SIMPLE_MD5
  2341.     if (!ret->oldNonce)
  2342.         ret->oldNonce_retries = 0;
  2343. #endif /* SIMPLE_MD5 */
  2344.     /*Another FORTEZZA addition*/
  2345.     if (!ret->oldChallenge)
  2346.         ret->oldChallenge_retries = 0;
  2347.     /*End FPRTEZZA  addition   */
  2348.     return ret;
  2349. }
  2350.  
  2351.  
  2352. #ifdef SIMPLE_MD5
  2353. /* ---------- New stuff: SimpleMD5 Authentication for proxies -------------- */
  2354.  
  2355. PRIVATE void do_md5(unsigned char *stuff, unsigned char digest[16])
  2356. {
  2357.     MD5Context *cx = MD5_NewContext();
  2358.     unsigned int len;
  2359.  
  2360.     if (!cx)
  2361.         return;
  2362.  
  2363.     MD5_Begin(cx);
  2364.     MD5_Update(cx, stuff, strlen((char*)stuff));
  2365.     MD5_End(cx, digest, &len, 16);    /* len had better be 16 when returned! */
  2366.  
  2367.     MD5_DestroyContext(cx, (DSBool)TRUE);
  2368. }
  2369.  
  2370.  
  2371. /*
  2372.  * Generate a response for a SimpleMD5 challenge.
  2373.  *
  2374.  *    HEX( MD5("challenge password method url"))
  2375.  *
  2376.  */
  2377. char *net_generate_md5_challenge_response(char *challenge,
  2378.                                           char *password,
  2379.                                           int   method,
  2380.                                           char *url)
  2381. {
  2382.     unsigned char digest[16];
  2383.     unsigned char *cookie =
  2384.       (unsigned char *)XP_ALLOC(strlen(challenge) + strlen(password) +
  2385.                                 strlen(url) + 10);
  2386.  
  2387.     if(!cookie)
  2388.         return NULL;
  2389.  
  2390.     sprintf((char *)cookie, "%s %s %s %s", challenge, password,
  2391.             (method==URL_POST_METHOD ? "POST" :
  2392.              method==URL_HEAD_METHOD ? "HEAD" : "GET"),
  2393.             url);
  2394.     do_md5(cookie, digest);
  2395.     return bin2hex(digest, 16);
  2396. }
  2397.  
  2398.  
  2399. #define SIMPLEMD5_AUTHORIZATION_FMT "SimpleMD5\
  2400.  username=\"%s\",\
  2401.  realm=\"%s\",\
  2402.  nonce=\"%s\",\
  2403.  response=\"%s\",\
  2404.  opaque=\"%s\""
  2405.  
  2406. #endif /* SIMPLE_MD5 */
  2407.  
  2408. PRIVATE
  2409. char *net_generate_auth_string(URL_Struct *url_s,
  2410.                                net_AuthStruct *auth_s)
  2411. {
  2412.     if (!auth_s)
  2413.         return NULL;
  2414.  
  2415.     switch (auth_s->auth_type) {
  2416.  
  2417.       case AUTH_INVALID:
  2418.         break;
  2419.  
  2420.       case AUTH_BASIC:
  2421.         if (!auth_s->auth_string) {
  2422.             int len;
  2423.             char *u_pass_string = NULL;
  2424.  
  2425.             StrAllocCopy(u_pass_string, auth_s->username);
  2426.             StrAllocCat (u_pass_string, ":");
  2427.             StrAllocCat (u_pass_string, auth_s->password);
  2428.  
  2429.             len = XP_STRLEN(u_pass_string);
  2430.             if (!(auth_s->auth_string = (char*) XP_ALLOC((((len+1)*4)/3)+20)))
  2431.               {
  2432.                   return NULL;
  2433.               }
  2434.  
  2435.             XP_STRCPY(auth_s->auth_string, "Basic ");
  2436.             NET_UUEncode((unsigned char *)u_pass_string,
  2437.                          (unsigned char *)&auth_s->auth_string[6],
  2438.                          len);
  2439.  
  2440.             FREE(u_pass_string);
  2441.         }
  2442.         break;
  2443.  
  2444. #ifdef SIMPLE_MD5
  2445.       case AUTH_SIMPLEMD5:
  2446.         if (auth_s->username && auth_s->password &&
  2447.             auth_s->nonce    && auth_s->opaque   &&
  2448.             url_s            && url_s->address)
  2449.           {
  2450.               char *resp;
  2451.  
  2452.               FREEIF(auth_s->auth_string);
  2453.               auth_s->auth_string = NULL;
  2454.  
  2455.               if ((resp = net_generate_md5_challenge_response(auth_s->nonce,
  2456.                                                               auth_s->password,
  2457.                                                               url_s->method,
  2458.                                                               url_s->address)))
  2459.                 {
  2460.                     if ((auth_s->auth_string =
  2461.                          (char *)XP_ALLOC(XP_STRLEN(auth_s->username) +
  2462.                                           XP_STRLEN(auth_s->realm)    +
  2463.                                           XP_STRLEN(auth_s->nonce)    +
  2464.                                           XP_STRLEN(resp)             +
  2465.                                           XP_STRLEN(auth_s->opaque)   +
  2466.                                           100)))
  2467.                       {
  2468.                           sprintf(auth_s->auth_string,
  2469.                                   SIMPLEMD5_AUTHORIZATION_FMT,
  2470.                                   auth_s->username,
  2471.                                   auth_s->realm,
  2472.                                   auth_s->nonce,
  2473.                                   resp,
  2474.                                   auth_s->opaque);
  2475.                       }
  2476.                     FREE(resp);
  2477.                 }
  2478.           }
  2479.         break;
  2480. #endif /* SIMPLE_MD5 */
  2481.         /* Handle the FORTEZZA case        */
  2482.             case AUTH_FORTEZZA:
  2483.           if (auth_s->signature && auth_s->challenge && 
  2484.               auth_s->certChain && auth_s->clientRan) {
  2485.                   int len;
  2486.  
  2487.               FREEIF(auth_s->auth_string);
  2488.               auth_s->auth_string = NULL;
  2489.  
  2490.               len = XP_STRLEN(auth_s->signature) + XP_STRLEN(auth_s->challenge)
  2491.                     + XP_STRLEN(auth_s->certChain) + XP_STRLEN(auth_s->clientRan) + 100;
  2492.               auth_s->auth_string = (char *)XP_ALLOC(len);
  2493.               if (auth_s->auth_string) {
  2494.                 sprintf(auth_s->auth_string,"signature=\"%s\" challenge=\"%s\" "
  2495.                     "clientRan=\"%s\" certChain=\"%s\"",auth_s->signature,
  2496.                     auth_s->challenge, auth_s->clientRan, auth_s->certChain);
  2497.               }
  2498.           }
  2499.           break;
  2500.         /* Done Handling the FORTEZZA case */
  2501.     }
  2502.  
  2503.     return auth_s->auth_string;
  2504. }
  2505.  
  2506.  
  2507. /* --------------- New stuff: client-proxy authentication --------------- */
  2508.  
  2509. PRIVATE net_AuthStruct *
  2510. net_CheckForProxyAuth(char * proxy_addr)
  2511. {
  2512.     XP_List * lp = net_proxy_auth_list;
  2513.     net_AuthStruct * s;
  2514.  
  2515.     while ((s = (net_AuthStruct *)XP_ListNextObject(lp)) != NULL)
  2516.       {
  2517.           if (!strcasecomp(s->proxy_addr, proxy_addr))
  2518.               return s;
  2519.       }
  2520.  
  2521.     return NULL;
  2522. }
  2523.  
  2524.  
  2525. /*
  2526.  * returns a proxy authorization string if one is required, otherwise
  2527.  * returns NULL
  2528.  */
  2529. PUBLIC char *
  2530. NET_BuildProxyAuthString(MWContext * context,
  2531.                          URL_Struct * url_s,
  2532.                          char * proxy_addr)
  2533. {
  2534.     net_AuthStruct * auth_s = net_CheckForProxyAuth(proxy_addr);
  2535.  
  2536.     return auth_s ? net_generate_auth_string(url_s, auth_s) : NULL;
  2537. }
  2538.  
  2539.  
  2540. /*
  2541.  * Returns FALSE if the user wishes to cancel proxy authorization
  2542.  * and TRUE if the user wants to continue with a new authorization
  2543.  * string.
  2544.  */
  2545. #define INVALID_AUTH_HEADER XP_GetString( XP_PROXY_REQUIRES_UNSUPPORTED_AUTH_SCHEME )
  2546.  
  2547. #define LOOPING_OLD_NONCES XP_GetString( XP_LOOPING_OLD_NONCES )
  2548.  
  2549. PUBLIC XP_Bool
  2550. NET_AskForProxyAuth(MWContext * context,
  2551.                     char *   proxy_addr,
  2552.                     char *   pauth_params,
  2553.                     XP_Bool  already_sent_auth)
  2554. {
  2555.     net_AuthStruct * prev;
  2556.     XP_Bool new_entry = FALSE;
  2557.     char * username = NULL;
  2558.     char * password = NULL;
  2559.     char * buf;
  2560.     int32  len=0;
  2561.  
  2562.     TRACEMSG(("Entering NET_AskForProxyAuth"));
  2563.  
  2564.     if (!proxy_addr || !*proxy_addr || !pauth_params || !*pauth_params)
  2565.         return FALSE;
  2566.  
  2567.     prev = net_CheckForProxyAuth(proxy_addr);
  2568.     if (prev) {
  2569.         new_entry = FALSE;
  2570.         net_parse_authenticate_line(pauth_params, prev);
  2571.     }
  2572.     else {
  2573.         new_entry = TRUE;
  2574.         if (!(prev = net_parse_authenticate_line(pauth_params, NULL)))
  2575.           {
  2576.               FE_Alert(context, INVALID_AUTH_HEADER);
  2577.               return FALSE;
  2578.           }
  2579.         StrAllocCopy(prev->proxy_addr, proxy_addr);
  2580.     }
  2581.  
  2582.     if (!prev->realm || !*prev->realm)
  2583.         StrAllocCopy(prev->realm, XP_GetString( XP_UNIDENTIFIED_PROXY_SERVER ) );
  2584.  
  2585.     if (!new_entry) {
  2586.         if (!already_sent_auth)
  2587.           {
  2588.               /* somehow the mapping changed since the time we sent
  2589.                * the authorization.
  2590.                * This happens sometimes because of the parrallel
  2591.                * nature of the requests.
  2592.                * In this case we want to just retry the connection
  2593.                * since it will probably succeed now.
  2594.                */
  2595.               return TRUE;
  2596.           }
  2597. #ifdef SIMPLE_MD5
  2598.         else if (prev->oldNonce && prev->oldNonce_retries++ < 3)
  2599.           {
  2600.               /*
  2601.                * We already sent the authorization string and the
  2602.                * nonce was expired -- auto-retry.
  2603.                */
  2604.               if (!FE_Confirm(context, LOOPING_OLD_NONCES))
  2605.                   return FALSE;
  2606.           }
  2607. #endif /* SIMPLE_MD5 */
  2608.         /* Do the good old FORTEZZA  stuff */
  2609.         else if (prev->oldChallenge && (prev->oldChallenge_retries++ > 3)) 
  2610.           {
  2611.               /*
  2612.                * We already sent the authorization string and the
  2613.                * nonce was expired -- auto-retry.
  2614.                */
  2615.               if (!FE_Confirm(context, XP_GetString(XP_CONFIRM_PROXYAUTHOR_FAIL)))
  2616.                   return FALSE;
  2617.           }
  2618.         else if (prev->auth_type != AUTH_FORTEZZA)
  2619.           {
  2620.               /*
  2621.                * We already sent the authorization string and it failed.
  2622.                */
  2623.               if (!FE_Confirm(context, XP_GetString(XP_CONFIRM_PROXYAUTHOR_FAIL)))
  2624.                   return FALSE;
  2625.           }
  2626.     }
  2627.  
  2628.     
  2629.     if (prev->auth_type == AUTH_FORTEZZA) {
  2630.         SECStatus rv;
  2631.         rv = SECNAV_ComputeFortezzaProxyChallengeResponse(context,
  2632.                                                           prev->challenge,
  2633.                                                           &prev->signature,
  2634.                                                           &prev->clientRan,
  2635.                                                           &prev->certChain);
  2636.         if ( rv != SECSuccess ) {
  2637.             return(FALSE);
  2638.         }
  2639.     } else
  2640.     {
  2641.     username = prev->username;
  2642.     password = prev->password;
  2643.  
  2644.     len = XP_STRLEN(prev->realm) + XP_STRLEN(proxy_addr) + 50;
  2645.     buf = (char*)XP_ALLOC(len*sizeof(char));
  2646.     
  2647.     if(buf)
  2648.       {
  2649.         PR_snprintf(buf, len*sizeof(char), XP_GetString( XP_PROXY_AUTH_REQUIRED_FOR ), prev->realm, proxy_addr);
  2650.  
  2651.         NET_Progress(context, XP_GetString( XP_CONNECT_PLEASE_ENTER_PASSWORD_FOR_PROXY ) );
  2652.         len = FE_PromptUsernameAndPassword(context, buf, 
  2653.                                            &username, &password);
  2654.         FREE(buf);
  2655.       }
  2656.     else
  2657.       {
  2658.         len = 0;
  2659.       }
  2660.  
  2661.     if (!len)
  2662.       {
  2663.           TRACEMSG(("User canceled login!!!"));
  2664.           return FALSE;
  2665.       }
  2666.     else if (!username || !password)
  2667.       {
  2668.           return FALSE;
  2669.       }
  2670.  
  2671.     FREEIF(prev->auth_string);
  2672.     prev->auth_string = NULL;        /* Generate a new one */
  2673.     FREEIF(prev->username);
  2674.     prev->username = username;
  2675.     FREEIF(prev->password);
  2676.     prev->password = password;
  2677.     }
  2678.  
  2679.     if (new_entry)
  2680.       {
  2681.           if (!net_proxy_auth_list)
  2682.             {
  2683.                 net_proxy_auth_list = XP_ListNew();
  2684.                 if (!net_proxy_auth_list)
  2685.                   {
  2686.                       return TRUE;
  2687.                   }
  2688.             }
  2689.           XP_ListAddObjectToEnd(net_proxy_auth_list, prev);
  2690.       }
  2691.  
  2692.     return TRUE;
  2693. }
  2694.  
  2695. #define BUFLEN 2048
  2696. /* create an HTML stream and push a bunch of HTML about cookies. Such as:
  2697.  * GENERAL INFO
  2698.  * The number of cookies you have in mem (expired cookies don't show up).
  2699.  * The maximum number allowed.
  2700.  * The maximum allowed per server.
  2701.  * The maximum allowable size of a cookie (in bytes).
  2702.  *
  2703.  * PER COOKIE INFO
  2704.  * Cookie name & Value.
  2705.  * The host it came from.
  2706.  * Whether or not there's a domain.
  2707.  * The path the cookie will be sent to.
  2708.  * Whether or not the cookie is sent secure.
  2709.  * When the cookie expires.
  2710.  * 
  2711.  */
  2712. MODULE_PRIVATE void 
  2713. NET_DisplayCookieInfoAsHTML(ActiveEntry * cur_entry) {
  2714.     char *buffer=(char*)XP_ALLOC(BUFLEN), *expireDate=NULL;
  2715.        NET_StreamClass *stream;
  2716.     int i, g, numOfCookies;
  2717.     XP_List *list=net_cookie_list;
  2718.     net_CookieStruct *cookie;
  2719.  
  2720.     if(!buffer) {
  2721.         cur_entry->status = MK_UNABLE_TO_CONVERT;
  2722.         return;
  2723.       }
  2724.  
  2725.     /* The the current entry's content type */
  2726.     StrAllocCopy(cur_entry->URL_s->content_type, TEXT_HTML);
  2727.  
  2728.     cur_entry->format_out = CLEAR_CACHE_BIT(cur_entry->format_out);
  2729.     stream = NET_StreamBuilder(cur_entry->format_out, 
  2730.                                cur_entry->URL_s, 
  2731.                                cur_entry->window_id);
  2732.  
  2733.     if(!stream) {
  2734.         cur_entry->status = MK_UNABLE_TO_CONVERT;
  2735.         XP_FREE(buffer);
  2736.         return;
  2737.       }
  2738.  
  2739.  
  2740. /* define a macro to push a string up the stream and handle errors */
  2741. #define PUT_PART(part)                                                    \
  2742. cur_entry->status = (*stream->put_block)(stream,            \
  2743.                                         part ? part : "Unknown",        \
  2744.                                         part ? XP_STRLEN(part) : 7);    \
  2745.     if(cur_entry->status < 0)                                                \
  2746.       goto END;
  2747. /* End PUT_PART macro */
  2748.  
  2749.     /* Get rid of any expired cookies now so user doesn't
  2750.      * think/see that we're keeping cookies in mem.
  2751.      */
  2752.     net_remove_expired_cookies();
  2753.     numOfCookies=XP_ListCount(net_cookie_list);
  2754.  
  2755.     /* Write out the initial statistics. */
  2756.     g = PR_snprintf(buffer, BUFLEN,
  2757. "<TITLE>%s</TITLE>\n"
  2758. "<h2>%s</h2>\n"
  2759. "<TABLE>\n"
  2760. "<TR>\n",
  2761.         XP_GetString(MK_ACCESS_YOUR_COOKIES),
  2762.         XP_GetString(MK_ACCESS_YOUR_COOKIES));
  2763.  
  2764.     g += PR_snprintf(buffer+g, BUFLEN-g,
  2765. "<TD ALIGN=RIGHT><b>%s</TD>\n"
  2766. "<TD>%ld</TD>\n"
  2767. "</TR>\n"
  2768. "<TR>\n",
  2769.         XP_GetString(MK_ACCESS_MAXIMUM_COOKS),
  2770.         MAX_NUMBER_OF_COOKIES);
  2771.  
  2772.     g += PR_snprintf(buffer+g, BUFLEN-g,
  2773. "<TD ALIGN=RIGHT><b>%s</TD>\n"
  2774. "<TD>%ld</TD>\n"
  2775. "</TR>\n"
  2776. "<TR>\n",
  2777.         XP_GetString(MK_ACCESS_COOK_COUNT),
  2778.         numOfCookies);
  2779.  
  2780.     g += PR_snprintf(buffer+g, BUFLEN-g,
  2781. "<TD ALIGN=RIGHT><b>%s</TD>\n"
  2782. "<TD>%ld</TD>\n"
  2783. "</TR>\n"
  2784. "<TR>\n",
  2785.         XP_GetString(MK_ACCESS_MAXIMUM_COOKS_PER_SERV),
  2786.         MAX_COOKIES_PER_SERVER);
  2787.  
  2788.     g += PR_snprintf(buffer+g, BUFLEN-g,
  2789. "<TD ALIGN=RIGHT><b>%s</TD>\n"
  2790. "<TD>%ld</TD>\n"
  2791. "</TR>\n"
  2792. "</TABLE>\n"
  2793. "<HR>",
  2794.         XP_GetString(MK_ACCESS_MAXIMUM_COOK_SIZE),
  2795.         MAX_BYTES_PER_COOKIE);
  2796.  
  2797.  
  2798.     PUT_PART(buffer);
  2799.  
  2800.     if(!numOfCookies) {
  2801.         XP_STRCPY(buffer, XP_GetString(MK_ACCESS_NO_COOKIES));
  2802.         PUT_PART(buffer);
  2803.         goto END;
  2804.       }
  2805.  
  2806. /* define some macros to help us output HTML */
  2807. #define HEADING(arg1)                    \
  2808.     XP_STRCPY(buffer, "<tt>");            \
  2809.     for(i=XP_STRLEN(arg1); i < 16; i++)    \
  2810.         XP_STRCAT(buffer, " ");    \
  2811.     XP_STRCAT(buffer, arg1);            \
  2812.     XP_STRCAT(buffer, " </tt>");        \
  2813.     PUT_PART(buffer);
  2814.  
  2815. #define BRCRLF                    \
  2816.     XP_STRCPY(buffer, "<BR>\n");        \
  2817.     PUT_PART(buffer);
  2818. /* End html macros */
  2819.  
  2820.     /* Write out each cookie */
  2821.     while ( (cookie=(net_CookieStruct *) XP_ListNextObject(list)) ) {
  2822.  
  2823.         HEADING(XP_GetString(MK_ACCESS_NAME));
  2824.         XP_STRCPY(buffer, cookie->name);
  2825.         PUT_PART(buffer);
  2826.         BRCRLF;
  2827.  
  2828.         HEADING(XP_GetString(MK_ACCESS_VALUE));
  2829.         XP_STRCPY(buffer, cookie->cookie);
  2830.         PUT_PART(buffer);
  2831.         BRCRLF;
  2832.  
  2833.         HEADING(XP_GetString(MK_ACCESS_HOST));
  2834.         XP_STRCPY(buffer, cookie->host);
  2835.         PUT_PART(buffer);
  2836.         BRCRLF;
  2837.  
  2838.         HEADING(XP_GetString(MK_ACCESS_SEND_TO_HOST));
  2839.         if(cookie->is_domain)
  2840.             XP_STRCPY(buffer, XP_GetString(MK_ACCESS_IS_DOMAIN));
  2841.         else
  2842.             XP_STRCPY(buffer, XP_GetString(MK_ACCESS_IS_NOT_DOMAIN));
  2843.         PUT_PART(buffer);
  2844.         BRCRLF;
  2845.  
  2846.         HEADING(XP_GetString(MK_ACCESS_SEND_TO_PATH));
  2847.         XP_STRCPY(buffer, cookie->path);
  2848.         PUT_PART(buffer);
  2849.         XP_STRCPY(buffer, XP_GetString(MK_ACCESS_AND_BELOW));
  2850.         PUT_PART(buffer);
  2851.         BRCRLF;
  2852.  
  2853.         HEADING(XP_GetString(MK_ACCESS_SECURE));
  2854.         if(cookie->secure)
  2855.             XP_STRCPY(buffer, "Yes");
  2856.         else
  2857.             XP_STRCPY(buffer, "No");
  2858.         PUT_PART(buffer);
  2859.         BRCRLF;
  2860.  
  2861.         HEADING(XP_GetString(MK_ACCESS_EXPIRES));
  2862.         if(cookie->expires) {
  2863.             expireDate=ctime(&(cookie->expires));
  2864.             if(expireDate)
  2865.                 XP_STRCPY(buffer, expireDate);
  2866.             else
  2867.                 XP_STRCPY(buffer, "NULL");
  2868.         } else {
  2869.             XP_STRCPY(buffer, XP_GetString(MK_ACCESS_END_OF_SESSION));
  2870.         }
  2871.         PUT_PART(buffer);
  2872.         XP_STRCPY(buffer, " GMT");
  2873.         PUT_PART(buffer);
  2874.         BRCRLF;
  2875.  
  2876.         XP_STRCPY(buffer, "\n<P>\n");
  2877.         PUT_PART(buffer);
  2878.     }
  2879.     /* End each cookie */
  2880.  
  2881. END:
  2882.     FREE(buffer);
  2883.     if(cur_entry->status < 0)
  2884.         (*stream->abort)(stream, cur_entry->status);
  2885.     else
  2886.         (*stream->complete)(stream);
  2887.     return;
  2888. }
  2889.  
  2890.