gecko-dev/security/psm/server/frontend.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;
}