⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dataconn.c

📁 安全开发库。含客户端建立ssl连接、签名、证书验证、证书发布和撤销等。编译用到nss
💻 C
字号:
/* -*- 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 "connect.h"#include "dataconn.h"#include "ctrlconn.h"#include "servimpl.h"#include "serv.h"#include "ssmerrs.h"#define SSMCONNECTION(p) (&(p)->super)#define SSMRESOURCE(p) (&(p)->super.super)/* How many milliseconds to wait for client input */#define SSM_READCLIENT_POKE_INTERVAL 30000SSMStatus SSMDataConnection_Create(void *arg, SSMControlConnection * connection,                                  SSMResource **res){    SSMStatus rv = PR_SUCCESS;    SSMDataConnection *conn;    *res = NULL; /* in case we fail */        conn = (SSMDataConnection *) PR_CALLOC(sizeof(SSMDataConnection));    if (!conn) goto loser;    rv = SSMDataConnection_Init(conn, (SSMControlConnection *) arg,                             SSM_RESTYPE_DATA_CONNECTION);    if (rv != PR_SUCCESS) goto loser;    SSMDataConnection_Invariant(conn);        *res = SSMRESOURCE(conn);    return PR_SUCCESS; loser:    if (rv == PR_SUCCESS) rv = PR_FAILURE;    if (conn)     {		SSM_ShutdownResource(SSMRESOURCE(conn), rv);        SSM_FreeResource(SSMRESOURCE(conn));    }            return rv;}SSMStatus SSMDataConnection_Init(SSMDataConnection *conn,                                 SSMControlConnection *parent,                                 SSMResourceType type){    SSMStatus rv = PR_SUCCESS;    SSMResourceType parentType = RESOURCE_CLASS(parent);    PR_ASSERT(parent != NULL);    PR_ASSERT((parentType == SSM_RESTYPE_CONTROL_CONNECTION) || (parentType == SSM_RESTYPE_CONNECTION));    if (!parent) goto loser;    rv = SSMConnection_Init(parent, SSMCONNECTION(conn), type);    if (rv != PR_SUCCESS) goto loser;    /* Initialize data shutdown queue. */    conn->m_shutdownQ = SSM_NewCollection();    if (conn->m_shutdownQ == NULL) {        goto loser;    }	/* Hang our shutdown func. */	SSMCONNECTION(conn)->m_auth_func = SSMDataConnection_Authenticate;    return PR_SUCCESS; loser:    if (rv == PR_SUCCESS) rv = PR_FAILURE;    return rv;}SSMStatus SSMDataConnection_Destroy(SSMResource *res, PRBool doFree){    SSMDataConnection *conn = (SSMDataConnection *) res;    /* We should be shut down. */    PR_ASSERT(res->m_threadCount == 0);    /* Drain and destroy the queue. */    if (conn->m_shutdownQ) {        ssm_DrainAndDestroyQueue(&(conn->m_shutdownQ));    }    /* Destroy superclass fields. */    SSMConnection_Destroy(&(conn->super.super), PR_FALSE);    /* Free the connection object if asked. */    if (doFree)        PR_DELETE(conn);    return PR_SUCCESS;}voidSSMDataConnection_Invariant(SSMDataConnection *conn){    if (conn)    {        SSMConnection_Invariant(&conn->super);        SSM_LockResource(SSMRESOURCE(conn));        PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), SSM_RESTYPE_DATA_CONNECTION));        PR_ASSERT(conn->m_shutdownQ != NULL);        SSM_UnlockResource(SSMRESOURCE(conn));    }}SSMStatusSSMDataConnection_GetAttrIDs(SSMResource *res,                             SSMAttributeID **ids,                             PRIntn *count){    SSMStatus rv;    rv = SSMConnection_GetAttrIDs(res, ids, count);    if (rv != PR_SUCCESS)        goto loser;    *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 1) * sizeof(SSMAttributeID));    if (! *ids) goto loser;    (*ids)[*count++] = SSM_FID_CONN_DATA_PENDING;    goto done; loser:    if (rv == PR_SUCCESS) rv = PR_FAILURE; done:    return rv;}SSMStatusSSMDataConnection_GetAttr(SSMResource *res,                          SSMAttributeID attrID,                          SSMResourceAttrType attrType,                          SSMAttributeValue *value){    SSMDataConnection *conn = (SSMDataConnection *) res;    SSMStatus rv = PR_SUCCESS;    /* see what it is */    switch(attrID)    {    case SSM_FID_CONN_DATA_PENDING:        /* this is not used: will set it to zero for now */        *(PRUint32*)value->u.numeric = (PRUint32)0;        value->type = SSM_NUMERIC_ATTRIBUTE;        break;    default:        rv = SSMConnection_GetAttr(res,attrID,attrType,value);        if (rv != PR_SUCCESS) goto loser;    }    goto done; loser:    value->type = SSM_NO_ATTRIBUTE; done:    return rv;}SSMStatus SSMDataConnection_SetupClientSocket(SSMDataConnection* conn){    SSMControlConnection* parent = NULL;    char* pNonce;    char* temp = NULL;    /* for nonce verification */    PRFileDesc* socket = NULL;    /* client socket */    PRNetAddr clientAddr;    SSMStatus status = PR_FAILURE;    PRIntn read;    PR_ASSERT(conn != NULL);    /* Allocate a nonce-sized chunk of memory to read into.       (See below.) */    parent = (SSMControlConnection*)(conn->super.m_parent);    PR_ASSERT(parent != NULL);    pNonce = parent->m_nonce;    PR_ASSERT(pNonce != NULL);    SSM_DEBUG("I think my parent's nonce is `%s'.\n", pNonce);    temp = (char*)PORT_ZAlloc(strlen(pNonce));    while ((socket == NULL) && (SSMRESOURCE(conn)->m_status == PR_SUCCESS)) {        SSM_DEBUG("accepting next connect.\n");        /* Wait forever for a connection. (for now) */        socket = PR_Accept(SSMRESOURCE(conn)->m_connection->m_dataSocket,                           &clientAddr, PR_INTERVAL_NO_TIMEOUT);        SSM_DEBUG("accepted connection.\n");        if ((SSMRESOURCE(conn)->m_status != PR_SUCCESS) && socket) {            /* May have gotten a socket, but we're shutting down.               Close and zero out the socket. */            PR_Close(socket);            SSM_LockResource(SSMRESOURCE(conn));            socket = conn->m_clientSocket = NULL;            SSM_UnlockResource(SSMRESOURCE(conn));        }                if (socket && !SSM_SocketPeerCheck(socket, PR_FALSE))        {            /*                Failed peer check. Close socket and listen again.                ### mwelch - Could have a denial of service attack here if               someone keeps trying to connect to this port.            */            PR_Close(socket);            socket = NULL;            continue;        }        if (socket) {            SSM_LockResource(SSMRESOURCE(conn));            conn->m_clientSocket = socket;            SSM_UnlockResource(SSMRESOURCE(conn));            SSM_DEBUG("reading/verifying nonce.\n");            status = PR_SUCCESS;            /* Read the nonce from the client.  If we didn't get the right               nonce, reject the connection. */            if ((temp) && (pNonce != NULL)) {                read = SSM_ReadThisMany(socket, temp, strlen(pNonce));                if ((unsigned int)read != strlen(pNonce)) {                    status = PR_GetError();                }            }            if ((status != PR_SUCCESS) || (memcmp(temp, pNonce,                                                  strlen(pNonce)))) {#ifdef DEBUG                char thing1[255];                char thing2[255];                                strncpy(thing1, temp, strlen(pNonce));                strncpy(thing2, temp, strlen(pNonce));                /* Bad nonce!  Shut down connection                   and wait for another on the data port. */                SSM_DEBUG("Bad nonce, no biscuit!\n");                SSM_DEBUG("(`%s' != `%s')\n", thing1, thing2);#endif                SSM_LockResource(SSMRESOURCE(conn));                PR_Close(conn->m_clientSocket);                conn->m_clientSocket = socket = NULL;                SSM_UnlockResource(SSMRESOURCE(conn));            }        }        else {            /* Tear everything down, didn't get a connection. */            SSM_DEBUG("Shutdown during connection setup.\n");            goto loser;        }    }    SSM_DEBUG("Nonce is valid.\n");    /* We have a socket.  Close the data port. */    SSM_LockResource(SSMRESOURCE(conn));    SSM_DEBUG("Socket is %ld.\n", socket);    SSM_UnlockResource(SSMRESOURCE(conn));loser:    if (temp != NULL) {        PR_Free(temp);    }    return status;}SSMStatus SSMDataConnection_ReadFromSocket(SSMDataConnection* conn,                                          PRInt32* read,                                          char* buffer){    SSMStatus status;#if 0    SSMStatus osStat;    char statBuf[256];#endif    PR_ASSERT(conn != NULL);    PR_ASSERT(buffer != NULL);    /* Attempt to read LINESIZE bytes from the socket. */    do {        SSM_DEBUG("Attempting to read %ld bytes.\n", *read);        *read = PR_Recv(conn->m_clientSocket, buffer, *read, 0,                        PR_MillisecondsToInterval(SSM_READCLIENT_POKE_INTERVAL));        if (*read < 0) {            status = PR_GetError();    /* save status for later use */#if 0            osStat = PR_GetOSError();            PR_GetErrorText(statBuf);#endif        }        SSM_DEBUG("Got %ld bytes of data, status == %ld.\n", (long)(*read),                  (long)status);    }    while ((*read == -1) && (status == PR_IO_TIMEOUT_ERROR) &&           SSMRESOURCE(conn)->m_status == PR_SUCCESS);    /* Don't mask an error if we got one, but set it if we didn't get any     * data (because that indicates a socket closure).     */    if ((*read < 0) && (status == PR_SUCCESS)) {        status = PR_FAILURE;    }    else if (*read >= 0) {        status = PR_SUCCESS;    /* clear the error from when we waited */    }#if 0    /* Null terminate the buffer so that we can dump it. */    if (*read >= 0) {        buffer[*read] = '\0';    }#endif    if (*read > 0) {        SSM_DEBUG("got %ld bytes of data: <%s>\n", *read, buffer);    }    return status;}SSMStatusSSMDataConnection_Shutdown(SSMResource *res, SSMStatus status){    SSMStatus rv, trv;    PRThread *closer = PR_GetCurrentThread();    SSMDataConnection *conn = (SSMDataConnection *) res;    /* SSMDataConnection_Invariant(conn); -- could be called from loser */    /* Lock down the resource before shutting it down */    SSM_LockResource(SSMRESOURCE(conn));        /* If we're called from a service thread, clear that thread's       place in the connection object so it doesn't get interrupted */    if ((closer == conn->m_dataServiceThread) && (closer != NULL)) {        conn->m_dataServiceThread = NULL;        /* Decrement living thread counter */        SSMRESOURCE(conn)->m_threadCount--;    }    /* shut down base class */    rv = SSMConnection_Shutdown(res, status);    if ((SSMRESOURCE(conn)->m_status != PR_SUCCESS) &&        (rv != SSM_ERR_ALREADY_SHUT_DOWN) &&        (conn->m_clientSocket != NULL))    {		SSM_DEBUG("Shutting down data connection abnormally (rv == %d).\n",                  SSMRESOURCE(conn)->m_status);        SSM_DEBUG("shutting down client socket.\n");        PR_Shutdown(conn->m_clientSocket, PR_SHUTDOWN_SEND);        /* if this is called by a control thread, send a message to the         * data service thread to shut down         */        if ((closer != conn->m_dataServiceThread) &&             (conn->m_shutdownQ != NULL)) {            SSM_DEBUG("Send shutdown msg to data Q.\n");            trv = SSM_SendQMessage(conn->m_shutdownQ, SSM_PRIORITY_SHUTDOWN,                                   SSM_DATA_PROVIDER_SHUTDOWN, 0, NULL,                                   PR_TRUE);        }        if (conn->m_dataServiceThread) {            PR_Interrupt(conn->m_dataServiceThread);        }    }        /* If the client sockets is/are now unused, close them. */    if (SSMRESOURCE(conn)->m_threadCount == 0)    {        /* Close the client socket with linger */        if (conn->m_clientSocket)        {            SSM_DEBUG("Close data socket.\n");            trv = PR_Close(conn->m_clientSocket);            conn->m_clientSocket = NULL;            SSM_DEBUG("Closed client socket (rv == %d).\n",trv);        }    }    SSM_UnlockResource(SSMRESOURCE(conn));    return rv; /* so that subclasses know to perform shutdown */}SSMStatus SSMDataConnection_Authenticate(SSMConnection *arg, char *nonce){	SSMStatus rv = SSM_FAILURE;    SSMConnection *parent = arg->m_parent;	/* Parent has the nonce, so authenticate there. */	if (parent &&		SSM_IsAKindOf(&(parent->super), SSM_RESTYPE_CONTROL_CONNECTION))		rv = SSMControlConnection_Authenticate(parent, nonce);	return rv;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -