зеркало из https://github.com/mozilla/gecko-dev.git
245 строки
7.6 KiB
C
245 строки
7.6 KiB
C
/*
|
|
* 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 "hashconn.h"
|
|
#include "servimpl.h"
|
|
#include "newproto.h"
|
|
#include "messages.h"
|
|
#include "serv.h"
|
|
#include "advisor.h"
|
|
#include "ssmerrs.h"
|
|
|
|
#ifdef TIMEBOMB
|
|
#include "timebomb.h"
|
|
#include "timebomb.c"
|
|
#endif
|
|
|
|
/* 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)
|
|
|
|
extern long ssm_ctrl_count;
|
|
|
|
|
|
/* This thread reads the control connection socket and
|
|
* forwards messages to appropriate queues.
|
|
*/
|
|
|
|
void SSM_FrontEndThread(void * arg)
|
|
{
|
|
PRFileDesc * socket = NULL;
|
|
SECItem * message = NULL;
|
|
SSMControlConnection * control = NULL;
|
|
PRIntn read;
|
|
SSMStatus rv = PR_SUCCESS;
|
|
char * passwd = NULL;
|
|
char * tmp;
|
|
PasswordReply reply;
|
|
CMTMessageHeader header;
|
|
|
|
control = (SSMControlConnection *)arg;
|
|
SSM_RegisterNewThread("ctrl frontend", (SSMResource *) arg);
|
|
SSM_DEBUG("initializing.\n");
|
|
if (!control || !control->m_socket)
|
|
{
|
|
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
|
|
goto loser;
|
|
}
|
|
control->m_frontEndThread = PR_GetCurrentThread();
|
|
socket = control->m_socket;
|
|
|
|
#ifdef TIMEBOMB
|
|
if (SSMTimeBombExpired)
|
|
SSM_CartmanHasExpired(control);
|
|
#endif
|
|
|
|
/* start a write thread for this connection */
|
|
SSM_DEBUG("creating accompanying write thread.\n");
|
|
control->m_writeThread = SSM_CreateThread(SSMRESOURCE(control),
|
|
SSM_WriteCtrlThread);
|
|
if (!control->m_writeThread)
|
|
{
|
|
rv = PR_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
/* initialize connection outgoing queue */
|
|
SSM_DEBUG("Initialize OUT queue for control connection\n");
|
|
SSM_SendQMessage(control->m_controlOutQ,
|
|
SSM_PRIORITY_NORMAL,
|
|
SSM_DATA_PROVIDER_OPEN, 0, NULL,
|
|
PR_TRUE);
|
|
|
|
while ((SSMRESOURCE(control)->m_status == PR_SUCCESS)
|
|
&& (rv == PR_SUCCESS))
|
|
{
|
|
/* read and process data here
|
|
*/
|
|
|
|
SSM_DEBUG("waiting for new message from socket.\n");
|
|
read = SSM_ReadThisMany(socket, &header, sizeof(CMTMessageHeader));
|
|
if (read != sizeof(CMTMessageHeader))
|
|
{
|
|
SSM_DEBUG("Bytes read (%ld) != bytes expected (%ld). (hdr)\n",
|
|
(long) read,
|
|
(long) sizeof(CMTMessageHeader));
|
|
rv = PR_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
message = SSM_ConstructMessage(PR_ntohl(header.len));
|
|
if (!message)
|
|
{
|
|
SSM_DEBUG("Missing message.\n");
|
|
rv = PR_OUT_OF_MEMORY_ERROR;
|
|
goto loser;
|
|
}
|
|
message->type = (SECItemType) PR_ntohl(header.type);
|
|
|
|
/* Read the message body */
|
|
SSM_DEBUG("reading %ld more from socket.\n", message->len);
|
|
read = SSM_ReadThisMany(socket, (void *)message->data, message->len);
|
|
if ((unsigned int) read != message->len)
|
|
{
|
|
SSM_DEBUG("Bytes read (%ld) != bytes expected (%ld). (msg)\n",
|
|
(long) read,
|
|
(long) message->len);
|
|
rv = PR_GetError();
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
/*
|
|
* Message successfully received, now file it to appropriate queue
|
|
*//*
|
|
if ((message->type & SSM_CATEGORY_MASK) == SSM_EVENT_MESSAGE) {
|
|
*/
|
|
switch (message->type &SSM_CATEGORY_MASK) {
|
|
case SSM_EVENT_MESSAGE:
|
|
switch (message->type & SSM_TYPE_MASK) {
|
|
case SSM_AUTH_EVENT:
|
|
/* deal with authentication message */
|
|
|
|
/* Decode the the password reply message */
|
|
if (CMT_DecodeMessage(PasswordReplyTemplate, &reply, (CMTItem*)message) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* Get the lock for the password hash table */
|
|
SSM_LockPasswdTable((SSMConnection *) control);
|
|
rv = SSM_HashRemove(control->m_passwdTable, reply.tokenID, (void **)&tmp);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("Passwd request for token %d hasn't been registered.\n",
|
|
reply.tokenID);
|
|
SSM_DEBUG("Drop the message, continue waiting...\n");
|
|
PR_Free(passwd);
|
|
passwd = NULL;
|
|
goto done_auth;
|
|
}
|
|
if (reply.result != 0) {
|
|
SSM_DEBUG("Error getting password %d.\n", reply.result);
|
|
reply.passwd = (char*)SSM_CANCEL_PASSWORD;
|
|
}
|
|
|
|
if (!reply.passwd) {
|
|
/* user entered a zero length password, which is valid */
|
|
reply.passwd = "";
|
|
}
|
|
|
|
rv = SSM_HashInsert(control->m_passwdTable, reply.tokenID,
|
|
reply.passwd);
|
|
if (rv != PR_SUCCESS)
|
|
SSM_DEBUG("%ld: can't enter passwd in hash table.\n", control);
|
|
|
|
passwd = NULL; /* passwd is now pointed to the hash table entry */
|
|
/* notify all waiting threads that the password has arrived */
|
|
SSM_DEBUG("%ld : notify password table that passwd is available\n",
|
|
control);
|
|
rv = SSM_NotifyAllPasswdTable((SSMConnection *)control);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("Error on NotifyAll on the password table:%d.\n",
|
|
PR_GetError());
|
|
goto done_auth;
|
|
}
|
|
done_auth:
|
|
/* We are done, release the lock */
|
|
SSM_UnlockPasswdTable((SSMConnection *)control);
|
|
break;
|
|
case SSM_FILE_PATH_EVENT:
|
|
SSM_HandleFilePathReply(control, message);
|
|
break;
|
|
case SSM_PROMPT_EVENT:
|
|
SSM_HandleUserPromptReply(control, message);
|
|
break;
|
|
#if 0
|
|
case SSM_GET_JAVA_PRINCIPALS_EVENT:
|
|
SSM_HandleGetJavaPrincipalsReply(control, message);
|
|
break;
|
|
#endif
|
|
case SSM_MISC_EVENT:
|
|
if ((message->type & SSM_SUBTYPE_MASK) == SSM_MISC_PUT_RNG_DATA)
|
|
{
|
|
/* Got fodder for the RNG. Seed it. */
|
|
SSM_DEBUG("Got %ld bytes of RNG seed data.\n", message->len);
|
|
rv = RNG_RandomUpdate(message->data, message->len)
|
|
== SECSuccess ? SSM_SUCCESS : SSM_FAILURE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
/* process the message */
|
|
rv = SSMControlConnection_ProcessMessage(control, message);
|
|
}
|
|
|
|
/* Free the message */
|
|
SSM_FreeMessage(message);
|
|
message = NULL;
|
|
} /* end of the read-socket loop */
|
|
loser:
|
|
SSM_DEBUG("shutting down, status = %ld.\n", rv);
|
|
if (control)
|
|
{
|
|
SSM_ShutdownResource(SSMRESOURCE(control), rv);
|
|
SSM_FreeResource(SSMRESOURCE(control));
|
|
}
|
|
return;
|
|
}
|
|
|