зеркало из https://github.com/mozilla/gecko-dev.git
1139 строки
36 KiB
C
1139 строки
36 KiB
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 "resource.h"
|
|
#include "hashtbl.h"
|
|
#include "collectn.h"
|
|
#include "connect.h"
|
|
#include "ctrlconn.h"
|
|
#include "dataconn.h"
|
|
#include "sslconn.h"
|
|
#include "sslskst.h"
|
|
#include "certres.h"
|
|
#include "keyres.h"
|
|
#include "crmfres.h"
|
|
#include "p7dconn.h"
|
|
#include "p7cinfo.h"
|
|
#include "p7econn.h"
|
|
#include "hashconn.h"
|
|
#include "kgenctxt.h"
|
|
#include "servimpl.h"
|
|
#include "ssmerrs.h"
|
|
#include "nlsutil.h"
|
|
#include "advisor.h"
|
|
#include "p12res.h"
|
|
#include "signtextres.h"
|
|
#include "sdrres.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
/* Type registration */
|
|
struct SSMResourceClass
|
|
{
|
|
/* The type of resource. */
|
|
SSMResourceType m_classType;
|
|
SSMResourceType m_superclass;
|
|
|
|
/* Name. */
|
|
char * m_className;
|
|
|
|
/* Data pertaining to each class. */
|
|
SSMClientDestroyAction m_clientDest;
|
|
|
|
/* Accessor functions. */
|
|
SSMResourceCreateFunc m_create_func;
|
|
SSMResourceDestroyFunc m_destroy_func;
|
|
SSMResourceShutdownFunc m_shutdown_func;
|
|
SSMResourceGetAttrIDsFunc m_getids_func;
|
|
SSMResourceGetAttrFunc m_get_func;
|
|
SSMResourceSetAttrFunc m_set_func;
|
|
SSMResourcePickleFunc m_pickle_func;
|
|
SSMResourceUnpickleFunc m_unpickle_func;
|
|
SSMResourceHTMLFunc m_html_func;
|
|
SSMResourcePrintFunc m_print_func;
|
|
SSMSubmitHandlerFunc m_submit_func;
|
|
};
|
|
|
|
SSMHashTable *ssm_classRegistry = NULL;
|
|
|
|
|
|
/* Declarations to keep the compiler happy */
|
|
SSMStatus SSM_FindResourceClass(SSMResourceType type, SSMResourceClass **cls);
|
|
|
|
SSMStatus
|
|
SSM_ResourceInit()
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
if (ssm_classRegistry == NULL)
|
|
{
|
|
rv = SSM_HashCreate(&ssm_classRegistry);
|
|
PR_ASSERT(ssm_classRegistry != NULL);
|
|
|
|
/* Register well-known types.
|
|
Connection classes fall into this category. */
|
|
SSM_RegisterResourceType("Resource",
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_RESTYPE_NULL,
|
|
SSM_CLIENTDEST_NOTHING,
|
|
SSMResource_Create,
|
|
SSMResource_Destroy,
|
|
SSMResource_Shutdown,
|
|
SSMResource_GetAttrIDs,
|
|
SSMResource_GetAttr,
|
|
SSMResource_SetAttr,
|
|
SSMResource_Pickle,
|
|
SSMResource_Unpickle,
|
|
SSMResource_HTML,
|
|
SSMResource_Print,
|
|
SSMResource_FormSubmitHandler);
|
|
SSM_RegisterResourceType("Connection",
|
|
SSM_RESTYPE_CONNECTION,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMConnection_Create,
|
|
SSMConnection_Destroy,
|
|
SSMConnection_Shutdown,
|
|
SSMConnection_GetAttrIDs,
|
|
SSMConnection_GetAttr,
|
|
SSMConnection_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("Control connection",
|
|
SSM_RESTYPE_CONTROL_CONNECTION,
|
|
SSM_RESTYPE_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMControlConnection_Create,
|
|
SSMControlConnection_Destroy,
|
|
SSMControlConnection_Shutdown,
|
|
SSMControlConnection_GetAttrIDs,
|
|
SSMControlConnection_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMControlConnection_FormSubmitHandler);
|
|
SSM_RegisterResourceType("Data connection",
|
|
SSM_RESTYPE_DATA_CONNECTION,
|
|
SSM_RESTYPE_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMDataConnection_Create,
|
|
SSMDataConnection_Destroy,
|
|
SSMDataConnection_Shutdown,
|
|
SSMDataConnection_GetAttrIDs,
|
|
SSMDataConnection_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("SSL connection",
|
|
SSM_RESTYPE_SSL_DATA_CONNECTION,
|
|
SSM_RESTYPE_DATA_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMSSLDataConnection_Create,
|
|
SSMSSLDataConnection_Destroy,
|
|
SSMSSLDataConnection_Shutdown,
|
|
SSMSSLDataConnection_GetAttrIDs,
|
|
SSMSSLDataConnection_GetAttr,
|
|
SSMSSLDataConnection_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMSSLDataConnection_FormSubmitHandler);
|
|
SSM_RegisterResourceType("Hash connection",
|
|
SSM_RESTYPE_HASH_CONNECTION,
|
|
SSM_RESTYPE_DATA_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMHashConnection_Create,
|
|
SSMHashConnection_Destroy,
|
|
SSMHashConnection_Shutdown,
|
|
SSMHashConnection_GetAttrIDs,
|
|
SSMHashConnection_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("PKCS7 decode connection",
|
|
SSM_RESTYPE_PKCS7_DECODE_CONNECTION,
|
|
SSM_RESTYPE_DATA_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMP7DecodeConnection_Create,
|
|
SSMP7DecodeConnection_Destroy,
|
|
SSMP7DecodeConnection_Shutdown,
|
|
SSMP7DecodeConnection_GetAttrIDs,
|
|
SSMP7DecodeConnection_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("PKCS7 encode connection",
|
|
SSM_RESTYPE_PKCS7_ENCODE_CONNECTION,
|
|
SSM_RESTYPE_DATA_CONNECTION,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMP7EncodeConnection_Create,
|
|
SSMP7EncodeConnection_Destroy,
|
|
SSMP7EncodeConnection_Shutdown,
|
|
NULL,
|
|
SSMP7EncodeConnection_GetAttr,
|
|
SSMP7EncodeConnection_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("PKCS7 content info",
|
|
SSM_RESTYPE_PKCS7_CONTENT_INFO,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE, /* client destroy */
|
|
SSMP7ContentInfo_Create,
|
|
SSMP7ContentInfo_Destroy,
|
|
NULL,
|
|
SSMP7ContentInfo_GetAttrIDs,
|
|
SSMP7ContentInfo_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("SSL socket status object",
|
|
SSM_RESTYPE_SSL_SOCKET_STATUS,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE, /* client destroy */
|
|
SSMSSLSocketStatus_Create,
|
|
SSMSSLSocketStatus_Destroy,
|
|
NULL,
|
|
SSMSSLSocketStatus_GetAttrIDs,
|
|
SSMSSLSocketStatus_GetAttr,
|
|
NULL,
|
|
SSMSSLSocketStatus_Pickle,
|
|
SSMSSLSocketStatus_Unpickle,
|
|
SSMSSLSocketStatus_HTML,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("Certificate",
|
|
SSM_RESTYPE_CERTIFICATE,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE, /* client destroy */
|
|
SSMResourceCert_Create,
|
|
SSMResourceCert_Destroy,
|
|
NULL,
|
|
SSMResourceCert_GetAttrIDs,
|
|
SSMResourceCert_GetAttr,
|
|
NULL,
|
|
SSMResourceCert_Pickle,
|
|
SSMResourceCert_Unpickle,
|
|
SSMResourceCert_HTML,
|
|
NULL,
|
|
SSMResourceCert_FormSubmitHandler);
|
|
SSM_RegisterResourceType("Key pair",
|
|
SSM_RESTYPE_KEY_PAIR,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE, /* client destroy */
|
|
SSMKeyPair_Create,
|
|
SSMKeyPair_Destroy,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMKeyPair_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("CRMF request",
|
|
SSM_RESTYPE_CRMF_REQUEST,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE, /* client destroy */
|
|
SSMCRMFRequest_Create,
|
|
SSMCRMFRequest_Destroy,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMCRMFRequest_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
SSM_RegisterResourceType("Key gen context",
|
|
SSM_RESTYPE_KEYGEN_CONTEXT, /* type */
|
|
SSM_RESTYPE_RESOURCE, /* superclass */
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
SSMKeyGenContext_Create, /* create */
|
|
SSMKeyGenContext_Destroy, /* destroy */
|
|
SSMKeyGenContext_Shutdown, /* shutdown */
|
|
NULL, /* get attr IDs */
|
|
SSMKeyGenContext_GetAttr, /* get attr */
|
|
SSMKeyGenContext_SetAttr,
|
|
NULL, /* pickle */
|
|
NULL, /* unpickle */
|
|
NULL, /* HTML */
|
|
SSMKeyGenContext_Print, /* Print */
|
|
SSMKeyGenContext_FormSubmitHandler);
|
|
SSM_RegisterResourceType("Security advisor context",
|
|
SSM_RESTYPE_SECADVISOR_CONTEXT,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_SHUTDOWN, /* client destroy */
|
|
NULL,
|
|
SSMSecurityAdvisorContext_Destroy,
|
|
NULL,
|
|
SSMSecurityAdvisorContext_GetAttrIDs,
|
|
SSMSecurityAdvisorContext_GetAttr,
|
|
SSMSecurityAdvisorContext_SetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMSecurityAdvisorContext_Print,
|
|
SSMSecurityAdvisorContext_FormSubmitHandler);
|
|
SSM_RegisterResourceType("PKCS12 Context",
|
|
SSM_RESTYPE_PKCS12_CONTEXT,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE,
|
|
SSMPKCS12Context_Create,
|
|
SSMPKCS12Context_Destroy,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMPKCS12Context_Print,
|
|
SSMPKCS12Context_FormSubmitHandler);
|
|
SSM_RegisterResourceType("SignText Context",
|
|
SSM_RESTYPE_SIGNTEXT,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE,
|
|
SSMSignTextResource_Create,
|
|
SSMSignTextResource_Destroy,
|
|
SSMSignTextResource_Shutdown,
|
|
NULL,
|
|
SSMSignTextResource_GetAttr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMSignTextResource_Print,
|
|
SSMSignTextResource_FormSubmitHandler);
|
|
SSM_RegisterResourceType("SDR Context",
|
|
SSM_RESTYPE_SDR_CONTEXT,
|
|
SSM_RESTYPE_RESOURCE,
|
|
SSM_CLIENTDEST_FREE,
|
|
SSMSDRContext_Create,
|
|
SSMSDRContext_Destroy,
|
|
NULL, /* Shutdown */
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
SSMSDRContext_FormSubmitHandler);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Destroy(SSMResource *res, PRBool doFree)
|
|
{
|
|
SSMStatus rv;
|
|
SSMResourceID tmpID;
|
|
|
|
/* We should have been called from a subclass destructor. */
|
|
PR_ASSERT(doFree == PR_FALSE);
|
|
|
|
SSM_DEBUG("Destroying %s (rid %ld).\n", res->m_class->m_className,
|
|
(long) res->m_id);
|
|
|
|
rv = SSM_HashRemove(res->m_connection->m_resourceDB, res->m_id,
|
|
(void **) &res);
|
|
if (rv != PR_SUCCESS)
|
|
return PR_FAILURE;
|
|
|
|
rv = SSM_HashRemove(res->m_connection->m_resourceIdDB, (SSMHashKey)res,
|
|
(void **) &tmpID);
|
|
if (rv != PR_SUCCESS)
|
|
return PR_FAILURE;
|
|
|
|
if (res->m_lock)
|
|
{
|
|
PR_DestroyMonitor(res->m_lock);
|
|
res->m_lock = NULL;
|
|
}
|
|
|
|
if (res->m_UILock)
|
|
{
|
|
PR_DestroyMonitor(res->m_UILock);
|
|
res->m_UILock = NULL;
|
|
}
|
|
if (res->m_formName) {
|
|
PR_Free(res->m_formName);
|
|
res->m_formName = NULL;
|
|
}
|
|
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Init(SSMControlConnection * conn, SSMResource *res,
|
|
SSMResourceType type)
|
|
{
|
|
SSMResourceClass *cls;
|
|
SSMStatus rv;
|
|
|
|
rv = SSM_FindResourceClass(type, &cls);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
res->m_class = cls;
|
|
res->m_classType = type;
|
|
res->m_buttonType = SSM_BUTTON_NONE;
|
|
res->m_clientDest = cls->m_clientDest;
|
|
res->m_destroy_func = cls->m_destroy_func;
|
|
res->m_shutdown_func = cls->m_shutdown_func;
|
|
res->m_getids_func = cls->m_getids_func;
|
|
res->m_get_func = cls->m_get_func;
|
|
res->m_set_func = cls->m_set_func;
|
|
res->m_pickle_func = cls->m_pickle_func;
|
|
res->m_html_func = cls->m_html_func;
|
|
res->m_print_func = cls->m_print_func;
|
|
res->m_submit_func = cls->m_submit_func;
|
|
res->m_connection = conn;
|
|
res->m_lock = PR_NewMonitor();
|
|
if (!res->m_lock)
|
|
goto loser;
|
|
|
|
if (conn != NULL)
|
|
res->m_id = SSMControlConnection_GenerateResourceID(conn);
|
|
|
|
/* will create this monitor when needed */
|
|
res->m_UILock = NULL;
|
|
res->m_formName = NULL;
|
|
res->m_fileName = NULL;
|
|
res->m_clientContext.len = 0;
|
|
res->m_clientContext.data = NULL;
|
|
|
|
res->m_clientCount = 0;
|
|
res->m_refCount = 1;
|
|
res->m_resourceShutdown = PR_FALSE;
|
|
|
|
SSM_DEBUG("Created %s with rid %ld.\n", cls->m_className,
|
|
(long)res->m_id);
|
|
|
|
if (SSMControlConnection_AddResource(res, res->m_id) != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_FindResourceClass(SSMResourceType type, SSMResourceClass **cls)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
*cls = NULL; /* in case we fail */
|
|
PR_ASSERT(ssm_classRegistry != NULL);
|
|
|
|
rv = SSM_HashFind(ssm_classRegistry, type, (void **) cls);
|
|
return rv;
|
|
}
|
|
|
|
PRBool
|
|
SSM_IsA(SSMResource *res, SSMResourceType type)
|
|
{
|
|
return (res && (res->m_classType == type));
|
|
}
|
|
|
|
PRBool
|
|
SSM_IsAKindOf(SSMResource *res, SSMResourceType type)
|
|
{
|
|
PRBool result = PR_FALSE;
|
|
SSMResourceClass *cls;
|
|
|
|
if (!res) return PR_FALSE;
|
|
|
|
SSM_FindResourceClass( res->m_classType, &cls);
|
|
while (cls && (cls->m_classType != type))
|
|
SSM_FindResourceClass(cls->m_superclass, &cls);
|
|
result = (cls != NULL);
|
|
return result;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_RegisterResourceType(char *name,
|
|
SSMResourceType type,
|
|
SSMResourceType superClass,
|
|
SSMClientDestroyAction destAction,
|
|
SSMResourceCreateFunc createFunc,
|
|
SSMResourceDestroyFunc destFunc,
|
|
SSMResourceShutdownFunc shutFunc,
|
|
SSMResourceGetAttrIDsFunc getIDsFunc,
|
|
SSMResourceGetAttrFunc getFunc,
|
|
SSMResourceSetAttrFunc setFunc,
|
|
SSMResourcePickleFunc pickleFunc,
|
|
SSMResourceUnpickleFunc unpickleFunc,
|
|
SSMResourceHTMLFunc htmlFunc,
|
|
SSMResourcePrintFunc printFunc,
|
|
SSMSubmitHandlerFunc submitFunc)
|
|
{
|
|
SSMResourceClass *cls, *super = NULL;
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
/* If a superclass was specified, find it. */
|
|
if (superClass)
|
|
{
|
|
rv = SSM_FindResourceClass(superClass, &super);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
}
|
|
|
|
/* Create a new entry for the class. */
|
|
cls = (SSMResourceClass *) PR_CALLOC(sizeof(SSMResourceClass));
|
|
if (!cls) goto loser;
|
|
|
|
/* Start with the superclass' methods, then overlay the new ones. */
|
|
if (super)
|
|
(void) memcpy(cls, super, sizeof(SSMResourceClass));
|
|
|
|
cls->m_className = name;
|
|
cls->m_classType = type;
|
|
cls->m_superclass = superClass;
|
|
cls->m_clientDest = destAction;
|
|
|
|
if (createFunc != NULL)
|
|
cls->m_create_func = createFunc;
|
|
if (destFunc != NULL)
|
|
cls->m_destroy_func = destFunc;
|
|
if (shutFunc != NULL)
|
|
cls->m_shutdown_func = shutFunc;
|
|
if (getIDsFunc != NULL)
|
|
cls->m_getids_func = getIDsFunc;
|
|
if (getFunc != NULL)
|
|
cls->m_get_func = getFunc;
|
|
if (setFunc != NULL)
|
|
cls->m_set_func = setFunc;
|
|
if (pickleFunc != NULL)
|
|
cls->m_pickle_func = pickleFunc;
|
|
if (unpickleFunc != NULL)
|
|
cls->m_unpickle_func = unpickleFunc;
|
|
if (htmlFunc != NULL)
|
|
cls->m_html_func = htmlFunc;
|
|
if (printFunc != NULL)
|
|
cls->m_print_func = printFunc;
|
|
if (submitFunc != NULL)
|
|
cls->m_submit_func = submitFunc;
|
|
|
|
rv = SSM_HashInsert(ssm_classRegistry, type, cls);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
return PR_SUCCESS;
|
|
loser:
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
if (cls) PR_Free(cls);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_CreateResource(SSMResourceType type, void *arg,
|
|
SSMControlConnection * connection,
|
|
SSMResourceID *resID, SSMResource **result)
|
|
{
|
|
SSMStatus rv;
|
|
SSMResourceClass *cls = NULL;
|
|
SSMResource *res = NULL;
|
|
|
|
rv = SSM_FindResourceClass(type, &cls);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
PR_ASSERT(cls != NULL);
|
|
|
|
/* Call the create function in this class. */
|
|
rv = (*cls->m_create_func)(arg, connection, &res);
|
|
if ((rv != PR_SUCCESS) && (rv != SSM_ERR_DEFER_RESPONSE))
|
|
goto loser;
|
|
|
|
*resID = res->m_id;
|
|
|
|
*result = res;
|
|
return rv;
|
|
|
|
loser:
|
|
if (res)
|
|
{
|
|
res->m_refCount = 1; /* so that it is destroyed */
|
|
SSM_FreeResource(res);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_GetResourceReference(SSMResource *res)
|
|
{
|
|
SSMResource_Invariant(res);
|
|
|
|
SSM_LockResource(res);
|
|
res->m_refCount++;
|
|
SSM_DEBUG("Get ref - rsrcid: %ld ++refcnt: %ld\n", res->m_id, res->m_refCount);
|
|
switch (res->m_classType) {
|
|
case SSM_RESTYPE_CONTROL_CONNECTION:
|
|
SSM_DEBUG("Getting a reference for the control connection\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
SSM_UnlockResource(res);
|
|
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_FreeResource(SSMResource *res)
|
|
{
|
|
PRIntn refcnt;
|
|
|
|
PR_ASSERT(res != NULL);
|
|
|
|
SSMResource_Invariant(res);
|
|
PR_ASSERT(res->m_refCount > 0);
|
|
|
|
SSM_LockResource(res);
|
|
refcnt = --(res->m_refCount);
|
|
SSM_DEBUG("Free ref - rsrcid: %ld --refcnt: %ld\n", res->m_id, res->m_refCount);
|
|
res->m_refCount = refcnt;
|
|
switch (res->m_classType) {
|
|
case SSM_RESTYPE_CONTROL_CONNECTION:
|
|
SSM_DEBUG("Giving up a reference to the control connection\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
SSM_UnlockResource(res);
|
|
|
|
/* need to handle race condition on destroy */
|
|
if (refcnt <= 0)
|
|
{
|
|
SSM_DEBUG("Destroying resource.\n",
|
|
refcnt);
|
|
return (*res->m_destroy_func)(res, PR_TRUE);
|
|
}
|
|
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_GetResAttribute(SSMResource *res, SSMAttributeID fieldID,
|
|
SSMResourceAttrType attrType, SSMAttributeValue *value)
|
|
{
|
|
PR_ASSERT(res != NULL);
|
|
SSMResource_Invariant(res);
|
|
return (*res->m_get_func)(res,fieldID,attrType,value);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_SetResAttribute(SSMResource *res, SSMAttributeID fieldID,
|
|
SSMAttributeValue *value)
|
|
{
|
|
PR_ASSERT(res != NULL);
|
|
SSMResource_Invariant(res);
|
|
return (*res->m_set_func)(res,fieldID,value);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_PickleResource(SSMResource * res, PRIntn * len, void ** value)
|
|
{
|
|
PR_ASSERT(res != NULL);
|
|
return(*res->m_pickle_func)(res, len, value);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_HTMLResource(SSMResource *res, PRIntn *len, void **value)
|
|
{
|
|
PR_ASSERT(res != NULL);
|
|
return(*res->m_html_func)(res, len, value);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_ClientGetResourceReference(SSMResource *res, SSMResourceID *id)
|
|
{
|
|
SSM_LockResource(res);
|
|
res->m_clientCount++;
|
|
SSM_DEBUG("Get client ref - rsrcid: %ld ++clientcnt: %ld\n",
|
|
res->m_id, res->m_clientCount);
|
|
SSM_GetResourceReference(res);
|
|
if (id)
|
|
*id = res->m_id;
|
|
SSM_UnlockResource(res);
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Unpickle function is similar to create function. Need the switch statement
|
|
* to call
|
|
* Unpickle function for different resources.
|
|
*/
|
|
SSMStatus
|
|
SSM_UnpickleResource(SSMResource ** res, SSMResourceType type,
|
|
SSMControlConnection * connection,
|
|
PRIntn len, void * value)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
|
|
PR_ASSERT(res != NULL);
|
|
if (!res || !value) {
|
|
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
|
goto loser;
|
|
}
|
|
*res = NULL; /* in case we fail */
|
|
switch (type) {
|
|
case SSM_RESTYPE_CERTIFICATE:
|
|
rv = SSMResourceCert_Unpickle(res, connection, len, value);
|
|
break;
|
|
case SSM_RESTYPE_SSL_SOCKET_STATUS:
|
|
rv = SSMSSLSocketStatus_Unpickle(res, connection, len, value);
|
|
break;
|
|
case SSM_RESTYPE_HASH_CONNECTION:
|
|
case SSM_RESTYPE_PKCS7_DECODE_CONNECTION:
|
|
case SSM_RESTYPE_SSL_DATA_CONNECTION:
|
|
default:
|
|
rv = PR_FAILURE;
|
|
}
|
|
goto done;
|
|
loser:
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
if (res && *res) {
|
|
PR_Free(*res);
|
|
*res = NULL;
|
|
}
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
|
|
SSMStatus
|
|
SSM_ShutdownResource(SSMResource *res, SSMStatus status)
|
|
{
|
|
PR_ASSERT(res->m_shutdown_func);
|
|
if (res->m_shutdown_func)
|
|
return (*res->m_shutdown_func)(res, status);
|
|
else
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_ClientDestroyResource(SSMControlConnection * connection,
|
|
SSMResourceID rid, SSMResourceType objType)
|
|
{
|
|
SSMStatus rv;
|
|
SSMResource *res = NULL;
|
|
PRIntn clientCount;
|
|
|
|
rv = SSMControlConnection_GetResource(connection, rid, &res);
|
|
if (rv != PR_SUCCESS)
|
|
goto done;
|
|
|
|
PR_ASSERT(res);
|
|
/* If the object is of the right type, free the reference. */
|
|
if (!SSM_IsAKindOf(res, objType))
|
|
{
|
|
rv = SSM_ERR_BAD_RESOURCE_TYPE;
|
|
goto done;
|
|
}
|
|
|
|
SSM_LockResource(res);
|
|
|
|
clientCount = --(res->m_clientCount);
|
|
SSM_DEBUG("Free client ref - rsrcid: %ld --clientcnt: %ld\n",
|
|
res->m_id, res->m_clientCount);
|
|
/* Also release the resource that was added when the client got
|
|
* its resource
|
|
*/
|
|
SSM_FreeResource(res);
|
|
PR_ASSERT(clientCount >= 0);
|
|
if((clientCount == 0) && (res->m_threadCount > 0))
|
|
{
|
|
SSM_DEBUG("ClientDestroy: Shutting down resource %ld.\n",
|
|
(long)res->m_id);
|
|
rv = SSM_ShutdownResource(res, SSM_ERR_CLIENT_DESTROY);
|
|
if (rv != PR_SUCCESS)
|
|
goto locked_done;
|
|
}
|
|
|
|
locked_done:
|
|
SSM_UnlockResource(res);
|
|
done:
|
|
if (res != NULL)
|
|
rv = SSM_FreeResource(res);
|
|
SSM_DEBUG("ClientDestroy returning status %d.\n", rv);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_MessageFormatResource(SSMResource *res,
|
|
char *fmt,
|
|
PRIntn numParams,
|
|
char ** value,
|
|
char **resultStr)
|
|
{
|
|
SSMStatus rv = SSM_FAILURE;
|
|
|
|
if (res->m_print_func)
|
|
rv = (*(res->m_print_func))(res, fmt, numParams, value, resultStr);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Shutdown(SSMResource *res, SSMStatus status)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSM_LockResource(res);
|
|
if ((res->m_status == PR_SUCCESS) || (res->m_status == SSM_ERR_CLIENT_DESTROY))
|
|
{
|
|
SSM_DEBUG("Shutting down %s with rid %ld. Status == %d.\n",
|
|
res->m_class->m_className,
|
|
(long) res->m_id, status);
|
|
res->m_status = status;
|
|
|
|
/* If there is a thread waiting for us to shut down, notify it. */
|
|
if (res->m_waitThread)
|
|
SSM_NotifyResource(res);
|
|
}
|
|
else
|
|
rv = SSM_ERR_ALREADY_SHUT_DOWN;
|
|
res->m_resourceShutdown = PR_TRUE;
|
|
SSM_UnlockResource(res);
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
SSMResource_Invariant(SSMResource *res)
|
|
{
|
|
#ifdef DEBUG
|
|
if (res)
|
|
{
|
|
PR_ASSERT(res->m_id != 0);
|
|
PR_ASSERT(SSM_IsAKindOf(res, SSM_RESTYPE_RESOURCE));
|
|
PR_ASSERT(res->m_refCount >= 0);
|
|
PR_ASSERT(res->m_destroy_func != NULL);
|
|
PR_ASSERT(res->m_shutdown_func != NULL);
|
|
PR_ASSERT(res->m_getids_func != NULL);
|
|
PR_ASSERT(res->m_get_func != NULL);
|
|
PR_ASSERT(res->m_set_func != NULL);
|
|
PR_ASSERT(res->m_connection != NULL);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Create(void *arg, SSMControlConnection * connection,
|
|
SSMResource **res)
|
|
{
|
|
/* never instantiate a bare SSMResource */
|
|
*res = NULL;
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_GetAttr(SSMResource *res,
|
|
SSMAttributeID fieldID,
|
|
SSMResourceAttrType attrType,
|
|
SSMAttributeValue *value)
|
|
{
|
|
return SSM_ERR_BAD_ATTRIBUTE_ID;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_GetAttrIDs(SSMResource *res,
|
|
SSMAttributeID **ids,
|
|
PRIntn *count)
|
|
{
|
|
/* return 0 attributes */
|
|
*ids = (SSMAttributeID *) PR_CALLOC(0);
|
|
*count = 0;
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_SetAttr(SSMResource *res,
|
|
SSMAttributeID attrID,
|
|
SSMAttributeValue *value)
|
|
{
|
|
return PR_FAILURE; /* nothing client-accessible in the base class */
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Pickle(SSMResource *res, PRIntn * len, void **value)
|
|
{
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Unpickle(SSMResource ** res, SSMControlConnection *conn,
|
|
PRIntn len, void * value)
|
|
{
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_HTML(SSMResource *res, PRIntn * len, void ** value)
|
|
{
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_Print(SSMResource *res, char *fmt, PRIntn numParams,
|
|
char ** value, char **resultStr)
|
|
{
|
|
PR_ASSERT(res != NULL && fmt != NULL && resultStr != NULL);
|
|
if (numParams > 3)
|
|
SSM_DEBUG("SSMResource_Print: too many parameters!\n");
|
|
switch (numParams) {
|
|
case (3):
|
|
*resultStr = PR_smprintf(fmt, res->m_id, *value, *(value+1),*(value+2));
|
|
break;
|
|
case (2):
|
|
*resultStr = PR_smprintf(fmt, res->m_id, *value, *(value+1));
|
|
break;
|
|
case (1):
|
|
*resultStr = PR_smprintf(fmt, res->m_id, *value);
|
|
break;
|
|
default:
|
|
*resultStr = PR_smprintf(fmt, res->m_id);
|
|
}
|
|
if (*resultStr == NULL) {
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMResource_FormSubmitHandler(SSMResource *res,
|
|
HTTPRequest *req)
|
|
{
|
|
return SSM_HTTPDefaultCommandHandler(req);
|
|
}
|
|
|
|
void
|
|
SSM_LockResource(SSMResource *res)
|
|
{
|
|
PR_EnterMonitor(res->m_lock);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_UnlockResource(SSMResource *res)
|
|
{
|
|
return PR_ExitMonitor(res->m_lock);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_WaitResource(SSMResource *res, PRIntervalTime ticks)
|
|
{
|
|
return PR_Wait(res->m_lock, ticks);
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_NotifyResource(SSMResource *res)
|
|
{
|
|
return PR_Notify(res->m_lock);
|
|
}
|
|
|
|
/*
|
|
Wait for a resource to shut down.
|
|
### mwelch We use WaitResource() in another context, namely where
|
|
data connections hand over a newly opened port number to their
|
|
control connections. Can we guard against the case where we have an
|
|
initializing data connection upon which a thread decides to wait for
|
|
shutdown?
|
|
*/
|
|
SSMStatus
|
|
SSM_WaitForResourceShutdown(SSMResource *res)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSM_LockResource(res);
|
|
PR_ASSERT(res->m_waitThread == NULL);
|
|
|
|
if (res->m_waitThread)
|
|
rv = PR_FAILURE;
|
|
else if (!res->m_resourceShutdown)
|
|
{
|
|
res->m_waitThread = PR_GetCurrentThread();
|
|
do
|
|
SSM_WaitResource(res, PR_INTERVAL_NO_TIMEOUT);
|
|
while (res->m_threadCount > 0);
|
|
res->m_waitThread = NULL;
|
|
}
|
|
else
|
|
{
|
|
rv = SSM_ERR_ALREADY_SHUT_DOWN;
|
|
}
|
|
|
|
SSM_UnlockResource(res);
|
|
return rv;
|
|
}
|
|
|
|
char *
|
|
SSM_ResourceClassName(SSMResource *res)
|
|
{
|
|
return res->m_class->m_className;
|
|
}
|
|
|
|
void SSM_LockUIEvent(SSMResource * res)
|
|
{
|
|
if (res->m_UILock == NULL)
|
|
res->m_UILock = PR_NewMonitor();
|
|
PR_ASSERT(res->m_UILock);
|
|
PR_EnterMonitor(res->m_UILock);
|
|
}
|
|
|
|
SSMStatus SSM_UnlockUIEvent(SSMResource *res)
|
|
{
|
|
PR_ASSERT(res->m_UILock);
|
|
if (res->m_UILock != NULL) {
|
|
return PR_ExitMonitor(res->m_UILock);
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus SSM_WaitUIEvent(SSMResource * res, PRIntervalTime ticks)
|
|
{
|
|
PR_ASSERT(res->m_UILock);
|
|
if (res->m_UILock)
|
|
{
|
|
res->m_UIBoolean = PR_FALSE;
|
|
while (!res->m_UIBoolean)
|
|
PR_Wait(res->m_UILock, ticks);
|
|
return PR_ExitMonitor(res->m_UILock);
|
|
}
|
|
/* if we used UILock once, chances are we'll need it again? */
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
SSMStatus SSM_NotifyUIEvent(SSMResource * res)
|
|
{
|
|
SSMStatus rv = PR_FAILURE;
|
|
|
|
PR_ASSERT(res->m_UILock);
|
|
if (res->m_UILock)
|
|
{
|
|
PR_EnterMonitor(res->m_UILock);
|
|
res->m_UIBoolean = PR_TRUE;
|
|
rv =PR_Notify(res->m_UILock);
|
|
PR_ExitMonitor(res->m_UILock);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
SSMStatus SSM_WaitForOKCancelEvent(SSMResource *res, PRIntervalTime ticks)
|
|
{
|
|
PRStatus rv;
|
|
if (res->m_UILock == NULL) {
|
|
/* We might have been waken up by a spurious notify,
|
|
* so we don't allocate a new monitor every time.
|
|
*/
|
|
res->m_UILock = PR_NewMonitor();
|
|
}
|
|
PR_EnterMonitor(res->m_UILock);
|
|
rv = PR_Wait(res->m_UILock, ticks);
|
|
PR_ExitMonitor(res->m_UILock);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSM_NotifyOKCancelEvent(SSMResource *res)
|
|
{
|
|
SSMStatus rv = PR_FAILURE;
|
|
|
|
if (res->m_UILock) {
|
|
PR_EnterMonitor(res->m_UILock);
|
|
rv = PR_Notify(res->m_UILock);
|
|
PR_ExitMonitor(res->m_UILock);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSM_HandlePromptReply(SSMResource *res, char *reply)
|
|
{
|
|
/* Currently, only SSMPKCS12Context supports this,
|
|
* perhaps in the future we'll add more general support.
|
|
*/
|
|
if (!SSM_IsAKindOf(res, SSM_RESTYPE_PKCS12_CONTEXT)) {
|
|
return PR_FAILURE;
|
|
}
|
|
return SSMPKCS12Context_ProcessPromptReply(res, reply);
|
|
}
|
|
|
|
PRThread *
|
|
SSM_CreateThread(SSMResource *res, void (*func)(void *arg))
|
|
{
|
|
PRThread *thd = NULL;
|
|
|
|
PR_ASSERT(res != NULL);
|
|
PR_ASSERT(func != NULL);
|
|
|
|
SSM_LockResource(res);
|
|
thd = SSM_CreateAndRegisterThread(PR_USER_THREAD,
|
|
func,
|
|
(void *)res,
|
|
PR_PRIORITY_NORMAL,
|
|
PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0);
|
|
if (thd) {
|
|
res->m_threadCount++;
|
|
}
|
|
SSM_UnlockResource(res);
|
|
|
|
return thd;
|
|
}
|
|
|