home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libpwcac / pwcacapi.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  18.9 KB  |  916 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. /* backend glue code to do password caching
  20.  * Accepts password queries and does lookups in a secure database
  21.  *
  22.  * Written by Lou Montulli Jan 98
  23.  */
  24. #include "xp.h"
  25. #include "mcom_db.h"
  26. #include "pwcacapi.h"
  27.  
  28. DB *pw_database=NULL;
  29. XP_List *pc_interpret_funcs=NULL;
  30.  
  31. struct _PCNameValuePair {
  32.         char *name;
  33.         char *value;
  34. };
  35.  
  36. struct _PCNameValueArray {
  37.  
  38.         int32           cur_ptr;
  39.         int32           size;
  40.         int32           first_empty;
  41.         PCNameValuePair *pairs;
  42. };
  43.  
  44. typedef struct {
  45.     char                *module;
  46.     PCDataInterpretFunc *func;
  47. } PCInterpretModuleAssoc;
  48.  
  49. PUBLIC void
  50. PC_Shutdown()
  51. {
  52.  
  53.     if(pw_database)
  54.     {
  55.         (*pw_database->close)(pw_database);
  56.  
  57.         pw_database = NULL;
  58.     }
  59. }
  60.  
  61. PRIVATE int
  62. pc_open_database(void)
  63. {
  64.     char* filename = "passcac.db";
  65.     static Bool have_tried_open=FALSE;
  66.  
  67.     if(!pw_database)
  68.       {
  69.     HASHINFO hash_info = {
  70.         4 * 1024,
  71.         0,
  72.         0,
  73. #ifdef WIN16
  74.         60 * 1024,
  75. #else
  76.         96 * 1024,
  77. #endif
  78.         0,
  79.         0};
  80.  
  81.         /* @@@ add .db to the end of the files
  82.          */
  83.         pw_database = dbopen(filename,
  84.                                 O_RDWR | O_CREAT,
  85.                                 0600,
  86.                                 DB_HASH,
  87.                                 &hash_info);
  88.  
  89.         if(!have_tried_open && !pw_database)
  90.           {
  91.             XP_StatStruct stat_entry;
  92.  
  93.             have_tried_open = TRUE; /* only do this once */
  94.  
  95.             TRACEMSG(("Could not open cache database -- errno: %d", errno));
  96.  
  97.             /* if the file is zero length remove it
  98.              */
  99.              if(XP_Stat("", &stat_entry, xpCacheFAT) != -1)
  100.               {
  101.                    if(stat_entry.st_size <= 0)
  102.                   {
  103.                     XP_FileRemove("", xpCacheFAT);
  104.                   }
  105.               }
  106.  
  107.             /* try it again */
  108.             if (filename) {
  109.                 pw_database = dbopen(filename,
  110.                                         O_RDWR | O_CREAT,
  111.                                         0600,
  112.                                         DB_HASH,
  113.                                         0);
  114.             }
  115.             else 
  116.                 pw_database = NULL;
  117.           }
  118.     }
  119.  
  120.     /* return non-zero if the pw_database pointer is
  121.      * non-zero
  122.      */
  123.     return((int) pw_database);
  124.  
  125. }
  126.  
  127. PRIVATE char * 
  128. pc_gen_key(char *module, char *module_key)
  129. {
  130.     char *combo=NULL;
  131.  
  132.     StrAllocCopy(combo, module);
  133.     StrAllocCat(combo, "\t");
  134.     StrAllocCat(combo, module_key);
  135.  
  136.     return combo;
  137. }
  138.  
  139. PRIVATE void
  140. pc_separate_key(char *key, char **module, char **module_key)
  141. {
  142.     char *tab;
  143.  
  144.     *module = NULL;
  145.     *module_key = NULL;
  146.  
  147.     if(!key)
  148.         return;
  149.  
  150.     tab = XP_STRCHR(key, '\t');
  151.  
  152.     if(!tab)
  153.         return;
  154.  
  155.     *tab = '\0';
  156.  
  157.     *module = XP_STRDUP(key);
  158.     *module_key = XP_STRDUP(tab+1);
  159.  
  160.     *tab = '\t';
  161. }
  162.  
  163. PRIVATE PCInterpretModuleAssoc *
  164. pc_find_interpret_func(char *module)
  165. {
  166.     XP_List *list_ptr = pc_interpret_funcs;
  167.     PCInterpretModuleAssoc *assoc;
  168.  
  169.     if(!module)
  170.         return NULL;
  171.  
  172.     while((assoc = (PCInterpretModuleAssoc *) XP_ListNextObject(list_ptr)) != NULL)
  173.     {
  174.         if(!XP_STRCMP(module, assoc->module))
  175.             return assoc;
  176.     }
  177.  
  178.     return NULL;
  179. }
  180.  
  181. /* returns 0 on success -1 on error */
  182. PUBLIC int
  183. PC_RegisterDataInterpretFunc(char *module, PCDataInterpretFunc *func)
  184. {
  185.     PCInterpretModuleAssoc *assoc;
  186.  
  187.     if(!pc_interpret_funcs)
  188.     {
  189.         pc_interpret_funcs = XP_ListNew();
  190.  
  191.         if(!pc_interpret_funcs)
  192.             return -1;
  193.     }
  194.  
  195.     if((assoc =    pc_find_interpret_func(module)) != NULL)
  196.     {
  197.         assoc->func = func;
  198.         return 0;
  199.     }
  200.  
  201.     assoc = XP_NEW(PCInterpretModuleAssoc);
  202.  
  203.     if(!assoc)
  204.         return -1;
  205.  
  206.     assoc->module = XP_STRDUP(module);
  207.     assoc->func = func;
  208.  
  209.     if(!assoc->module)
  210.     {
  211.         XP_FREE(assoc);
  212.         return -1;
  213.     }
  214.  
  215.     XP_ListAddObject(pc_interpret_funcs, assoc);
  216.  
  217.     return 0;
  218. }
  219.  
  220. PRIVATE void
  221. pc_lookup_module_info(char *key,
  222.                       char *data, int32 data_size,
  223.                       char *type_buffer, int type_buffer_size, 
  224.                       char *url_buffer, int url_buffer_size,
  225.                       char *username_buffer, int username_buffer_size,
  226.                       char *password_buffer, int password_buffer_size)
  227. {
  228.     char *module, *module_key;
  229.     PCInterpretModuleAssoc *assoc;
  230.  
  231.     *type_buffer = '\0';
  232.     *url_buffer = '\0';
  233.     *username_buffer = '\0';
  234.     *password_buffer = '\0';
  235.  
  236.     pc_separate_key(key, &module, &module_key);
  237.  
  238.     if(!module || !module_key)
  239.     {
  240.         XP_FREEIF(module);
  241.         XP_FREEIF(module_key);
  242.         return;
  243.     }
  244.  
  245.     /* lookup an explain function from the modules list and use it to interpret the data */
  246.     /* @@@@ */
  247.     if(0 == (assoc = pc_find_interpret_func(module)))
  248.     {
  249.         /* cant find one */
  250.         return;
  251.     }
  252.  
  253.     (*assoc->func)(module,
  254.                     module_key,
  255.                     data, data_size,
  256.                     type_buffer, type_buffer_size, 
  257.                     url_buffer, url_buffer_size,
  258.                     username_buffer, username_buffer_size,
  259.                     password_buffer, password_buffer_size);
  260.  
  261. }
  262.  
  263. /*, returns status
  264.  */
  265. PUBLIC int
  266. PC_DisplayPasswordCacheAsHTML(URL_Struct *URL_s, 
  267.                                FO_Present_Types format_out,
  268.                                MWContext *context)
  269. {
  270.     DBT key, data;
  271.     int status = 1;
  272.     NET_StreamClass *stream; 
  273.     char tmp_buffer[512];
  274.     char type_buffer[256];
  275.     char url_buffer[512];
  276.     char username_buffer[256];
  277.     char password_buffer[256];
  278.  
  279.     format_out = CLEAR_CACHE_BIT(format_out);
  280.     StrAllocCopy(URL_s->content_type, TEXT_HTML);
  281.     stream = NET_StreamBuilder(format_out,
  282.                                URL_s,
  283.                                context);
  284.  
  285.     if(!stream)
  286.     {
  287.         return MK_UNABLE_TO_CONVERT;
  288.     }
  289.  
  290.  
  291.     /* define a macro to push a string up the stream
  292.      * and handle errors
  293.      */
  294. #define PUT_PART(part)                                                  \
  295. status = (*stream->put_block)(stream,                      \
  296.                                         part ? part : "Unknown",        \
  297.                                         part ? XP_STRLEN(part) : 7);    \
  298. if(status < 0)                                                          \
  299.   goto END;
  300.  
  301.     if(!pc_open_database())
  302.     {
  303.         XP_STRCPY(tmp_buffer, "The password database is currently unopenable");
  304.         PUT_PART(tmp_buffer);
  305.         goto END;
  306.     }
  307.  
  308.     if(0 != (*pw_database->seq)(pw_database, &key, &data, R_FIRST))
  309.     {
  310.         XP_STRCPY(tmp_buffer, "The password database is currently empty");
  311.         PUT_PART(tmp_buffer);
  312.         goto END;
  313.     }
  314.  
  315.     do {
  316.  
  317.         pc_lookup_module_info(key.data, 
  318.                              data.data, data.size,
  319.                              type_buffer, sizeof(type_buffer), 
  320.                              url_buffer, sizeof(url_buffer),
  321.                              username_buffer, sizeof(username_buffer),
  322.                              password_buffer, sizeof(password_buffer));
  323.  
  324.         PUT_PART("Protocol: ");
  325.         PUT_PART(type_buffer);
  326.  
  327.         PUT_PART("<br>\nURL: ");
  328.         PUT_PART(url_buffer);
  329.  
  330.         PUT_PART("<br>\nUsername: ");
  331.         PUT_PART(username_buffer);
  332.         
  333.         PUT_PART("<br>\nPassword: ");
  334.         PUT_PART(password_buffer);
  335.  
  336.         PUT_PART("\n<HR>\n");
  337.  
  338.     } while (0 == (*pw_database->seq)(pw_database, &key, &data, R_NEXT));
  339.     
  340. END:
  341.     if(status < 0)
  342.         (*stream->abort)(stream, status);
  343.     else
  344.         (*stream->complete)(stream);
  345.  
  346.     return status;
  347. }
  348.         
  349. PUBLIC int
  350. PC_PromptUsernameAndPassword(MWContext *context,
  351.                              char *prompt,
  352.                              char **username,
  353.                              char **password,
  354.                              XP_Bool *remember,
  355.                              XP_Bool is_secure)
  356. {
  357.     *remember = TRUE;
  358.     *remember = FALSE;
  359.  
  360.     return FE_PromptUsernameAndPassword(context, prompt, username, password);
  361. }
  362.  
  363. PUBLIC char *
  364. PC_PromptPassword(MWContext *context,
  365.                              char *prompt,
  366.                              XP_Bool *remember,
  367.                              XP_Bool is_secure)
  368. {
  369.     *remember = TRUE;
  370.     *remember = FALSE;
  371.  
  372.     return FE_PromptPassword(context, prompt);
  373. }
  374.  
  375. PUBLIC char *
  376. PC_Prompt(MWContext *context,
  377.          char *prompt,
  378.          char *deflt,
  379.          XP_Bool *remember,
  380.          XP_Bool is_secure)
  381. {
  382.     *remember = TRUE;
  383.     *remember = FALSE;
  384.  
  385.     return FE_Prompt(context, prompt, deflt);
  386. }
  387.  
  388. PUBLIC void
  389. PC_FreeNameValueArray(PCNameValueArray *array)
  390. {
  391.     int index;
  392.     if(array)
  393.     {
  394.         if(array->pairs)
  395.         {
  396.             for(index=0; index < array->first_empty; index++)
  397.             {
  398.                 XP_FREEIF(array->pairs[index].name);
  399.                 XP_FREEIF(array->pairs[index].value);
  400.             }
  401.             XP_FREE(array->pairs);
  402.         }
  403.         XP_FREE(array);
  404.     }
  405. }
  406.  
  407.  
  408. #define MIN_ARRAY_SIZE 4
  409. #define GROW_ARRAY_BY 4
  410.  
  411. PRIVATE PCNameValueArray *
  412. pc_new_namevaluearray(int init_size)
  413. {
  414.     PCNameValueArray *array = XP_NEW_ZAP(PCNameValueArray);
  415.  
  416.     if(!array)
  417.         return NULL;
  418.  
  419.     array->pairs = (PCNameValuePair*)XP_CALLOC(init_size, sizeof(PCNameValuePair));
  420.     array->size = init_size;
  421.     array->first_empty = 0;
  422.     array->cur_ptr = 0;
  423.  
  424.     if(!array->pairs)
  425.     {
  426.         PC_FreeNameValueArray(array);
  427.         return NULL;
  428.     }
  429.  
  430.     return array;
  431. }
  432.  
  433. PUBLIC PCNameValueArray *
  434. PC_NewNameValueArray()
  435. {
  436.     return pc_new_namevaluearray(MIN_ARRAY_SIZE);
  437. }
  438.  
  439. PUBLIC uint32
  440. PC_ArraySize(PCNameValueArray *array)
  441. {
  442.     return(array->first_empty);
  443. }
  444.  
  445. /* returns value for a given name
  446.  */
  447. char *
  448. PC_FindInNameValueArray(PCNameValueArray *array, char *name)
  449. {
  450.     int i;
  451.     for(i=0; i<array->first_empty; i++)
  452.     {
  453.         if(!XP_STRCMP(array->pairs[i].name, name))
  454.             return XP_STRDUP(array->pairs[i].value);
  455.     }
  456.     
  457.     return NULL;
  458.     
  459. }
  460.  
  461. PUBLIC int
  462. PC_DeleteNameFromNameValueArray(PCNameValueArray *array, char *name)
  463. {
  464.     int i;
  465.  
  466.     if(!array)
  467.         return -1;
  468.  
  469.     for(i=0; i<array->first_empty; i++)
  470.     {
  471.         if(!XP_STRCMP(array->pairs[i].name, name))
  472.         {
  473.             /* found it */
  474.  
  475.             /* delete it */
  476.             XP_FREE(array->pairs[i].name);
  477.             XP_FREEIF(array->pairs[i].value);
  478.  
  479.             /* move everything */
  480.             array->first_empty--;
  481.  
  482.             if(array->first_empty > i+1)
  483.                 XP_MEMCPY(&array->pairs[i], &array->pairs[i+1], (array->first_empty - (i+1)) * sizeof(PCNameValuePair));
  484.  
  485.             return 0;
  486.         }
  487.     }
  488.  
  489.     return -1;
  490. }
  491.  
  492. /* enumerates the array.  DO NOT free the name and value results 
  493.  *
  494.  * set beggining to TRUE to start over at the beginning
  495.  */
  496. PUBLIC void
  497. PC_EnumerateNameValueArray(PCNameValueArray *array, char **name, char **value, XP_Bool beginning)
  498. {
  499.  
  500.     *name = NULL;
  501.     *value = NULL;
  502.     
  503.     if(!array)
  504.         return;
  505.  
  506.     if(beginning)
  507.     {
  508.         array->cur_ptr = 0;
  509.     }
  510.     else if(array->cur_ptr >= array->first_empty)
  511.     {
  512.         return;
  513.     }
  514.  
  515.     *name = array->pairs[array->cur_ptr].name;
  516.     *value = array->pairs[array->cur_ptr].value;
  517.  
  518.     array->cur_ptr++;
  519.         
  520.     return;
  521. }
  522.  
  523. /* private ver. takes pre malloced name and value strings */
  524. PRIVATE int
  525. pc_add_to_namevaluearray(PCNameValueArray *array, char *name, char *value)
  526. {
  527.     if(array)
  528.     {
  529.         if(array->first_empty >= array->size-1)
  530.         {
  531.             /* need to grow */
  532.  
  533.             array->size += GROW_ARRAY_BY;
  534.             array->pairs = (PCNameValuePair *)XP_REALLOC(array->pairs, array->size * sizeof(PCNameValuePair));
  535.         }
  536.  
  537.         if(!array->pairs)
  538.         {
  539.             array->size = 0;
  540.             return -1;
  541.         }
  542.         
  543.         array->pairs[array->first_empty].name = name;
  544.         array->pairs[array->first_empty].value = value;
  545.         array->first_empty++;
  546.  
  547.         if(!array->pairs[array->first_empty-1].name
  548.            || !array->pairs[array->first_empty-1].value)
  549.             return -1;
  550.  
  551.         return 0;
  552.     }
  553.  
  554.     return -1;
  555. }
  556.  
  557. /* adds to end of name value array 
  558.  *
  559.  * Possible to add duplicate names with this
  560.  */
  561. PUBLIC int
  562. PC_AddToNameValueArray(PCNameValueArray *array, char *name, char *value)
  563. {
  564.     char *m_name = XP_STRDUP(name);
  565.     char *m_value = XP_STRDUP(value);
  566.  
  567.     if(!m_name || !m_value)
  568.     {
  569.         XP_FREEIF(m_name);
  570.         XP_FREEIF(m_value);
  571.         return -1;
  572.     }
  573.  
  574.     return pc_add_to_namevaluearray(array, name, value);
  575. }
  576.  
  577. /* takes a key string as input and returns a char * pointer
  578.  * in data to the serialized data structure previously stored or NULL.
  579.  * len will be filled in to the length of the data string
  580.  *
  581.  * A module name is also passed in to guarentee that a key from
  582.  * another module is never returned by an accidental key match.
  583.  */
  584. PUBLIC void
  585. PC_CheckForStoredPasswordData(char *module, char *key, char **data, int32 *len)
  586. {
  587.     DBT k_key, k_data;
  588.     char *combo;
  589.     int status;
  590.  
  591.     *len = 0;
  592.     *data = NULL;
  593.  
  594.     if(!pc_open_database())
  595.         return;
  596.  
  597.     if((combo = pc_gen_key(module, key)) == NULL)
  598.         return;
  599.  
  600.     k_key.size = XP_STRLEN(combo);
  601.     k_key.data = combo;
  602.  
  603.     status = (*pw_database->get)(pw_database, &k_key, &k_data, 0);
  604.         
  605.     XP_FREE(combo);
  606.  
  607.     if(status != 0)
  608.         return;
  609.  
  610.     *data = k_data.data;
  611.     *len = k_data.size;
  612.  
  613.     return;
  614. }
  615.  
  616. /* returns 0 on success else -1 
  617.  */
  618. PUBLIC int
  619. PC_DeleteStoredPassword(char *module, char *key)
  620. {
  621.     DBT k_key;
  622.     char *combo;
  623.     int status;
  624.  
  625.     if(!pc_open_database())
  626.         return -1;
  627.  
  628.     if((combo = pc_gen_key(module, key)) == NULL)
  629.         return -1;
  630.  
  631.     k_key.size = XP_STRLEN(combo);
  632.     k_key.data = combo;
  633.  
  634.     status = (*pw_database->del)(pw_database, &k_key, 0);
  635.  
  636.     XP_FREE(combo);
  637.  
  638.     if(status != 0)
  639.         return -1;
  640.  
  641.     return 0;
  642. }
  643.  
  644. /* takes a key string as input and returns a name value array
  645.  *
  646.  * A module name is also passed in to guarentee that a key from
  647.  * another module is never returned by an accidental key match.
  648.  */
  649. PUBLIC PCNameValueArray *
  650. PC_CheckForStoredPasswordArray(char *module, char *key)
  651. {
  652.     char *data;
  653.     int32 len;
  654.  
  655.     PC_CheckForStoredPasswordData(module, key, &data, &len);
  656.  
  657.     if(!data)
  658.         return NULL;
  659.  
  660.     return PC_CharToNameValueArray(data, len);
  661. }
  662.  
  663. /* stores a serialized data stream in the password database
  664.  * returns 0 on success
  665.  */
  666. PUBLIC int
  667. PC_StoreSerializedPassword(char *module, char *key, char *data, int32 len)
  668. {
  669.     char *combo;
  670.     DBT k_key, k_data;
  671.     int status;
  672.  
  673.     if(!pc_open_database())
  674.         return 0;
  675.  
  676.     if((combo = pc_gen_key(module, key)) == NULL)
  677.         return -1;
  678.  
  679.     k_key.size = XP_STRLEN(combo)+1;
  680.     k_key.data = combo;
  681.  
  682.     k_data.data = data;
  683.     k_data.size = len;
  684.  
  685.     status = (*pw_database->put)(pw_database, &k_key, &k_data, 0);
  686.         
  687.     XP_FREE(combo);
  688.  
  689.     if(status != 0)
  690.         return -1;
  691.  
  692.     status = (*pw_database->sync)(pw_database, 0);
  693.  
  694.     return 0;
  695. }
  696.  
  697. /* stores a name value array in the password database
  698.  * returns 0 on success
  699.  */
  700. PUBLIC int
  701. PC_StorePasswordNameValueArray(char *module, char *key, PCNameValueArray *array)
  702. {
  703.     char *data;
  704.     int32 len;
  705.     int status;
  706.  
  707.     PC_SerializeNameValueArray(array, &data, &len);
  708.  
  709.     if(!data)
  710.         return -1;
  711.  
  712.     status = PC_StoreSerializedPassword(module, key, data, len);
  713.  
  714.     XP_FREE(data);
  715.  
  716.     return status;
  717. }
  718.  
  719. #define SERIALIZER_VERSION_NUM 1
  720.  
  721. /* takes a name value array and serializes to a char string.
  722.  * string is returned in "data" with length "len"
  723.  *
  724.  * data will always be NULL on error
  725.  */
  726. PUBLIC void
  727. PC_SerializeNameValueArray(PCNameValueArray *array, char **data, int32 *len)
  728. {
  729.     int32 total_size, net_long;
  730.     char *cur_ptr;
  731.     char *name, *value;
  732.  
  733.     *len = 0;
  734.     *data = NULL;
  735.  
  736.     XP_ASSERT(array && array->pairs);
  737.  
  738.     if(!array)
  739.         return;
  740.  
  741.     total_size = sizeof(int32)*3; /* start with checksum + ver + array_size amount */
  742.     
  743.     /* determine size of arrays */
  744.     PC_EnumerateNameValueArray(array, &name, &value, TRUE);
  745.     while(name)
  746.     {
  747.         total_size += sizeof(int32); /* size of name len */
  748.         total_size += XP_STRLEN(name)+1;
  749.  
  750.         total_size += sizeof(int32); /* size of value len */
  751.         if(value)
  752.             total_size += XP_STRLEN(value)+1;
  753.  
  754.         PC_EnumerateNameValueArray(array, &name, &value, FALSE);
  755.     }
  756.  
  757.     /* malloc enough space */
  758.     *data = XP_ALLOC(sizeof(char) * total_size);
  759.     
  760.     if(!*data)
  761.         return;
  762.     
  763.     cur_ptr = *data;
  764.  
  765.     net_long = PR_htonl(total_size);
  766.       XP_MEMCPY(cur_ptr, &net_long, sizeof(int32));
  767.       cur_ptr += sizeof(int32);
  768.     
  769.     net_long = PR_htonl(SERIALIZER_VERSION_NUM);
  770.       XP_MEMCPY(cur_ptr, &net_long, sizeof(int32));
  771.       cur_ptr += sizeof(int32);
  772.     
  773.     net_long = PR_htonl(PC_ArraySize(array));
  774.       XP_MEMCPY(cur_ptr, &net_long, sizeof(int32));
  775.       cur_ptr += sizeof(int32);
  776.     
  777.     PC_EnumerateNameValueArray(array, &name, &value, TRUE);
  778.     while(name)
  779.     {
  780.           net_long = PR_htonl((name ? XP_STRLEN(name)+1 : 0)); 
  781.           XP_MEMCPY(cur_ptr, &net_long, sizeof(int32));
  782.           cur_ptr += sizeof(int32);
  783.         net_long = PR_ntohl(net_long);  /* convert back to true len */
  784.           if(net_long)
  785.               XP_MEMCPY((void *)cur_ptr, name, net_long);
  786.           cur_ptr += net_long;
  787.  
  788.           net_long = PR_htonl((value ? XP_STRLEN(value)+1 : 0)); 
  789.           XP_MEMCPY(cur_ptr, &net_long, sizeof(int32));
  790.           cur_ptr += sizeof(int32);
  791.         net_long = PR_ntohl(net_long);  /* convert back to true len */
  792.           if(net_long)
  793.               XP_MEMCPY((void *)cur_ptr, value, net_long);
  794.           cur_ptr += net_long;
  795.  
  796.         PC_EnumerateNameValueArray(array, &name, &value, FALSE);
  797.     }
  798.     
  799.     *len = total_size;
  800.  
  801.     return;
  802. }
  803.  
  804. /* returns a PCNameValueArray from serialized char data.
  805.  *
  806.  * returns NULL on error
  807.  */
  808. PUBLIC PCNameValueArray *
  809. PC_CharToNameValueArray(char *data, int32 len)
  810. {
  811.     int32 host_long, str_len, len_read, array_size, index;
  812.     char *cur_ptr;
  813.     char *name, *value;
  814.     PCNameValueArray *array;
  815.  
  816.     /* must be at least 12 bytes, len and ver and array_size */
  817.     XP_ASSERT(len >= 12);
  818.     
  819.     if(len < 12)
  820.         return NULL;
  821.  
  822.     cur_ptr = data;
  823.  
  824.     /* read first 4 bytes as checksum */
  825.     XP_MEMCPY(&host_long, cur_ptr, 4);
  826.     host_long = PR_ntohl(host_long);
  827.     cur_ptr += sizeof(int32);
  828.     len_read = sizeof(int32);
  829.     
  830.     if(host_long != len)
  831.     {
  832.         XP_ASSERT(0); /* this one might happen on db error */
  833.         return NULL;  /* failed checksum */
  834.     }
  835.  
  836.     /* read next 4 bytes as ver */
  837.     XP_MEMCPY(&host_long, cur_ptr, 4);
  838.     host_long = PR_ntohl(host_long);
  839.     cur_ptr += sizeof(int32);
  840.     len_read += sizeof(int32);
  841.     
  842.     if(host_long != SERIALIZER_VERSION_NUM)
  843.     {
  844.         XP_ASSERT(0);
  845.         return NULL;  /* failed ver check */
  846.     }
  847.  
  848.     /* read next 4 bytes as array_size */
  849.     XP_MEMCPY(&array_size, cur_ptr, 4);
  850.     array_size = PR_ntohl(array_size);
  851.     cur_ptr += sizeof(int32);
  852.     len_read += sizeof(int32);
  853.  
  854.     /* malloc arrays */
  855.     array = pc_new_namevaluearray(array_size);
  856.     if(!array)
  857.         return NULL;
  858.  
  859.     index = 0;
  860.     while(len_read < len)
  861.     {
  862.         /* next 4 bytes is length of name string */
  863.         XP_MEMCPY(&str_len, cur_ptr, 4);
  864.         str_len = PR_ntohl(str_len);
  865.         cur_ptr += sizeof(int32);
  866.         len_read += sizeof(int32);
  867.  
  868.         if(len_read + str_len > len)
  869.             goto error_out;
  870.     
  871.         name = XP_ALLOC(str_len * sizeof(char));
  872.         if(!name)
  873.             goto error_out;
  874.  
  875.         XP_MEMCPY(name, cur_ptr, str_len);
  876.         len_read += str_len;
  877.         cur_ptr += str_len;
  878.  
  879.         if(len_read >= len)
  880.             goto error_out;
  881.         
  882.         /* next 4 bytes is length of value string */
  883.         XP_MEMCPY(&str_len, cur_ptr, 4);
  884.         str_len = PR_ntohl(str_len);
  885.         cur_ptr += sizeof(int32);
  886.         len_read += sizeof(int32);
  887.  
  888.         if(len_read + str_len > len)
  889.             goto error_out;
  890.     
  891.         value = XP_ALLOC(str_len * sizeof(char));
  892.         if(!value)
  893.             goto error_out;
  894.  
  895.         XP_MEMCPY(value, cur_ptr, str_len);
  896.         len_read += str_len;
  897.         cur_ptr += str_len;
  898.  
  899.         pc_add_to_namevaluearray(array, name, value);
  900.  
  901.         index++;
  902.     }
  903.  
  904.     XP_ASSERT(len_read == len);
  905.  
  906.     return array;
  907.  
  908. error_out:
  909.  
  910.     XP_ASSERT(0);
  911.  
  912.     PC_FreeNameValueArray(array);
  913.  
  914.     return NULL;
  915. }
  916.