ctrlconn.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,170 行 · 第 1/5 页
C
2,170 行
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "ctrlconn.h"#include "dataconn.h"#include "sslconn.h"#include "p7cinfo.h"#include "p7econn.h"#include "p7dconn.h"#include "secmime.h"#include "hashconn.h"#include "certres.h"#include "cert.h"#include "certdb.h"#include "cdbhdl.h"#include "servimpl.h"#include "newproto.h"#include "messages.h"#include "serv.h"#include "ssmerrs.h"#include "minihttp.h"#include "secmod.h"#include "kgenctxt.h"#include "advisor.h"#include "processmsg.h"#include "signtextres.h"#include "p12res.h"#include "p12plcy.h"#include "secmime.h"#include "ciferfam.h"#include "profile.h"#include "prefs.h"#include "ocsp.h"#include "msgthread.h"#ifdef XP_MAC#include "macshell.h"#endif/* * The structure passed to get an attribute for the control connection, * which may require a password prompt. */typedef struct GetAttrArgStr { SSMResource *res; SSMAttributeID attrID; SSMResourceAttrType attrType;} GetAttrArg;static SSMStatusssmcontrolconnection_encodegetattr_reply(SECItem *msg, SSMStatus rv, SSMAttributeValue *value, SSMResourceAttrType attrType);/* The ONLY reason why we can use these macros for both control and data connections is that they inherit from the same superclass. Do NOT try this at home. */#define SSMCONNECTION(c) (&(c)->super)#define SSMRESOURCE(c) (&(c)->super.super)/* Special resource id values */#define SSM_BASE_RID 0x00000003#define SSM_MAX_RID 0x0FFFFFFFstatic long ssm_ctrl_count = 0;static SSMResourceID ssm_next_ctrlrid = SSM_MAX_RID;static char * gUserDir = NULL;static PRMonitor *policySetLock = NULL;static PRBool policySet = PR_FALSE;SSMStatus SSM_InitPolicyHandler(void){ policySetLock = PR_NewMonitor(); if (policySetLock == NULL) { return PR_FAILURE; } return PR_SUCCESS;}#ifdef TIMEBOMB#include "timebomb.h"PRBool SSMTimeBombExpired = PR_FALSE;#endifSSMStatus SSMControlConnection_Create(void *arg, SSMControlConnection * connection, SSMResource **res){ SSMStatus rv = PR_SUCCESS; SSMControlConnection *conn; *res = NULL; /* in case we fail */ conn = (SSMControlConnection *) PR_CALLOC(sizeof(SSMControlConnection)); if (!conn) goto loser; SSMRESOURCE(conn)->m_connection = conn; rv = SSMControlConnection_Init(conn, SSM_RESTYPE_CONTROL_CONNECTION, (PRFileDesc *) arg); if (rv != PR_SUCCESS) goto loser; SSMControlConnection_Invariant(conn); ssm_ctrl_count++; SSM_DEBUG("Control count is now %ld.\n", ssm_ctrl_count); *res = SSMRESOURCE(conn); rv = SSM_HashInsert(ctrlConnections, (SSMHashKey)(*res)->m_id, (void *)*res); if (rv != PR_SUCCESS) goto loser; return PR_SUCCESS; loser: if (rv == PR_SUCCESS) rv = PR_FAILURE; if (conn) { SSM_ShutdownResource(SSMRESOURCE(conn), rv); /* force destroy */ SSM_FreeResource(SSMRESOURCE(conn)); } return rv;}#ifdef XP_MACinttoascii(char c){ return (int) c;}#endifSSMStatus SSMControlConnection_GenerateNonce(SSMControlConnection *conn){ SSMStatus rv = PR_FAILURE; SECStatus srv; char* buf = NULL; char* n = NULL; const int NONCE_SIZE = 8; int i; conn->m_nonce = NULL; /* in case of failure */ buf = (char*)PR_CALLOC(NONCE_SIZE); if (buf == NULL) { goto loser; } srv = RNG_GenerateGlobalRandomBytes(buf, NONCE_SIZE); if (srv != SECSuccess) { goto loser; } n = PL_strdup("nonce"); for (i = 0; i < NONCE_SIZE; i++) { n = PR_sprintf_append(n, "%d", (int)toascii(buf[i])); if (n == NULL) { goto loser; } } conn->m_nonce = n; rv = PR_SUCCESS;loser: if (buf != NULL) { PR_Free(buf); } return rv;}SSMStatus SSMControlConnection_Init(SSMControlConnection *conn, SSMResourceType type, PRFileDesc *socket){ SSMStatus rv = PR_SUCCESS; PRBool locked = PR_FALSE; PRNetAddr dataAddr; rv = SSM_HashCreate(&conn->m_resourceDB); if (rv != PR_SUCCESS || !conn->m_resourceDB) goto loser; /* We need to see if there are any other control connections already * established. If there are, then we need to use the next RID * as ours so the correct control connection is found for UI events. * Before all control connections would get the RID of 3, and that would * cause problems. */ conn->m_lastRID = ssm_next_ctrlrid; conn->m_secAdvisorList = NULL; rv = SSM_HashCreate(&conn->m_resourceIdDB); if (rv != PR_SUCCESS || conn->m_resourceIdDB == NULL) goto loser; rv = SSMConnection_Init(NULL, &conn->super, type); if (rv != PR_SUCCESS) goto loser; ssm_next_ctrlrid = conn->super.super.m_id; SSM_LockResource(SSMRESOURCE(conn)); locked = PR_TRUE; /* Current version. Allow this to drop when the Hello request comes in. */ conn->m_version = SSM_PROTOCOL_VERSION; /* Generate a nonce. */ rv = SSMControlConnection_GenerateNonce(conn); if (rv != PR_SUCCESS) goto loser; SSM_DEBUG("Generated nonce of `%s'.\n",conn->m_nonce); conn->m_controlOutQ = SSM_NewCollection(); if (!conn->m_controlOutQ) goto loser; conn->m_socket = socket; /* Create the data socket */ conn->m_dataSocket = SSM_OpenPort(); if (!conn->m_dataSocket) { goto loser; } /* Get the data port */ rv = PR_GetSockName(conn->m_dataSocket, &dataAddr); if (rv != PR_SUCCESS) { goto loser; } conn->m_dataPort = PR_ntohs(dataAddr.inet.port); SSMCONNECTION(conn)->m_auth_func = SSMControlConnection_Authenticate; /* Creat password handling stuff:temporary and long-term password tables */ rv = SSM_HashCreate(&conn->m_passwdTable); if (rv != PR_SUCCESS || !conn->m_passwdTable) goto loser; conn->m_passwdLock = PR_NewMonitor(); if (!conn->m_passwdLock) goto loser; conn->m_waiting = 0; rv = SSM_HashCreate(&conn->m_encrPasswdTable); if (rv != PR_SUCCESS || !conn->m_encrPasswdTable) goto loser; conn->m_encrPasswdLock = PR_NewMonitor(); if (!conn->m_encrPasswdLock) goto loser; /* database for cert look-up by cert ID */ rv = SSM_HashCreate(&conn->m_certIdDB); if (rv != PR_SUCCESS || !conn->m_certIdDB) goto loser; conn->m_prefs = PREF_NewPrefs(); if (conn->m_prefs == NULL) { goto loser; } conn->m_doesUI = PR_FALSE; /* Spin threads after we set the shutdown function. */ SSM_DEBUG("spawning read msg thread for %lx.\n", (long) conn);#ifdef ALLOW_STANDALONE if (!standalone) {#endif /* Get reference for front end thread */ SSM_GetResourceReference(SSMRESOURCE(conn)); conn->m_frontEndThread = SSM_CreateThread(SSMRESOURCE(conn), SSM_FrontEndThread); if (conn->m_frontEndThread == NULL) goto loser;#ifdef ALLOW_STANDALONE }#endif SSM_UnlockResource(SSMRESOURCE(conn)); return PR_SUCCESS; loser: if (rv == PR_SUCCESS) rv = PR_FAILURE; if (locked) SSM_UnlockResource(SSMRESOURCE(conn)); if (socket) { PR_Close(socket); /* close this */ conn->m_socket = NULL; } if (conn->m_passwdLock) PR_DestroyMonitor(conn->m_passwdLock); if (conn->m_passwdTable) SSM_HashDestroy(conn->m_passwdTable); if (conn->m_encrPasswdLock) PR_DestroyMonitor(conn->m_encrPasswdLock); if (conn->m_encrPasswdTable) SSM_HashDestroy(conn->m_encrPasswdTable); if (conn->m_certIdDB) SSM_HashDestroy(conn->m_certIdDB); if (conn->m_prefs) PREF_ClosePrefs(conn->m_prefs); if (conn->m_resourceDB) SSM_HashDestroy(conn->m_resourceDB); if (conn->m_resourceIdDB) SSM_HashDestroy(conn->m_resourceIdDB); return rv;}SSMStatus SSMControlConnection_Shutdown(SSMResource *arg, SSMStatus status){ SSMStatus rv, trv; /* rv propagates superclass shutdown */ PRThread *closer = PR_GetCurrentThread(); SSMControlConnection *conn = (SSMControlConnection *) arg; SSMControlConnection_Invariant(conn); #ifdef TIMEBOMB if (SSMTimeBombExpired) return;#endif SSM_LockResource(arg); /* if the thread calling this routine is a service thread, clear its place in the connection object. this is a prelude to the wakeup call just below. */ arg->m_threadCount--; /* decrement if service thread */ if (closer == conn->m_writeThread) conn->m_writeThread = NULL; if (closer == conn->m_frontEndThread) conn->m_frontEndThread = NULL; else arg->m_threadCount++; /* not a service thread, restore thread count */ /* shut down our base class. */ rv = SSMConnection_Shutdown(arg, status); /* wake up threads if this is the first time throwing an error */ if ((arg->m_status != PR_SUCCESS) && (rv != SSM_ERR_ALREADY_SHUT_DOWN)) { SSM_DEBUG("First time aborting control connection.\n"); SSM_DEBUG("Posting shutdown msgs to queues.\n"); /* close queues that our threads may be listening on */ if (conn->m_controlOutQ) SSM_SendQMessage(conn->m_controlOutQ, SSM_PRIORITY_SHUTDOWN, SSM_DATA_PROVIDER_SHUTDOWN, 0, NULL, PR_TRUE); if (conn->m_writeThread) PR_Interrupt(conn->m_writeThread); if (conn->m_frontEndThread) PR_Interrupt(conn->m_frontEndThread); } /* If the front end thread is down, close the client socket */ if ((!conn->m_frontEndThread) && (conn->m_socket)) { /* Got a socket but nothing to work on it with. Close the socket. */#ifndef XP_UNIX /* Don't close socket with linger on UNIX since the * control socket on UNIX is a UNIX domain socket. */ SSM_DEBUG("Closing control socket with linger.\n"); trv = SSM_CloseSocketWithLinger(conn->m_socket);#else SSM_DEBUG("Closing control socket.\n"); trv = PR_Close(conn->m_socket);#endif PR_ASSERT(trv == PR_SUCCESS); conn->m_socket = NULL; /* don't try closing more than once */ SSM_DEBUG("Closed control socket (rv == %d).\n",rv); } if (SSMRESOURCE(conn)->m_threadCount == 0) { /* All service threads are down. Shut down NSS. */ ssm_ShutdownNSS(conn); } SSM_UnlockResource(arg); return rv;}SSMStatus SSMControlConnection_Destroy(SSMResource *res, PRBool doFree){ SSMControlConnection *conn = (SSMControlConnection *) res; void *value; /* Drain and destroy the queue. */ if (conn->m_controlOutQ) ssm_DrainAndDestroyQueue(&(conn->m_controlOutQ)); /* Free our fields. */ PR_FREEIF(conn->m_nonce); PR_FREEIF(conn->m_profileName); PR_FREEIF(conn->m_dirRoot);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?