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

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 "ctrlconn.h"
  35. #include "dataconn.h"
  36. #include "sslconn.h"
  37. #include "p7cinfo.h"
  38. #include "p7econn.h"
  39. #include "p7dconn.h"
  40. #include "secmime.h"
  41. #include "hashconn.h"
  42. #include "certres.h"
  43. #include "cert.h"
  44. #include "certdb.h"
  45. #include "cdbhdl.h"
  46. #include "servimpl.h"
  47. #include "newproto.h"
  48. #include "messages.h"
  49. #include "serv.h"
  50. #include "ssmerrs.h"
  51. #include "minihttp.h"
  52. #include "secmod.h"
  53. #include "kgenctxt.h"
  54. #include "advisor.h"
  55. #include "processmsg.h"
  56. #include "signtextres.h"
  57. #include "p12res.h"
  58. #include "p12plcy.h"
  59. #include "secmime.h"
  60. #include "ciferfam.h"
  61. #include "profile.h"
  62. #include "prefs.h"
  63. #include "ocsp.h"
  64. #include "msgthread.h"
  65. #ifdef XP_MAC
  66. #include "macshell.h"
  67. #endif
  68. /*
  69.  * The structure passed to get an attribute for the control connection,
  70.  * which may require a password prompt.
  71.  */
  72. typedef struct GetAttrArgStr {
  73.     SSMResource *res;
  74.     SSMAttributeID attrID;
  75.     SSMResourceAttrType attrType;
  76. } GetAttrArg;
  77. static SSMStatus
  78. ssmcontrolconnection_encodegetattr_reply(SECItem *msg, SSMStatus rv, 
  79.                                          SSMAttributeValue *value,
  80.                                          SSMResourceAttrType attrType);
  81. /* The ONLY reason why we can use these macros for both control and
  82.    data connections is that they inherit from the same superclass.
  83.    Do NOT try this at home. */
  84. #define SSMCONNECTION(c) (&(c)->super)
  85. #define SSMRESOURCE(c) (&(c)->super.super)
  86. /* Special resource id values */
  87. #define SSM_BASE_RID  0x00000003
  88. #define SSM_MAX_RID   0x0FFFFFFF
  89. static long ssm_ctrl_count = 0;
  90. static SSMResourceID ssm_next_ctrlrid = SSM_MAX_RID;
  91. static char * gUserDir = NULL;
  92. static PRMonitor *policySetLock = NULL;
  93. static PRBool policySet = PR_FALSE;
  94. SSMStatus SSM_InitPolicyHandler(void)
  95. {
  96.     policySetLock = PR_NewMonitor();
  97.     if (policySetLock == NULL) {
  98.         return PR_FAILURE;
  99.     }
  100.     return PR_SUCCESS;
  101. }
  102. #ifdef TIMEBOMB
  103. #include "timebomb.h"
  104. PRBool SSMTimeBombExpired = PR_FALSE;
  105. #endif
  106. SSMStatus SSMControlConnection_Create(void *arg, 
  107.                                      SSMControlConnection * connection, 
  108.                                      SSMResource **res)
  109. {
  110.     SSMStatus rv = PR_SUCCESS;
  111.     SSMControlConnection *conn;
  112.     *res = NULL; /* in case we fail */
  113.     
  114.     conn = (SSMControlConnection *) PR_CALLOC(sizeof(SSMControlConnection));
  115.     if (!conn) goto loser;
  116.     
  117.     SSMRESOURCE(conn)->m_connection = conn;
  118.     rv = SSMControlConnection_Init(conn, SSM_RESTYPE_CONTROL_CONNECTION, 
  119.                                    (PRFileDesc *) arg);
  120.     if (rv != PR_SUCCESS) 
  121.         goto loser;
  122.    
  123.     SSMControlConnection_Invariant(conn);
  124.     ssm_ctrl_count++;
  125.     SSM_DEBUG("Control count is now %ld.n", ssm_ctrl_count);
  126.     *res = SSMRESOURCE(conn);
  127.     rv = SSM_HashInsert(ctrlConnections, (SSMHashKey)(*res)->m_id, 
  128.                         (void *)*res);
  129.     if (rv != PR_SUCCESS) 
  130.         goto loser;
  131.     return PR_SUCCESS;
  132.  loser:
  133.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  134.     if (conn) 
  135.     {
  136.         SSM_ShutdownResource(SSMRESOURCE(conn), rv); /* force destroy */
  137.         SSM_FreeResource(SSMRESOURCE(conn));
  138.     }
  139.        
  140.     return rv;
  141. }
  142. #ifdef XP_MAC
  143. int
  144. toascii(char c)
  145. {
  146. return (int) c;
  147. }
  148. #endif
  149. SSMStatus SSMControlConnection_GenerateNonce(SSMControlConnection *conn)
  150. {
  151.     SSMStatus rv = PR_FAILURE;
  152.     SECStatus srv;
  153.     char* buf = NULL;
  154.     char* n = NULL;
  155.     const int NONCE_SIZE = 8;
  156.     int i;
  157.     conn->m_nonce = NULL; /* in case of failure */
  158.     buf = (char*)PR_CALLOC(NONCE_SIZE);
  159.     if (buf == NULL) {
  160.         goto loser;
  161.     }
  162.     srv = RNG_GenerateGlobalRandomBytes(buf, NONCE_SIZE);
  163.     if (srv != SECSuccess) {
  164.         goto loser;
  165.     }
  166.     n = PL_strdup("nonce");
  167.     for (i = 0; i < NONCE_SIZE; i++) {
  168.         n = PR_sprintf_append(n, "%d", (int)toascii(buf[i]));
  169.         if (n == NULL) {
  170.             goto loser;
  171.         }
  172.     }
  173.     conn->m_nonce = n;
  174.     rv = PR_SUCCESS;
  175. loser:
  176.     if (buf != NULL) {
  177.         PR_Free(buf);
  178.     }
  179.     return rv;
  180. }
  181. SSMStatus SSMControlConnection_Init(SSMControlConnection *conn, 
  182.                                    SSMResourceType type,
  183.                                    PRFileDesc *socket)
  184. {
  185.     SSMStatus rv = PR_SUCCESS;
  186.     PRBool locked = PR_FALSE;
  187.     PRNetAddr dataAddr;
  188.     rv = SSM_HashCreate(&conn->m_resourceDB);
  189.     if (rv != PR_SUCCESS || !conn->m_resourceDB) 
  190.         goto loser;
  191.     /* We need to see if there are any other control connections already
  192.      * established.  If there are, then we need to use the next RID 
  193.      * as ours so the correct control connection is found for UI events.
  194.      * Before all control connections would get the RID of 3, and that would
  195.      * cause problems.
  196.      */
  197.     conn->m_lastRID = ssm_next_ctrlrid;
  198.     conn->m_secAdvisorList = NULL;
  199.     rv = SSM_HashCreate(&conn->m_resourceIdDB);
  200.     if (rv != PR_SUCCESS || conn->m_resourceIdDB == NULL)
  201.         goto loser;
  202.     rv = SSMConnection_Init(NULL, &conn->super, type);
  203.     if (rv != PR_SUCCESS) goto loser;
  204.     ssm_next_ctrlrid = conn->super.super.m_id;
  205.     SSM_LockResource(SSMRESOURCE(conn));
  206.     locked = PR_TRUE;
  207.     /* Current version. Allow this to drop when the Hello request comes in. */
  208.     conn->m_version = SSM_PROTOCOL_VERSION;
  209.     /* Generate a nonce. */
  210.     rv = SSMControlConnection_GenerateNonce(conn);
  211.     if (rv != PR_SUCCESS) goto loser;
  212.     SSM_DEBUG("Generated nonce of `%s'.n",conn->m_nonce);
  213.     conn->m_controlOutQ = SSM_NewCollection();
  214.     if (!conn->m_controlOutQ) 
  215.         goto loser;
  216.     conn->m_socket = socket;
  217.     /* Create the data socket */
  218.     conn->m_dataSocket = SSM_OpenPort();
  219.     if (!conn->m_dataSocket) {
  220.         goto loser;
  221.     }
  222.     /* Get the data port */
  223.     rv = PR_GetSockName(conn->m_dataSocket, &dataAddr);
  224.     if (rv != PR_SUCCESS) {
  225.         goto loser;
  226.     }
  227.     conn->m_dataPort = PR_ntohs(dataAddr.inet.port);
  228.     SSMCONNECTION(conn)->m_auth_func = SSMControlConnection_Authenticate;
  229.     
  230.     /* Creat password handling stuff:temporary and long-term password tables */
  231.     rv = SSM_HashCreate(&conn->m_passwdTable);
  232.     if (rv != PR_SUCCESS || !conn->m_passwdTable) 
  233.         goto loser;
  234.     conn->m_passwdLock = PR_NewMonitor();
  235.     if (!conn->m_passwdLock) 
  236.         goto loser;
  237.     conn->m_waiting = 0;
  238.     rv = SSM_HashCreate(&conn->m_encrPasswdTable);
  239.     if (rv != PR_SUCCESS || !conn->m_encrPasswdTable)
  240.         goto loser;
  241.     conn->m_encrPasswdLock = PR_NewMonitor();
  242.     if (!conn->m_encrPasswdLock)
  243.         goto loser;
  244.     /* database for cert look-up by cert ID */
  245.     rv = SSM_HashCreate(&conn->m_certIdDB);
  246.     if (rv != PR_SUCCESS || !conn->m_certIdDB)
  247.         goto loser;
  248.     conn->m_prefs = PREF_NewPrefs();
  249.     if (conn->m_prefs == NULL) {
  250.         goto loser;
  251.     }
  252.     conn->m_doesUI = PR_FALSE;
  253.     /* Spin threads after we set the shutdown function. */
  254.     SSM_DEBUG("spawning read msg thread for %lx.n", (long) conn);
  255. #ifdef ALLOW_STANDALONE
  256.     if (!standalone)
  257.     {
  258. #endif
  259.         /* Get reference for front end thread */
  260.         SSM_GetResourceReference(SSMRESOURCE(conn));
  261.         conn->m_frontEndThread = SSM_CreateThread(SSMRESOURCE(conn),
  262.                                                   SSM_FrontEndThread);
  263.         if (conn->m_frontEndThread == NULL) 
  264.             goto loser;
  265. #ifdef ALLOW_STANDALONE
  266.     }
  267. #endif
  268.     SSM_UnlockResource(SSMRESOURCE(conn));
  269.     return PR_SUCCESS;
  270.  loser:
  271.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  272.     if (locked)
  273.         SSM_UnlockResource(SSMRESOURCE(conn));
  274.     if (socket)
  275.     {
  276.         PR_Close(socket); /* close this */
  277.         conn->m_socket = NULL;
  278.     }
  279.     if (conn->m_passwdLock) 
  280.         PR_DestroyMonitor(conn->m_passwdLock);
  281.     if (conn->m_passwdTable) 
  282.         SSM_HashDestroy(conn->m_passwdTable);
  283.     if (conn->m_encrPasswdLock) 
  284.         PR_DestroyMonitor(conn->m_encrPasswdLock);
  285.     if (conn->m_encrPasswdTable) 
  286.         SSM_HashDestroy(conn->m_encrPasswdTable);
  287.     if (conn->m_certIdDB) 
  288.         SSM_HashDestroy(conn->m_certIdDB);
  289.     if (conn->m_prefs)
  290.         PREF_ClosePrefs(conn->m_prefs);
  291.     if (conn->m_resourceDB) 
  292.         SSM_HashDestroy(conn->m_resourceDB);
  293.     if (conn->m_resourceIdDB)
  294.         SSM_HashDestroy(conn->m_resourceIdDB);
  295.  
  296.     return rv;
  297. }
  298. SSMStatus SSMControlConnection_Shutdown(SSMResource *arg, SSMStatus status)
  299. {
  300.     SSMStatus rv, trv; /* rv propagates superclass shutdown */
  301.     PRThread *closer = PR_GetCurrentThread();
  302.     SSMControlConnection *conn = (SSMControlConnection *) arg;
  303.     SSMControlConnection_Invariant(conn);
  304.  
  305. #ifdef TIMEBOMB
  306.     if (SSMTimeBombExpired)
  307.       return;
  308. #endif
  309.     SSM_LockResource(arg);
  310.     
  311.     /* if the thread calling this routine is a service thread,
  312.        clear its place in the connection object. this is a
  313.        prelude to the wakeup call just below. */
  314.     arg->m_threadCount--; /* decrement if service thread */
  315.     if (closer == conn->m_writeThread)
  316.         conn->m_writeThread = NULL;
  317.     if (closer == conn->m_frontEndThread)
  318.         conn->m_frontEndThread = NULL;
  319.     else
  320.         arg->m_threadCount++; /* not a service thread, restore thread count */
  321.     /* shut down our base class. */
  322.     rv = SSMConnection_Shutdown(arg, status);
  323.     /* wake up threads if this is the first time throwing an error */
  324.     if ((arg->m_status != PR_SUCCESS) &&
  325.         (rv != SSM_ERR_ALREADY_SHUT_DOWN))
  326.     {
  327. SSM_DEBUG("First time aborting control connection.n");
  328. SSM_DEBUG("Posting shutdown msgs to queues.n");
  329.         /* close queues that our threads may be listening on */
  330.         if (conn->m_controlOutQ)
  331.             SSM_SendQMessage(conn->m_controlOutQ, 
  332.                                   SSM_PRIORITY_SHUTDOWN,
  333.                                   SSM_DATA_PROVIDER_SHUTDOWN,
  334.                                   0, NULL, PR_TRUE);
  335.         if (conn->m_writeThread) PR_Interrupt(conn->m_writeThread);
  336.         if (conn->m_frontEndThread) PR_Interrupt(conn->m_frontEndThread);
  337.     }
  338.     /* If the front end thread is down, close the client socket */
  339.     if ((!conn->m_frontEndThread) && (conn->m_socket))
  340.     {
  341.         /* Got a socket but nothing to work on it with. Close the socket. */
  342. #ifndef XP_UNIX
  343. /* Don't close socket with linger on UNIX since the
  344.  * control socket on UNIX is a UNIX domain socket.
  345.  */
  346.         SSM_DEBUG("Closing control socket with linger.n");
  347.         trv = SSM_CloseSocketWithLinger(conn->m_socket);
  348. #else
  349. SSM_DEBUG("Closing control socket.n");
  350. trv = PR_Close(conn->m_socket);
  351. #endif
  352.         PR_ASSERT(trv == PR_SUCCESS);
  353.         conn->m_socket = NULL; /* don't try closing more than once */
  354.         SSM_DEBUG("Closed control socket (rv == %d).n",rv);
  355.     }
  356. if (SSMRESOURCE(conn)->m_threadCount == 0)
  357. {
  358. /* All service threads are down. Shut down NSS. */
  359. ssm_ShutdownNSS(conn);
  360. }
  361.     SSM_UnlockResource(arg);
  362.     return rv;
  363. }
  364. SSMStatus SSMControlConnection_Destroy(SSMResource *res, 
  365.                                       PRBool doFree)
  366. {
  367.     SSMControlConnection *conn = (SSMControlConnection *) res;
  368.     void *value;
  369.     /* Drain and destroy the queue. */
  370.     if (conn->m_controlOutQ)
  371.         ssm_DrainAndDestroyQueue(&(conn->m_controlOutQ));
  372.     /* Free our fields. */
  373.     PR_FREEIF(conn->m_nonce);
  374.     PR_FREEIF(conn->m_profileName);
  375.     PR_FREEIF(conn->m_dirRoot);
  376.     PR_DestroyMonitor(conn->m_passwdLock);
  377.     PR_DestroyMonitor(conn->m_encrPasswdLock);
  378.     SSM_HashDestroy(conn->m_passwdTable);
  379.     SSM_HashDestroy(conn->m_encrPasswdTable);
  380.     PREF_ClosePrefs(conn->m_prefs);
  381.     
  382.     /* log out all pk11 slots for now */
  383.     if (conn->m_pkcs11Init) {
  384.         PK11_LogoutAll();
  385.     }
  386.     if (conn->m_secAdvisorList)
  387.       SECITEM_ZfreeItem(conn->m_secAdvisorList, PR_TRUE);
  388.     /* Destroy superclass fields. */
  389.     SSMConnection_Destroy(SSMRESOURCE(conn), PR_FALSE);
  390.     SSM_HashRemove(ctrlConnections, 
  391.                    (SSMHashKey)(conn->super.super.m_id), &value);
  392.                                 
  393.     /* If this is the last control connection, quit. */
  394.     --ssm_ctrl_count;
  395.     SSM_DEBUG("Control count is now %ld.n", ssm_ctrl_count);
  396.     if ((ssm_ctrl_count <= 0)
  397. #ifdef DEBUG
  398.         && (PR_GetEnv("NSM_SUPPRESS_EXIT") == NULL)
  399. #endif
  400.         )
  401.     {
  402.         SSM_DEBUG("Last control connection gone, quitting.n");
  403. #ifdef XP_UNIX
  404. SSM_ReleaseLockFile();
  405. #endif
  406. #ifdef XP_MAC
  407. SetQuitFlag(PR_TRUE); // tell primordial thread to quit
  408. #else
  409.         exit(0);
  410. #endif
  411.     }
  412.     /* Free the connection object if asked. */
  413.     if (doFree)
  414.         PR_DELETE(conn);
  415.     return PR_SUCCESS;
  416. }
  417. SSMStatus SSMControlConnection_GetAttrIDs(SSMResource* res,
  418.  SSMAttributeID** ids, PRIntn* count)
  419. {
  420.     SSMStatus rv;
  421. if (res == NULL || ids == NULL || count == NULL) {
  422. goto loser;
  423. }
  424.     rv = SSMConnection_GetAttrIDs(res, ids, count);
  425.     if (rv != PR_SUCCESS) {
  426.         goto loser;
  427. }
  428.     *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 2)*sizeof(SSMAttributeID));
  429.     if (!*ids) {
  430. goto loser;
  431. }
  432.     (*ids)[*count++] = SSM_FID_DEFAULT_EMAIL_SIGNER_CERT;
  433.     (*ids)[*count++] = SSM_FID_DEFAULT_EMAIL_RECIPIENT_CERT;
  434.     goto done;
  435. loser:
  436.     if (rv == PR_SUCCESS) {
  437. rv = PR_FAILURE;
  438. }
  439. done:
  440.     return rv;
  441. }
  442. static void ssmcontrolconnection_getattr_thread(void* inArg)
  443. {
  444.     GetAttrArg *arg = (GetAttrArg*)inArg;
  445.     SSMResource *res = arg->res;
  446.     SSMAttributeID attrID = arg->attrID;
  447.     SSMResourceAttrType attrType = arg->attrType;
  448.     SSMControlConnection* conn = (SSMControlConnection*)res;
  449.     SSMStatus rv = PR_SUCCESS;
  450.     CERTCertificate *cert = NULL;
  451.     SSMResourceCert *certRes;
  452.     SSMResourceID certID = 0;
  453.     char *certNickname = NULL;
  454.     PRBool locked = PR_FALSE;
  455.     SSMAttributeValue realValue, *value;
  456.     SECItem msg;
  457.     value = &realValue;
  458.     /* see what it is */
  459. #ifdef DEBUG
  460.     SSM_RegisterThread("ctrlconn getattr",NULL);
  461. #endif    
  462.     switch(attrID) {
  463.     case SSM_FID_DEFAULT_EMAIL_SIGNER_CERT:
  464.         SSM_LockResource(SSMRESOURCE(conn));
  465.         locked = PR_TRUE;
  466.         rv = PREF_GetStringPref(conn->m_prefs, "security.default_mail_cert", 
  467.                                 &certNickname);
  468.         if (rv != PR_SUCCESS) {
  469.             goto loser;
  470.         }
  471.         if (certNickname) {
  472.             cert = CERT_FindUserCertByUsage(conn->m_certdb,
  473.                                             certNickname,
  474.                                             certUsageEmailSigner,
  475.                                             PR_FALSE,
  476.                                             conn);
  477.             if (cert) {
  478.                 SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert, conn,
  479.                                    &certID, (SSMResource**)&certRes);
  480.                 rv = SSM_ClientGetResourceReference(&certRes->super, &certID);
  481.                 SSM_FreeResource(&certRes->super);
  482.                 if (rv != SSM_SUCCESS)
  483.                     goto loser;
  484.             }
  485.         }
  486.         if (cert == NULL)
  487.             goto loser;
  488.         value->u.rid = certID;
  489.         value->type = SSM_RID_ATTRIBUTE;
  490.         SSM_UnlockResource(SSMRESOURCE(conn));
  491.         locked = PR_FALSE;
  492.         break;
  493.     case SSM_FID_DEFAULT_EMAIL_RECIPIENT_CERT:
  494.         SSM_LockResource(SSMRESOURCE(conn));
  495.         locked = PR_TRUE;
  496.         rv = PREF_GetStringPref(conn->m_prefs, "security.default_mail_cert", 
  497.                                 &certNickname);
  498.         if (rv != PR_SUCCESS) {
  499.             goto loser;
  500.         }
  501.         if (certNickname) {
  502.             cert = CERT_FindUserCertByUsage(conn->m_certdb,
  503.                                             certNickname,
  504.                                             certUsageEmailRecipient,
  505.                                             PR_FALSE,
  506.                                             conn);
  507.             if (cert) {
  508.                 SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert, conn,
  509.                                    &certID, (SSMResource**)&certRes);
  510.                 rv = SSM_ClientGetResourceReference(&certRes->super, &certID);
  511.                 SSM_FreeResource(&certRes->super);
  512.                 if (rv != SSM_SUCCESS)
  513.                     goto loser;
  514.             }
  515.         }
  516.         value->u.rid = certID;
  517.         value->type = SSM_RID_ATTRIBUTE;
  518.         SSM_UnlockResource(SSMRESOURCE(conn));
  519.         locked = PR_FALSE;
  520. break;
  521.     default:
  522.         rv = SSMConnection_GetAttr(res, attrID, attrType, value);
  523.         if (rv != PR_SUCCESS) {
  524. goto loser;
  525. }
  526.     }
  527.     if (value->type != attrType) {
  528.         goto loser;
  529.     }
  530.     goto done;
  531. loser:
  532.     value->type = SSM_NO_ATTRIBUTE;
  533.     if (rv == PR_SUCCESS) {
  534. rv = PR_FAILURE;
  535. }
  536. done:
  537.     if (locked) {
  538.         SSM_UnlockResource(SSMRESOURCE(conn));
  539.     }
  540.     rv = ssmcontrolconnection_encodegetattr_reply(&msg, rv, value,
  541.                                                   attrType);
  542.     if (rv != SSM_SUCCESS) {
  543.         rv = ssmcontrolconnection_encode_err_reply(&msg, rv);
  544.         PR_ASSERT(rv == SSM_SUCCESS);
  545.     }
  546.     ssmcontrolconnection_send_message_to_client(conn, &msg);
  547.     PR_FREEIF(msg.data);
  548.     SSM_FreeResource(res);
  549. }
  550. SSMStatus SSMControlConnection_GetAttr(SSMResource *res, SSMAttributeID attrID,
  551.                                        SSMResourceAttrType attrType,
  552.                                        SSMAttributeValue *value)
  553. {
  554.     GetAttrArg *arg = NULL;
  555.     if (res == NULL || value == NULL) {
  556.         goto loser;
  557.     }
  558.     arg = SSM_NEW(GetAttrArg);
  559.     if (arg == NULL) {
  560.         goto loser;
  561.     }
  562.     arg->res = res;
  563.     arg->attrID = attrID;
  564.     arg->attrType = attrType;
  565.     if (SSM_CreateAndRegisterThread(PR_USER_THREAD, ssmcontrolconnection_getattr_thread, 
  566.                         (void *)arg, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  567.                         PR_UNJOINABLE_THREAD, 0) == NULL) {
  568.         goto loser;
  569.     }
  570.     return SSM_ERR_DEFER_RESPONSE;
  571.  loser:
  572.     if (arg != NULL) {
  573.         PR_Free(arg);
  574.     }
  575.     return SSM_FAILURE;
  576. }
  577. void
  578. SSMControlConnection_Invariant(SSMControlConnection *conn)
  579. {
  580.     if (conn)
  581.     {
  582.         SSMConnection_Invariant(SSMCONNECTION(conn));
  583.         SSM_LockResource(SSMRESOURCE(conn));
  584.         PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), SSM_RESTYPE_CONTROL_CONNECTION));
  585.         PR_ASSERT(conn->m_controlOutQ != NULL);
  586.         SSM_UnlockResource(SSMRESOURCE(conn));
  587.     }
  588. }
  589. void SSMControlConnection_RecycleItem(SECItem* msg)
  590. {
  591.     PR_ASSERT(msg != NULL);
  592.     if (msg->data != NULL) {
  593.         cmt_free(msg->data);
  594.         msg->data = NULL;
  595.     }
  596.     return;
  597. }
  598. /*
  599.  * Read msgs from the control connection queue and send them back to client
  600.  */
  601. void SSM_WriteCtrlThread(void * arg)
  602. {
  603.     PRIntn sent, len, type;
  604.     SSMControlConnection * ctrl    = NULL;
  605.     SSMStatus rv= PR_FAILURE;
  606.     char * data;
  607. #ifdef TIMEBOMB
  608.     if (SSMTimeBombExpired)
  609.       return;
  610. #endif 
  611.     ctrl = (SSMControlConnection *)arg;
  612.     SSM_RegisterNewThread("ctrl write", (SSMResource*) arg);
  613.     SSM_DEBUG("initializing.n");
  614.     if (!ctrl)
  615.     {
  616.         rv = (SSMStatus) PR_INVALID_ARGUMENT_ERROR;
  617.         goto loser;
  618.     }
  619.     if (!ctrl->m_socket)     
  620.     {
  621.         rv = (SSMStatus) PR_INVALID_ARGUMENT_ERROR;
  622.         goto loser;
  623.     }
  624.     ctrl->m_writeThread = PR_GetCurrentThread();
  625.     /* wait for SSM_DATA_PROVIDER_OPEN message */
  626.     rv = SSM_RecvQMessage(ctrl->m_controlOutQ, 
  627.                           SSM_PRIORITY_ANY,
  628.                           &type, &len, &data, 
  629.                           PR_TRUE);
  630.     if (rv != PR_SUCCESS || type != SSM_DATA_PROVIDER_OPEN)
  631.         goto loser;
  632.     SSM_DEBUG("got queue open message.n");
  633.   
  634.     /* look for data in the incoming queue and send it to the client */
  635.     while ((SSMRESOURCE(ctrl)->m_status == PR_SUCCESS) && (rv == PR_SUCCESS))
  636.     {
  637.         rv = SSM_RecvQMessage(ctrl->m_controlOutQ, 
  638.                               SSM_PRIORITY_ANY,
  639.                               &type, &len, &data, 
  640.                               PR_TRUE);
  641.         if (rv != PR_SUCCESS)
  642.         {
  643.             SSM_DEBUG("Couldn't read or block on outgoing queue (%d).n",
  644.       rv);
  645.             goto loser;
  646.     }
  647.         switch (type) 
  648.         {
  649.           case SSM_DATA_PROVIDER_SHUTDOWN:
  650.               SSM_DEBUG("got queue close message.n");
  651.               goto loser;
  652.           default:
  653.               {
  654.                   CMTMessageHeader header;
  655.                   /* got a regular control message. send it to the client */
  656.                   SSM_DEBUG("got message for client (type=%lx,len=%ld).n", 
  657.                             type, len);
  658.                   header.type = PR_htonl(type);
  659.                   header.len = PR_htonl(len);
  660.                   /* Send the message header */
  661.                   sent = SSM_WriteThisMany(ctrl->m_socket, &header, sizeof(CMTMessageHeader));
  662.                   if (sent != sizeof(CMTMessageHeader)) {
  663.                       rv = (SSMStatus) PR_GetError();
  664.                       SSM_DEBUG("cannot send message type: %d.n", rv);
  665.                       goto loser;
  666.                   }
  667.                   /* Send the message body */
  668.                   sent = SSM_WriteThisMany(ctrl->m_socket, data, len);
  669.                   if (sent != len) 
  670.                   {
  671.                       rv = (SSMStatus) PR_GetError();
  672.                       SSM_DEBUG("cannot send message data: %d.n", rv);
  673.                     goto loser;
  674.                   }
  675.                   PR_Free(data);
  676.               }
  677.               break;
  678.         }  /* end of switch */
  679.     } /* end of while alive loop */
  680.   
  681.  loser: 
  682.     if (ctrl)
  683.     {
  684.         SSM_DEBUG("Shutting down, rv = %d.n", rv);
  685.         SSM_ShutdownResource(SSMRESOURCE(ctrl), rv);
  686.         SSM_FreeResource(SSMRESOURCE(ctrl));
  687.     }
  688.     return;
  689. }
  690. /* 
  691.  * Check if given cert (arg) already exists in our cert resource db.
  692.  */
  693. void SSMControlConnection_CertLookUp(SSMControlConnection * connection, 
  694.                                      void * arg, SSMResource ** res)
  695. {
  696.     PR_ASSERT(res);
  697.     SSM_HashFind(connection->m_certIdDB, (SSMHashKey) arg, (void **)res);
  698.     if (*res != NULL)
  699.         SSM_GetResourceReference(*res);
  700. }
  701. /* NSS_Init does not open the cert and key db's read/write.  Cartman needs
  702.  * them to be opened read/write in order to do key gen's and import 
  703.  * certificate chains.
  704.  *
  705.  * For now, we pretty much re-create the code of NSS_Init in this file.  If
  706.  * NSS_Init is ever modified so that we can open the db's read/write, then
  707.  * we just call the new function from the function SSM_InitNSS.
  708.  */
  709. static char *
  710. ssm_certdb_name_cb(void *arg, int dbVersion)
  711. {
  712.     const char *configdir = (const char*)arg;
  713.     const char *dbver;
  714.     switch (dbVersion) {
  715.     case 7:
  716.       dbver = "7";
  717.       break;
  718.     case 6:
  719.       dbver = "6";
  720.       break;
  721.     case 5:
  722.       dbver = "5";
  723.       break;
  724.     case 4:
  725.     default:
  726.       dbver = "";
  727.       break;
  728.     }
  729. #ifdef XP_MAC
  730. /* on Mac, :: means parent directory. does non-Mac get // with Seamonkey? */
  731.     if(configdir[PL_strlen(configdir) - 1] == ':') {
  732.      return PR_smprintf("%sCertificates%s", configdir, dbver);
  733.     } else {
  734.      return PR_smprintf("%s:Certificates%s", configdir, dbver);
  735.     }
  736. #else
  737.     return PR_smprintf("%s/cert%s.db", configdir, dbver);
  738. #endif
  739. }
  740. static char *ssm_keydb_name_cb(void *arg, int dbVersion)
  741. {
  742.     const char *configdir = (const char*)arg;
  743.     const char *dbver;
  744.     switch (dbVersion) {
  745.     case 3:
  746.       dbver = "3";
  747.       break;
  748.     case 2:
  749.     default:
  750.       dbver = "";
  751.       break;
  752.     }
  753. #ifdef XP_MAC
  754.     if (configdir[PL_strlen(configdir) - 1] == ':') {
  755.      return PR_smprintf("%sKey Database%s", configdir, dbver);
  756.     } else {
  757.      return PR_smprintf("%s:Key Database%s", configdir, dbver);
  758.     }
  759. #else
  760.     return PR_smprintf("%s/key%s.db", configdir, dbver);
  761. #endif
  762. }
  763. SECStatus
  764. ssm_OpenCertDB(const char * configdir,SSMControlConnection *ctrl)
  765. {
  766.     CERTCertDBHandle *certdb;
  767.     SECStatus         status = SECFailure;
  768. #ifdef ALLOW_STANDALONE
  769.     PRBool readonly = standalone;
  770. #else
  771.     PRBool readonly = PR_FALSE;
  772. #endif
  773.     
  774.     /* We should not be doing this! */
  775.     if (0) {
  776.         certdb = CERT_GetDefaultCertDB();
  777.         if (certdb) {
  778.             return SECSuccess;
  779.         }
  780.     }
  781.     certdb = PORT_ZNew(CERTCertDBHandle);
  782.     if (certdb == NULL) {
  783.         goto loser;
  784.     }
  785.     status = CERT_OpenCertDB(certdb, readonly, ssm_certdb_name_cb, 
  786.      (void*)configdir);
  787.     if (status == SECSuccess) {
  788.         CERT_SetDefaultCertDB(certdb);
  789.         ctrl->m_certdb = certdb;
  790.     } else {
  791.         PR_Free(certdb);
  792. ctrl->m_certdb = NULL;
  793.     }
  794. loser:
  795.     return status;
  796. }
  797. SECStatus
  798. ssm_OpenKeyDB(const char * configdir, SSMControlConnection *ctrl)
  799. {
  800.     SECKEYKeyDBHandle *keydb;
  801. #ifdef ALLOW_STANDALONE
  802.     PRBool readonly = standalone;
  803. #else
  804.     PRBool readonly = PR_FALSE;
  805. #endif
  806.     
  807.     /* we should not be doing this! */
  808.     if (0) { 
  809.         keydb = SECKEY_GetDefaultKeyDB();
  810.         if (keydb) {
  811.             return SECSuccess;
  812.         }
  813.     }
  814.     
  815.     keydb = SECKEY_OpenKeyDB(readonly, ssm_keydb_name_cb, (void*)configdir);
  816.     if (keydb == NULL) {
  817.         ctrl->m_keydb = NULL;
  818.         return SECFailure;
  819.     }
  820.     SECKEY_SetDefaultKeyDB(keydb);
  821.     ctrl->m_keydb = keydb;
  822.     return SECSuccess;
  823. }
  824. SECStatus
  825. ssm_OpenSecModDB(const char * configdir)
  826. {
  827.     static char *secmodname;
  828.     if (secmodname) {
  829.         return SECSuccess;
  830.     }
  831. #ifdef XP_UNIX
  832.     secmodname = PR_smprintf("%s/secmodule.db", configdir);
  833. #elif defined(XP_MAC)
  834.     if (configdir[PL_strlen(configdir) - 1] == ':') {
  835.      secmodname = PR_smprintf("%sSecurity Modules", configdir);
  836.     } else {
  837.      secmodname = PR_smprintf("%s:Security Modules", configdir);
  838.     }
  839. #else
  840.     secmodname = PR_smprintf("%s/secmod.db", configdir);
  841. #endif
  842.     if (secmodname == NULL) {
  843.         return SECFailure;
  844.     }
  845.     SECMOD_init(secmodname);
  846.     return SECSuccess;
  847. }
  848. void
  849. ssm_ShutdownNSS(SSMControlConnection *ctrl)
  850. {
  851.     if (ctrl->m_certdb != NULL) {
  852.         CERT_ClosePermCertDB(ctrl->m_certdb);
  853.     }
  854.     if (ctrl->m_keydb != NULL) {
  855.         SECKEY_CloseKeyDB(ctrl->m_keydb);
  856.     }
  857. }
  858. #if 0
  859. SSMPolicyType
  860. SSM_ConvertSVRPlcyToSSMPolicy(PRInt32 policy)
  861. {
  862.     return ssmDomestic;
  863. }
  864. #endif
  865. void
  866. SSM_SetP12Export(void)
  867. {
  868.     SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
  869.     SEC_PKCS12EnableCipher(PKCS12_RC4_128, 0);
  870.     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
  871.     SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 0);
  872.     SEC_PKCS12EnableCipher(PKCS12_DES_56, 0);
  873.     SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 0);
  874. }
  875. void
  876. SSM_SetSMIMEExport(void)
  877. {
  878.     SECMIME_EnableCipher(SMIME_RC2_CBC_40, 1);
  879. #if 0
  880.     SECMIME_EnableCipher(SMIME_RC2_CBC_64, 0);
  881.     SECMIME_EnableCipher(SMIME_RC2_CBC_128, 0);
  882.     SECMIME_EnableCipher(SMIME_RC5PAD_64_16_40, 1);
  883.     SECMIME_EnableCipher(SMIME_RC5PAD_64_16_64, 0);
  884.     SECMIME_EnableCipher(SMIME_RC5PAD_64_16_128, 0);
  885.     SECMIME_EnableCipher(SMIME_DES_CBC_56, 0);
  886.     SECMIME_EnableCipher(SMIME_DES_EDE3_168, 0);
  887.     SECMIME_EnableCipher(SMIME_FORTEZZA, 0);
  888. #endif
  889.     SECMIME_EnableCipher(CIPHER_FAMILYID_MASK, 0);
  890. }
  891. SECStatus
  892. SSM_InitNSS(char* certpath, SSMControlConnection *ctrl, PRInt32 policy)
  893. {
  894.     SECStatus status;
  895.     SECStatus rv = SECFailure;
  896.     PR_EnterMonitor(policySetLock);
  897.     if (policySet) {
  898.         SSM_DEBUG("We got another hello request. If this is for "
  899.                   "a different user then the first, bad things may happenn");
  900. #if 0
  901.         if (reqPolicy != policyType) {
  902.             SSM_DEBUG("Got a hello request with different policy type "
  903.                       "than has already been established.  "
  904.                       "Refusing connectionn");
  905.             rv = SECFailure;
  906.             goto loser;
  907.         }
  908. #endif
  909.     } 
  910. #if 0
  911.     else if (policyType != reqPolicy) {
  912.         SSM_DEBUG("Initial hello message has different policy type than "
  913.                   "the server.  Setting policy to Exportn");
  914.         NSS_SetExportPolicy();
  915.         SSM_SetP12Export();
  916.         SSM_SetSMIMEExport();
  917.         policyType = ssmExport;
  918.     }
  919. #endif
  920.     SSM_DEBUG("First time initializing NSS.n");
  921.     status = ssm_OpenCertDB(certpath, ctrl);
  922.     if (status != SECSuccess) {
  923.         goto loser;
  924.     }
  925.     status = ssm_OpenKeyDB(certpath, ctrl);
  926.     if (status != SECSuccess) {
  927.         goto loser;
  928.     }
  929.     status = ssm_OpenSecModDB(certpath);
  930.     if (status != SECSuccess) {
  931.         goto loser;
  932.     }
  933.     ctrl->m_pkcs11Init = PR_TRUE;
  934.     rv = SECSuccess;
  935.     PORT_SetUCS2_ASCIIConversionFunction(SSM_UCS2_ASCIIConversion);
  936.     PORT_SetUCS2_UTF8ConversionFunction(SSM_UCS2_UTF8Conversion);
  937.     policySet = PR_TRUE;
  938.     /* set default policy strings */
  939.     CERT_SetCAPolicyStringCallback(SSM_GetCAPolicyString, ctrl);
  940. loser:
  941.     if (rv != SECSuccess) {
  942.         ssm_ShutdownNSS(ctrl);
  943.     }
  944.     PR_ExitMonitor(policySetLock);
  945.     return rv;
  946. }
  947. /* End the section of code shamelessly copied and modified from NSS_Init*/
  948. static int ssm_ask_pref_to_pk11(int asktype)
  949. {
  950.     switch (asktype) {
  951.     case 1:
  952.         return -1;
  953.     case 2:
  954.         return 1;
  955.     }
  956.     return 0;
  957. }
  958. #ifdef XP_MAC
  959. extern OSErr ConvertMacPathToUnixPath(const char *macPath, char **unixPath);
  960. #endif
  961. /* Set up profile and password information. */
  962. SSMStatus
  963. SSMControlConnection_SetupNSS(SSMControlConnection *ctrl, PRInt32 policy)
  964. {
  965.     SSMStatus rv = PR_SUCCESS;
  966.     SECStatus srv = SECSuccess;
  967.     PRFileInfo info;
  968. #ifdef XP_MAC
  969. char *unixPath;
  970. #endif
  971.     /* check the profile directory */
  972. #ifdef XP_UNIX
  973.     /* we expect a non-empty string here: bail if we don't have one */
  974.     if ((PR_GetFileInfo(ctrl->m_dirRoot, &info) != PR_SUCCESS) ||
  975.         (info.type != PR_FILE_DIRECTORY)) {
  976.         SSM_DEBUG("Cannot find a profile in %s.n", ctrl->m_dirRoot);
  977.         goto loser;
  978.     }
  979. #elif defined(XP_MAC)
  980. /* we expect a path that is already Macified. */
  981. ConvertMacPathToUnixPath(ctrl->m_dirRoot, &unixPath);
  982. if (!unixPath)
  983. goto loser;
  984. if (unixPath[0] != '')
  985. {
  986.         /* profile directory was supplied: check to make sure it exists */
  987.         if ((PR_GetFileInfo(unixPath, &info) != PR_SUCCESS) ||
  988.             (info.type != PR_FILE_DIRECTORY)) {
  989.             SSM_DEBUG("Cannot find a profile in %s.n", ctrl->m_dirRoot);
  990.             goto loser;
  991.         }
  992.     }
  993.     else 
  994. goto loser; /* for now */
  995. /* ### mwelch - we're leaking unixPath for now */
  996. #else
  997.     if (ctrl->m_dirRoot[0] != '') {
  998.         /* profile directory was supplied: check to make sure it exists */
  999.         if ((PR_GetFileInfo(ctrl->m_dirRoot, &info) != PR_SUCCESS) ||
  1000.             (info.type != PR_FILE_DIRECTORY)) {
  1001.             SSM_DEBUG("Cannot find a profile in %s.n", ctrl->m_dirRoot);
  1002.             goto loser;
  1003.         }
  1004.     }
  1005.     else {
  1006.         /* profile directory was not supplied: get the "default" directory */
  1007.         if (ctrl->m_profileName[0] == '') {
  1008.             /* this is (almost always) a 3rd party application on win32 that
  1009.              * wants to use a "default" profile
  1010.              * set it to "Default" and hope for the best
  1011.              */
  1012.             ctrl->m_profileName = PL_strdup("Default");
  1013.         }
  1014.         ctrl->m_dirRoot = SSM_PROF_GetProfileDirectory(ctrl);
  1015.         if (ctrl->m_dirRoot == NULL) {
  1016.             goto loser;
  1017.         }
  1018.     }
  1019. #endif
  1020.     /* Do the libsec initialization */
  1021.     
  1022.     if (gUserDir != NULL) {
  1023. #ifndef WIN32
  1024.         if (strcmp(ctrl->m_dirRoot, gUserDir) != 0) {
  1025.             goto loser;
  1026.         }    
  1027. #else 
  1028.         if (STRNCASECMP(ctrl->m_dirRoot, gUserDir, strlen(gUserDir))) {
  1029.             goto loser;
  1030.         }
  1031. #endif  
  1032.         /*
  1033.          * This is the best way to get the current key and cert dbs.
  1034.          * When NSS fully supports multiple profiles, we'll have to do 
  1035.          * away with this call.
  1036.          */
  1037.         ctrl->m_certdb = CERT_GetDefaultCertDB();
  1038.         ctrl->m_keydb  = SECKEY_GetDefaultKeyDB();
  1039.     } else {
  1040.         gUserDir = strdup(ctrl->m_dirRoot);
  1041.         /*
  1042.          * We only want to initialize NSS once.
  1043.          */
  1044.         srv = SSM_InitNSS(ctrl->m_dirRoot, ctrl, policy);
  1045.         if (srv != SECSuccess) {
  1046.             goto loser;
  1047.         }
  1048.     }
  1049. #ifdef ALLOW_STANDALONE
  1050.     if (standalone)
  1051.     {
  1052.         /* Set password callback to be a function which uses a
  1053.            preset password. Very insecure, which is why this is
  1054.            set in debug code only. */
  1055.         PK11_SetPasswordFunc(SSM_StandaloneGetPasswdCallback);
  1056.         PK11_SetVerifyPasswordFunc(SSM_StandaloneVerifyPasswdCallback);
  1057.     }
  1058.     else
  1059.     {
  1060. #endif
  1061.         /* set passwd callback */
  1062.         PK11_SetPasswordFunc(SSM_GetPasswdCallback);
  1063.         /* verify passwd */
  1064.         PK11_SetVerifyPasswordFunc(SSM_VerifyPasswdCallback);
  1065. #ifdef ALLOW_STANDALONE
  1066.     }
  1067. #endif
  1068.     goto done;
  1069.  loser:
  1070.     /* Gather the error from wherever it came */
  1071.     if (rv == PR_SUCCESS)
  1072.         rv = (srv == SECSuccess) ? PR_SUCCESS : PR_FAILURE;
  1073.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1074.     
  1075.  done:
  1076.     return rv;
  1077. }
  1078. SSMStatus SSMControlConnection_ProcessHello(SSMControlConnection *ctrl, SECItem *msg)
  1079. {
  1080.     SSMStatus rv = PR_SUCCESS;
  1081.     HelloRequest request;
  1082.     HelloReply reply;
  1083.     /* parse client info and store it in the connection object 
  1084.      */
  1085. #ifdef NSM_PROTOCOL_STRICT
  1086.     /* we should only ever get one hello request */
  1087.     PR_ASSERT(ctrl->m_profileName == NULL);
  1088. #endif
  1089.     if (CMT_DecodeMessage(HelloRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1090.         goto loser;
  1091.     }
  1092.     /* allow earlier client libs to try to talk to us, but not later ones */
  1093.     if (request.version > ctrl->m_version) {
  1094.         goto loser;
  1095.     }
  1096.     ctrl->m_doesUI = request.doesUI;
  1097.     ctrl->m_profileName = request.profile;
  1098.     if (request.profileDir == NULL) {
  1099.         /* it may be an empty string but it should not be NULL */
  1100.         goto loser;
  1101.     }
  1102.     ctrl->m_dirRoot = request.profileDir;
  1103.     SSM_DEBUG("Selected profile directory <%s>.n", ctrl->m_dirRoot);
  1104.     msg->data = NULL;
  1105.     rv = SSMControlConnection_SetupNSS(ctrl, request.policy);
  1106. /* Create the auto-renewal thread */
  1107. ctrl->m_certRenewalThread = SSM_CreateThread(SSMRESOURCE(ctrl),
  1108. SSM_CertificateRenewalThread);
  1109.     goto done;
  1110.  loser:
  1111.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1112.     
  1113.  done:
  1114.     /* construct HELLO_REPLY message
  1115.      */
  1116.     SSM_DEBUG("composing Hello reply.n");
  1117.     reply.result = rv;
  1118.     reply.sessionID = SSMRESOURCE(ctrl)->m_id;
  1119.     reply.version = ctrl->m_version;
  1120.     reply.httpPort = SSM_GetHTTPPort();
  1121.     reply.nonce.len = strlen(ctrl->m_nonce);
  1122.     reply.nonce.data = (unsigned char *) ctrl->m_nonce;
  1123.     reply.policy = SSM_GetPolicy();
  1124.     reply.stringVersion = SSMVersionString;
  1125.     if (rv == PR_SUCCESS) {
  1126.         msg->type = (SECItemType) (SSM_HELLO_MESSAGE | SSM_REPLY_OK_MESSAGE);
  1127.     }
  1128.     else {
  1129.         msg->type = (SECItemType) (SSM_HELLO_MESSAGE | SSM_REPLY_ERR_MESSAGE);
  1130.     }
  1131.     CMT_EncodeMessage(HelloReplyTemplate, (CMTItem*)msg, &reply);
  1132.     return rv;
  1133. }
  1134. typedef struct {
  1135.     char* pref; /* pref key */
  1136.     long id; /* cipher ID for NSS */
  1137. } SSMCipherPref;
  1138. /* cipher suites are listed in the order of decreasing preference in each
  1139.  * cipher family
  1140.  */
  1141. SSMCipherPref SSMSSLCiphers[] = {
  1142.     /* SSL2 ciphers */
  1143.     {"security.ssl2.rc4_128", SSL_EN_RC4_128_WITH_MD5},
  1144.     {"security.ssl2.rc2_128", SSL_EN_RC2_128_CBC_WITH_MD5},
  1145.     {"security.ssl2.des_ede3_192", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
  1146.     {"security.ssl2.des_64", SSL_EN_DES_64_CBC_WITH_MD5},
  1147.     {"security.ssl2.rc4_40", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
  1148.     {"security.ssl2.rc2_40", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
  1149.     /* SSL3 ciphers */
  1150.     {"security.ssl3.fortezza_fortezza_sha", 
  1151.      SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
  1152.     {"security.ssl3.fortezza_rc4_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
  1153.     {"security.ssl3.rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
  1154.     {"security.ssl3.rsa_fips_des_ede3_sha", 
  1155.      SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
  1156.     {"security.ssl3.rsa_des_ede3_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
  1157.     {"security.ssl3.rsa_fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
  1158.     {"security.ssl3.rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
  1159.     {"security.ssl3.rsa_1024_rc4_56_sha",
  1160.      TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
  1161.     {"security.ssl3.rsa_1024_des_cbc_sha",
  1162.      TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
  1163.     {"security.ssl3.rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
  1164.     {"security.ssl3.rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
  1165.     {"security.ssl3.fortezza_null_sha", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
  1166.     {"security.ssl3.rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
  1167.     {NULL, 0} /* end marker */
  1168. };
  1169. SSMCipherPref SSMSMIMECiphers[] = {
  1170.     /* SMIME bulk ciphers */
  1171.     {"security.smime.fortezza", SMIME_FORTEZZA},
  1172.     {"security.smime.des_ede3", SMIME_DES_EDE3_168},
  1173.     {"security.smime.rc2_128", SMIME_RC2_CBC_128},
  1174.     {"security.smime.des", SMIME_DES_CBC_56},
  1175.     {"security.smime.rc2_64", SMIME_RC2_CBC_64},
  1176.     {"security.smime.rc2_40", SMIME_RC2_CBC_40},
  1177.     {NULL, 0} /* end marker */
  1178. };
  1179. static void ssm_enable_ssl_cipher_prefs(SSMControlConnection* ctrl)
  1180. {
  1181.     int i;
  1182.     PRBool boolVal = PR_TRUE;
  1183.     for (i = 0; SSMSSLCiphers[i].pref != NULL; i++) {
  1184.         if ((PREF_GetBoolPref(ctrl->m_prefs, SSMSSLCiphers[i].pref, 
  1185.                               &boolVal) == PR_SUCCESS) && 
  1186.             (boolVal == PR_FALSE)) {
  1187.             /* we only have to disable a cipher, not enable one, because 
  1188.              * prefs only restrict ciphers further over the policies
  1189.              */
  1190.             SSL_EnableCipher(SSMSSLCiphers[i].id, boolVal);
  1191.         }
  1192.     }
  1193. }
  1194. static void ssm_enable_smime_cipher_prefs(SSMControlConnection* ctrl)
  1195. {
  1196.     int i;
  1197.     PRBool boolVal = PR_TRUE;
  1198.     for (i = 0; SSMSMIMECiphers[i].pref != NULL; i++) {
  1199.         if ((PREF_GetBoolPref(ctrl->m_prefs, SSMSMIMECiphers[i].pref, 
  1200.                               &boolVal) == PR_SUCCESS) && 
  1201.             (boolVal == PR_FALSE)) {
  1202.             SECMIME_EnableCipher(SSMSMIMECiphers[i].id, boolVal);
  1203.         }
  1204.     }
  1205. }
  1206. static SSMStatus ssm_enable_security_prefs(SSMControlConnection* ctrl)
  1207. {
  1208.     PRBool prefval;
  1209.     PRIntn ask;
  1210.     PRIntn timeout;
  1211.     PK11SlotInfo* slot = NULL;
  1212.     PRBool ocspOn;
  1213.     char *ocspURL = NULL, *ocspSigner = NULL;
  1214.     PR_ASSERT((ctrl != NULL) && (ctrl->m_prefs != NULL));
  1215.     /* enforce the user's preferences for SSL cipher families */
  1216.     if (PREF_GetBoolPref(ctrl->m_prefs, "security.enable_ssl2", &prefval) != 
  1217.         PR_SUCCESS) {
  1218.         goto loser;
  1219.     }
  1220.     SSL_EnableDefault(SSL_ENABLE_SSL2, prefval);
  1221.     if (PREF_GetBoolPref(ctrl->m_prefs, "security.enable_ssl3", &prefval) != 
  1222.         PR_SUCCESS) {
  1223.         goto loser;
  1224.     }
  1225.     SSL_EnableDefault(SSL_ENABLE_SSL3, prefval);
  1226.     /* set password values */
  1227.     if (PREF_GetIntPref(ctrl->m_prefs, "security.ask_for_password", &ask) !=
  1228.         PR_SUCCESS) {
  1229.         goto loser;
  1230.     }
  1231.     if (PREF_GetIntPref(ctrl->m_prefs, "security.password_lifetime", 
  1232.                         &timeout) != PR_SUCCESS) {
  1233.         goto loser;
  1234.     }
  1235.     slot = PK11_GetInternalKeySlot();
  1236.     PK11_SetSlotPWValues(slot, ssm_ask_pref_to_pk11((int)ask), 
  1237.                          (int)timeout);
  1238.     PK11_FreeSlot(slot);
  1239.     /* disable any additional ciphers that might be marked in prefs */
  1240.     ssm_enable_ssl_cipher_prefs(ctrl);
  1241.     ssm_enable_smime_cipher_prefs(ctrl);
  1242.     /*
  1243.      * Let's take care of OCSP prefs.
  1244.      */
  1245.     if (PREF_GetBoolPref(ctrl->m_prefs, "security.OCSP.enabled", 
  1246.                          &ocspOn) != SSM_SUCCESS   ||
  1247.         !ocspOn) {
  1248.         CERT_DisableOCSPChecking(ctrl->m_certdb);
  1249.         CERT_DisableOCSPDefaultResponder(ctrl->m_certdb);
  1250.     } else {
  1251.         /* OCSP should be enabled */
  1252.         CERT_EnableOCSPChecking(ctrl->m_certdb);
  1253.         /* Do we have a default responder set? */
  1254.         if (PREF_GetBoolPref(ctrl->m_prefs,
  1255.                "security.OCSP.useDefaultResponder", &ocspOn) == SSM_SUCCESS &&
  1256.             ocspOn) {
  1257.             /* First let's make sure the default URL and 
  1258.              * signer have been set. 
  1259.              */
  1260.             PREF_GetStringPref(ctrl->m_prefs, "security.OCSP.URL", &ocspURL);
  1261.             PREF_GetStringPref(ctrl->m_prefs, "security.OCSP.signingCA",
  1262.                                &ocspSigner);
  1263.             if (ocspURL != NULL && ocspSigner != NULL) {
  1264.                 CERT_SetOCSPDefaultResponder(ctrl->m_certdb, ocspURL, 
  1265.                                              ocspSigner);
  1266.                 CERT_EnableOCSPDefaultResponder(ctrl->m_certdb);
  1267.             }
  1268.         }
  1269.     }
  1270.     return PR_SUCCESS;
  1271. loser:
  1272.     return PR_FAILURE;
  1273. }
  1274. SSMStatus SSMControlConnection_ProcessPrefs(SSMControlConnection* ctrl,
  1275.                                             SECItem* msg)
  1276. {
  1277.     SSMStatus rv = PR_SUCCESS;
  1278.     SetPrefListMessage request;
  1279.     SingleNumMessage reply;
  1280.     int i;
  1281.     PRBool boolval;
  1282.     PRIntn intval;
  1283.     SSM_DEBUG("Preferences were passed in from the plugin.n");
  1284.     /* decode the message */
  1285.     if (CMT_DecodeMessage(SetPrefListMessageTemplate, &request, 
  1286.                           (CMTItem*)msg) != CMTSuccess) {
  1287.         goto loser;
  1288.     }
  1289.     for (i = 0; i < request.length; i++) {
  1290.         if (request.list[i].key == NULL) {
  1291.             /* misconfigured pref item: look at the next */
  1292.             continue;
  1293.         }
  1294.         switch (request.list[i].type) {
  1295.         case STRING_PREF:    /* string type */
  1296.             rv = PREF_SetStringPref(ctrl->m_prefs, request.list[i].key, 
  1297.                                     request.list[i].value);
  1298.             break;
  1299.         case BOOL_PREF:    /* boolean type */
  1300.             if (PL_strcmp(request.list[i].value, "true") == 0) {
  1301.                 boolval = PR_TRUE;
  1302.             }
  1303.             else if (PL_strcmp(request.list[i].value, "false") == 0) {
  1304.                 boolval = PR_FALSE;
  1305.             }
  1306.             else {
  1307.                 /* misconfigured */
  1308.                 break;
  1309.             }
  1310.             rv = PREF_SetBoolPref(ctrl->m_prefs, request.list[i].key,
  1311.                                   boolval);
  1312.             break;
  1313.         case INT_PREF:    /* integer type */
  1314.             intval = atoi(request.list[i].value);
  1315.             rv = PREF_SetIntPref(ctrl->m_prefs, request.list[i].key,
  1316.                                  intval);
  1317.             break;
  1318.         default:
  1319.             SSM_DEBUG("We do not understand the pref type.n");
  1320.             break;
  1321.         }
  1322.     }
  1323.     /* prefs are all stored: now take action to apply prefs */
  1324.     rv = ssm_enable_security_prefs(ctrl);
  1325.     rv = PR_SUCCESS;
  1326. loser:
  1327.     reply.value = rv;
  1328.     msg->type =(SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_PREF_ACTION);
  1329.     CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
  1330.     return rv;
  1331. }
  1332.         
  1333. SSMStatus
  1334. SSMControlConnection_ProcessDataRequest(SSMControlConnection * ctrl, 
  1335.                                         SECItem * msg)
  1336. {
  1337.     SSMInfoSSL infoSSL;
  1338.     SSMInfoP7Encode infoP7Encode;
  1339.     SSMInfoP7Decode infoP7Decode;
  1340.     SSMHashInitializer infoHash;
  1341.     SSMDataConnection *datac;
  1342. void *createArg;
  1343. SSMResourceType connType = SSM_RESTYPE_NULL;
  1344.     SSMStatus rv = PR_SUCCESS;
  1345.     SSMResourceID dataRID = 0;
  1346. PRInt32 msgtype = msg->type & SSM_SUBTYPE_MASK;
  1347.     DataConnectionReply reply;
  1348.     switch (msgtype)
  1349.     { 
  1350.     case SSM_SSL_CONNECTION:
  1351.         {
  1352.         SSLDataConnectionRequest request;
  1353.         SSM_DEBUG("... specifically, an SSL data request.n");
  1354.         /* Decode the SSL request message */
  1355.         if (CMT_DecodeMessage(SSLDataConnectionRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1356.             goto loser;
  1357.         }
  1358.         (void) memset(&infoSSL, 0, sizeof(SSMInfoSSL));
  1359.         infoSSL.isTLS = PR_FALSE;
  1360.         infoSSL.flags = request.flags;
  1361.         infoSSL.port = request.port;
  1362.         infoSSL.hostIP = request.hostIP;
  1363.         infoSSL.hostName = request.hostName;
  1364.         infoSSL.forceHandshake = request.forceHandshake;
  1365.         infoSSL.clientContext = request.clientContext;
  1366.         msg->data = NULL;
  1367.         /* fill in the control connection... */
  1368.         infoSSL.parent = ctrl;
  1369. connType = SSM_RESTYPE_SSL_DATA_CONNECTION;
  1370. createArg = &infoSSL;
  1371.         }
  1372.         break;
  1373.     case SSM_PKCS7DECODE_STREAM:
  1374.         {
  1375.         SingleItemMessage request;
  1376.         SSM_DEBUG("PKCS7 Decode Request.n");
  1377.         if (CMT_DecodeMessage(SingleItemMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1378.             goto loser;
  1379.         }
  1380. connType = SSM_RESTYPE_PKCS7_DECODE_CONNECTION;
  1381.         infoP7Decode.ctrl = ctrl;
  1382.         infoP7Decode.clientContext = request.item;
  1383. createArg = &infoP7Decode;
  1384.         }
  1385.         break;
  1386.     case SSM_TLS_CONNECTION:
  1387.     case SSM_PROXY_CONNECTION:
  1388.         {
  1389.         TLSDataConnectionRequest request;
  1390.         SSM_DEBUG("... specifically, a TLS connection request.n");
  1391.         /* decode the TLS request message */
  1392.         if (CMT_DecodeMessage(TLSDataConnectionRequestTemplate, &request,
  1393.                               (CMTItem*)msg) != CMTSuccess) {
  1394.             goto loser;
  1395.         }
  1396.         (void)memset(&infoSSL, 0, sizeof(SSMInfoSSL));
  1397.         /* notify that this is either an SMTP or an SSL proxy connection, not 
  1398.          * a regular SSL connection
  1399.          */
  1400.         infoSSL.isTLS = PR_TRUE;
  1401.         infoSSL.port = request.port;
  1402.         infoSSL.hostIP = request.hostIP;
  1403.         infoSSL.hostName = request.hostName;
  1404.         msg->data = NULL;
  1405.         /* fill in the control connection... */
  1406.         infoSSL.parent = ctrl;
  1407.         connType = SSM_RESTYPE_SSL_DATA_CONNECTION;
  1408.         createArg = &infoSSL;
  1409.         }
  1410.         break;
  1411.     case SSM_PKCS7ENCODE_STREAM:
  1412.         {
  1413.         PKCS7DataConnectionRequest request;
  1414.         SSM_DEBUG("... specifically, a PKCS#7 Encode request.n");
  1415.         if (CMT_DecodeMessage(PKCS7DataConnectionRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1416.             goto loser;
  1417.         }
  1418.         infoP7Encode.ciRID = request.resID;
  1419.         connType = SSM_RESTYPE_PKCS7_ENCODE_CONNECTION;
  1420.         infoP7Encode.ctrl = ctrl;
  1421.         infoP7Encode.clientContext = request.clientContext;
  1422.         createArg = &infoP7Encode;
  1423.         }
  1424.         break;
  1425.     case SSM_HASH_STREAM:
  1426.         {
  1427.         SingleNumMessage request;
  1428. connType = SSM_RESTYPE_HASH_CONNECTION;
  1429.         infoHash.m_parent = ctrl;
  1430.         if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1431.             goto loser;
  1432.         }
  1433.         infoHash.m_hashtype = (HASH_HashType) request.value;
  1434.         msg->data = NULL;
  1435. createArg = &infoHash;
  1436.         }
  1437. break;
  1438.     default:
  1439.         SSM_DEBUG("Unknown data connection type (%lx).n", 
  1440.                   (msg->type & SSM_SUBTYPE_MASK));
  1441.     }
  1442. if (connType != SSM_RESTYPE_NULL)
  1443. {
  1444. /* ... then create the data connection */
  1445. SSM_DEBUG("Firing up data connection.n");
  1446. rv = SSM_CreateResource(connType, createArg, ctrl, &dataRID,
  1447. (SSMResource **) &datac);
  1448. if ((rv != PR_SUCCESS) || (!datac)) {
  1449.             goto loser;
  1450.         }
  1451. } else  {
  1452. rv = (SSMStatus) SSM_ERR_BAD_RESOURCE_TYPE;
  1453. goto loser;
  1454. }
  1455.     /* compose reply message */
  1456.     SSM_DEBUG("Composing reply.n");
  1457.     msg->type = (SECItemType) (SSM_DATA_CONNECTION | msgtype | SSM_REPLY_OK_MESSAGE);
  1458.     reply.result = rv;
  1459.     reply.connID = dataRID;
  1460.     reply.port = ctrl->m_dataPort;
  1461.     if (CMT_EncodeMessage(DataConnectionReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  1462.         goto loser;
  1463.     }
  1464.     if (rv != PR_SUCCESS) goto loser;
  1465.     goto done;
  1466.  loser:
  1467.     if (msg->data) 
  1468.     {
  1469.         PR_Free(msg->data);
  1470.         msg->data = NULL;
  1471.     }
  1472.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1473.     reply.result = PR_GetError();
  1474.     reply.connID = 0;
  1475.     reply.port = 0;
  1476.     CMT_EncodeMessage(DataConnectionReplyTemplate, (CMTItem*)msg, &reply);
  1477.  done:
  1478.     return rv;
  1479. }
  1480. SSMStatus
  1481. SSMControlConnection_ProcessDupResourceRequest(SSMControlConnection * ctrl, 
  1482.                                                SECItem * msg)
  1483. {
  1484.     SSMResourceID objID;
  1485.     SSMResource *obj = NULL;
  1486.     SSMStatus rv = PR_SUCCESS;
  1487.     SingleNumMessage request;
  1488.     DupResourceReply reply;
  1489.     SSM_DEBUG("Got a Duplicate Resource request.n");
  1490.     /* parse message and get resource/field ID */
  1491.     if (CMT_DecodeMessage(SingleNumMessageTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1492.         goto loser;
  1493.     }
  1494.     objID = request.value;
  1495.     /* ### mwelch Should free this here, instead of in the actual 
  1496.                   message parsing code. (4/13/99) */
  1497.     msg->data = NULL;
  1498.     
  1499.     SSM_DEBUG("Rsrc ID %ld.n", objID);
  1500.     
  1501.     rv = SSMControlConnection_GetResource(ctrl, objID, &obj);
  1502.     if (rv != PR_SUCCESS)
  1503.         goto loser;
  1504.     
  1505.     PR_ASSERT(obj != NULL);
  1506.     rv = SSM_ClientGetResourceReference(obj, &objID);
  1507.     if (rv != PR_SUCCESS)
  1508.         goto loser;
  1509.     SSM_DEBUG("DuplicateResource: result %ld, new rsrc ID %ld.n",
  1510.               (long) rv, (long)obj->m_id);
  1511.     goto done;
  1512.  loser:
  1513.     /* Got an error while getting the reference. This is recoverable, 
  1514.        because we just report the error back to the client. */
  1515.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1516.  done:
  1517.     msg->data = NULL;
  1518.     msg->len = 0;
  1519.     /* compose reply message */
  1520.     SSM_DEBUG("Composing reply.n");
  1521.     msg->type = (SECItemType) (SSM_RESOURCE_ACTION | SSM_DUPLICATE_RESOURCE
  1522.         | ((rv == SSM_SUCCESS) ? SSM_REPLY_OK_MESSAGE : SSM_REPLY_ERR_MESSAGE));
  1523.     reply.result = rv;
  1524.     reply.resID = (obj ? obj->m_id : 0);
  1525.     if (CMT_EncodeMessage(DupResourceReplyTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
  1526.         goto loser;
  1527.     }
  1528.     rv = PR_SUCCESS;
  1529.     if ((msg->data == NULL) || (msg->len == 0)) rv = PR_FAILURE;
  1530.     if (obj != NULL)
  1531.         SSM_FreeResource(obj);
  1532.     return rv;
  1533. }
  1534. SSMStatus
  1535. SSMControlConnection_ProcessDestroyRequest(SSMControlConnection * ctrl, 
  1536.                                           SECItem * msg)
  1537. {
  1538.     SSMStatus rv = PR_SUCCESS;
  1539.     DestroyResourceRequest request;
  1540.     SingleNumMessage reply;
  1541.     SSM_DEBUG("Got a Destroy Resource request.n");
  1542.     /* parse message and get resource/field ID */
  1543.     if (CMT_DecodeMessage(DestroyResourceRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1544.         goto loser;
  1545.     }
  1546.     msg->data = NULL;
  1547.     
  1548.     SSM_DEBUG("RID %ld, expected type %ld.n", request.resID, request.resType);
  1549.     
  1550.     rv = SSM_ClientDestroyResource(ctrl, request.resID, (SSMResourceType) request.resType);
  1551.     goto done;
  1552.  loser:
  1553.     /* Got an error while getting the reference. This is recoverable, 
  1554.        because we just report the error back to the client. */
  1555.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1556.  done:
  1557.     msg->data = NULL;
  1558.     msg->len = 0;
  1559.     /* compose reply message */
  1560.     SSM_DEBUG("Composing reply.n");
  1561.     msg->type = (SECItemType) (SSM_RESOURCE_ACTION
  1562.         | SSM_DESTROY_RESOURCE
  1563.         | ((rv == SSM_SUCCESS) ? SSM_REPLY_OK_MESSAGE : SSM_REPLY_ERR_MESSAGE));
  1564.     reply.value = rv;
  1565.     CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
  1566.     rv = PR_SUCCESS;
  1567.     if ((msg->data == NULL) || (msg->len == 0)) rv = PR_FAILURE;
  1568.     return rv;
  1569. }
  1570. static SSMStatus
  1571. ssmcontrolconnection_encodegetattr_reply(SECItem *msg, SSMStatus rv, 
  1572.                                          SSMAttributeValue *value, 
  1573.                                          SSMResourceAttrType attrType)
  1574. {
  1575.     GetAttribReply reply;
  1576.     msg->data = NULL;
  1577.     msg->len = 0;
  1578.     /* compose reply message */
  1579.     SSM_DEBUG("Composing reply.n");
  1580.     msg->type = (SECItemType) (SSM_RESOURCE_ACTION
  1581.         | SSM_GET_ATTRIBUTE
  1582.         | SSM_REPLY_OK_MESSAGE 
  1583.         | attrType);
  1584.     reply.result = rv;
  1585.     reply.value = *value;
  1586.     CMT_EncodeMessage(GetAttribReplyTemplate, (CMTItem*)msg, &reply);
  1587.     SSM_DestroyAttrValue(value, PR_FALSE);
  1588.     rv = SSM_SUCCESS;
  1589.     if ((msg->data == NULL) || (msg->len == 0))
  1590.         rv = SSM_FAILURE;
  1591.     return rv;
  1592. }
  1593. SSMStatus
  1594. SSMControlConnection_ProcessGetAttrRequest(SSMControlConnection * ctrl, 
  1595.                                             SECItem * msg)
  1596. {
  1597.     SSMResource *obj = NULL;
  1598.     SSMResourceAttrType mAttrType;
  1599.     SSMStatus rv;
  1600.     SSMAttributeValue value = {SSM_NO_ATTRIBUTE};
  1601.     GetAttribRequest request;
  1602.     SSM_DEBUG("Got a Get Attribute request.n");
  1603.     /* parse message and get resource/field ID */
  1604.     if (CMT_DecodeMessage(GetAttribRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1605.         goto loser;
  1606.     }
  1607.     msg->data = NULL;
  1608.  
  1609.     SSM_DEBUG("Rsrc ID %ld, attr ID %ld.n", request.resID, request.fieldID);
  1610.     
  1611.     if (request.resID == SSM_SESSION_RESOURCE) {
  1612.         SSM_GetResourceReference(&ctrl->super.super);
  1613.         obj = (SSMResource *)ctrl;
  1614.     } else {
  1615.         rv = SSMControlConnection_GetResource(ctrl, request.resID, &obj);
  1616.         if (rv != PR_SUCCESS)
  1617.             goto loser;
  1618.     }
  1619.     
  1620.     PR_ASSERT(obj != NULL);
  1621.     mAttrType = (SSMResourceAttrType) (msg->type & SSM_SPECIFIC_MASK);
  1622.     rv = SSM_GetResAttribute(obj, (SSMAttributeID) request.fieldID, mAttrType,
  1623.                              &value);
  1624.     SSM_DEBUG("GetResAttribute: result %ld, type %lx.n",
  1625.                           (long) rv, (long) value.type);
  1626.     if (rv == SSM_ERR_DEFER_RESPONSE)
  1627.         goto defer;
  1628.     if (rv != PR_SUCCESS)
  1629.         goto loser;
  1630.     
  1631.     /* Make sure the type returned matches what was asked. */
  1632.     if (mAttrType != value.type) {
  1633.         rv = SSM_ERR_ATTRIBUTE_TYPE_MISMATCH;
  1634.         /* pick default values for resource result that work
  1635.            for all three resource replies*/
  1636.         SSM_DestroyAttrValue(&value, PR_FALSE);
  1637.         value.type = SSM_NUMERIC_ATTRIBUTE;
  1638.         value.u.numeric = 0;
  1639.     }
  1640.     goto done;
  1641.  loser:
  1642.     /* Got an error while getting resource and/or attributes. This
  1643.        is recoverable, because we just report the error back to the
  1644.        client. */
  1645.     if (rv == PR_SUCCESS)
  1646.         rv = PR_FAILURE;
  1647.     /* Create a suitable zero value for any type requested */
  1648.     SSM_DestroyAttrValue(&value, PR_FALSE);
  1649.     value.type = SSM_NUMERIC_ATTRIBUTE;
  1650.     value.u.numeric = 0;
  1651.  done:
  1652.     rv = ssmcontrolconnection_encodegetattr_reply(msg, rv, &value, 
  1653.                                              (SSMResourceAttrType) (msg->type & SSM_SPECIFIC_MASK));
  1654.     if (obj != NULL)
  1655.         SSM_FreeResource(obj);
  1656.  defer:
  1657.     return rv;
  1658. }
  1659. SSMStatus
  1660. SSMControlConnection_ProcessSetAttrRequest(SSMControlConnection * ctrl, 
  1661.    SECItem * msg)
  1662. {
  1663.     SSMStatus       rv;
  1664.     SSMResource       *obj;
  1665.     SetAttribRequest  request;
  1666.     SSM_DEBUG("Got a Set Attribute Request.n");
  1667.     if (CMT_DecodeMessage(SetAttribRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1668.         goto loser;
  1669.     }
  1670.     PORT_Free(msg->data);
  1671.     msg->data = NULL;
  1672.     msg->len  = 0;
  1673.     SSM_DEBUG("Rsrc ID %ld, attr ID %ld.n", request.resID, request.fieldID);
  1674.     rv = SSMControlConnection_GetResource(ctrl, request.resID, &obj);
  1675.     if (rv != PR_SUCCESS) {
  1676.         goto loser;
  1677.     }
  1678.     PR_ASSERT(obj != NULL);
  1679.     rv = SSM_SetResAttribute(obj, (SSMAttributeID)request.fieldID, &request.value);
  1680.     SSM_FreeResource(obj);
  1681.     SSM_DestroyAttrValue(&request.value, PR_FALSE);
  1682.     if (rv != PR_SUCCESS) {
  1683.         goto loser;
  1684.     }
  1685.     msg->type = (SECItemType) (SSM_RESOURCE_ACTION  | SSM_SET_ATTRIBUTE |
  1686.                 SSM_REPLY_OK_MESSAGE | (msg->type & SSM_SPECIFIC_MASK));
  1687.     return PR_SUCCESS;
  1688.  loser:
  1689.     return PR_FAILURE;
  1690. }
  1691. SSMStatus
  1692. SSMControlConnection_ProcessCreateRequest(SSMControlConnection * ctrl, 
  1693.                                           SECItem * msg)
  1694. {
  1695.     SSMStatus  rv;
  1696.     SSMResourceID rid = 0;
  1697.     SSMResource *res = NULL;
  1698.     unsigned char *params = NULL;
  1699.     CreateResourceRequest request;
  1700.     CreateResourceReply reply;
  1701.     SSM_DEBUG("Got a Create Resource Request.n");
  1702.     if (CMT_DecodeMessage(CreateResourceRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1703.         goto loser;
  1704.     }
  1705.     msg->data = NULL;
  1706.     msg->len  = 0;
  1707.     SSM_DEBUG("Type %ld, param len %ld.n", request.type, request.params.len);
  1708.     /* Bleah. Switch on the type.
  1709.        ### mwelch Must replace, since many of these resources can be
  1710.        generically created using control connection + single param */
  1711.     switch(request.type)
  1712.     {
  1713.     case SSM_RESTYPE_KEYGEN_CONTEXT:
  1714.         {
  1715.             SSMKeyGenContextCreateArg arg;
  1716.             arg.parent = ctrl;
  1717.             arg.type   = SSM_CRMF_KEYGEN;
  1718.             arg.param  = &request.params;
  1719.             SSM_DEBUG("Creating key gen context.n");
  1720.             rv = SSM_CreateResource((SSMResourceType) request.type, &arg, 
  1721.                                     ctrl, &rid, &res);
  1722.         }
  1723.         break;
  1724.     case SSM_RESTYPE_SIGNTEXT:
  1725.         {
  1726.             rv = SSMSignTextResource_Create(request.params.data, ctrl, &res);
  1727.             if (rv == PR_SUCCESS) {
  1728.                 PR_ASSERT(res != NULL);
  1729.                 rid = res->m_id;
  1730.             }
  1731.         }
  1732.         break;
  1733.     default:
  1734.         rv = (SSMStatus) PR_INVALID_ARGUMENT_ERROR;
  1735.         break;
  1736.     }
  1737.     if (rv != PR_SUCCESS && rv != SSM_ERR_DEFER_RESPONSE)
  1738.         goto loser;
  1739.     PR_ASSERT(res != NULL);
  1740.     if (SSM_ClientGetResourceReference(res, &res->m_id) != PR_SUCCESS)
  1741.         goto loser;
  1742.     /* if deferred response don't create reply message */
  1743.     if (rv != PR_SUCCESS)
  1744.       goto done;
  1745.     msg->type = (SECItemType) (SSM_RESOURCE_ACTION  
  1746.         | SSM_CREATE_RESOURCE 
  1747.         | SSM_REPLY_OK_MESSAGE);
  1748.     goto done;
  1749.  loser:
  1750.     if (rv == PR_SUCCESS)
  1751.         rv = PR_FAILURE;
  1752.  done:
  1753.     if (params)
  1754.         PR_Free(params);
  1755.     /* Create a reply message here. */
  1756.     reply.result = rv;
  1757.     reply.resID = rid;
  1758.     CMT_EncodeMessage(CreateResourceReplyTemplate,(CMTItem*)msg, &reply);
  1759.     return rv;
  1760. }
  1761. SSMStatus
  1762. SSMControlConnection_ProcessResourceRequest(SSMControlConnection * ctrl, 
  1763.                                             SECItem * msg)
  1764. {
  1765.     SSMStatus rv = PR_SUCCESS;
  1766.     SSM_DEBUG("Got a resource-related request.n");
  1767.     switch (msg->type & SSM_SUBTYPE_MASK) 
  1768.     { 
  1769.     case SSM_GET_ATTRIBUTE:
  1770.         rv = SSMControlConnection_ProcessGetAttrRequest(ctrl, msg);
  1771.         break;
  1772.     case SSM_CONSERVE_RESOURCE:
  1773.         rv = SSMControlConnection_ProcessConserveRequest(ctrl, msg);
  1774.         break;
  1775.     case SSM_DESTROY_RESOURCE:
  1776.         rv = SSMControlConnection_ProcessDestroyRequest(ctrl, msg);
  1777.         break;
  1778.     case SSM_DUPLICATE_RESOURCE:
  1779.         rv = SSMControlConnection_ProcessDupResourceRequest(ctrl, msg);
  1780.         break;
  1781.     case SSM_SET_ATTRIBUTE:
  1782.         rv = SSMControlConnection_ProcessSetAttrRequest(ctrl, msg);
  1783. break;
  1784.     case SSM_CREATE_RESOURCE:
  1785.         rv = SSMControlConnection_ProcessCreateRequest(ctrl, msg);
  1786.         break;
  1787.     case SSM_TLS_STEPUP:
  1788.         rv = SSMControlConnection_ProcessTLSRequest(ctrl, msg);
  1789.         break;
  1790.     case SSM_PROXY_STEPUP:
  1791.         rv = SSMControlConnection_ProcessProxyStepUpRequest(ctrl, msg);
  1792.         break;
  1793.     default:
  1794.         SSM_DEBUG("Unknown resource request (%lx).n", 
  1795.                   (msg->type & SSM_SUBTYPE_MASK));
  1796.         goto loser;
  1797.     }
  1798.     goto done;
  1799.  loser:
  1800.     SSM_DEBUG("ProcessResourceRequest: loser hit, rv = %ld.n", rv);
  1801.     if (msg->data) 
  1802.     {
  1803.         PR_Free(msg->data);
  1804.         msg->data = NULL;
  1805.         msg->len = 0;
  1806.     }
  1807.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  1808.  done:
  1809.     return rv;
  1810. }
  1811. static SSMStatus ssm_verifydetachedthread(SSMControlConnection *ctrl,
  1812.                                           SECItem *msg)
  1813. {
  1814.     VerifyDetachedSigRequest request;
  1815.     SingleNumMessage reply;
  1816. SSMP7ContentInfo *ci;
  1817.     SSMStatus rv;
  1818.     
  1819.     SSM_DEBUG("Processing Verify Detached Signature request.n");
  1820.     if (CMT_DecodeMessage(VerifyDetachedSigRequestTemplate, &request, 
  1821.                           (CMTItem*)msg) != CMTSuccess) {
  1822.         rv = SSM_FAILURE;
  1823.     } else {
  1824.         rv = SSM_SUCCESS;
  1825.     }
  1826.     msg->data = NULL;
  1827.     
  1828.     if (rv == SSM_SUCCESS) {
  1829.         
  1830.         /* Get the content info resource, if it exists. */
  1831.         rv = SSMControlConnection_GetResource(ctrl, request.pkcs7ContentID,
  1832.                                               (SSMResource **) &ci);
  1833.     }
  1834.     
  1835.     if (rv == SSM_SUCCESS) {
  1836.         
  1837.         PR_ASSERT(SSM_IsAKindOf(&ci->super, SSM_RESTYPE_PKCS7_CONTENT_INFO));
  1838.         SSM_DEBUG("Found content info (%s at %ld).n",
  1839.                   SSM_ResourceClassName(&ci->super),
  1840.                   ci->super.m_id);
  1841.         rv = SSMP7ContentInfo_VerifyDetachedSignature(ci,
  1842.                                              (SECCertUsage)request.certUsage,
  1843.                                              (HASH_HashType) request.hashAlgID,
  1844.                                              (PRBool) request.keepCert, 
  1845.                                              (PRIntn) request.hash.len,
  1846.  (char *)request.hash.data);
  1847.         SSM_DEBUG("VerifyDetachedSig rv = %d.n", rv);
  1848.     }
  1849.     msg->type = (SECItemType) (SSM_OBJECT_SIGNING | SSM_VERIFY_DETACHED_SIG |
  1850.                                SSM_REPLY_OK_MESSAGE);
  1851.     if (rv != SSM_SUCCESS) {
  1852.         reply.value = PR_GetError();
  1853.     } else {
  1854.         reply.value = 0;
  1855.     }
  1856.     CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
  1857.     ssmcontrolconnection_send_message_to_client(ctrl, msg);
  1858.     return SSM_SUCCESS;
  1859. }
  1860. SSMStatus
  1861. SSMControlConnection_ProcessSigningRequest(SSMControlConnection *ctrl, 
  1862.    SECItem *msg)
  1863. {
  1864.     SSMStatus rv = PR_FAILURE;
  1865. SSMP7ContentInfo *ci;
  1866. SSMResourceID ciRID;
  1867.     SEC_PKCS7ContentInfo *cinfo;
  1868.     SSMResourceCert *scert, *ecert, *rcert;
  1869.     CERTCertificate **rcerts;
  1870.     PRInt32 i;
  1871. /* Handle a Verify Detached Signature message */
  1872. switch(msg->type & SSM_SUBTYPE_MASK)
  1873. {
  1874. case SSM_VERIFY_DETACHED_SIG:
  1875.         {
  1876.             if (PK11_IsFIPS()) {
  1877.                 /*
  1878.                  * When FIPS is enabled, we want to do the verification on a
  1879.                  * separate thread so that we don't block the front end 
  1880.                  * thread when the password response comes back
  1881.                  */
  1882.                 rv = SSM_ProcessMsgOnThread(ssm_verifydetachedthread,
  1883.                                             ctrl, msg);
  1884.             } else {
  1885.                 rv = ssm_verifydetachedthread(ctrl, msg);
  1886.             }
  1887.             if (rv == SSM_SUCCESS) {
  1888.                 return SSM_ERR_DEFER_RESPONSE;
  1889.             } else {
  1890.                 return SSM_FAILURE;
  1891.             }
  1892.         }
  1893. break;
  1894.     case SSM_CREATE_SIGNED:
  1895.         {
  1896.         CreateSignedRequest request;
  1897.         CreateContentInfoReply reply;
  1898.         SSM_DEBUG("Processing Create Signed request.n");
  1899.         if (CMT_DecodeMessage(CreateSignedRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1900.             goto create_signed_loser;
  1901.         }
  1902.         msg->data = NULL;
  1903.         rv = SSMControlConnection_GetResource(ctrl, request.scertRID,
  1904.                                               (SSMResource **)&scert);
  1905.         if (rv != PR_SUCCESS)
  1906.             goto create_signed_loser;
  1907.         if (!SSM_IsAKindOf(&scert->super, SSM_RESTYPE_CERTIFICATE))
  1908.             goto create_signed_loser;
  1909.         rv = SSMControlConnection_GetResource(ctrl, request.ecertRID,
  1910.                                               (SSMResource **)&ecert);
  1911.         if (rv == PR_SUCCESS && 
  1912.     !SSM_IsAKindOf(&ecert->super, SSM_RESTYPE_CERTIFICATE))
  1913.             goto create_signed_loser;
  1914.         cinfo = SECMIME_CreateSigned(scert->cert,
  1915.      (ecert) ? ecert->cert : NULL, 
  1916.      ctrl->m_certdb,
  1917.                                      (SECOidTag) request.dig_alg, 
  1918.                                      (SECItem*)&request.digest, 
  1919.                                      (SECKEYGetPasswordKey) NULL, NULL);
  1920.         if (cinfo == NULL)
  1921.             goto create_signed_loser;
  1922.         rv = SSM_CreateResource(SSM_RESTYPE_PKCS7_CONTENT_INFO, cinfo,
  1923.                                 ctrl, &ciRID, (SSMResource **)&ci);
  1924.         if (rv != PR_SUCCESS)
  1925.             goto create_signed_loser;
  1926. /* Get a client reference */
  1927. rv = SSM_ClientGetResourceReference(&ci->super, &ciRID);
  1928. if (rv != PR_SUCCESS) {
  1929.             goto create_signed_loser;
  1930. }
  1931.         msg->type = (SECItemType) (SSM_OBJECT_SIGNING | SSM_CREATE_SIGNED |
  1932.             SSM_REPLY_OK_MESSAGE);
  1933.         reply.ciRID = ciRID;
  1934.         reply.result = PR_SUCCESS;
  1935.         reply.errorCode = 0;
  1936.         CMT_EncodeMessage(CreateContentInfoReplyTemplate, (CMTItem*)msg, &reply);
  1937.         break;
  1938.         
  1939.       create_signed_loser:
  1940.         msg->type = (SECItemType) (SSM_OBJECT_SIGNING | SSM_CREATE_SIGNED |
  1941.             SSM_REPLY_ERR_MESSAGE);
  1942.         reply.ciRID = 0;
  1943.         reply.result = PR_FAILURE;
  1944.         reply.errorCode = PORT_GetError();
  1945.         CMT_EncodeMessage(CreateContentInfoReplyTemplate, (CMTItem*)msg, &reply);
  1946.         /* Return success here so that ProcessMessage doesn't just send
  1947.          * back a message with only the rv.  That's not interesting return
  1948.          * value in this case.
  1949.          */
  1950.         return PR_SUCCESS;
  1951.         }
  1952.     case SSM_CREATE_ENCRYPTED:
  1953.         {
  1954.         CreateEncryptedRequest request;
  1955.         CreateContentInfoReply reply;
  1956.         SSM_DEBUG("Processing Create Encrypted request.n");
  1957.         if (CMT_DecodeMessage(CreateEncryptedRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
  1958.             goto create_encrypted_loser;
  1959.         }
  1960.         msg->data = NULL;
  1961.         rv = SSMControlConnection_GetResource(ctrl, request.scertRID,
  1962.                                               (SSMResource **)&scert);
  1963.         if (rv != PR_SUCCESS)
  1964.             goto create_encrypted_loser;
  1965.         if (!SSM_IsAKindOf(&scert->super, SSM_RESTYPE_CERTIFICATE))
  1966.             goto create_encrypted_loser;
  1967.         rcerts = (CERTCertificate **) PR_Calloc(request.nrcerts+1, sizeof(CERTCertificate *));
  1968.         if (rcerts == NULL)
  1969.             goto create_encrypted_loser;
  1970.         for(i = 0; i < request.nrcerts; i++) {
  1971.             rv = SSMControlConnection_GetResource(ctrl, request.rcertRIDs[i],
  1972.                                                   (SSMResource **)&rcert);
  1973.             if (rv != PR_SUCCESS)
  1974.                 goto create_encrypted_loser;
  1975.             if (!SSM_IsAKindOf(&rcert->super, SSM_RESTYPE_CERTIFICATE))
  1976.                 goto create_encrypted_loser;
  1977.             rcerts[i] = CERT_DupCertificate(rcert->cert);
  1978.             SSM_FreeResource(&rcert->super);
  1979.         }
  1980.         cinfo = SECMIME_CreateEncrypted(scert->cert, rcerts, ctrl->m_certdb,
  1981.                                         NULL, NULL);
  1982.         if (cinfo == NULL)
  1983.             goto create_encrypted_loser;
  1984.         rv = SSM_CreateResource(SSM_RESTYPE_PKCS7_CONTENT_INFO, cinfo,
  1985.                                 ctrl, &ciRID, (SSMResource **)&ci);
  1986.         if (rv != PR_SUCCESS)
  1987.             goto create_encrypted_loser;
  1988. /* Get a client reference */
  1989. rv = SSM_ClientGetResourceReference(&ci->super, &ciRID);
  1990. if (rv != PR_SUCCESS) {
  1991.             goto create_encrypted_loser;
  1992. }
  1993.         msg->type = (SECItemType) (SSM_OBJECT_SIGNING | SSM_CREATE_ENCRYPTED |
  1994.             SSM_REPLY_OK_MESSAGE);
  1995.         reply.ciRID = ciRID;
  1996.         reply.result = PR_SUCCESS;
  1997.         CMT_EncodeMessage(CreateContentInfoReplyTemplate, (CMTItem*)msg, &reply);
  1998.         break;
  1999.         /*
  2000.         goto create_encrypted_done;
  2001.         */
  2002.       create_encrypted_loser:
  2003.         msg->type = (SECItemType) (SSM_OBJECT_SIGNING | SSM_CREATE_ENCRYPTED |
  2004.             SSM_REPLY_ERR_MESSAGE);
  2005.         reply.ciRID = 0;
  2006.         reply.result = PR_FAILURE;
  2007.         CMT_EncodeMessage(CreateContentInfoReplyTemplate, (CMTItem*)msg, &reply);
  2008.         /*
  2009.     create_encrypted_done:
  2010.         */
  2011.         if (rcerts != NULL) {
  2012.             for(i = 0; i < request.nrcerts; i++) {
  2013.                 if (rcerts[i] != NULL)
  2014.                     CERT_DestroyCertificate(rcerts[i]);
  2015.             }
  2016.             PR_Free(rcerts);
  2017.         }
  2018.         }
  2019.         return PR_FAILURE;
  2020. default: 
  2021.         {
  2022.         SingleNumMessage reply;
  2023. SSM_DEBUG("Unknown signing-related request (%lx).n", msg->type & SSM_SUBTYPE_MASK);
  2024.         reply.value = SSM_ERR_BAD_REQUEST;
  2025.         CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
  2026.         }
  2027. break;
  2028. }
  2029. return PR_SUCCESS;
  2030. }
  2031. /*
  2032.  * Called by the ReadCtrlThread, processes messages for control connection
  2033.  *       and places response messages in the queue
  2034.  */
  2035. SSMStatus SSMControlConnection_ProcessMessage(SSMControlConnection * ctrl, SECItem * msg)
  2036.     SSMStatus rv                    = PR_FAILURE;
  2037.     SECStatus secstatus = SECFailure;
  2038.     SSM_DEBUG("SSMControlConnection_ProcessMessage called.n");
  2039.     if (!ctrl || !msg)
  2040.     {
  2041.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2042.         goto loser;
  2043.     }
  2044.     if ((msg->type & SSM_CATEGORY_MASK)!= SSM_REQUEST_MESSAGE) 
  2045.     {
  2046.         /* post CARTMAN_ERROR here */
  2047.         goto loser;
  2048.     }
  2049.     /* action depending on the message type and data */
  2050.     switch (msg->type & SSM_TYPE_MASK) 
  2051.     {
  2052.     case SSM_HELLO_MESSAGE:
  2053.         SSM_DEBUG("we have a Hello request.n");
  2054.         rv = SSMControlConnection_ProcessHello(ctrl, msg);
  2055.         if (rv != PR_SUCCESS) goto hello_loser;
  2056.         break;
  2057.     case SSM_DATA_CONNECTION: 
  2058.         /* differentiate between different data connection types */
  2059.         SSM_DEBUG("we have a data connection request.n");
  2060.         rv = SSMControlConnection_ProcessDataRequest(ctrl,msg);
  2061.         break;
  2062.     case SSM_RESOURCE_ACTION:
  2063.         rv = SSMControlConnection_ProcessResourceRequest(ctrl,msg);
  2064.         break;
  2065.     case SSM_CERT_ACTION:
  2066.         rv = SSMControlConnection_ProcessCertRequest(ctrl, msg);
  2067.         break;
  2068.     case SSM_KEYGEN_TAG:
  2069.         rv = SSMControlConnection_ProcessKeygenTag(ctrl, msg);
  2070.         break;
  2071.     case SSM_OBJECT_SIGNING:
  2072. /* Handle an object signing related message */
  2073. rv = SSMControlConnection_ProcessSigningRequest(ctrl,msg);
  2074. break;
  2075.     case SSM_PKCS11_ACTION:
  2076.         rv = SSMControlConnection_ProcessPKCS11Request(ctrl, msg);
  2077. break;
  2078.     case SSM_LOCALIZED_TEXT:
  2079.         rv = SSMControlConnection_ProcessLocalizedTextRequest(ctrl, msg);
  2080.         break;
  2081.     case SSM_CRMF_ACTION:
  2082.         rv = SSMControlConnection_ProcessCRMFRequest(ctrl, msg);
  2083.      break;
  2084.     case SSM_FORMSIGN_ACTION:
  2085.         rv = SSMControlConnection_ProcessFormSigningRequest(ctrl, msg);
  2086.         break;
  2087.     case SSM_SECURITY_ADVISOR:
  2088.         rv = SSMControlConnection_ProcessSecurityAdvsiorRequest(ctrl, msg);
  2089.         break;
  2090.     case SSM_SEC_CFG_ACTION:
  2091.         rv = SSMControlConnection_ProcessSecCfgRequest(ctrl, msg);
  2092.         break;
  2093.     case SSM_PREF_ACTION:
  2094.         rv = SSMControlConnection_ProcessPrefs(ctrl, msg);
  2095.         break;
  2096.     case SSM_MISC_ACTION:
  2097.         rv = SSMControlConnection_ProcessMiscRequest(ctrl, msg);
  2098.         break;
  2099.     default:
  2100.         /* just send it back to the client or post an error 
  2101.          */
  2102.         SSM_DEBUG("Unknown request type (%lx).n", msg->type & SSM_TYPE_MASK);
  2103.         break;
  2104.     }
  2105.     if (rv == SSM_ERR_DEFER_RESPONSE) {
  2106.         /* If asked to defer response, don't send anything back. 
  2107.            Just indicate that we did what we needed to do. */
  2108.         rv = PR_SUCCESS;
  2109.         goto done;
  2110.     }
  2111.     if (rv != PR_SUCCESS) {
  2112.         rv = ssmcontrolconnection_encode_err_reply(msg,rv);
  2113.     }
  2114. hello_loser:
  2115.     ssmcontrolconnection_send_message_to_client(ctrl, msg);
  2116.     SSMControlConnection_RecycleItem(msg);
  2117.     msg = NULL; /* so that exception handling doesn't try to free it */
  2118.     SSM_DEBUG("SSMControlConnection_ProcessMessage returning rv == %ld.n", rv);
  2119.     goto done;
  2120.  loser: 
  2121.     if (rv == PR_SUCCESS) rv = (SSMStatus) secstatus;
  2122.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  2123.     SSM_DEBUG("FAILURE in SSMControlConnection_ProcessMessage, rv = %ld.n", rv);
  2124. /* Attempt to pack a generic error message. ### mwelch todo */
  2125.  done:
  2126.     if (msg) SSMControlConnection_RecycleItem(msg);
  2127.     return rv;
  2128. }
  2129. SSMStatus
  2130. ssmcontrolconnection_send_message_to_client(SSMControlConnection *ctrl,
  2131.                                             SECItem *msg)
  2132. {
  2133.     SSM_DEBUG("queueing reply: type %lx, len %ld.n", msg->type, msg->len);
  2134.     SSM_SendQMessage(ctrl->m_controlOutQ, 
  2135.                      SSM_PRIORITY_NORMAL,
  2136.                      msg->type, msg->len, 
  2137.                      (char *)msg->data, PR_TRUE);
  2138.     
  2139.     return SSM_SUCCESS;
  2140. }
  2141. SSMStatus 
  2142. ssmcontrolconnection_encode_err_reply(SECItem *msg, SSMStatus rv)
  2143. {
  2144.     SingleNumMessage reply;
  2145.     
  2146.     msg->type = (SECItemType) SSM_REPLY_ERR_MESSAGE;
  2147.     reply.value = rv;
  2148.     CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
  2149.     if (!msg->data || msg->len == 0){
  2150.         rv = SSM_FAILURE;
  2151.     } else {
  2152.         rv = SSM_SUCCESS;
  2153.     }
  2154.     return rv;
  2155. }
  2156. SSMStatus
  2157. SSMControlConnection_Authenticate(SSMConnection *arg, char *nonce)
  2158. {
  2159. SSMStatus rv = SSM_FAILURE;
  2160. SSMControlConnection *ctrl = (SSMControlConnection *) arg;
  2161. if (!SSM_IsAKindOf(SSMRESOURCE(ctrl), SSM_RESTYPE_CONTROL_CONNECTION))
  2162. goto loser;
  2163. /* Compare the nonce against what we have. */
  2164. if (!strncmp(ctrl->m_nonce, nonce, strlen(ctrl->m_nonce)))
  2165. rv = SSM_SUCCESS;
  2166.  loser:
  2167. return rv;
  2168. }
  2169. SSMStatus 
  2170. SSMControlConnection_SendUIEvent(SSMControlConnection *conn,
  2171.                                  char *command,
  2172.                                  char *baseRef,
  2173.                                  SSMResource *target, /* can pass NULL */
  2174.                                  char *otherParams /* can pass NULL */,
  2175.                                  CMTItem * clientContext /* can pass NULL */,
  2176.                                  PRBool isModal)
  2177. {
  2178.     char *url;
  2179.     SECItem event;
  2180.     SSMStatus rv = PR_SUCCESS;
  2181.     PRUint32 width, height;
  2182.     SSMResourceID rid = 0;
  2183.     UIEvent reply;
  2184.     if (!conn->m_doesUI) {
  2185.         return SSM_FAILURE;
  2186.     }
  2187.     if ((!target) && (conn))
  2188.         target = &conn->super.super;
  2189.     PR_ASSERT(target);
  2190.     if (target)
  2191.         rid = ((SSMResource *) target)->m_id;
  2192.     /* Construct a URL out of the parameters we've been given. */
  2193.     rv = SSM_GenerateURL(conn, command, baseRef, target, otherParams,
  2194.                          &width, &height, &url);
  2195.     if (rv != PR_SUCCESS) {
  2196.       goto loser;
  2197.     }
  2198.     /* Generate the actual message to send to the client. */
  2199.     reply.resourceID = rid;
  2200.     reply.width = width;
  2201.     reply.height = height;
  2202. reply.isModal = isModal;
  2203.     reply.url = url;
  2204.     if (clientContext) {
  2205.         reply.clientContext = *clientContext;
  2206.     } else {
  2207.         reply.clientContext.len = 0;
  2208.         reply.clientContext.data = NULL;
  2209.     }
  2210.     if (CMT_EncodeMessage(UIEventTemplate, (CMTItem*)&event, &reply) != CMTSuccess) {
  2211.         goto loser;
  2212.     }
  2213.     /* Post the message on the outgoing control channel. */
  2214.     rv = SSM_SendQMessage(conn->m_controlOutQ, SSM_PRIORITY_NORMAL, 
  2215.                           SSM_EVENT_MESSAGE | SSM_UI_EVENT,
  2216.                           (int) event.len, (char *) event.data, PR_FALSE);
  2217.     if (rv != PR_SUCCESS) goto loser;
  2218.     goto done;
  2219.  loser:
  2220.     if (rv == PR_SUCCESS) rv = PR_FAILURE;
  2221.  done:
  2222.     PR_FREEIF(event.data);
  2223.     return rv;
  2224. }
  2225. static SSMStatus SSMControlConnection_SavePref(SSMControlConnection* ctrl,
  2226.                                                char* key, char* value, 
  2227.                                                PRIntn type)
  2228. {
  2229.     SSMStatus rv = PR_FAILURE;
  2230.     SetPrefElement item = {0};
  2231.     SetPrefListMessage request = {0};
  2232.     CMTItem message = {0};
  2233.     /* pack the request */
  2234.     item.key = PL_strdup(key);
  2235.     item.type = type;
  2236.     if (value != NULL) {
  2237.         item.value = PL_strdup(value);
  2238.     }
  2239.     else if (type == STRING_PREF) {
  2240.         item.value = NULL; /* this is legal */
  2241.     }
  2242.     else {
  2243.         goto loser;
  2244.     }
  2245.      
  2246.     request.length = 1;
  2247.     request.list = &item;
  2248.     message.type = SSM_EVENT_MESSAGE | SSM_SAVE_PREF_EVENT;
  2249.     if (CMT_EncodeMessage(SetPrefListMessageTemplate, &message, 
  2250.                           &request) != CMTSuccess) {
  2251.         goto loser;
  2252.     }
  2253.     /* send the message through the control out queue */
  2254.     SSM_SendQMessage(ctrl->m_controlOutQ, SSM_PRIORITY_NORMAL,
  2255.                      message.type, message.len, (char*)message.data,
  2256.                      PR_TRUE);
  2257.     rv = PR_SUCCESS;
  2258. loser:
  2259.     PR_FREEIF(item.key);
  2260.     PR_FREEIF(item.value);
  2261.     return rv;
  2262. }
  2263. SSMStatus SSMControlConnection_SaveStringPref(SSMControlConnection* ctrl,
  2264.                                               char* key, char* value)
  2265. {
  2266.     SSMStatus rv = PR_SUCCESS;
  2267.     if ((ctrl == NULL) || (ctrl->m_prefs == NULL) || (key == NULL)) {
  2268.         return PR_FAILURE;
  2269.     }
  2270.     if (PREF_StringPrefChanged(ctrl->m_prefs, key, value)) {
  2271.         rv = PREF_SetStringPref(ctrl->m_prefs, key, value);
  2272.         if (rv != PR_SUCCESS) {
  2273.             return rv;
  2274.         }
  2275.         rv = SSMControlConnection_SavePref(ctrl, key, value, STRING_PREF);
  2276.     }
  2277.     return rv;
  2278. }
  2279. SSMStatus SSMControlConnection_SaveBoolPref(SSMControlConnection* ctrl,
  2280.                                             char* key, PRBool value)
  2281. {
  2282.     SSMStatus rv = PR_SUCCESS;
  2283.     if ((ctrl == NULL) || (ctrl->m_prefs == NULL) || (key == NULL)) {
  2284.         return PR_FAILURE;
  2285.     }
  2286.     if (PREF_BoolPrefChanged(ctrl->m_prefs, key, value)) {
  2287.         rv = PREF_SetBoolPref(ctrl->m_prefs, key, value);
  2288.         if (rv != PR_SUCCESS) {
  2289.             return rv;
  2290.         }
  2291.         if (value) {
  2292.             rv = SSMControlConnection_SavePref(ctrl, key, "true", BOOL_PREF);
  2293.         }
  2294.         else {
  2295.             rv = SSMControlConnection_SavePref(ctrl, key, "false", BOOL_PREF);
  2296.         }
  2297.     }
  2298.     return rv;
  2299. }
  2300. SSMStatus SSMControlConnection_SaveIntPref(SSMControlConnection* ctrl,
  2301.                                            char* key, PRIntn value)
  2302. {
  2303.     SSMStatus rv = PR_SUCCESS;
  2304.     if ((ctrl == NULL) || (ctrl->m_prefs == NULL) || (key == NULL)) {
  2305.         return PR_FAILURE;
  2306.     }
  2307.     if (PREF_IntPrefChanged(ctrl->m_prefs, key, value)) {
  2308.         char* tmp = NULL;
  2309.         rv = PREF_SetIntPref(ctrl->m_prefs, key, value);
  2310.         if (rv != PR_SUCCESS) {
  2311.             return rv;
  2312.         }
  2313.         tmp = PR_smprintf("%d", value);
  2314.         rv = SSMControlConnection_SavePref(ctrl, key, tmp, INT_PREF);
  2315.         PR_FREEIF(tmp);
  2316.     }
  2317.     return rv;
  2318. }
  2319. extern SSMControlConnection * SSM_PARENT_CONN (SSMConnection * x);
  2320. void SSM_LockPasswdTable(SSMConnection * conn)
  2321. {
  2322.     SSMControlConnection * control = SSM_PARENT_CONN(conn);
  2323.     PR_EnterMonitor(control->m_passwdLock);
  2324. }
  2325. SSMStatus SSM_UnlockPasswdTable(SSMConnection * conn)
  2326.     SSMControlConnection * control = SSM_PARENT_CONN(conn);
  2327.     return PR_ExitMonitor(control->m_passwdLock);
  2328. }
  2329. SSMStatus SSM_WaitPasswdTable(SSMConnection * conn)
  2330. {
  2331.     SSMControlConnection * control = SSM_PARENT_CONN(conn);
  2332.     return  PR_Wait(control->m_passwdLock, SSM_PASSWORD_WAIT_TIME);
  2333. }
  2334. SSMStatus SSM_NotifyAllPasswdTable(SSMConnection * conn)
  2335. {
  2336.     SSMControlConnection * control = SSM_PARENT_CONN(conn);
  2337.     return PR_NotifyAll(control->m_passwdLock);
  2338. }
  2339. /* Find the next unallocated resource ID */
  2340. SSMResourceID
  2341. SSMControlConnection_GenerateResourceID(SSMControlConnection *conn)
  2342. {
  2343.     void *junk;
  2344.     SSMResourceID rid;
  2345.     rid = conn->m_lastRID;
  2346.     do {
  2347.         rid++;
  2348.         if(rid > SSM_MAX_RID)
  2349.             rid = SSM_BASE_RID;
  2350.         SSM_HashFind(conn->m_resourceDB, rid, &junk);
  2351.     } while(junk != NULL);
  2352.     conn->m_lastRID = rid;
  2353.     return rid;
  2354. }
  2355. SSMStatus 
  2356. SSM_GetControlConnection(SSMResourceID rid, SSMControlConnection **res)
  2357. {
  2358.     return SSM_HashFind(ctrlConnections, rid, (void **)res);
  2359. }
  2360. SSMStatus 
  2361. SSMControlConnection_AddResource(SSMResource *res, SSMResourceID rid)
  2362. {
  2363.     SSMStatus rv;
  2364.     rv = SSM_HashInsert(res->m_connection->m_resourceDB, rid, res);
  2365.     if (rv != PR_SUCCESS) 
  2366.         return rv;
  2367.     rv = SSM_HashInsert(res->m_connection->m_resourceIdDB, (SSMHashKey)res, 
  2368.                         (void *)rid);
  2369.     return rv;
  2370. }
  2371. SSMStatus 
  2372. SSMControlConnection_GetResource(SSMControlConnection * connection,
  2373.                       SSMResourceID rid, SSMResource **res)
  2374. {
  2375.     SSMStatus rv = PR_FAILURE;
  2376.     if (connection->m_resourceDB) {
  2377.         rv = SSM_HashFind(connection->m_resourceDB, rid, (void **) res);
  2378.         if (*res)
  2379.             SSM_GetResourceReference(*res);
  2380.     }
  2381.     return rv;
  2382. }
  2383. SSMStatus 
  2384. SSMControlConnection_GetGlobalResourceID(SSMControlConnection * connection,
  2385.                       SSMResource * res, SSMResourceID *rid)
  2386. {
  2387.     return SSM_HashFind(connection->m_resourceIdDB, (SSMHashKey)res, 
  2388.                         (void **) rid);
  2389. }
  2390. SSMStatus 
  2391. SSMControlConnection_FormSubmitHandler(SSMResource * res, HTTPRequest * req)
  2392. {
  2393.     SSMStatus rv;
  2394.     char* tmpStr = NULL;
  2395.     SSMSSLDataConnection* conn;
  2396.         
  2397.     conn = (SSMSSLDataConnection*)res;
  2398.     /* make sure you got the right baseRef */
  2399.     rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
  2400.     if (rv != SSM_SUCCESS ||
  2401.         PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
  2402.         goto loser;
  2403.     }
  2404.     rv = SSM_HTTPCloseAndSleep(req);
  2405.     if (rv != SSM_SUCCESS)
  2406.         SSM_DEBUG("Errors closing window in FormSubmitHandler: %dn", rv);
  2407.  
  2408.     
  2409.     if (!res->m_formName)
  2410.         goto loser;
  2411.     if (PL_strcmp(res->m_formName, "choose_cert_by_usage") == 0)
  2412.         rv = SSM_ChooseCertUsageHandler(req);
  2413.     else if (PL_strcmp(res->m_formName, "set_db_password") == 0)
  2414.         rv = SSM_SetDBPasswordHandler(req);
  2415.     else /* other cases where this could be used will go here */
  2416.         goto loser;
  2417.     return rv;
  2418.  loser:
  2419.     SSM_DEBUG("FormSubmit handler is called with no valid formNamen");
  2420.     SSM_NotifyUIEvent(res);
  2421.     return SSM_FAILURE;
  2422. }
  2423. typedef struct DefaultCertLookupArgStr {
  2424.     char *defaultEmailCert;
  2425.     SSMControlConnection *conn;
  2426.     PRBool isOwnThread;
  2427.     CERTCertificate *cert;
  2428.     SSMStatus rv;
  2429. } DefaultCertLookupArg;
  2430. static void
  2431. ssm_lookup_default_cert(void *arg) 
  2432. {
  2433.     DefaultCertLookupArg *lookupArg = (DefaultCertLookupArg*)arg;
  2434.     char *defaultEmailCert = lookupArg->defaultEmailCert;
  2435.     SSMControlConnection *conn = lookupArg->conn;
  2436.     CERTCertificate *tmp;
  2437.     CERTCertificate *cert = lookupArg->cert;
  2438.     
  2439. #ifdef DEBUG
  2440.     if (lookupArg->isOwnThread) {
  2441.         SSM_RegisterThread("email cert lookup", NULL);
  2442.     }
  2443. #endif
  2444.     SSM_DEBUG("Looking up the cert %s", defaultEmailCert);
  2445.     tmp = CERT_FindUserCertByUsage(conn->m_certdb, 
  2446.                                    defaultEmailCert,
  2447.                                    certUsageEmailSigner,
  2448.                                    PR_FALSE,
  2449.                                    conn);
  2450.     if (tmp == NULL) {
  2451.         lookupArg->rv =
  2452.             SSMControlConnection_SaveStringPref(conn, 
  2453.                                                 "security.default_mail_cert",
  2454.                                                 cert->nickname);
  2455.     } else {
  2456.         CERT_DestroyCertificate(tmp);
  2457.         lookupArg->rv = SSM_FAILURE;
  2458.     }
  2459.     SSM_FreeResource(&conn->super.super);
  2460.     if (lookupArg->isOwnThread) {
  2461.         PR_Free(arg);
  2462.     }
  2463.     CERT_DestroyCertificate(cert);
  2464. }
  2465. SSMStatus
  2466. SSM_UseAsDefaultEmailIfNoneSet(SSMControlConnection *conn, 
  2467.                                CERTCertificate *cert, 
  2468.                                PRBool onFrontEndThread)
  2469. {
  2470.     SSMStatus rv = SSM_FAILURE;
  2471.     char *defaultEmailCert;
  2472.     if (cert->emailAddr) {
  2473.         rv = PREF_GetStringPref(conn->m_prefs, "security.default_mail_cert", 
  2474.                                 &defaultEmailCert);
  2475.         if (rv != SSM_SUCCESS || defaultEmailCert == NULL) {
  2476.             rv = SSMControlConnection_SaveStringPref(conn, 
  2477.                                                   "security.default_mail_cert",
  2478.                                                   cert->nickname);
  2479.         } else {
  2480.             DefaultCertLookupArg *arg = SSM_ZNEW(DefaultCertLookupArg);
  2481.             SSM_GetResourceReference(&conn->super.super);
  2482.             PR_ASSERT(arg);
  2483.             if (arg == NULL) {
  2484.                 goto loser;
  2485.             }
  2486.             arg->defaultEmailCert = defaultEmailCert;
  2487.             arg->conn = conn;
  2488.             arg->cert = CERT_DupCertificate(cert);
  2489.             if (strchr(defaultEmailCert, ':') != NULL && onFrontEndThread) {
  2490.                 /* ARGH!! The default email cert is on an external token
  2491.                  * this may require an authentication event, so in order
  2492.                  * to prevent dead-locking the front end thread, we'll
  2493.                  * do the look up on a separate thread.
  2494.                  */
  2495.                 arg->isOwnThread = PR_TRUE;
  2496.                 SSM_CreateAndRegisterThread(PR_USER_THREAD, ssm_lookup_default_cert, 
  2497.                                 (void *)arg,
  2498.                                 PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
  2499.                                 PR_UNJOINABLE_THREAD, 0);
  2500.                 /*
  2501.                  * We don't know if the cert was made default, so we'll return
  2502.                  * failure in this case.
  2503.                  */
  2504.                 rv = SSM_FAILURE;
  2505.             } else {
  2506.                 /*
  2507.                  * It's in the internal database, so just lookup
  2508.                  * on this same thread.
  2509.                  */
  2510.                 arg->isOwnThread = PR_FALSE;
  2511.                 ssm_lookup_default_cert((void*)arg);
  2512.                 rv = arg->rv;
  2513.                 PR_Free(arg);
  2514.             }
  2515.         }
  2516.     }
  2517.     return rv;
  2518.  loser:
  2519.     return SSM_FAILURE;
  2520. }