servutil.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:33k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #include "serv.h"
  35. #include "secport.h"
  36. #include "collectn.h"
  37. #include "resource.h"
  38. #include "connect.h"
  39. #include "plstr.h"
  40. #include "prprf.h"
  41. #include "base64.h"
  42. #include "textgen.h"
  43. #include "protocolf.h"
  44. #include "p12res.h"
  45. #include "ctrlconn.h"
  46. #include "newproto.h"
  47. #include "messages.h"
  48. #ifdef XP_UNIX
  49. #include "private/pprio.h"
  50. #include <unistd.h>
  51. #define GET_LOCK_FILE_PATH(b)  
  52.         sprintf(b, "/tmp/.nsmc-%d-lock", (int)geteuid())
  53. #define GET_CONTROL_SOCK_PATH(b) 
  54.         sprintf(b, "/tmp/.nsmc-%d", (int)geteuid())
  55. PRFileDesc *lockfile = NULL;
  56. #endif
  57. #define DEBUG_QUEUES
  58. extern SSMCollection * connections;
  59. /* Dumps a (potentially binary) buffer using SSM_DEBUG. 
  60.    (We could have used the version in ssltrace.c, but that's
  61.    specifically tailored to SSLTRACE. Sigh. */
  62. #define DUMPBUF_LINESIZE 8
  63. void
  64. SSM_DumpBuffer(char *buf, PRIntn len)
  65. {
  66.     char hexbuf[DUMPBUF_LINESIZE*3+1];
  67.     char chrbuf[DUMPBUF_LINESIZE+1];
  68.     static const char *hex = "0123456789abcdef";
  69.     PRIntn i = 0, l = 0;
  70.     char ch, *c, *h;
  71.     hexbuf[DUMPBUF_LINESIZE*3] = '';
  72.     chrbuf[DUMPBUF_LINESIZE] = '';
  73.     (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
  74.     (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
  75.     h = hexbuf;
  76.     c = chrbuf;
  77.     while (i < len)
  78.     {
  79.         ch = buf[i];
  80.         if (l == DUMPBUF_LINESIZE)
  81.         {
  82.             SSM_DEBUG("%s%sn", hexbuf, chrbuf);
  83.             (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
  84.             (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
  85.             h = hexbuf;
  86.             c = chrbuf;
  87.             l = 0;
  88.         }
  89.         /* Convert a character to hex. */
  90.         *h++ = hex[(ch >> 4) & 0xf];
  91.         *h++ = hex[ch & 0xf];
  92.         h++;
  93.         
  94.         /* Put the character (if it's printable) into the character buffer. */
  95.         if ((ch >= 0x20) && (ch <= 0x7e))
  96.             *c++ = ch;
  97.         else
  98.             *c++ = '.';
  99.         i++; l++;
  100.     }
  101.     SSM_DEBUG("%s%sn", hexbuf, chrbuf);
  102. }
  103. PRIntn SSM_ReadThisMany(PRFileDesc * sockID, void * buffer, PRIntn thisMany)
  104. {
  105.     int got = 0;
  106.     PRIntn total = 0;
  107.   
  108.     while (total < thisMany) {
  109.         got = PR_Recv(sockID, (void *)((char *)buffer + total), thisMany-total, 
  110.                       0, PR_INTERVAL_NO_TIMEOUT);
  111.         if (got <= 0 ) break;
  112.         total += got;
  113.     } 
  114.     /* Clear the PR error if we got EOF in the final read, 
  115.        as opposed to -1 bytes. */
  116.     if (got == 0)
  117.         PR_SetError(0, 0);
  118.     
  119.     return total;
  120. }
  121.  
  122. PRIntn SSM_WriteThisMany(PRFileDesc * sockID, void * buffer, PRIntn thisMany)
  123. {
  124.   PRIntn total = 0;
  125.   
  126.   while (total < thisMany) {
  127.     PRIntn got;
  128.     got = PR_Send(sockID, (void *)((char *)buffer+total), thisMany-total, 
  129.   0, PR_INTERVAL_NO_TIMEOUT);
  130.     if (got < 0) break;
  131.     total += got;
  132.   }
  133.   return total;
  134. }
  135. SECItem * SSM_ConstructMessage(PRUintn size) 
  136. {
  137.   SECItem * ptr = NULL;
  138.   
  139. #if 0
  140.   SSM_DEBUG("allocating message of size %ld.n", (long) size);
  141. #endif
  142.   
  143.   ptr = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  144.   if (!ptr) {
  145.     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  146.     goto loser;
  147.   }
  148.   ptr->len = size;
  149.   if (size > 0) { 
  150.     ptr->data = (unsigned char *)PORT_ZAlloc(size);
  151.     if (!ptr->data) {
  152.       PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  153.       goto loser;
  154.       }
  155.   }
  156.   return ptr;
  157. loser:
  158.   SSM_FreeMessage(ptr);
  159.   return NULL;
  160. }
  161. void SSM_FreeMessage(SECItem * msg)
  162. {
  163.   if (!msg) return;
  164.   if (msg->data)
  165.     PORT_Free(msg->data);
  166.   PORT_Free(msg);
  167. }
  168. void
  169. ssm_DrainAndDestroyQueue(SSMCollection **coll)
  170. {
  171.     SSMCollection *v;
  172.     PRIntn type, len;
  173.     char *data;
  174.     if ((coll == NULL) || (*coll == NULL))
  175. return;
  176.     v = *coll;
  177.     /* Drain the collection. Don't block; presumably this is
  178.        being done at destruction time. */
  179.     while(SSM_RecvQMessage(v, SSM_PRIORITY_ANY, 
  180.    &type, &len, &data, 
  181.    PR_FALSE) == PR_SUCCESS)
  182.     {
  183. if (data)
  184.     PR_Free(data);
  185.     }
  186. #if 0
  187.     /* NotifyAll on the lock and yield time. */
  188.     /* ### mwelch - Causing problems on Linux, and shouldn't even 
  189.                     be here since we don't have the queue locked, 
  190.                     so I'm removing it. */
  191.     PR_NotifyAll(v->lock);
  192. #endif
  193.     /* Destroy the collection. */
  194.     SSM_DestroyCollection(v);
  195.     /* Zero out the original member. */
  196.     *coll = NULL;
  197. }
  198. void
  199. ssm_DrainAndDestroyChildCollection(SSMCollection **coll)
  200. {
  201.     SSMCollection *v;
  202.     SSMConnection *conn;
  203.     if ((coll == NULL) || (*coll == NULL))
  204. return;
  205.     v = *coll;
  206.     /* Drain the collection. Don't block; presumably this is
  207.        being done at destruction time. */
  208.     while(SSM_Dequeue(v, SSM_PRIORITY_ANY, (void **) &conn, PR_FALSE) == PR_SUCCESS) {;}
  209.     /* Destroy the collection. */
  210.     SSM_DestroyCollection(v);
  211.     /* Zero out the original member. */
  212.     *coll = NULL;
  213. }
  214. static SSMHashTable *ssmThreads = NULL;
  215. void SSM_ConnectionThreadName(char *buf)
  216. {
  217.     PRThread * threadptr = PR_GetCurrentThread();
  218.     char *name;
  219.     buf[0] = ''; /* in case we fail */
  220.     if (!ssmThreads) return;
  221.     if (SSM_HashFind(ssmThreads, (SSMHashKey) threadptr, (void **) &name)
  222.         != SSM_SUCCESS)
  223.         return;
  224.     
  225.     if (name)
  226.         PL_strcpy(buf, name);
  227. }
  228. static SSMCollection *logSockets = NULL;
  229. static PRMonitor *logSocketLock = NULL;
  230. /* Add the filedesc to a list of sockets to receive log output */
  231. SSMStatus
  232. SSM_AddLogSocket(PRFileDesc *fd)
  233. {
  234.     SSMStatus rv = SSM_SUCCESS;
  235.     PR_ASSERT(logSockets);
  236.     PR_ASSERT(logSocketLock);
  237.     PR_EnterMonitor(logSocketLock);
  238.     rv = SSM_Enqueue(logSockets, SSM_PRIORITY_NORMAL, fd);
  239.     PR_ExitMonitor(logSocketLock);    
  240.     if (rv != SSM_SUCCESS) 
  241.         SSM_DEBUG("SSM_AddLogSocket returned error %d.n", rv);
  242.     return rv;
  243. }
  244. /* Called by a newly created thread, this associates a name with the thread. */
  245. void
  246. SSM_RegisterThread(char *threadName, SSMResource *ptr)
  247. {
  248.     SSMStatus rv = SSM_SUCCESS;
  249.     PRThread *thr = PR_GetCurrentThread();
  250.     char *value;
  251. #ifdef XP_MAC
  252.     /* 
  253.      Each thread, when registering itself using one of the two functions
  254.      below, assigns itself as private data at index (thdIndex). This is
  255.      necessary because when a thread exits, we want it to delete itself
  256.      from the list of threads we need to kill at exit time. 
  257.     */
  258.     { 
  259.       PRUintn threadIndex = GetThreadIndex();
  260.       if (threadIndex > 0) {
  261.        if (PR_GetThreadPrivate(threadIndex) != thr)
  262.        PR_SetThreadPrivate(threadIndex, thr);
  263.       }
  264.     }
  265. #endif
  266.     if (ptr)
  267.     {
  268.         PR_ASSERT(SSM_IsAKindOf(ptr, SSM_RESTYPE_RESOURCE));
  269.         /* Increment the thread count for this resource. */
  270.         SSM_LockResource(ptr);
  271.         ptr->m_threadCount++;
  272.         SSM_UnlockResource(ptr);
  273.     }
  274.     if (threadName)
  275.     {
  276.         if (ptr)
  277.             value = PR_smprintf("%s %p", threadName, ptr);
  278.         else
  279.             value = PL_strdup(threadName);
  280.     }
  281.     else
  282.         value = PR_smprintf("unknown %p/%p", thr, ptr);
  283.     if ((!ssmThreads) &&
  284.         ((rv = SSM_HashCreate(&ssmThreads)) != SSM_SUCCESS))
  285.         return;
  286.     if (!value) return;
  287.     SSM_HashInsert(ssmThreads, (SSMHashKey) thr, value);
  288. }
  289. /* Called by a newly created thread, this associates a name with the thread. */
  290. void
  291. SSM_RegisterNewThread(char *threadName, SSMResource *ptr)
  292. {
  293.     SSMStatus rv = SSM_SUCCESS;
  294.     PRThread *thr = PR_GetCurrentThread();
  295.     char *value;
  296.     if (threadName)
  297.     {
  298.         if (ptr)
  299.             value = PR_smprintf("%s %p", threadName, ptr);
  300.         else
  301.             value = PL_strdup(threadName);
  302.     }
  303.     else
  304.         value = PR_smprintf("unknown %p/%p", thr, ptr);
  305.     if ((!ssmThreads) &&
  306.         ((rv = SSM_HashCreate(&ssmThreads)) != SSM_SUCCESS))
  307.         return;
  308.     if (!value) return;
  309.     SSM_HashInsert(ssmThreads, (SSMHashKey) thr, value);
  310. }
  311. void SSM_Debug(SSMResource *conn, char *msg)
  312. {
  313. #ifdef DEBUG
  314.   char name[256];
  315.   
  316.   SSM_ConnectionThreadName(name);
  317.   printf("%s: %s", name, msg);
  318.   fflush(stdout); 
  319.   PR_Free(msg);
  320. #endif
  321. }
  322. void SSM_DebugP(char *fmt, ...)
  323. {
  324. #if defined(DEBUG)
  325.     char *tmp = NULL, *tmp2 = NULL;
  326. char *timeStamp = NULL;
  327.     PRFileDesc *sock = NULL;
  328.     PRIntn len;
  329.     PRIntn numWritten;
  330.     char name[256];
  331.     va_list argp;
  332.     PRIntn count, i;
  333.     PRUint32 rv = 0;
  334. PRExplodedTime exploded;
  335.     /* protect against another socket add */
  336.     PR_EnterMonitor(logSocketLock);
  337.     if (!logSockets)
  338.         goto done;
  339.     
  340.     count = SSM_Count(logSockets);
  341.     if (count == 0)
  342.         goto done;
  343.     va_start(argp, fmt);
  344.     tmp = PR_vsmprintf(fmt, argp);
  345.     va_end(argp);
  346.     if (!tmp)
  347.         goto done;
  348. PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &exploded);
  349. timeStamp = PR_smprintf("%02i:%02i:%02i.%03i", exploded.tm_hour, 
  350.                             exploded.tm_min, exploded.tm_sec, 
  351.                             exploded.tm_usec/1000);
  352.     SSM_ConnectionThreadName(name);
  353.     tmp2 = PR_smprintf("[%s] %s: %s", timeStamp, name, tmp);
  354.     if (!tmp2)
  355.         goto done;
  356.     len = strlen(tmp2);
  357.     count = SSM_Count(logSockets);
  358.     /* count backwards in case we get an error */
  359.     for(i=(count-1);i>=0;i--)
  360.     {
  361.         numWritten = 0;
  362.         sock = (PRFileDesc *) SSM_At(logSockets, i);
  363.         if (sock)
  364.             numWritten = PR_Write(sock, tmp2, len);
  365.         if (numWritten < len)
  366.         {
  367.             /*SSM_Remove(logSockets, sock);*/
  368.             /*PR_Close(sock);*/
  369.             /*PR_Shutdown(sock, PR_SHUTDOWN_BOTH);*/
  370.             rv = 0;
  371.         }
  372.     }
  373.  done:
  374.     if (tmp)
  375.         PR_smprintf_free(tmp);
  376.     if (tmp2)
  377.         PR_smprintf_free(tmp2);
  378. if (timeStamp) 
  379. PR_smprintf_free(timeStamp);
  380.     PR_ExitMonitor(logSocketLock);
  381. #endif
  382. }
  383. #ifdef DEBUG
  384. void
  385. SSM_InitLogging(void)
  386. {
  387.     char *suppressConsole = NULL;
  388.     char *debugFile = NULL;
  389.     /* Create the condition variable we use to control logging. */
  390.     if (!(logSocketLock = PR_NewMonitor()))
  391.         goto loser;
  392.     if (!(logSockets = SSM_NewCollection()))
  393.         goto loser; 
  394.     suppressConsole = PR_GetEnv(SSM_ENV_SUPPRESS_CONSOLE);
  395.     debugFile = PR_GetEnv(SSM_ENV_LOG_FILE);
  396.     if (!suppressConsole)
  397.     {
  398.         PRFileDesc *stdfd = PR_GetSpecialFD(PR_StandardOutput);
  399.         if (!stdfd)
  400.             stdfd = PR_GetSpecialFD(PR_StandardError);
  401.         if (stdfd)
  402.             SSM_AddLogSocket(stdfd);
  403.     }
  404.     if (debugFile)
  405.     {
  406.         PRFileDesc *fd = PR_Open(debugFile, 
  407.                                  PR_WRONLY | PR_APPEND | 
  408.                                  PR_CREATE_FILE | PR_SYNC, 
  409.                                  0644);
  410.         if (fd)
  411.             SSM_AddLogSocket(fd);
  412.     }
  413.     SSM_DEBUG("Started logging.n");
  414.     return;
  415.  loser:
  416.     fprintf(stderr, "Can't initialize logging! Exiting.n");
  417.     exit(1);
  418. }
  419. #endif
  420. SSMStatus SSM_SendQMessage(SSMCollection *q,
  421.   PRIntn priority,
  422.   PRIntn type, PRIntn length, char *data,
  423.   PRBool doBlock)
  424. {
  425.   SECItem *n = NULL;
  426.   unsigned char *c = NULL;
  427.   SSMStatus rv = PR_FAILURE;
  428.   PR_ASSERT(priority != SSM_PRIORITY_ANY);
  429. #ifdef DEBUG_QUEUES
  430.   SSM_DEBUG("SendQMessage on %lx: prio %d, type %lx, len %dn", 
  431.             (unsigned long) q, priority, (unsigned long) type, length);
  432. #endif
  433.   /* Create a new message. */
  434.   n = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
  435.   if (!n)
  436.       goto loser;
  437.   
  438.   if (data && length > 0) {
  439.      c = (unsigned char *) PORT_ZAlloc(length);
  440.      if (!c)
  441.          goto loser;
  442.      memcpy(c, data, length);
  443.   }
  444.   
  445.   n->type = (SECItemType) type;
  446.   n->len = length;
  447.   n->data = c;
  448.   /* ### mwelch We'll want to put a throttle here when we
  449.                 start really securing Cartman. It's currently
  450. possible for someone to make us run out of
  451. memory very quickly by flooding us with data. */
  452.                 
  453.   /* Put the msg in the queue. */
  454.   SSM_Enqueue(q, priority, n);
  455.   return PR_SUCCESS;
  456. loser:
  457.   if (n) PORT_Free(n);
  458.   if (c) PORT_Free(c);
  459.   return rv;
  460. }
  461. SSMStatus SSM_RecvQMessage(SSMCollection *q,
  462.   PRIntn priority,
  463.   PRIntn *type, PRIntn *length, char **data,
  464.   PRBool doBlock)
  465. {
  466.   SECItem *p;
  467.   void *v;
  468. #ifdef DEBUG_QUEUES
  469.   SSM_DEBUG("RecvQMessage on %lx: %s read at prio %dn", 
  470.             (unsigned long) q, 
  471.             (doBlock ? "blocking" : "nonblocking"), 
  472.             priority);
  473. #endif
  474.   /* Remove the item at the head of the queue. */
  475.   SSM_Dequeue(q, priority, &v, doBlock);
  476.   p = (SECItem *) v;
  477.   if (!p)
  478.     return PR_FAILURE;
  479.   /* Strip out the items. */
  480.   *data = (char *)p->data;
  481.   *length = p->len;
  482.   *type = p->type;
  483.   
  484. #ifdef DEBUG_QUEUES
  485.   SSM_DEBUG("RecvQMessage on %lx: type %lx, len %dn", 
  486.             (unsigned long) q, (unsigned long) *type, 
  487.             *length);
  488. #endif
  489.   /* Free the containing SECItem. */
  490.   PORT_Free(p);
  491.   return PR_SUCCESS;
  492. }
  493. SSMStatus
  494. SSM_SECItemToSSMString(void ** ssmstring, SECItem * data)
  495. {
  496.  SSMString * result = NULL;
  497.  if (!ssmstring || !data || data->len <= 0 ) 
  498. goto loser;
  499.  
  500.  *ssmstring = NULL; /* in case we fail */
  501.  result = (SSMString *) SSMPORT_ZAlloc(sizeof(data->len) + 
  502. SSMSTRING_PADDED_LENGTH(data->len));
  503.  if (!result) 
  504. goto loser;
  505.  memcpy((char *)(&(result->m_data)), data->data, data->len);
  506.  result->m_length = data->len;
  507.  *ssmstring = result;
  508.  return PR_SUCCESS;
  509. loser:
  510.  if (result) 
  511.      PR_Free(result);
  512.  return PR_FAILURE;
  513. }
  514. SSMStatus
  515. SSM_CopyCMTItem(CMTItem * dest, CMTItem * source)
  516. {
  517.     SSMStatus rv = SSM_FAILURE;
  518.     
  519.     if (!dest || !source) 
  520.         goto loser;
  521.     
  522.     dest->len = source->len;
  523.     if (!dest->len) 
  524.         goto done;
  525.     
  526.     dest->data = (unsigned char *) PR_Malloc(dest->len);
  527.     if (!dest->data) 
  528.         goto loser;
  529.     memcpy(dest->data, source->data, dest->len);
  530.  done: 
  531.     rv = SSM_SUCCESS;
  532.  loser:
  533.     return rv;
  534. }
  535. PRFileDesc * SSM_OpenControlPort(void)
  536. {
  537.     PRFileDesc * datasocket          = NULL;
  538.     PRNetAddr servaddr;
  539.     SSMStatus status;
  540.     PRSocketOptionData sockOpData;
  541. #ifdef XP_UNIX
  542.     char lock_name_buf[32];
  543. #endif
  544.     /* disable Nagle algorithm delay for control sockets */
  545.     sockOpData.option = PR_SockOpt_NoDelay;
  546.     sockOpData.value.no_delay = PR_TRUE;
  547. #ifdef XP_UNIX
  548.     GET_LOCK_FILE_PATH(lock_name_buf);
  549.     lockfile = PR_Open(lock_name_buf, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
  550.        0600);
  551.     if (!lockfile)
  552. goto loser;
  553.     status = PR_TLockFile(lockfile);
  554.     if (status != PR_SUCCESS)
  555. goto loser;
  556.     datasocket = PR_Socket(AF_UNIX, SOCK_STREAM, 0);
  557.     if (!datasocket)
  558.         goto loser;
  559.     servaddr.local.family = AF_UNIX;
  560.     GET_CONTROL_SOCK_PATH(servaddr.local.path);
  561.     PR_Delete(servaddr.local.path);
  562. #else
  563.     datasocket = PR_NewTCPSocket();
  564.     if (!datasocket)
  565.         goto loser;
  566.     status = PR_SetSocketOption(datasocket, &sockOpData);
  567.     if (status != PR_SUCCESS) {
  568.         goto loser;
  569.     }
  570.     /* Bind to PSM port on loopback address: connections from non-localhosts
  571.      * will be disallowed
  572.      */
  573.     status = PR_InitializeNetAddr(PR_IpAddrLoopback, (PRUint16) PSM_PORT,
  574.   &servaddr);
  575.     if (status != PR_SUCCESS)
  576.         goto loser;
  577. #endif
  578.     status = PR_Bind(datasocket, &servaddr);
  579.     if (status != PR_SUCCESS)
  580.         goto loser;
  581.     status = PR_Listen(datasocket, MAX_CONNECTIONS);
  582.     if (status != PR_SUCCESS)
  583.         goto loser;
  584. #ifdef XP_UNIX  
  585.     SSM_DEBUG("Ready for client connection on port %s.n", servaddr.local.path);
  586. #else
  587.     SSM_DEBUG("Ready for client connection on port %d.n", PSM_PORT);
  588. #endif
  589.     return datasocket;
  590.  loser:
  591.     return NULL;
  592. }
  593. /* Make sure that the peer is on the same machine that we are */
  594. PRBool
  595. SSM_SocketPeerCheck(PRFileDesc *sock, PRBool isCtrl)
  596. {
  597.     PRBool rv = PR_FALSE;
  598.     SSMStatus st = PR_SUCCESS;
  599.     PRNetAddr theirAddr;
  600.     char localaddr[] = {0x7F,0x00,0x00,0x01};/* 127.0.0.1 in network order */
  601. #if defined(XP_UNIX) || defined(XP_MAC)
  602. #ifdef XP_UNIX
  603.     if (isCtrl)
  604.     {
  605.         /* unix domain socket == same machine */
  606.         /* ### mwelch Well, the only time this isn't true is when
  607.            one wants to join many unix machines in a cluster, but 
  608.            even in that case the cluster should be treated as a 
  609.            single machine anyway. */
  610. #endif
  611. /*
  612. GetPeerName isn't implemented on the Mac, so say yes and hope/pray for now 
  613. ### mwelch - Need to implement GetPeerName in Mac NSPR before Mac Cartman RTM 
  614. */
  615.         rv = PR_TRUE;
  616.         goto done;
  617. #ifdef XP_UNIX
  618.     }
  619. #endif
  620. #endif
  621.     st = PR_GetPeerName(sock, &theirAddr);
  622.     if (st != PR_SUCCESS)
  623.         goto done; /* default is to fail */
  624.     /* Compare against localhost IP */
  625.     if (!memcmp(&(theirAddr.inet.ip), localaddr, 4))
  626.         rv = PR_TRUE;
  627.     if (rv != PR_TRUE)
  628.         SSM_DEBUG("Failed IP address check!n");
  629.  done:
  630.     return rv;
  631. }
  632. PRFileDesc * SSM_OpenPort(void)
  633. {
  634.     PRFileDesc * datasocket          = NULL;
  635.     PRNetAddr servaddr;
  636.     SSMStatus status;
  637.     PRSocketOptionData sockOpData;
  638.     /* disable Nagle algorithm delay for data sockets */
  639.     sockOpData.option = PR_SockOpt_NoDelay;
  640.     sockOpData.value.no_delay = PR_TRUE;
  641.     datasocket = PR_NewTCPSocket();
  642.     if (!datasocket)
  643.         goto loser;
  644.     status = PR_SetSocketOption(datasocket, &sockOpData);
  645.     if (status != PR_SUCCESS) {
  646.         goto loser;
  647.     }
  648.     /* Bind to PSM port on loopback address: connections from non-localhosts
  649.      * will be disallowed
  650.      */
  651.     status = PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &servaddr);
  652.     if (status != PR_SUCCESS)
  653.         goto loser;
  654.     status = PR_Bind(datasocket, &servaddr);
  655.     if (status != PR_SUCCESS)
  656.         goto loser;
  657.     status = PR_Listen(datasocket, MAX_CONNECTIONS);
  658.     if (status != PR_SUCCESS)
  659.         goto loser;
  660.   
  661.     return datasocket;
  662.  loser:
  663.     return NULL;
  664. }
  665. #if 0
  666. /* Whee. Base 64 decoding. Have to do it for basic authentication. */
  667. #define XX 127
  668. /*
  669.  * Table for decoding base64. We have this everywhere else, why not here.
  670.  */
  671. static char index64[256] = {
  672.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  673.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  674.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
  675.     52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
  676.     XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
  677.     15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
  678.     XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
  679.     41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
  680.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  681.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  682.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  683.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  684.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  685.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  686.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  687.     XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
  688. };
  689. #ifdef XP_OS2_HACK
  690. /*DSR102196 - the OS/2 Visual Age compiler croaks when it tries*/
  691. /*to optomize this macro (/O+ on CSD4)                         */ 
  692. char CHAR64(int c)
  693. {
  694.    unsigned char index;
  695.    char rc;
  696.    index = (unsigned char) c;
  697.    rc = index64[index];
  698.    return rc;
  699. #else /*normal code...*/
  700. #define CHAR64(c)  (index64[(unsigned char)(c)])
  701. #endif
  702. /* Decode a base 64 string in place. */
  703. void decode_base64_string(char *str)
  704. {
  705.     char *s = str;
  706.     char *d = str;
  707.     char c[4];
  708.     PRIntn i;
  709.     PRBool done = PR_FALSE;
  710.     
  711.     while((!done) && (*s))
  712.     {
  713.         /* Process 4 bytes at a time. */
  714.         for(i=0;i<4;i++)
  715.             c[i] = 0;
  716.         
  717.         for(i=0;i<4;i++)
  718.         {
  719.             if ((IS_WHITESPACE(*s)) || (IS_EOL(*s)))
  720.             {
  721.                 /* End here, because we're out of bytes. */
  722.                 done = PR_TRUE;
  723.             }
  724.             else
  725.                 c[i] = *s++;
  726.         }
  727.         
  728.         /* Make sure we can at least decode one character. */
  729.         if ((!done) && ((c[0] == '=') || (c[1] == '=')))
  730.             done = PR_TRUE; /* don't even have enough for one character, leave */
  731.         
  732.         if (!done)
  733.         {
  734.             /* Decode the first character. */
  735.             c[0] = CHAR64(c[0]);
  736.             c[1] = CHAR64(c[1]);
  737.             *d++ = ((c[0]<<2) | ((c[1] & 0x30)>>4));
  738.             
  739.             /* If we have data for a second character, decode that. */
  740.             if (c[2] != '=')
  741.             {
  742.                 c[2] = CHAR64(c[2]);
  743.                 *d++ = (((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2));
  744.                 
  745.                 /* If we have data for a third character, decode that. */
  746.                 if (c[3] != '=')
  747.                 {
  748.                     c[3] = CHAR64(c[3]);
  749.                     *d++ = (((c[2] & 0x03) << 6) | c[3]);
  750.                 }
  751.                 else
  752.                     done = PR_TRUE;
  753.             }
  754.             else
  755.                 done = PR_TRUE;
  756.         }
  757.     }
  758.     /* Terminate the string. */
  759.     *d = '';
  760. }
  761. #endif
  762. #ifdef DEBUG
  763. char * 
  764. SSM_StandaloneGetPasswdCallback(PK11SlotInfo *slot, PRBool retry, 
  765.                                 void *arg)
  766. {
  767.     char *result = NULL;
  768.     char *env = NULL;
  769.     SECItem theItem = {siBuffer, NULL, 0};
  770.     if (retry)
  771.     {
  772.         /* Don't spin forever, just bail */
  773.         SSM_DEBUG("Static password you provided was not accepted. "
  774.                   "Cancelling request.n");
  775.         return NULL;
  776.     }
  777.     env = PR_GetEnv(SSM_ENV_STATIC_PASSWORD);
  778.     if (!env)
  779.         goto done;
  780.     
  781.     ATOB_ConvertAsciiToItem(&theItem, env);
  782.     if (theItem.data == NULL)
  783.         goto done;
  784.     result = (char *) PR_CALLOC(theItem.len + 1);
  785.     if (!result)
  786.         goto done;
  787.     strncpy(result, (char *) theItem.data, theItem.len);
  788.  done:
  789.     if (theItem.data != NULL)
  790.         SECITEM_FreeItem(&theItem, PR_FALSE);
  791.     if (result)
  792.         SSM_DEBUG("Responding to password request with a password.n");
  793.     else
  794.         SSM_DEBUG("Responding to password callback with NULL password.n");
  795.     return result;
  796. }
  797. PRBool 
  798. SSM_StandaloneVerifyPasswdCallback(PK11SlotInfo * slot, void * arg)
  799. {
  800.     /* yeah, sure, trust me, we're the ones who are sposta be logged in */
  801.     return PR_TRUE; 
  802. }
  803. #endif
  804. SSMStatus
  805. SSM_CloseSocketWithLinger(PRFileDesc *sock)
  806. {
  807.     PRSocketOptionData opt;
  808.     SSMStatus rv = PR_SUCCESS;
  809.     
  810.     /* 
  811.        Set linger for 15 minutes.
  812.        ### mwelch This time should really depend on what has been written
  813.        to the socket. For example, if we've just written 5 megabytes of data
  814.        down a 14.4 wire, we should wait considerably longer than 15 minutes.
  815.        The point here is that there's no way to determine a constant value 
  816.        ahead of time. So, 15 minutes. (Note that generally only client sockets
  817.        are closed in this way, so we hopefully will avoid major trouble.)
  818.      */
  819.     opt.option = PR_SockOpt_Linger;
  820.     opt.value.linger.polarity = PR_TRUE;
  821.     opt.value.linger.linger = PR_SecondsToInterval(60*15);
  822.     rv = PR_SetSocketOption(sock, &opt);
  823.     /* Now close the socket. */
  824.     if (rv == PR_SUCCESS)
  825.         rv = PR_Close(sock);
  826.     return rv;
  827. }
  828. char*
  829. SSM_GetCharFromKey(const char *key, const char *locale)
  830. {
  831.     SSMTextGenContext *textGenCxt  = NULL;
  832.     char              *asciiString = NULL;
  833.     SSMStatus           rv;
  834.     rv = SSMTextGen_NewContext(NULL, NULL, NULL, NULL, &textGenCxt);
  835.     if (rv != PR_SUCCESS) {
  836.         goto loser;
  837.     }
  838.     rv = SSM_FindUTF8StringInBundles(textGenCxt, key,
  839.                                      &asciiString);
  840.     if (rv != PR_SUCCESS) {
  841.         goto loser;
  842.     }
  843.     SSMTextGen_DestroyContext(textGenCxt);
  844.     return asciiString;
  845.  loser:
  846.     if (textGenCxt != NULL) {
  847.         SSMTextGen_DestroyContext(textGenCxt);
  848.     }
  849.     if (asciiString != NULL) {
  850.         PR_Free(asciiString);
  851.     }
  852.     return NULL;
  853. }
  854. SSMStatus SSM_RequestFilePathFromUser(SSMResource *res,
  855.                                       const char  *promptKey,
  856.                                       const char  *fileRegEx,
  857.                                       PRBool       getExistingFile)
  858. {
  859.     SECItem           *filePathRequest = NULL;
  860.     char              *asciiPrompt     = NULL;
  861.     SSMStatus          rv;
  862.     FilePathRequest    request;
  863.     filePathRequest = SSM_ZNEW(SECItem);
  864.     if (filePathRequest == NULL) {
  865.         return SSM_FAILURE;
  866.     }
  867.     asciiPrompt = SSM_GetCharFromKey(promptKey, "ISO_8859-1");
  868.     if (asciiPrompt == NULL) {
  869.         goto loser;
  870.     }
  871.     request.resID = res->m_id;
  872.     request.prompt = asciiPrompt;
  873.     request.getExistingFile = (CMBool) getExistingFile;
  874.     request.fileRegEx = fileRegEx;
  875.     if (CMT_EncodeMessage(FilePathRequestTemplate, (CMTItem*)filePathRequest, (void*)&request) != CMTSuccess) {
  876.         goto loser;
  877.     }
  878.     filePathRequest->type = (SECItemType) (SSM_EVENT_MESSAGE | SSM_FILE_PATH_EVENT);
  879.     SSM_LockResource(res);
  880.     rv = SSM_SendQMessage(res->m_connection->m_controlOutQ,
  881.                           20,
  882.                           filePathRequest->type,
  883.                           filePathRequest->len,
  884.                           (char*)filePathRequest->data,
  885.                           PR_TRUE);
  886.     SECITEM_FreeItem(filePathRequest, PR_TRUE);
  887.     SSM_WaitResource(res, PR_INTERVAL_NO_TIMEOUT);
  888.     SSM_UnlockResource(res);
  889.     return (res->m_fileName == NULL) ? SSM_FAILURE : SSM_SUCCESS;
  890.     
  891.  loser:
  892.     if (filePathRequest != NULL) {
  893.         SECITEM_FreeItem(filePathRequest, PR_TRUE);
  894.     }
  895.     return SSM_FAILURE;
  896. }
  897. void SSM_HandleFilePathReply(SSMControlConnection *ctrl, 
  898.                              SECItem              *message)
  899. {
  900.   SSMStatus rv;
  901.   SSMResource  *res;
  902.   FilePathReply reply;
  903.   if (CMT_DecodeMessage(FilePathReplyTemplate, &reply, (CMTItem*)message) != CMTSuccess) {
  904.       return;
  905.   }
  906.   rv = SSMControlConnection_GetResource(ctrl, reply.resID, &res);
  907.   if (rv != PR_SUCCESS || res == NULL) {
  908.       return;
  909.   }
  910.   if (reply.filePath != NULL) {
  911.     if (reply.filePath[0] == '') {
  912.       res->m_fileName = NULL;
  913.     } else {
  914.       res->m_fileName = PL_strdup(reply.filePath);
  915.     }
  916.     PR_Free(reply.filePath);
  917.   } else {
  918.     res->m_fileName = NULL;
  919.     res->m_buttonType = SSM_BUTTON_CANCEL;
  920.   }
  921.   SSM_LockResource(res);
  922.   SSM_NotifyResource(res);
  923.   SSM_UnlockResource(res);
  924.   SSM_FreeResource(res);
  925. }
  926. void SSM_HandleUserPromptReply(SSMControlConnection *ctrl,
  927.                                SECItem              *msg)
  928. {
  929.     SSMStatus rv;
  930.     SSMResource *res;
  931.     PromptReply reply;
  932.     if (CMT_DecodeMessage(PromptReplyTemplate, &reply, (CMTItem*)msg) != CMTSuccess) {
  933.         return;
  934.     }
  935.     rv = SSMControlConnection_GetResource(ctrl, reply.resID, &res);
  936.     if (rv != PR_SUCCESS || res == NULL)  {
  937.         return;
  938.     }
  939.     /* XXX sjlee: if the password length was zero, it would have been 
  940.      * translated as a null pointer through transport.  We need to restore it 
  941.      * to an empty string.  We can do that by looking up the cancel value of 
  942.      * the reply.
  943.      */
  944.     if ((reply.promptReply == NULL) && !reply.cancel) {
  945.         reply.promptReply = "";
  946.     }
  947.     SSM_HandlePromptReply(res, reply.promptReply);
  948. }
  949. #ifdef TIMEBOMB
  950. SECItem * SSMTimebomb_GetMessage(SSMControlConnection * control)
  951. {
  952.   SECItem * message = NULL;
  953.   PRInt32 read, type, len;
  954.   char * buffer = NULL;
  955.   SSMStatus rv = PR_FAILURE;
  956.  
  957.   buffer = (char *)PORT_ZAlloc(sizeof(type)+ sizeof(len));
  958.   if (!buffer)
  959.     goto loser;
  960.   SSM_DEBUG("waiting for new message from socket.n");
  961.   read = SSM_ReadThisMany(control->m_socket,(void *)buffer,sizeof(type)+sizeof(len));
  962.   if (read != sizeof(type)+sizeof(len))
  963.     {
  964.      SSM_DEBUG("Bytes read (%ld) != bytes expected (%ld). (hdr)n",
  965.                (long) read,
  966.                (long) (sizeof(type)+sizeof(len)));
  967.      rv = PR_FAILURE;
  968.      goto loser;
  969.     }
  970.   message = SSM_ConstructMessage(PR_ntohl(((unsigned long *)buffer)[1]));
  971.   if (!message || !message->data)
  972.     {
  973.       SSM_DEBUG("Missing %s.n",(!message) ? "message" : "message data");
  974.       rv = PR_OUT_OF_MEMORY_ERROR;
  975.       goto loser;
  976.     }
  977.   message->type = PR_ntohl(((unsigned long *)buffer)[0]);
  978.   SSM_DEBUG("reading %ld more from socket.n", message->len);
  979.   read = SSM_ReadThisMany(control->m_socket, (void *)message->data, message->len);
  980.   if ((unsigned int) read != message->len)
  981.     {
  982.      SSM_DEBUG("Bytes read (%ld) != bytes expected (%ld). (msg)n",
  983.                            (long) read,
  984.                            (long) message->len);
  985.      rv = PR_GetError();
  986.      if (rv == PR_SUCCESS) rv = PR_FAILURE;
  987.      goto loser;
  988.    }
  989.   if (buffer) 
  990.     PR_Free(buffer);
  991.   return message;
  992. loser:
  993.   if (buffer)
  994.     PR_Free(buffer);
  995.   return NULL;
  996. }
  997. SSMStatus SSMTimebomb_SendMessage(SSMControlConnection * control, 
  998.                                  SECItem * message)
  999. {
  1000.   PRInt32 tmp, sent;
  1001.   if (!message)
  1002.     goto loser;
  1003.   /* now send message.
  1004.    * I want to do it here to keep timebomb code close together -jane */
  1005.   tmp = PR_htonl(message->type);
  1006.   sent =  SSM_WriteThisMany(control->m_socket, &tmp, sizeof(tmp));
  1007.   if (sent != sizeof(tmp))
  1008.     goto loser;
  1009.   tmp = PR_htonl(message->len);
  1010.   sent =  SSM_WriteThisMany(control->m_socket, &tmp, sizeof(tmp));
  1011.   if (sent != sizeof(tmp))
  1012.     goto loser;
  1013.   sent = SSM_WriteThisMany(control->m_socket, message->data, message->len);
  1014.   if (sent != message->len)
  1015.     goto loser;
  1016.   return SSM_SUCCESS;
  1017. loser: 
  1018.   SSM_DEBUG("timebomb: can't send error message!n");
  1019.   return SSM_FAILURE;
  1020. }
  1021. #endif
  1022. void SSM_DestroyAttrValue(SSMAttributeValue *value, PRBool freeit)
  1023. {
  1024.     if ((value->type == SSM_STRING_ATTRIBUTE) && (value->u.string.data))
  1025.         PR_Free(value->u.string.data);
  1026.     value->type = (SSMResourceAttrType) 0;
  1027.     if (freeit)
  1028.         PR_Free(value);
  1029. }
  1030. CMTStatus SSM_SSMStringToString(char ** string,
  1031.        int *len, 
  1032.        SSMString * ssmString) 
  1033. {
  1034.   char * str = NULL;
  1035.   int realLen;
  1036.   CMTStatus rv = CMTSuccess;
  1037.   if (!ssmString || !string ) { 
  1038.     rv = (CMTStatus) PR_INVALID_ARGUMENT_ERROR;
  1039.     goto loser;
  1040.   }
  1041.   /* in case we fail */
  1042.   *string = NULL;
  1043.   if (len) *len = 0;
  1044.   /* Convert from net byte order */
  1045.   realLen = SSMPR_ntohl(ssmString->m_length);
  1046.   str = (char *)PR_CALLOC(realLen+1); /* add 1 byte for end 0 */
  1047.   if (!str) {
  1048.     rv = (CMTStatus) PR_OUT_OF_MEMORY_ERROR;
  1049.     goto loser;
  1050.   }
  1051.   
  1052.   memcpy(str, (char *) &(ssmString->m_data), realLen);
  1053.   /* str[realLen]=0; */
  1054.   if (len) *len = realLen;
  1055.   *string = str;
  1056.   return rv;
  1057.   
  1058. loser:
  1059.   if (str) 
  1060.     PR_Free(str);
  1061.   if (string && *string) {
  1062.     PR_Free(*string);
  1063.     *string = NULL;
  1064.   }
  1065.   if (rv == CMTSuccess) 
  1066.     rv = CMTFailure;
  1067.   return rv;
  1068. }
  1069. CMTStatus SSM_StringToSSMString(SSMString ** ssmString, int length, 
  1070.   char * string)
  1071. {
  1072.   SSMPRUint32 len;
  1073.   SSMString *result = NULL;
  1074.   CMTStatus rv = CMTSuccess;
  1075.   
  1076.   if (!string || !ssmString) {
  1077.     rv = (CMTStatus) PR_INVALID_ARGUMENT_ERROR;
  1078.     goto loser;
  1079.   }
  1080.   *ssmString = NULL; /* in case we fail */
  1081.   if (length) len = length; 
  1082.   else len = strlen(string);
  1083.   if (len <= 0) {
  1084.     rv = (CMTStatus) PR_INVALID_ARGUMENT_ERROR;
  1085.     goto loser;
  1086.   }
  1087.   result = (SSMString *) PR_CALLOC(sizeof(PRUint32) + 
  1088.    SSMSTRING_PADDED_LENGTH(len));
  1089.   if (!result) {
  1090.     rv = (CMTStatus) PR_OUT_OF_MEMORY_ERROR;
  1091.     goto loser;
  1092.   }
  1093.   result->m_length = SSMPR_htonl(len);
  1094.   memcpy((char *) (&(result->m_data)), string, len);
  1095.   *ssmString = result;
  1096.   goto done;
  1097.   
  1098. loser:
  1099.   if (result)
  1100.     PR_Free(result);
  1101.   *ssmString = NULL;
  1102.   if (rv == CMTSuccess)
  1103.     rv = CMTFailure;
  1104. done:
  1105.   return rv;
  1106. }
  1107. #ifdef XP_UNIX
  1108. void SSM_ReleaseLockFile()
  1109. {
  1110.   if (lockfile) {
  1111.     char filePath[64];
  1112.     
  1113.     GET_LOCK_FILE_PATH(filePath);
  1114.     SSM_DEBUG("Releasing and deleting the file %sn", filePath);
  1115.     PR_UnlockFile(lockfile);
  1116.     PR_Close(lockfile);
  1117.     lockfile = NULL;
  1118.     PR_Delete(filePath);
  1119.     GET_CONTROL_SOCK_PATH(filePath);
  1120.     SSM_DEBUG("Deleting %s. (The control connection socket)n", filePath);
  1121.     PR_Delete(filePath);
  1122.   }
  1123. }
  1124. #endif
  1125. int SSM_strncasecmp(const char *s1, const char *s2, size_t count)
  1126. {
  1127.     char *myS1 = NULL, *myS2 = NULL;
  1128.     int rv, len, i;
  1129.     myS1 = strdup(s1);
  1130.     myS2 = strdup(s2);
  1131.     len = strlen(myS1);
  1132.     for (i=0;i<len;i++) {
  1133.         myS1[i] = tolower(myS1[i]);
  1134.     }
  1135.     len = strlen(myS2);
  1136.     for (i=0;i<len;i++) {
  1137.         myS2[i] = tolower(myS2[i]);
  1138.     }
  1139.     rv = strncmp(myS1,myS2,count);
  1140.     free(myS1);
  1141.     free(myS2);
  1142.     return rv;
  1143. }