/* SCCSID: fwk/cssm/regfunc.c, dss_cdsa_fwk, fwk_rel2, dss_971010 1.20 10/10/97 10:49:48 */
/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

/*-----------------------------------------------------------------------
 *      File:   REGFUNC.C
 *
 * This file contains the functions that are contained in the registry portion
 * of the CSSM exported functions.
 */
/*
 * (C) COPYRIGHT International Business Machines Corp. 1996, 1997
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * Copyright (c) 1995, 1996, 1997 Intel Corporation. All rights reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 */
/*
 * WARNING: EXPORT RESTRICTED.
 * This software listing contains cryptographic methods and technology.
 * It is export restricted by the Office of Defense Trade Controls, United
 * States Department of State and cannot be downloaded or otherwise
 * exported or re-exported (i) into (or to a national or resident of) Cuba,
 * Iraq, Libya, Yugoslavia, North Korea, Iran, Syria or any other country
 * to which the US has embargoed goods; or (ii) to anyone on the US
 * Treasury Department's list of Specially Designated Nationals or the US
 * Commerce Department's Table of Denial Orders. By downloading or using
 * this product, you are agreeing to the foregoing and you are representing
 * and warranting that you are not located in, under the control of, or a
 * national or resident of any such country or on any such list.
 */

#include "cssm.h"
#include "cssmport.h"
#include "internal.h"
#include "vendor.h"

#define CSSM_PREFERENCE_GLOBAL 0
#define CSSM_PREFERENCE_PERSONAL 1

/*---------------------------------------------------------------
 * Mapping of context class types to registry category strings
 *-------------------------------------------------------------*/
char * classNameList[] = {
    "None",
    "Custom",                /* ALGCLASS_CUSTOM */
    "KeyExchange",            /* ALGCLASS_KEYXCH */
    "Signature",            /* ALGCLASS_SIGNATURE */
    "Symmetric Encrypt",                /* ALGCLASS_SYMMETRIC */
    "Digest",                /* ALGCLASS_DIGEST */
    "RandomGen",            /* ALGCLASS_RANDOMGEN */
    "RandomGen",            /* ALGCLASS_UNIQUEGEN */
    "MAC",                    /* ALGCLASS_MAC */
    "Asymmetric Encrypt",                /* ALGCLASS_ASYMMETRIC */
    "KeyPairGen",            /* ALGCLASS_KEYPAIRGEN */
    NULL
};

/*---------------------------------------------------------------
 *
 *Name: cssm_GUIDToStr
 *
 *Description:
 *   Given a guid, covert it to a string.
 *
 *Parameters:
 *   GUID - pointer to a guid
 *   ID - pointer to a string to receive guid
 *
 *Returns:
 *  NOne
 *-------------------------------------------------------------*/
void CSSMAPI cssm_GUIDToStr (const CSSM_GUID_PTR GUID, char *ID)
{

	if ((GUID == NULL) || (ID == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return;
	}

    sprintf (ID, "{%lx-%x-%x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
                     GUID->Data1, GUID->Data2, GUID->Data3, GUID->Data4[0],
                     GUID->Data4[1], GUID->Data4[2], GUID->Data4[3],
                     GUID->Data4[4], GUID->Data4[5], GUID->Data4[6],
                     GUID->Data4[7]);
	return;
}

/*---------------------------------------------------------------
 *
 *Name: cssm_StrToGUID
 *
 *Description:
 *   Given a string, covert it to a guid.
 *
 *Parameters:
 *   ID - pointer to the guid string
 *   GUID - pointer to a CSSM_GUID to receive the guid
 *
 *Returns:
 *  NOne
 *-------------------------------------------------------------*/
void CSSMAPI cssm_StrToGUID (char *ID, CSSM_GUID_PTR GUID)
{
	int i, Data1, Data2, Data3, Data4[8];

	if ((ID == NULL) || (GUID == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return;
	}

	sscanf (ID, "{%lx-%x-%x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
                     &Data1, &Data2, &Data3, &Data4[0],
                     &Data4[1], &Data4[2], &Data4[3],
                     &Data4[4], &Data4[5], &Data4[6],
                     &Data4[7]);

	GUID->Data1 = Data1;
	GUID->Data2 = Data2;
	GUID->Data3 = Data3;
	for (i=0; i<8; i++)
	      GUID->Data4[i] = Data4[i];

	return;
}


/*---------------------------------------------------------------
 *
 *Name: IsAdminUser
 *
 *Description:
 * Returns 1 or 0 depending on whether the current user is or is
 *  not an administrative user on the machine. Administrator
 *  login names are considered to be "root" and "administrator".
 *
 *Parameters:
 * none
 *
 *Returns:
 * 1 or 0 depending on user name.
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_IsAdminUser() {
    CSSM_RETURN isAdmin = CSSM_FAIL;

    return(isAdmin);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_ClassToKey
 *
 *Description:
 * Returns a pointer to a string that represents the class of
 *  algorithm specified by serviceClass.
 *
 *Parameters:
 * serviceClass(input) - Service class bit array to convert.
 *
 *Returns:
 * Pointer to an internal string buffer containing the name of
 * the service class. The value will be overwritten on the next
 * call to ClassToKey.
 *-------------------------------------------------------------*/
char * CSSMAPI cssm_ClassToKey (uint32 serviceClass) {
    /* May need to change this from a static variable to a global
     * non-static variable if this DLL will be loaded using LoadLibrary()
     * instead of explicit binding with the LIB file.
     */
    static char classString[32];

    if (serviceClass > CSSM_ALGCLASS_KEYGEN || serviceClass < 0) {
        strcpy(classString,"Unknown");
    } else {
        strcpy(classString,classNameList[serviceClass]);
    }

    return(classString);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_KeyToClassMask
 *
 *Description:
 * Returns an unsigned long value that represents a service class
 * mask for the key in question. The results of multiple calls
 * to this function can be combined to generate a complete mask
 * for a CSP.
 *
 *Parameters:
 * keyname(input) - Null terminated string with the key name to
 *  convert.
 *
 *Returns:
 * Service class mask value for the key passed.
 * zero(0) if the keyname is invalid.
 *-------------------------------------------------------------*/
uint32 CSSMAPI cssm_KeyToClassMask(char * keyname) {
    uint32 index = 1;
	uint32	rc;

	if (keyname == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(0);
	}

    /* Find the key that matches the passed keyname */
    while ((index <= 8) && (strcmp(keyname,classNameList[index]) != 0)) {
        index++;
    }

    /* Calculate the bitmask for the class and return it */
    if (index > 8) {
        return(0);
    } else {
        rc = (uint32)(1 << (index - 1));
		return(rc);
    }
}

CSSM_RETURN cssm_WriteBinary (char *RegKey, char *Label, uint32 Data)
{
    uint32 i;

	if ((RegKey == NULL) || (Label == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    i = sizeof (Data);
    if (cssm_SetValue (RegKey, Label, (void *)&Data, i,
                         CSSM_VALUE_BINARY,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

// Write a string to the Registry without trucating it.
CSSM_RETURN cssm_RegWriteString (char *RegKey, char *Label, char *Data)
{

	if ((RegKey == NULL) || (Label == NULL) || (Data == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_SetValue (RegKey, Label, (uint8 *)Data, strlen(Data) + 1,
                         CSSM_VALUE_STRING,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

// Write a string to the Registry, but first trucate it so that it fits in CSS_MODULE_STRING_SIZE
CSSM_RETURN cssm_RegWriteCSSMString (char *RegKey, char *Label,
                                     CSSM_STRING Data)
{

	if ((RegKey == NULL) || (Label == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Data[CSSM_MODULE_STRING_SIZE] = 0;
    if (cssm_SetValue (RegKey, Label, Data, strlen(Data) + 1,
                         CSSM_VALUE_STRING,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

CSSM_RETURN cssm_WriteUTC (char *RegKey, char *Label, char *Data)
{

	if ((RegKey == NULL) || (Label == NULL) || (Data == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_SetValue (RegKey, Label, (uint8 *)Data, 16,
                         CSSM_VALUE_STRING,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_GetAlgCount
 *
 *Description:
 * Returns the value of the key "AlgCount" in the specified key
 *  and subkey. Used by RegWriteCSPServices,
 *  RegReadCSPServices and RegCountCSPAlgorithms.
 *
 *Parameters:
 * hBaseKey(input) - Already opened registry key.
 * subkey(input) - key from which to extract the AlgCount value
 *
 *Returns:
 * zero(0) - if no key or value could be read
 * count - value of AlgCount in the specified key
 *-------------------------------------------------------------*/
sint32 CSSMAPI cssm_GetAlgCount(sint32 PersonalPref,char * subkey) {
    uint32 count;
    sint32 dataSize = sizeof (count);
    sint32 regResult;
    sint32 dataType = CSSM_VALUE_BINARY;

	if (subkey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(0);
	}

    regResult = cssm_GetValue (subkey,"AlgCount",
                             (void *)&count,&dataSize,&dataType,
                             PersonalPref);

    CSSM_ClearError ();
    if (regResult != CSSM_OK)
        return(0);

    return(count);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_IncrementAlgCount
 *
 *Description:
 * Increments the "AlgCount" value in the registry key specified
 * or sets the initial value to 1 if the value is not found.
 *
 *Parameters:
 * hBaseKey(input) - Already opened registry key.
 * subkey(input) - key in which to increment the AlgCount value
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - registry could not be mainpulated
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_IncrementAlgCount(sint32 PersonalPref,char * subkey) {
    sint32 count;
    sint32 regResult;

	if (subkey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    count = cssm_GetAlgCount(PersonalPref,subkey);
    count++;

    /* Write updated value to the registry */
    regResult = cssm_SetValue(subkey,"AlgCount",
                             &count,sizeof(count),CSSM_VALUE_BINARY,
                             PersonalPref);

    if (regResult != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegWriteDataStruct
 *
 *Description:
 *   Generic function for writing a CSSM_DATA structure to the
 *   registry
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Label - pointer to label to tag data
 *   Data - pointer to the CSSM_DATA structure
 *
 *Returns:
 *   CSSM_FAIL - unable to update registry
 *   CSSM_OK - registry is updated
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegWriteDataStruct (char *regKey, char *Label,
                                             CSSM_DATA_PTR Data)
{
    char st[MAX_REG];

	if ((regKey == NULL) || (Label == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy (st, Label);
    strcat (st, "Len");

    if (!IsBadReadPtr (Data, sizeof (CSSM_DATA))) {
        if (!IsBadReadPtr (Data->Data, Data->Length)) {
            if (cssm_SetValue (regKey, st, (void *)&Data->Length, sizeof (Data->Length),
                                  CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }

            if (cssm_SetValue (regKey, Label, (void *)Data->Data, Data->Length,
                                  CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
            return(CSSM_OK);
        }
    }
    return(CSSM_FAIL);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadDataStruct
 *
 *Description:
 *   Generic function to read a CSSM_DATA structure from the registry
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Label - pointer to label to tag data
 *   Data - pointer to the CSSM_DATA structure
 *
 *Returns:
 *   CSSM_FAIL - unable to read from registry
 *   CSSM_OK - data is read from registry
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadDataStruct (char *regKey, char *Label,
                                            CSSM_DATA_PTR const Data)
{
    char st[MAX_REG];
    sint32 i;
	sint32 type, Len;

	if ((regKey == NULL) || (Label == NULL) || (Data == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy (st, Label);
    strcat (st, "Len");
    Len = sizeof (Data->Length);
    if (cssm_GetValue (regKey, st, (void *)&i, &Len,
                          &type, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if ((Data->Data = app_malloc (i, memRef)) == NULL) {
        app_free (Data, memRef);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    if (cssm_GetValue (regKey, Label, (void *)Data->Data, &i,
                          &type, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    } else {
		Data->Length = i;
	}

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadString
 *
 *Description:
 *   Given a registry string and label, get the data associated
 *   with that label
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Label - pointer to label to tag data
 *   Str - pointer to pointer that contains string
 *
 *Returns:
 *   CSSM_FAIL - unable to read string from registry
 *   CSSM_OK - string is in buffer
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadString (char *regKey, char *Label,
                                        char **Str)
{
    sint32 dataType;
    char TempStr[1024];
    sint32 Len = 1024;

	if ((regKey == NULL) || (Label == NULL) || (Str == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* vendor strint */
    if (cssm_GetValue(regKey, Label, (void *)TempStr,
                     &Len, &dataType, CSSM_PREFERENCE_GLOBAL) == CSSM_FAIL) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if ((*Str = app_malloc (Len + 1, memRef)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    if (cssm_CheckCopy (*Str, TempStr, Len) == CSSM_FAIL)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadCSSMString
 *
 *Description:
 *   Given a registry string and label, get the string of
 *   maximum length CSSM_MODULE_STRING_SIZE + 4
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Label - pointer to label to tag data
 *   Str - pointer to pointer that contains string
 *
 *Returns:
 *   CSSM_FAIL - unable to read string from registry
 *   CSSM_OK - string is in buffer
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadCSSMString (char *regKey, char *Label,
                                            CSSM_STRING Str)
{
    sint32 dataType;
    sint32 Len = CSSM_MODULE_STRING_SIZE + 4;

	if ((regKey == NULL) || (Label == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_GetValue(regKey, Label, (void *)Str,
                     &Len, &dataType, CSSM_PREFERENCE_GLOBAL) == CSSM_FAIL) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadCSPList
 *
 *Description:
 * Returns an array of pointers to strings that contain the
 *  logical names of the CSP installed on the system. The array
 *  storage is allocated by this function.
 *
 *Parameters:
 * list(ouput) - pointer to an array of character strings that
 *  contain the logical names of the installed CSPs.
 * pCount(output) - The number of names actually in the list.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_MEMORY_ERROR - memory could not be allocated for the
 *  strings.
 * CSSM_FAIL - no registry entry could be read
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadCSPList(char *** list,sint32 *pCount) {
    char regKey[MAX_REG];
    sint32 regResult;

	if ((list == NULL) || (pCount == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

	/* Generate the registry key for the CSP information */
    strcpy(regKey, CSSMSECTION);
    strcat(regKey,"CSP");

    /* Get the count of CSPs registered */
    regResult = cssm_GetSectionCount (regKey,pCount,CSSM_PREFERENCE_GLOBAL);
    if (regResult != CSSM_OK)
        return(regResult);

    /* Fetch the CSP list */
    regResult = cssm_GetSectionList (regKey,list,CSSM_PREFERENCE_GLOBAL);

    return(regResult);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadCSPServiceClasses
 *
 *Description:
 * Returns a bitmap representing the service classes supported by
 *  the passed CSP name.
 *
 *Parameters:
 * szCSPName(input) - Null terminated character buffer containing
 *  logical name of the CSP to query.
 * pServiceClass(output) - Pointer to a user supplied
 *  CSSMServiceClassBitArray value in which to place the CSP
 *  capabilities mask.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - no registry entry could be read
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadCSPServiceClasses (char * szCSPName,
                                           uint32 * pServiceClass) {
    char regKey[MAX_REG];
    sint32 index = 0;
    sint32 regResult;
    uint32 services = 0;
    char ** serviceList;

	if ((szCSPName == NULL) || (pServiceClass == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* Generate the registry key for the CSP information */
    strcpy(regKey, CSSMSECTION);
    strcat(regKey,"CSP\\");
    strcat(regKey,szCSPName);

    /* Enumerate the CSP class keys and generate capabilities list */
    regResult = cssm_GetSectionList(regKey,&serviceList,CSSM_PREFERENCE_GLOBAL);
    if (regResult != CSSM_OK)
        return(regResult);

    /* Convert the key list to a class bitmap */
    index = 0;
    while (serviceList[index])
        services |= cssm_KeyToClassMask(serviceList[index++]);
    app_free(serviceList, memRef);

    *pServiceClass = services;
    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegCountCSPAlgorithms
 *
 *Description:
 * Counts the number of algorithms that the CSP supports. The
 *  class(es) of algorithm(s) to count can be specified.
 *
 *Parameters:
 * szCSPName(input) - Null terminated character buffer containing
 *  logical name of the CSP to query.
 * pServiceClasses(input) - Pointer to a CSSMServiceClassBitArray
 *  value of algorithm types to count. A NULL value counts all
 *  algorithms.
 * pAlgCount(output) - number of algorithms that match the
 *  specified algorithm type.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - no registry entry could be read
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegCountCSPAlgorithms(char * regKey,
                                 uint32 * pServiceClasses,
                                 sint32 *pAlgCount) {
    char classname[MAX_REG];
    sint32 index = 0;
    sint32 regResult;
    uint32 services;
    char ** list;

	if ((regKey == NULL) || (pAlgCount == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    /* Enumerate the CSP class keys */
    regResult = cssm_GetSectionList (regKey,&list,CSSM_PREFERENCE_GLOBAL);
    if (regResult != CSSM_OK)
        return(regResult);

    *pAlgCount = 0;
    index = 0;
    while (list[index]) {
        /* Fetch algorithm count and add to total if proper class */
        services = cssm_KeyToClassMask(list[index]);
        if (pServiceClasses == NULL || *pServiceClasses & services) {
            strcpy (classname,regKey);
            strcat (classname,"\\");
            strcat (classname,list[index]);
            *pAlgCount += cssm_GetAlgCount (CSSM_PREFERENCE_GLOBAL,classname);
        }
        cssm_free(list[index++], 0);
    }

    return(CSSM_OK);
}

CSSM_KEY_PTR cssm_RegReadContextAttribKeyType(char *szRegKey, const sint32 PersonalPref)
{
    sint32 dataType = CSSM_VALUE_BINARY;
    sint32 dataLength = sizeof(CSSM_KEYHEADER);
    CSSM_KEY_PTR pKey;

	if (szRegKey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(NULL);
	}

    if ((pKey = app_malloc(sizeof(CSSM_KEY), memRef)) == NULL)
    {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    if (cssm_GetValue(szRegKey,"KeyHeader", (void *)&pKey->KeyHeader,
        &dataLength, &dataType, PersonalPref) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        app_free(pKey, memRef);
        return(NULL);
    }

    if (cssm_RegReadDataStruct(szRegKey,"Key", &pKey->KeyData) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        app_free(pKey, memRef);
        return(NULL);
    }

    return(pKey);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadContextAttrib
 *
 *Description:
 * Reads the registry key specified and places it in a
 *  CSSMContextAttribute structure allocated by the caller for
 *  the data. Space for the attribute data in the pAttribute
 *  field of the CSSMContextAttribute fields will be allocated
 *  here as needed.
 *
 *Parameters:
 * hBaseKey(input) - Opened databse key from which to open the
 *  attribute storage key.
 * szRegKey(input) - Null terminated string containing the
 *  subkey in which to store the attribute data.
 * ppAttrib(input/output) - Pointer to a pointer that will point
 *  to the allocated CSSMContextAttributes structure on exit. If
 *  the structure is not successfully loaded, the value will be
 *  NULL.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - all data could not be stored in the registry
 * CSSM_MEMORY_ERROR - memory could not be allocated for the data
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadContextAttrib(char * szRegKey,
                                sint32 PersonalPref,
                                CSSM_CONTEXT_ATTRIBUTE_PTR pAttrib)
{
    sint32 dataType = CSSM_VALUE_BINARY;
    sint32 dataLength = 4;

	if ((szRegKey == NULL) || (pAttrib == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    if (CSSM_OK != cssm_GetValue(szRegKey,"Type", (void *)&pAttrib->AttributeType,
            &dataLength, &dataType, PersonalPref))
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }


    if (CSSM_OK != cssm_GetValue(szRegKey,"Length", (void *)&pAttrib->AttributeLength,
            &dataLength, &dataType, PersonalPref))
        return(CSSM_FAIL);

    switch (pAttrib->AttributeType & 0xf0000000) {
        case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA :
        case CSSM_ATTRIBUTE_DATA_KEY:
            return(CSSM_FAIL);

        case CSSM_ATTRIBUTE_NONE :
            pAttrib->Attribute.Data = NULL;
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_STRING :
            if (cssm_RegReadString(szRegKey, "Description", &pAttrib->Attribute.String) != CSSM_OK)
            {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                app_free(pAttrib->Attribute.String, memRef);
                return(CSSM_FAIL);
            }
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_UINT32:
            if (CSSM_OK != cssm_GetValue(szRegKey,"Attribute", (void *)&pAttrib->Attribute.Uint32,
                &dataLength, &dataType, PersonalPref))
            {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_CSSM_DATA :
            if (NULL == (pAttrib->Attribute.Data = app_malloc(sizeof(CSSM_DATA), memRef)) )
            {
                CSSM_SetError(&cssm_GUID, CSSM_MEMORY_ERROR);
                return(CSSM_FAIL);
            }

            if (cssm_RegReadDataStruct(szRegKey, "Attribute", pAttrib->Attribute.Data) != CSSM_OK)
            {
                app_free(pAttrib->Attribute.Data,memRef);
                pAttrib->Attribute.Data = NULL;
                return(CSSM_FAIL);
            }
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_DATE :
            if ((pAttrib->Attribute.Date = app_malloc(sizeof(CSSM_DATE), memRef)) == NULL)
            {
                CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                return(CSSM_FAIL);
            }

            if (cssm_GetValue(szRegKey,"Year", (void *)&pAttrib->Attribute.Date->Year,
                &dataLength, &dataType, PersonalPref))
            {
                app_free(pAttrib->Attribute.Date, memRef);
                pAttrib->Attribute.Date = NULL;
                CSSM_SetError(&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }

            dataLength = 2;
            if (cssm_GetValue(szRegKey,"Month", (void *)&pAttrib->Attribute.Date->Month,
                &dataLength, &dataType, PersonalPref) ||
                cssm_GetValue(szRegKey,"Day", (void *)&pAttrib->Attribute.Date->Day,
                &dataLength, &dataType, PersonalPref) )
            {
                app_free(pAttrib->Attribute.Date, memRef);
                pAttrib->Attribute.Date = NULL;
                CSSM_SetError(&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_RANGE:

            if ((pAttrib->Attribute.Range = app_malloc(sizeof(CSSM_RANGE), memRef)) == NULL)
            {
                CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                return(CSSM_FAIL);
            }

            if( cssm_GetValue(szRegKey,"Min", (void *)&pAttrib->Attribute.Range->Min,
                &dataLength, &dataType, PersonalPref) ||
                cssm_GetValue(szRegKey,"Max", (void *)&pAttrib->Attribute.Range->Max,
                &dataLength, &dataType, PersonalPref) )
            {
                app_free(pAttrib->Attribute.Date, memRef);
                pAttrib->Attribute.Date = NULL;
                CSSM_SetError(&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
            return(CSSM_OK);
    }
    return(CSSM_FAIL);
} /* End RegReadContextAttrib() */

/*---------------------------------------------------------------
 *
 *Name: cssm_RegWriteContextAttrib
 *
 *Description:
 * Writes the passed context attribute structure to the registry
 * key specified.
 *
 *Parameters:
 * hBaseKey(input) - Opened databse key from which to open the
 *  attribute storage key.
 * szRegKey(input) - Null terminated string containing the
 *  subkey in which to store the attribute data.
 * pAttrib(input) - CSSMContextAttributes structure to save in
 *  the registry.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - all data could not be stored in the registry
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegWriteContextAttrib(char * szRegKey,
                                 const sint32 PersonalPref,
                                 CSSM_CONTEXT_ATTRIBUTE_PTR pAttrib) {

	CSSM_RETURN	rc;

	if ((szRegKey == NULL) || (pAttrib == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* Save the structure values in the opened key */
    if (CSSM_OK != cssm_SetValue(szRegKey,"Type", (void *)&pAttrib->AttributeType,
            sizeof(pAttrib->AttributeType), CSSM_VALUE_BINARY,PersonalPref))
        return(CSSM_FAIL);


    if (CSSM_OK != cssm_SetValue(szRegKey,"Length", (void *)&pAttrib->AttributeLength,
            sizeof(pAttrib->AttributeLength), CSSM_VALUE_BINARY,PersonalPref))
        return(CSSM_FAIL);

    switch (pAttrib->AttributeType & 0xf0000000) {
        case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA :
        case CSSM_ATTRIBUTE_DATA_KEY:
            return(CSSM_FAIL);

        case CSSM_ATTRIBUTE_NONE :
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_STRING :
            rc = cssm_RegWriteString(szRegKey, "Description", pAttrib->Attribute.String);
			return(rc);

        case CSSM_ATTRIBUTE_DATA_UINT32:
            rc = cssm_SetValue(szRegKey,"Attribute", (void *)&pAttrib->Attribute.Uint32,
                4, CSSM_VALUE_BINARY, PersonalPref);
			return(rc);;
        case CSSM_ATTRIBUTE_DATA_CSSM_DATA :
            rc = cssm_RegWriteDataStruct(szRegKey, "Attribute", pAttrib->Attribute.Data);
			return(rc);

        case CSSM_ATTRIBUTE_DATA_DATE :
            if( cssm_SetValue(szRegKey,"Year", (void *)&pAttrib->Attribute.Date->Year,
                4, CSSM_VALUE_BINARY, PersonalPref) ||
                cssm_SetValue(szRegKey,"Month", (void *)&pAttrib->Attribute.Date->Month,
                2, CSSM_VALUE_BINARY, PersonalPref) ||
                cssm_SetValue(szRegKey,"Day", (void *)&pAttrib->Attribute.Date->Day,
                2, CSSM_VALUE_BINARY, PersonalPref)
              )
				{
					return(CSSM_FAIL);
				}
            return(CSSM_OK);

        case CSSM_ATTRIBUTE_DATA_RANGE:
            if( cssm_SetValue(szRegKey,"Min", (void *)&pAttrib->Attribute.Range->Min,
                4, CSSM_VALUE_BINARY, PersonalPref) ||
                cssm_SetValue(szRegKey,"Max", (void *)&pAttrib->Attribute.Range->Max,
                4, CSSM_VALUE_BINARY, PersonalPref)
              )
				{
					return(CSSM_FAIL);
				}
            return(CSSM_OK);
    }
    return(CSSM_FAIL);
} /* End RegWriteContextAttrib() */

/*---------------------------------------------------------------
 *
 *Name: cssm_RegWriteContext
 *
 *Description:
 * Writes the passed context structure to the registry key
 *  specified. Will write all context attributes as subkeys of
 *  the passed key in the format Attribute0..Attributen
 *
 *Parameters:
 * hBaseKey(input) - Opened databse key from which to open the
 *  context storage key.
 * szRegKey(input) - Null terminated string containing the
 *  subkey in which to store the context data.
 * Context(input) - CSSMContext structure to save in
 *  the registry.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - all data could not be stored in the registry
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegWriteContext(char * regKey,
                           sint32 PersonalPref,
                           CSSM_CONTEXT_PTR pContext) {
    sint32 regResult;
    uint32 i;
    char keyname[16];
    char tempstr[MAX_REG];

	if ((regKey == NULL) || (pContext == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* Save the structure values in the opened key */
    regResult = cssm_SetValue(regKey,"Type",
                             (void *)&pContext->ContextType,
                             sizeof(pContext->ContextType),
                             CSSM_VALUE_BINARY,PersonalPref);

    regResult |= cssm_SetValue(regKey,"AlgType",
                              (void *)&pContext->AlgorithmType,
                              sizeof(pContext->AlgorithmType),
                              CSSM_VALUE_BINARY,PersonalPref);

    regResult |= cssm_SetValue(regKey,"AttribCount",
                              (void *)&pContext->NumberOfAttributes,
                              sizeof(pContext->NumberOfAttributes),
                              CSSM_VALUE_BINARY,PersonalPref);

    regResult |= cssm_SetValue(regKey,"Reserve",
                              (void *)&pContext->Reserve,
                              sizeof(pContext->NumberOfAttributes),
                              CSSM_VALUE_BINARY,PersonalPref);

    /* Save each of the attributes for the context */
    for (i = 0; !regResult && (i < pContext->NumberOfAttributes); i++) {
        strcpy(tempstr,regKey);
        sprintf(keyname,"\\Attribute%d", i+1);
        strcat(tempstr,keyname);
        regResult |= cssm_RegWriteContextAttrib (tempstr,PersonalPref, &pContext->ContextAttributes[i]);
    }

    return(regResult);

} /* End RegWriteContext() */


/*---------------------------------------------------------------
 *
 *Name: cssm_RegWriteCSPCapList
 *
 *Description:
 * Writes to the registy the number of capabilites and calls
 * a function to write each capability
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   pList - a pointer to a Capabilites list to be written
 *
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - all data was written
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegWriteCSPCapList (char *regKey,
                                             uint32 Count,
                                             CSSM_CSP_CAPABILITY_PTR Capability)
{
    uint32 i;

	if ((regKey == NULL) || (Capability == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary (regKey, "NumberOfCapabilities", Count) != CSSM_OK)
        return(CSSM_FAIL);

    /* Write each algorithm supported to the registry */
    if (!IsBadReadPtr (Capability, sizeof (CSSM_CONTEXT) * Count)) {
        for (i = 0; i < Count; i++) {
            char algRegKey[MAX_REG], szTemp[16];

            strcpy (algRegKey, regKey);
            sprintf(szTemp, "\\Capability%d", i+1);
            strcat (algRegKey, szTemp);

            if (cssm_RegWriteContext (algRegKey, CSSM_PREFERENCE_GLOBAL,
                    &Capability[i]) != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
        return(CSSM_FAIL);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadContext
 *
 *Description:
 * Reads the passed key from the registry to the passed context
 *  structure. Will allocate memory for all attributes and read
 *  them in recursively.
 *
 *Parameters:
 * hBaseKey(input) - Opened databse key from which to open the
 *  context storage key.
 * szRegKey(input) - Null terminated string containing the
 *  subkey from which to read the context data.
 * Context(input/output) - CSSMContext structure to read from
 *  the registry.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_MEMORY_ERROR - attribute memory could not be allocated
 * CSSM_FAIL - all data could not be read from the registry
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadContext (char *Section,
                          sint32 PersonalPref,
                          CSSM_CONTEXT_PTR pContext) {
    sint32 regResult;
    uint32 i;
    char keyname[16];
    sint32 dataType = CSSM_VALUE_BINARY;
    sint32 dataSize = 4;
    char tempstr[MAX_REG];

 	if ((Section == NULL) || (pContext == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

	/* Read the structure values from the opened key */
    regResult = cssm_GetValue(Section,"Type",
                             (void *)&pContext->ContextType,
                             &dataSize,&dataType,
                             PersonalPref);

    regResult |= cssm_GetValue(Section,"AlgType",
                              (void *)&pContext->AlgorithmType,
                              &dataSize,&dataType,
                              PersonalPref);

    regResult |= cssm_GetValue(Section,"AttribCount",
                              (void *)&pContext->NumberOfAttributes,
                              &dataSize,&dataType,
                              PersonalPref);

    regResult = cssm_GetValue(Section,"Reserve",
                             (void *)&pContext->Reserve,
                             &dataSize,&dataType,
                             PersonalPref);

    if (regResult != CSSM_OK)
        return(regResult);

    if ( pContext->NumberOfAttributes != 0 ) {

		/* allocate memory for each attribute structure */
		if ((pContext->ContextAttributes = app_malloc(pContext->NumberOfAttributes * sizeof(CSSM_CONTEXT_ATTRIBUTE), memRef)) == NULL) {
			pContext->ContextAttributes = NULL;
			return(CSSM_MEMORY_ERROR);
		}

		/* Read each of the attributes for the context */
		for (i = 0; i < pContext->NumberOfAttributes; i++)
		{
			strcpy(tempstr,Section);
			sprintf(keyname,"\\Attribute%d", i+1);
			strcat(tempstr,keyname);
			regResult = cssm_RegReadContextAttrib(tempstr,PersonalPref,&pContext->ContextAttributes[i]);
			if (regResult != CSSM_OK)
				return(regResult);
		}

	}	/* if (pContext->NumberOfAttributes != 0) */


    return(CSSM_OK);
} /* End RegReadContext() */

/*---------------------------------------------------------------
 *
 *Name: cssm_RegWriteVersion
 *
 *Description:
 *   function for writing the version information to the registry
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   VerMajor - major version number
 *   Version.Minor - minor version number
 *
 *Returns:
 *  CSSM_FAIL - unable to update registry
 *  CSSM_OK - registry is updated
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegWriteVersion (char *regKey, char *Label,
                                  uint32 VerMajor, uint32 VerMinor)
{
    char Version[MAX_REG];

	if ((regKey == NULL) || (Label == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    sprintf (Version, "%ld.%ld\0", VerMajor, VerMinor);

    if (cssm_SetValue(regKey, Label, (void *)Version, strlen (Version) + 1,
                          CSSM_VALUE_STRING, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadUTC (char *regKey, char *Label,
                                        char *Str)
{
    sint32 dataType;
    char TempStr[17];
    sint32 Len = 17;

	if ((regKey == NULL) || (Label == NULL) || (Str == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* vendor strint */
    if (cssm_GetValue(regKey, Label, (void *)TempStr,
                     &Len, &dataType, CSSM_PREFERENCE_GLOBAL) == CSSM_FAIL) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (cssm_CheckCopy (Str, TempStr, 16) == CSSM_FAIL)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCommonInfo (char *regKey,
                                             CSSM_VERSION Version,
                                             char *Description,
                                             char *Vendor,
                                             CSSM_BOOL ThreadSafe,
                                             uint32 NumberOfSubServices)
{

	if ((regKey == NULL) || (Description == NULL) || (Vendor == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegWriteVersion (regKey, "Version", Version.Major, Version.Minor) != CSSM_OK)
        return(CSSM_FAIL);

    /* Save the vendor & description */
    if (cssm_RegWriteString (regKey, "Vendor", Vendor) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteString (regKey, "Description", Description) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "ThreadSafe", ThreadSafe) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "NumberOfSubService", NumberOfSubServices)
                              != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegFindServiceNum
 *
 *Description:
 *   Find the Service Number (psRegKey/Service#) that corespons to a InfoTag
 *
 *Parameters:
 *   InfoTag - InfoTag (psRegKey/Service#/InfoTag) that you are looking for
 *   szRegKey - pointer to the register key
 *   LastServices - The last service number to examine
 *
 *Returns:
 *   0 - Error, SubservicID not found
 *   Else - Specifies the subservice number where the Subservice ID can be found
 *
 *-------------------------------------------------------------*/
uint32 CSSMAPI cssm_RegFindServiceNum(uint32 InfoTag, char *szRegKey, uint32 LastService)
{
    uint32 cnt, Tag;
    int dataType, dataSize = 4;

	if (szRegKey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(0);
	}

    for (cnt = 1; cnt <= LastService; cnt++)
    {
        // Read in the Info Tag, see if the Tag is the same as what I am looking for
        char LocalKey[MAX_REG];

        strcpy (LocalKey, szRegKey);
        strcat (LocalKey, "\\Service");
        _itoa (cnt, &LocalKey[strlen (LocalKey)], 10);

        if (cssm_GetValue (szRegKey, "InfoTag", &Tag, &dataSize, &dataType,
               CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
            CSSM_ClearError();
        }
        else if (InfoTag == Tag)
            return(cnt);
    }

    return(0);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegFindSubServiceNum
 *
 *Description:
 *   Find the Subservice Number (psRegKey/Subservice#) that corespons to a subservice ID,
 *
 *Parameters:
 *   SubserviceID - SubserviceID (psRegKey/Subservice#/SubServiceID) that you are looking for
 *   szRegKey - pointer to the register key
 *   LastSubServices - The number of the last subservices to examine
 *
 *Returns:
 *   CSSM_ALL_SUBSERVICES (-1) - The function was asked to find all Subservices
 *   0 - Error, SubservicID not found
 *   Else - Specifies the subservice number where the Subservice ID can be found
 *
 *-------------------------------------------------------------*/
int CSSMAPI cssm_RegFindSubServiceNum(uint32 SubserviceID, char * szRegKey, uint32 LastSubServices)
{
    uint32 i;

	if (szRegKey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(0);
	}

    if (SubserviceID == CSSM_ALL_SUBSERVICES)
        return(CSSM_ALL_SUBSERVICES);

    for (i = 1; i <= LastSubServices; i++)
    {
        uint32 id;
        char LocalKey[MAX_REG];

        strcpy (LocalKey, szRegKey);
        strcat (LocalKey, "\\SubService");
        _itoa (i, &LocalKey[strlen (LocalKey)], 10);

        if (cssm_RegReadBinary (LocalKey, "SubServiceID", &id, 4) != CSSM_OK) {
            CSSM_ClearError();
        }
        else if (id == SubserviceID)
            return(i);
    }
    return(0);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCSPSWService (char *regKey,
                                       CSSM_SOFTWARE_CSPSUBSERVICE_INFO_PTR Info)
{
	CSSM_RETURN	rc;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (Info->Reserved && (cssm_RegReadDataStruct (regKey, "Reserved", Info->Reserved) != CSSM_OK))
        return(CSSM_FAIL);

    rc = cssm_RegWriteCSPCapList(regKey, Info->NumberOfCapabilities,
                                  Info->CapabilityList);
	return(rc);
}


CSSM_RETURN CSSMAPI cssm_RegWriteCSPHardwareService (char *TregKey,
                                       CSSM_HARDWARE_CSPSUBSERVICE_INFO_PTR Info)

{
    char regKey[MAX_REG];

	if ((TregKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(regKey, TregKey);
    strcat(regKey, "\\Hardware");

    if (Info->Reserved && (cssm_RegReadDataStruct (regKey, "Reserved", Info->Reserved) != CSSM_OK))
        return(CSSM_FAIL);

    if (cssm_RegWriteCSPCapList(TregKey, Info->NumberOfCapabilities,
                                   Info->CapabilityList))
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (regKey, "ReaderDescription", Info->ReaderDescription)
            != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (regKey, "ReaderVendor", Info->ReaderVendor) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (regKey, "ReaderSerialNumber", Info->ReaderSerialNumber)
            != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteVersion (regKey, "ReaderHardwareVersion",
            Info->ReaderHardwareVersion.Major, Info->ReaderHardwareVersion.Minor)
            != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteVersion (regKey, "ReaderFirmwareVersion",
            Info->ReaderFirmwareVersion.Major, Info->ReaderFirmwareVersion.Minor)
            != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "ReaderFlags", Info->ReaderFlags) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "ReaderCustomFlags", Info->ReaderCustomFlags) != CSSM_OK)
        return(CSSM_FAIL);

    if ((Info->TokenDescription != NULL) || (CSSM_CSP_RDR_TOKENPRESENT & Info->ReaderFlags))
    {
        if ((Info->TokenDescription != NULL) && cssm_RegWriteCSSMString (regKey, "TokenDescription",
                Info->TokenDescription) != CSSM_OK)
            return(CSSM_FAIL);

        if ((Info->TokenVendor != NULL) && cssm_RegWriteCSSMString (regKey, "TokenVendor",
                Info->TokenVendor) != CSSM_OK)
            return(CSSM_FAIL);

        if ((Info->TokenSerialNumber != NULL) && cssm_RegWriteCSSMString (regKey,
                "TokenSerialNumber", Info->TokenSerialNumber) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_RegWriteVersion (regKey, "TokenHardwareVersion",
                Info->TokenHardwareVersion.Major, Info->TokenHardwareVersion.Minor)
                != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_RegWriteVersion (regKey, "TokenFirmwareVersion",
                Info->TokenFirmwareVersion.Major, Info->TokenFirmwareVersion.Minor)
                != CSSM_OK)
            return(CSSM_FAIL);

        if ((cssm_WriteBinary (regKey, "TokenFlags", Info->TokenFlags) != CSSM_OK))
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenCustomFlags", Info->TokenCustomFlags) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenMaxSessionCount", Info->TokenMaxSessionCount) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenOpenedSessionCount", Info->TokenOpenedSessionCount) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenMaxRWSessionCount", Info->TokenMaxRWSessionCount) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenOpenedRWSessionCount", Info->TokenOpenedRWSessionCount) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenTotalPublicMem", Info->TokenTotalPublicMem) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenFreePublicMem", Info->TokenFreePublicMem) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenTotalPrivateMem", Info->TokenTotalPrivateMem) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenFreePrivateMem", Info->TokenFreePrivateMem) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenMaxPinLen", Info->TokenMaxPinLen) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteBinary (regKey, "TokenMinPinLen", Info->TokenMinPinLen) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteUTC (regKey, "TokenUTCTime", Info->TokenUTCTime) != CSSM_OK)
            return(CSSM_FAIL);
    }

    if ((Info->UserLabel != NULL) && cssm_RegWriteCSSMString (regKey, "UserLabel",
            Info->UserLabel) != CSSM_OK)
        return(CSSM_FAIL);

    if ((Info->UserCACertificate.Data != NULL) && cssm_RegWriteDataStruct (regKey,
            "UserCACertificate", &Info->UserCACertificate) != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_RETURN cssm_RegWriteCSPWrapped (char *regKey,
                                     CSSM_CSP_WRAPPEDPRODUCT_INFO_PTR const WrappedProduct)
{
    char wpKey[MAX_REG];

	if ((regKey == NULL) || (WrappedProduct == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy (wpKey, regKey);
    strcat (wpKey, "\\WrappedProduct");

    cssm_RegWriteVersion (wpKey, "StandardVersion",
                             WrappedProduct->StandardVersion.Major,
                             WrappedProduct->StandardVersion.Minor);

    if (cssm_RegWriteCSSMString (wpKey, "StandardDescription",
                          WrappedProduct->StandardDescription) != CSSM_OK)
        return(CSSM_FAIL);

    cssm_RegWriteVersion (wpKey, "ProductVersion",
                             WrappedProduct->ProductVersion.Major,
                             WrappedProduct->ProductVersion.Minor);

    if (cssm_RegWriteCSSMString (wpKey, "ProductDescription",
                          WrappedProduct->ProductDescription) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (wpKey, "ProductVendor",
                          WrappedProduct->ProductVendor) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (wpKey, "ProductFlags", WrappedProduct->ProductFlags)
                                     != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCSPSubService (char *regKey,
                                               CSSM_CSPSUBSERVICE_PTR const Sub)
{

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    if (cssm_WriteBinary (regKey, "SubServiceID", Sub->SubServiceId) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (regKey, "Description", Sub->Description) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "CspFlags", Sub->CspFlags) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "CspCustomFlags", Sub->CspCustomFlags)
             != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "AccessFlags", Sub->AccessFlags) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary (regKey, "CspType", Sub->CspType) != CSSM_OK)
        return(CSSM_FAIL);

    switch (Sub->CspType) {
        case CSSM_CSP_SOFTWARE :
            if (cssm_RegWriteCSPSWService (regKey, &Sub->SoftwareCspSubService) != CSSM_OK)
                return(CSSM_FAIL);
        break;

        case CSSM_CSP_HARDWARE :
            if (cssm_RegWriteCSPHardwareService (regKey, &Sub->HardwareCspSubService) != CSSM_OK)
                return(CSSM_FAIL);
        break;
    }

    if (cssm_RegWriteCSPWrapped (regKey, &Sub->WrappedProduct) != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: RegReadAllContext
 *
 *Description:
 * Takes the register key CSP and allocates enough memory to hold
 *  the information about that CSP. Returns NULL for the CSPInfo
 *  structure if there was an error in reading the information.
 *
 *Parameters:
 * szCSPName(input) - Null terminated string containing the
 *  logical name of the CSP.
 * ppCSPInfo(output) - Pointer to a CSPInfo structure that will
 *  point to the allocated data at exit.
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_MEMORY_ERROR - enough memory could not be allocated
 * CSSM_FAIL - all subkeys could not be read.
 *-------------------------------------------------------------*/
CSSM_CONTEXT_PTR CSSMAPI cssm_RegReadAllContext (char * regKey,
                                 uint32 *NumberOfContexts)
{
    char algKey[MAX_REG];
    sint32 regResult;
    sint32 index;
    sint32 contextindex;
    uint32 i;
    char ** list;
    CSSM_CONTEXT_PTR Contexts;

	if ((regKey == NULL) || (NumberOfContexts == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(NULL);
	}

    /* Get the algorithm count for the CSP */
    if (cssm_RegCountCSPAlgorithms (regKey,NULL,(sint32 *)NumberOfContexts) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(NULL);
    }

    /* Allocate memory for the algorithm information */
    if ((Contexts = app_malloc(*NumberOfContexts * sizeof(CSSM_CONTEXT), memRef)) == NULL) {
        app_free(Contexts, memRef);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }
    memset(Contexts,0,*NumberOfContexts * sizeof(CSSM_CONTEXT));

    /* Enumerate through the algorithm types and add each context to the CSPInfo structure */
    if (cssm_GetSectionList (regKey,&list,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        app_free(Contexts, memRef);
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(NULL);
    }

    index = 0;
    contextindex = 0;
    while (list[index]) {
        uint32 classmask;
        uint32 contextcount;
        char subKey[MAX_REG];
        sint32 dataType = CSSM_VALUE_BINARY;
        sint32 dataSize = sizeof (contextcount);;

        /* Read in all algorithms for the current class */
        classmask = cssm_KeyToClassMask (list[index]);
        strcpy (subKey, regKey);
        strcat (subKey, "\\");
        strcat (subKey, list[index]);
        cssm_GetValue (subKey,"AlgCount", (void *)&contextcount,
                              &dataSize,&dataType,
                                 CSSM_PREFERENCE_GLOBAL);
        for (i = 0; i < contextcount; i++) {
            /* Generate the key name for the current algorithm number */
            strcpy (algKey,subKey);
            strcat (algKey,"\\Algorithm");
            _itoa (i,&algKey[strlen(algKey)],10);

            /* Read in the context and bump count */
            regResult = cssm_RegReadContext (algKey,CSSM_PREFERENCE_GLOBAL,
                                       &Contexts[contextindex]);
            contextindex++;
            if (regResult != CSSM_OK) {
                uint32 i,j;

                for (i = 0; i < *NumberOfContexts; i++) {
                    if (Contexts[i].ContextAttributes != NULL) {
                        for (j = 0; j < Contexts[i].NumberOfAttributes; j++) {
                            if (Contexts[i].ContextAttributes[j].Attribute.Data)
                                app_free(Contexts[i].ContextAttributes[j].Attribute.Data, memRef);
                        }
                        app_free(Contexts[i].ContextAttributes, memRef);
                    }
                }

                cssm_free(list[index], 0);
                app_free(Contexts, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(NULL);
            }
        }
        cssm_free(list[index], 0);
        index++;
    }

    /* Set the return values and exit */
    return(Contexts);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegRemoveModule
 *
 *Description:
 * Wipes references to the passed DBP from the registry.
 *
 *Parameters:
 *   GUID - pointer to the guid of add-in
 *
 *Returns:
 * CSSM_OK - call is successful
 * CSSM_FAIL - all data could not be read
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegRemoveModule (const CSSM_GUID_PTR GUID)
{
    char		regKey[MAX_REG];
    char		ID[MAX_REG];
	CSSM_RETURN	rc;

	if (GUID == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* Generate sub-key name */
    strcpy(regKey, CSSMSECTION);
    cssm_GUIDToStr (GUID, ID);
    strcat(regKey, ID);

    /* Kill it */
    rc = cssm_DeleteSection (regKey,CSSM_PREFERENCE_GLOBAL);
	return(rc);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadAddInList
 *
 *Description:
 *  Returns an array of CSSM_LIST_ITEM entries that list the names
 *  of add-ins found in the registry
 *
 *Parameters:
 * AddInType(output) - Add-in type identifier
 *
 *Returns:
 * Null - unable to return list of add-in entries
 * not null - pointer to cssm_list
 *-------------------------------------------------------------*/
CSSM_LIST_PTR CSSMAPI cssm_RegReadModuleList (CSSM_SERVICE_MASK UsageMask,
                                             CSSM_BOOL MatchAll)
{
    sint32 numkeys, regResult;
    CSSM_LIST_PTR returnList;
    CSSM_LIST_ITEM_PTR returnListItem;
    sint32 i, Actual = 0;
    char regSection[MAX_REG];
    char **GUIDList;
    char** tempguid;
    char* tempptr;

    /* Generate the registry Section for the add in information */

    strcpy (regSection, CSSMSECTION);

    /* Get the count of GUIDs install */
    regResult = cssm_GetSectionCount (regSection, &numkeys,
                                            CSSM_PREFERENCE_GLOBAL);
    if (regResult != CSSM_OK || numkeys == 0) {
        CSSM_SetError (&cssm_GUID, CSSM_NO_ADDIN);
        return(NULL);
    }

    /* Enumerate the add in keys and place in string list */
    regResult = cssm_GetSectionList (regSection, &GUIDList, CSSM_PREFERENCE_GLOBAL);
    if (regResult != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(NULL);
    }

    if ((returnList = app_malloc (sizeof (CSSM_LIST), memRef)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    if ((returnListItem = app_malloc (sizeof (CSSM_LIST_ITEM) * numkeys, memRef)) == NULL) {
        app_free (returnList, memRef);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    tempguid = GUIDList;
    tempptr = *(tempguid);

    for (i=0; i < numkeys; i++) {
        char regKey[MAX_REG], Name[MAX_REG];
        sint32 dataLength = MAX_REG;
        sint16 j;
        uint32 Mask;
        sint32 dataSize = sizeof (Mask);
        sint32 dataType = CSSM_VALUE_BINARY;
        CSSM_BOOL MatchRes;

        strcpy (regKey, CSSMSECTION);
        strcat (regKey, tempptr);

        if (cssm_GetValue (regKey, "ServiceMasks", (void *)&Mask, &dataSize,
                           &dataType, CSSM_PREFERENCE_GLOBAL) != CSSM_FAIL) {

            if (MatchAll)
                MatchRes = (Mask == UsageMask);
            else
                MatchRes = Mask & UsageMask;

            if (MatchRes) {
                dataType = CSSM_VALUE_STRING;

                if (cssm_GetValue (regKey, "Name", (void *)Name, &dataLength,
                                   &dataType, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
                    for (j=0; j < Actual; j++)
                        app_free (returnListItem[j].Name, memRef);

                    app_free (returnList, memRef);
                    app_free (returnListItem, memRef);
                    return(NULL);
                }

                cssm_StrToGUID (tempptr, &returnListItem[Actual].GUID);

                dataLength = max ((uint32)dataLength, strlen (Name));
                if ((returnListItem[Actual].Name = app_malloc (dataLength, memRef)) == NULL) {

                    for (j=0; j < Actual; j++)
                        app_free (returnListItem[j].Name, memRef);

                    app_free (returnList, memRef);
                    app_free (returnListItem, memRef);
                    CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                    return(NULL);
                }

                strcpy (returnListItem[Actual].Name, Name);
                Actual++;
            }
        }

        /* advance to next GUID */
        if (i < numkeys-1) {
            tempguid++;
            tempptr = *tempguid;
        }
    }

    if (GUIDList != NULL) {
	    for (i=0; i < numkeys; i++) {
			cssm_free(GUIDList[i], NULL);
		}
        cssm_free(GUIDList, NULL);
	}

    if (Actual == 0) {
        app_free (returnList, memRef);
        app_free (returnListItem, memRef);
		CSSM_SetError (&cssm_GUID, CSSM_NO_ADDIN); //no addin found matching desired parameters
        return(NULL);
    } else {
		CSSM_ClearError (); //clears temporary errors set by cssm_GetValue
        returnListItem = app_realloc (returnListItem, sizeof (CSSM_LIST_ITEM) * Actual, memRef);
        returnList->NumberItems = Actual;
        returnList->Items = returnListItem;
        return(returnList);
    }
}

CSSM_SERVICE_MASK CSSMAPI cssm_RegReadUsage (const CSSM_GUID_PTR GUID)
{
    char regSection[MAX_REG];
    char ID[MAX_REG];
    uint32 Mask;
    sint32 dataSize = sizeof (Mask);
    sint32 dataType = CSSM_VALUE_BINARY;

	if (GUID == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(0);
	}

    /* Generate the registry Section for the add in information */
    strcpy (regSection, CSSMSECTION);

    /* Get the summary usage of GUIDs install */
    cssm_GUIDToStr (GUID, ID);
    strcat(regSection, ID);

    if (cssm_GetValue (regSection, "ServiceMasks", (void *)&Mask, &dataSize,
                           &dataType, CSSM_PREFERENCE_GLOBAL)) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(0);
    } else
        return(Mask);
}


CSSM_RETURN cssm_WriteFields(char *regKey, uint32 NumberOfPolicyIds,
                             CSSM_FIELD_PTR PolicyIds)
{
    uint32 i;

	if (regKey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (!IsBadReadPtr (PolicyIds, sizeof (CSSM_FIELD) * NumberOfPolicyIds)) {
        for (i = 0; i < NumberOfPolicyIds; i++) {
            char Label[MAX_REG];

            strcpy (Label, "OID\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            if (cssm_RegWriteDataStruct (regKey, Label, &PolicyIds[i].FieldOid)
                                        != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }

            strcpy (Label, "Value\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            if (cssm_RegWriteDataStruct (regKey, Label, &PolicyIds[i].FieldValue)
 != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
        return(CSSM_OK);
    } else
        return(CSSM_FAIL);
}

CSSM_RETURN CSSMAPI cssm_RegWriteTPWrapped(char *regKey,
                                           CSSM_TP_WRAPPEDPRODUCT_INFO_PTR pWrapped)
{
    char wpKey[MAX_REG];
    CSSM_RETURN Result;

	if ((regKey == NULL) || (pWrapped == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    sprintf(wpKey, "%s\\WrappedProduct", regKey);

    Result = cssm_RegWriteVersion(wpKey, "WrappedStandardVersion", pWrapped->StandardVersion.Major,
        pWrapped->StandardVersion.Minor);
    Result |= cssm_RegWriteCSSMString(wpKey, "StandardDescription", pWrapped->StandardDescription);
    Result |= cssm_RegWriteCSSMString(wpKey, "ProductVendor", pWrapped->ProductVendor);
    Result |= cssm_WriteBinary(wpKey, "ProductFlags", pWrapped->ProductFlags);

    return(Result);
}


CSSM_RETURN CSSMAPI cssm_RegWriteTPSubService (char *regKey,
                                               CSSM_TPSUBSERVICE_PTR Sub)
{
    CSSM_RETURN Result;
	CSSM_RETURN	rc;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_WriteBinary (regKey, "SubServiceID", Sub->SubServiceId);
    Result |= cssm_RegWriteCSSMString (regKey, "Description", Sub->Description);
    Result |= cssm_WriteBinary (regKey, "Authentication Mechanism",
                                  Sub->AuthenticationMechanism);
    Result |= cssm_WriteBinary (regKey, "CertType", Sub->CertType);

    if (Result != CSSM_OK)
        return(Result);

    if (Sub->NumberOfPolicyIdentifiers > 0) {
        if (cssm_WriteBinary (regKey, "Number Policies", Sub->NumberOfPolicyIdentifiers) != CSSM_OK)
            return(CSSM_FAIL);

        if (cssm_WriteFields (regKey, Sub->NumberOfPolicyIdentifiers, Sub->PolicyIdentifiers) != CSSM_OK)
            return(CSSM_FAIL);
    }

    rc = cssm_RegWriteTPWrapped(regKey, &Sub->WrappedProduct);
	return(rc);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCLWrapped(char *regKey,
                                           CSSM_CL_WRAPPEDPRODUCT_INFO_PTR const pWP)
{
    uint32 i;
    char wpKey[MAX_REG];

	if ((regKey == NULL) || (pWP == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(wpKey, regKey);
    strcat(wpKey, "\\WrappedProduct");

    if (cssm_WriteBinary(wpKey, "NumberOfEncoderProducts", pWP->NumberOfEncoderProducts) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_WriteBinary(wpKey, "NumberOfCAProducts", pWP->NumberOfCAProducts) != CSSM_OK)
        return(CSSM_FAIL);

    for (i = 0; i < pWP->NumberOfEncoderProducts; i++)
    {
        CSSM_CL_ENCODER_PRODUCTINFO_PTR EEP = &pWP->EmbeddedEncoderProducts[i];
        char szTemp[MAX_REG];
        sprintf(szTemp, "%s\\WrappedEncoderProduct%d", wpKey, i+1);

        if (cssm_RegWriteVersion(szTemp, "StandardVersion", EEP->StandardVersion.Major,
                EEP->StandardVersion.Minor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "StandardDescription", EEP->StandardDescription) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteVersion(szTemp, "ProductVersion", EEP->ProductVersion.Major,
                EEP->ProductVersion.Minor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "ProductDescription", EEP->ProductDescription) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "ProductVendor", EEP->ProductVendor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(szTemp, "CertType", EEP->CertType) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(szTemp, "ProductFlags", EEP->ProductFlags) != CSSM_OK)
            return(CSSM_FAIL);
    }

    for (i = 0; i < pWP->NumberOfCAProducts; i++)
    {
        uint32 j;
        CSSM_CL_CA_PRODUCTINFO_PTR CAP = &pWP->AccessibleCAProducts[i];
        char szTemp[MAX_REG];
        sprintf(szTemp, "%s\\WrappedCAProduct%d", wpKey, i+1);

        if (cssm_RegWriteVersion(szTemp, "StandardVersion", CAP->StandardVersion.Major,
                CAP->StandardVersion.Minor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "StandardDescription", CAP->StandardDescription) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteVersion(szTemp, "ProductVersion", CAP->ProductVersion.Major,
                CAP->ProductVersion.Minor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "ProductDescription", CAP->ProductDescription) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteCSSMString(szTemp, "ProductVendor", CAP->ProductVendor) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(szTemp, "CertType", CAP->CertType) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(szTemp, "AdditionalServiceFlags", CAP->AdditionalServiceFlags) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(szTemp, "NumberOfCertClasses", CAP->NumberOfCertClasses) != CSSM_OK)
            return(CSSM_FAIL);

        for (j = 0; j < CAP->NumberOfCertClasses; j++)
        {

            char Label[MAX_REG];
            sprintf(Label, "CertClassName%d", j+1);
            if (cssm_RegWriteCSSMString(szTemp, Label, CAP->CertClasses[j].CertClassName) != CSSM_OK)
                return(CSSM_FAIL);
            sprintf(Label, "CACert%d", j+1);
            if (cssm_RegWriteDataStruct(szTemp, Label, &CAP->CertClasses[j].CACert) != CSSM_OK)
                return(CSSM_FAIL);
        }
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCLSubService (char *regKey,
                                               CSSM_CLSUBSERVICE_PTR Sub)
{
    CSSM_RETURN Result;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_WriteBinary(regKey,"SubServiceID", Sub->SubServiceId);
    Result |= cssm_RegWriteCSSMString(regKey, "Description", Sub->Description);
    Result |= cssm_WriteBinary(regKey, "CertType", Sub->CertType);
    Result |= cssm_WriteBinary(regKey,"CertEncoding", Sub->CertEncoding);
    Result |= cssm_WriteBinary(regKey, "Authentication Mechanism", Sub->AuthenticationMechanism);

    if (Result != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(Result);
    }

    /* Write each template entry to the registry */
    if (!IsBadReadPtr (Sub->CertTemplates, sizeof (CSSM_OID) * Sub->NumberOfTemplateFields)) {
        uint32 i;
        if (cssm_WriteBinary (regKey,"NumberOfTemplateFields", Sub->NumberOfTemplateFields) != CSSM_OK) {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        for (i = 0; i < Sub->NumberOfTemplateFields; i++) {
            char algRegKey[MAX_REG], Label[MAX_REG];

            strcpy (algRegKey, regKey);
            strcat (algRegKey, "\\");
            strcat (algRegKey, "CertTemplates");

            strcpy (Label, "OID\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            if (cssm_RegWriteDataStruct (algRegKey, Label, &Sub->CertTemplates[i]) != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }

    /* Write each algorithm supported to the registry */
    if (!IsBadReadPtr (Sub->CertTranslationTypes, sizeof (CSSM_CERT_TYPE) * Sub->NumberOfTranslationTypes)) {
        uint32 i;
        if (cssm_WriteBinary (regKey,"NumberOfTranslationTypes", Sub->NumberOfTranslationTypes) != CSSM_OK) {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        for (i = 0; i < Sub->NumberOfTranslationTypes; i++) {
            sint32 size;
            char algRegKey[MAX_REG], Label[MAX_REG];

            strcpy (algRegKey, regKey);
            strcat (algRegKey, "\\");
            strcat (algRegKey, "CertTypes");

            strcpy (Label, "Type\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            size = sizeof (Sub->CertType);
            if (cssm_WriteBinary (algRegKey,Label, Sub->CertTranslationTypes[i]) != CSSM_OK) {
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }

    cssm_RegWriteCLWrapped(regKey, &Sub->WrappedProduct);

    return(CSSM_OK);
}

CSSM_RETURN cssm_RegWriteDLWrapped (char *regKey,
                                    CSSM_DL_WRAPPEDPRODUCT_INFO_PTR const WrappedProduct)
{
    char wpKey[MAX_REG];

	if ((regKey == NULL) || (WrappedProduct == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(wpKey, regKey);
    strcat(wpKey, "\\WrappedProduct");

    if (cssm_RegWriteVersion (wpKey, "StandardVersion", WrappedProduct->StandardVersion.Major,
            WrappedProduct->StandardVersion.Minor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegWriteCSSMString(wpKey, "StandardDescription", WrappedProduct->StandardDescription) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteVersion (wpKey, "ProductVersion", WrappedProduct->ProductVersion.Major,
            WrappedProduct->ProductVersion.Minor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegWriteCSSMString(wpKey, "ProductDescription", WrappedProduct->ProductDescription) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegWriteCSSMString(wpKey, "ProductVendor", WrappedProduct->ProductVendor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_WriteBinary(wpKey, "ProductFlags", WrappedProduct->ProductFlags) != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLDataStoreName(char *regKey,
                                                 CSSM_NAME_LIST_PTR NameList)
{
    uint32 i;

	if ((regKey == NULL) || (NameList == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary(regKey, "NumStrings", NameList->NumStrings) != CSSM_OK)
        return(CSSM_FAIL);

    for (i = 0; i < NameList->NumStrings; i++)
    {
        char Label[32];
        sprintf(Label, "String%d", i);

        if (cssm_RegWriteString (regKey, Label, NameList->String[i]) != CSSM_OK)
            return(CSSM_FAIL);
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLDBAttributeInfo(char *regKey,
                                                   CSSM_DB_ATTRIBUTE_INFO_PTR Info)

{

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary(regKey, "AttributeNameFormat", Info->AttributeNameFormat) != CSSM_OK)
        return(CSSM_FAIL);
    if (Info->AttributeNameFormat == CSSM_DB_ATTRIBUTE_NAME_AS_STRING)
    {
        if (cssm_RegWriteString(regKey, "AttributeName", Info->AttributeName) != CSSM_OK)
            return(CSSM_FAIL);
    }
    else
    {
        if (cssm_RegWriteDataStruct(regKey, "AttributeID", &Info->AttributeID) != CSSM_OK)
            return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLDBRecordAttribute(char *regKey,
                                                     CSSM_DB_RECORD_ATTRIBUTE_INFO_PTR Info)
{
    uint32 i;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary(regKey, "AttributeDataRecordType", Info->DataRecordType) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary(regKey, "NumberOfAttributes", Info->NumberOfAttributes) != CSSM_OK)
        return(CSSM_FAIL);

    for (i = 0; i < Info->NumberOfAttributes; i++)
    {
        char LocalKey[MAX_REG];

        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\Attribute");
        _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);

        if (cssm_RegWriteDLDBAttributeInfo(LocalKey, &Info->AttributeInfo[i]) != CSSM_OK)
            return(CSSM_FAIL);
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLDBRecordIndex(char *regKey,
                                                 CSSM_DB_RECORD_INDEX_INFO_PTR Info)
{
    uint32 i;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary(regKey, "IndexDataRecordType", Info->DataRecordType) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary(regKey, "NumberOfIndexes", Info->NumberOfIndexes) != CSSM_OK)
        return(CSSM_FAIL);

    for (i = 0; i < Info->NumberOfIndexes; i++)
    {
        char LocalKey[MAX_REG];

        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\Index");
        _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);

        if (cssm_WriteBinary(LocalKey, "IndexType", Info->IndexInfo[i].IndexType) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_WriteBinary(LocalKey, "IndexedDataLocation", Info->IndexInfo[i].IndexedDataLocation) != CSSM_OK)
            return(CSSM_FAIL);
        if (cssm_RegWriteDLDBAttributeInfo(LocalKey, &Info->IndexInfo[i].Info) != CSSM_OK)
            return(CSSM_FAIL);
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLDataStoreInfo(char *regKey,
                                                 CSSM_DBINFO_PTR DSInfo)
{
    uint32 cType;

	if ((regKey == NULL) || (DSInfo == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_WriteBinary(regKey, "NumberOfRecordTypes", DSInfo->NumberOfRecordTypes) != CSSM_OK)
        return(CSSM_FAIL);

    for (cType = 0; cType < DSInfo->NumberOfRecordTypes; cType++)
    {
        char Label[MAX_REG];

        strcpy (Label, regKey);
        strcat (Label, "\\RecordType");
        _itoa (cType+1, &Label[strlen (Label)], 10);

        if (cssm_SetValue (Label,"ParsingModule", (void *)&DSInfo->DefaultParsingModules[cType],
                sizeof(CSSM_DB_PARSING_MODULE_INFO), CSSM_VALUE_BINARY,CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
            return(CSSM_FAIL);

        if ((cssm_RegWriteDLDBRecordAttribute(Label, &DSInfo->RecordAttributeNames[cType]) != CSSM_OK) ||
            (cssm_RegWriteDLDBRecordIndex(Label, &DSInfo->RecordIndexes[cType]) != CSSM_OK))
            return(CSSM_FAIL);
    }

    if (cssm_WriteBinary(regKey, "AuthenticationMechanism", DSInfo->AuthenticationMechanism) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary(regKey, "RecordSigningImplemented", DSInfo->RecordSigningImplemented) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteDataStruct(regKey, "SigningCertificate", &DSInfo->SigningCertificate) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_SetValue (regKey,"SigningCsp", (void *)&DSInfo->SigningCsp,
            sizeof(CSSM_GUID), CSSM_VALUE_BINARY,CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_WriteBinary(regKey, "IsLocal", DSInfo->IsLocal) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteString(regKey, "AccessPath", DSInfo->AccessPath) != CSSM_OK)
        return(CSSM_FAIL);

    // Reserved is not being written/read

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteDLSubService (char *regKey,
                                               CSSM_DLSUBSERVICE_PTR Sub)
{
    uint32					i;
    CSSM_DB_OPERATOR_PTR	RelOpr;
    CSSM_DB_CONJUNCTIVE_PTR Conj;
    CSSM_RETURN				Result;
	CSSM_RETURN				rc;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_WriteBinary (regKey, "SubServiceID", Sub->SubServiceId);
    Result |= cssm_RegWriteCSSMString(regKey, "Description", Sub->Description);
    Result |= cssm_WriteBinary (regKey, "Type", Sub->Type);

    switch (Sub->Type) {
        case CSSM_DL_PKCS11 :
            Result |= cssm_WriteBinary (regKey, "Attributes",
                Sub->Attributes.Pkcs11Attributes->DeviceAccessFlags);
        break;
    }

    Result |= cssm_RegWriteDLWrapped (regKey, &Sub->WrappedProduct);
    Result |= cssm_WriteBinary (regKey, "Authentication Mechanism", Sub->AuthenticationMechanism);
    Result |= cssm_WriteBinary (regKey, "NumberOfRelOperators", Sub->NumberOfRelOperatorTypes);

    if (Result != CSSM_OK)
        return(Result);

    RelOpr = Sub->RelOperatorTypes;
    for (i=0; i<Sub->NumberOfRelOperatorTypes; i++) {
        char LocalKey[MAX_REG];
        char Label[MAX_REG];

        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\RelOperators");
        strcpy (Label, "Operator");
        _itoa (i+1, &Label[strlen (Label)], 10);

        if (cssm_WriteBinary (LocalKey, Label, *RelOpr) != CSSM_OK)
            return(CSSM_FAIL);

        RelOpr++;
    }

    if (cssm_WriteBinary (regKey, "NumberOfConjOperators",
                                  Sub->NumberOfConjOperatorTypes) != CSSM_OK)
        return(CSSM_FAIL);

    Conj = Sub->ConjOperatorTypes;
    for (i=0; i<Sub->NumberOfConjOperatorTypes; i++) {
        char LocalKey[MAX_REG];
        char Label[MAX_REG];

        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\ConjOperators");
        strcpy (Label, "Operator");
        _itoa (i+1, &Label[strlen (Label)], 10);

        if (cssm_WriteBinary (LocalKey, Label, *Conj) != CSSM_OK)
            return(CSSM_FAIL);

        Conj++;
    }

    if (cssm_WriteBinary (regKey, "QueryLimitsSupported",
                                  Sub->QueryLimitsSupported) != CSSM_OK)
        return(CSSM_FAIL);

    if (Sub->Reserved)
        if (!cssm_IsBadReadPtr (Sub->Reserved, sizeof (Sub->Reserved))) {
            rc = cssm_RegWriteDataStruct (regKey, "Reserved", Sub->Reserved);
			return(rc);
		}

    if (cssm_WriteBinary (regKey, "NumberOfDataStores",
                                  Sub->NumberOfDataStores) != CSSM_OK)
        return(CSSM_FAIL);

    if (Sub->NumberOfDataStores != CSSM_DB_DATASTORES_UNKNOWN)
        for (i = 0; i < Sub->NumberOfDataStores; i++) {
            char Label[MAX_REG];

            strcpy (Label, regKey);
            strcat (Label, "\\DataStoreNum");
            _itoa (i+1, &Label[strlen (Label)], 10);

            if (cssm_RegWriteDLDataStoreName(Label, &Sub->DataStoreNames[i]) != CSSM_OK)
                return(CSSM_FAIL);
            if (cssm_RegWriteDLDataStoreInfo(Label, &Sub->DataStoreInfo[i]) != CSSM_OK)
                return(CSSM_FAIL);
        }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteCSSMInfo (char *regKey,
                                           CSSM_MODULE_INFO_PTR Info,
                                           CSSM_GUID_PTR GUID)
{
    char ID[MAX_REG];

    if ((Info == NULL) || (regKey == NULL) || (GUID == NULL))
	{
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
        return(CSSM_FAIL);
    }

    if (cssm_RegWriteCommonInfo (regKey, Info->Version, (char *)Info->Description,
                                 (char *)Info->Vendor, 1, 0) != CSSM_OK)
        return(CSSM_FAIL);

    cssm_GUIDToStr (GUID, ID);
    if (cssm_RegWriteString (regKey, "GUID", ID) != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegWriteModule (
                                 const char *ModuleName,
                                 const char *ModuleFileName,
                                 const char *ModulePathName,
                                 const CSSM_GUID_PTR GUID,
                                 const CSSM_MODULE_INFO_PTR ModuleDescription,
                                 const void * Reserved1,
                                 const CSSM_DATA_PTR Reserved2)
{
    char		regKey[MAX_REG];
    char		ID[MAX_REG];
    char		url[MAX_REG];
    uint32		index;
	CSSM_RETURN	rc;

	if ((ModuleName == NULL) || (ModuleFileName == NULL) || (ModulePathName == NULL) ||
		(GUID == NULL) || (ModuleDescription == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    /* Generate sub-key name */
    strcpy (regKey, CSSMSECTION);
        cssm_GUIDToStr (GUID, ID);
        strcat (regKey, ID);

    /* Delete any information that may already be in the registry */
    cssm_DeleteSection (regKey,CSSM_PREFERENCE_GLOBAL);
    CSSM_ClearError ();

    /* Write each value passed */

#ifdef WIN32
    strcpy (url,"file:///");
    strcat (url,ModulePathName);
    index = 8;

    while (url[index] != 0) {            /* convert MS-DOS paths */
        if (url[index] == '\\')
            url[index] = '/';
        if (url[index] == ':')
            url[index] = '|';
        index++;
    }
#else
    strcpy (url,"file://");
    strcat (url,ModulePathName);
#endif

    strcat (url,"/");
    strcat (url, ModuleFileName);

    if (cssm_RegWriteString(regKey,"Location", url) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteString(regKey,"Name", (char *)ModuleName) != CSSM_OK)
        return(CSSM_FAIL);

    if (ModuleDescription->ServiceMask != CSSM_SERVICE_CSSM) {
        rc = cssm_RegWriteModuleInfo(regKey, ModuleDescription);
		return(rc);
	}
    else {
        rc = cssm_RegWriteCSSMInfo (regKey, ModuleDescription, GUID);
		return(rc);
	}
}

CSSM_RETURN CSSMAPI cssm_RegWriteModuleInfo (char *regKey,
                                             CSSM_MODULE_INFO_PTR Module)

{
    uint32 i;

	if ((regKey == NULL) || (Module == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    cssm_RegWriteVersion (regKey, "Version",
                             Module->Version.Major,
                             Module->Version.Minor);

    cssm_RegWriteVersion (regKey, "CompatibleCSSMVersion",
                             Module->CompatibleCSSMVersion.Major,
                             Module->CompatibleCSSMVersion.Minor);

    if (cssm_RegWriteCSSMString (regKey, "Description", Module->Description) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegWriteCSSMString (regKey, "Vendor", Module->Vendor) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_SetValue (regKey,"Flags",
                          (void *)&Module->Flags,
                          sizeof (Module->Flags),
                          CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_SetValue (regKey,"ServiceMasks",
                          (void *)&Module->ServiceMask,
                          sizeof (Module->ServiceMask),
                          CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_SetValue (regKey,"NumberOfServices",
                          (void *)&Module->NumberOfServices,
                          sizeof (Module->NumberOfServices),
                          CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
        return(CSSM_FAIL);

	if (Module->ServiceList == NULL) {
        uint32 dynamic = 1;

        cssm_SetValue (regKey,"Dynamic Capabilities",&dynamic,
                       sizeof(dynamic),CSSM_VALUE_BINARY,CSSM_CONFIG_GLOBAL);

        return(CSSM_OK);
    }

    for (i=0; i<Module->NumberOfServices; i++)
    {
        char LocalKey[MAX_REG];
        int regResult;

        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\Service");
        _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);

        if (cssm_RegWriteCSSMString (LocalKey, "Description", Module->ServiceList[i].Description) != CSSM_OK)
            return(CSSM_FAIL);

        if ((regResult = cssm_SetValue (LocalKey,"Type",
                             (void *)&Module->ServiceList[i].Type,
                             sizeof (Module->ServiceList[i].Type),
                             CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL)) != CSSM_OK)
            return(regResult);

        if ((regResult = cssm_SetValue (LocalKey,"Flags",
                             (void *)&Module->ServiceList[i].Flags,
                             sizeof (Module->ServiceList[i].Flags),
                             CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL)) != CSSM_OK)
            return(regResult);

        if ((regResult = cssm_SetValue (LocalKey,"NumberOfSubServices",
                            (void *)&Module->ServiceList[i].NumberOfSubServices,
                            sizeof (Module->ServiceList[i].NumberOfSubServices),
                            CSSM_VALUE_BINARY, CSSM_PREFERENCE_GLOBAL)) != CSSM_OK)
            return(regResult);

        switch (Module->ServiceList[i].Type) {
            uint32 j;
            char SubKey[MAX_REG];

            case CSSM_SERVICE_TP:

                for (j=0; j < Module->ServiceList[i].NumberOfSubServices; j++) {
                    strcpy (SubKey, LocalKey);
                    strcat (SubKey, "\\SubService");
                    _itoa (j+1, &SubKey[strlen (SubKey)], 10);
                    regResult = cssm_RegWriteTPSubService (SubKey, &Module->ServiceList[i].TpSubServiceList[j]);
                }
            break;

            case CSSM_SERVICE_CSP:

                for (j=0; j < Module->ServiceList[i].NumberOfSubServices; j++) {
                    strcpy (SubKey, LocalKey);
                    strcat (SubKey, "\\SubService");
                    _itoa (j+1, &SubKey[strlen (SubKey)], 10);
                    regResult = cssm_RegWriteCSPSubService (SubKey, &Module->ServiceList[i].CspSubServiceList[j]);
                }
            break;

            case CSSM_SERVICE_CL:
                for (j=0; j < Module->ServiceList[i].NumberOfSubServices; j++) {
                    strcpy (SubKey, LocalKey);
                    strcat (SubKey, "\\SubService");
                    _itoa (j+1, &SubKey[strlen (SubKey)], 10);
                    regResult = cssm_RegWriteCLSubService (SubKey, &Module->ServiceList[i].ClSubServiceList[j]);
                 }
            break;

            case CSSM_SERVICE_DL:
                for (j=0; j < Module->ServiceList[i].NumberOfSubServices; j++) {
                    strcpy (SubKey, LocalKey);
                    strcat (SubKey, "\\SubService");
                    _itoa (j+1, &SubKey[strlen (SubKey)], 10);
                    regResult = cssm_RegWriteDLSubService (SubKey, &Module->ServiceList[i].DlSubServiceList[j]);
                }
            break;

        if (regResult != CSSM_OK)
            return(regResult);

        }
    }

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegGetLocation
 *
 *Description:
 *   Get the data associated with the local label
 *
 *Parameters:
 *   AddInType - Identifier for add-in type
 *   GUID - pointer to the guid for the add-in
 *   path - pointer to buffer to store the path to the add-in
 *
 *Returns:
 *   CSSM_FAIL - unable to get the path
 *   CSSM_OK - location to the add-in is retreive
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegGetLocation (const CSSM_GUID_PTR GUID,
                                         char *path)
{
    char regKey[MAX_REG];
    CSSM_RETURN regResult;
    sint32 dataType = CSSM_CONFIG_BINARY;
    sint32 dataLength;
    char AddInURL[MAX_REG];
    char ID[MAX_REG];

	if ((path == NULL) || (GUID == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    /* Generate sub-key name */
    strcpy (regKey, CSSMSECTION);
    cssm_GUIDToStr (GUID, ID);
    strcat(regKey, ID);

    /* Get filename and location information */
    dataLength = MAX_REG;
    dataType = CSSM_VALUE_STRING;
    regResult = cssm_GetValue (regKey,"Location", (void *)AddInURL,
                               &dataLength, &dataType, CSSM_PREFERENCE_GLOBAL);

    if (regResult != CSSM_OK) {
        return(regResult);
    }

    /* Fix for WINNT 3.51 not nulling the string */
    AddInURL[dataLength] = 0;

    if (strncmp(AddInURL,"file://",7) == 0) {
#ifdef WIN32
        sint16 index = 7;
        while (AddInURL[index] != 0) {            /* convert MS-DOS paths */
            if (AddInURL[index] == '/')
                AddInURL[index] = '\\';
            if (AddInURL[index] == '|')
                AddInURL[index] = ':';
            index++;
        }
        strcpy(path, &AddInURL[8]);
#else
        strcpy(path, &AddInURL[7]);
#endif
    }

    return(CSSM_OK);
}


/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadBinary
 *
 *Description:
 *   Given a registry key and label, get the binary data associated
 *   with that label
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Label - pointer to label to tag data
 *   Bin - pointer to binary data
 *   Len = length of binary data
 *
 *Returns:
 *   CSSM_FAIL - unable to read data from registry
 *   CSSM_OK - data is in buffer
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadBinary (char *regKey, char *Label,
                                        void *Bin, uint32 Len)
{
    sint32 dataType;

	if ((regKey == NULL) || (Label == NULL) || (Bin == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

	if (Len > INT_MAX)
	{
        CSSM_SetError (&cssm_GUID, CSSM_VALUE_TOO_LARGE);
        return(CSSM_FAIL);
	}

    if (cssm_GetValue(regKey, Label, (void *)Bin, (sint32 *)&Len,
					  &dataType, CSSM_PREFERENCE_GLOBAL) == CSSM_FAIL) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RegReadVersion
 *
 *Description:
 *   Given a registry key and label, get the binary data associated
 *   with that label
 *
 *Parameters:
 *   regKey - pointer to the register key
 *   Major - pointer to hold major version number
 *   Minor = pointer to hold major version number
 *
 *Returns:
 *   CSSM_FAIL - unable to read data from registry
 *   CSSM_OK - data is in buffer
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RegReadVersion (char *regKey, char *Label,
                                         uint32 *Major, uint32 *Minor)
{
    sint32 dataType = CSSM_VALUE_STRING;
    sint32 dataLength = MAX_REG;
    char Version[MAX_REG], *p;

	if ((regKey == NULL) || (Label == NULL) ||
		(Major == NULL) || (Minor == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    if (cssm_GetValue (regKey, Label, (void *)Version, &dataLength,
               &dataType, CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    *Major = atoi (Version);
    p = strrchr (Version, '.');
    p ++;
    *Minor = atoi (p);

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadCommonInfo (char *regKey,
                                            uint32 *Major,
                                            uint32 *Minor,
                                            char **Description,
                                            char **Vendor,
                                            CSSM_BOOL *ThreadSafe,
                                            uint32 *NumberOfSubServices)
{
    uint32 i = 4;

	if ((regKey == NULL) || (Major == NULL) ||
		(Minor == NULL) || (Description == NULL) ||
		(Vendor == NULL) || (ThreadSafe == NULL) ||
		(NumberOfSubServices == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadVersion (regKey, "Version", Major, Minor) != CSSM_OK)
        return(CSSM_FAIL);

    /* Save the vendor & description */
    if (cssm_RegReadString (regKey, "Vendor", Vendor) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegReadString (regKey, "Description", Description) != CSSM_OK)
        return(CSSM_FAIL);

    if (ThreadSafe != NULL)
        if (cssm_RegReadBinary (regKey, "ThreadSafe", ThreadSafe, i) != CSSM_OK)
            return(CSSM_FAIL);

    if (cssm_RegReadBinary (regKey, "NumberOfSubService", NumberOfSubServices, i)
                              != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}

CSSM_FIELD_PTR cssm_ReadField (char *regKey, uint32 NumberOfPolicyId)
{
    CSSM_FIELD_PTR PolicyId = NULL;
    uint32 i;

	if (regKey == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(NULL);
	}

    if (NumberOfPolicyId < 1)
        return(NULL);

    if ((PolicyId = app_malloc (sizeof(CSSM_FIELD) * NumberOfPolicyId, memRef)) == NULL){
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    for (i=0; i<NumberOfPolicyId; i++) {
        char  Label[MAX_REG];

        strcpy (Label, "OID\0");
        _itoa (i+1, &Label[strlen(Label)], 10);

        if (cssm_RegReadDataStruct (regKey, Label, &PolicyId[i].FieldOid) != CSSM_OK) {
            /* Need to free memory allocated!! */
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            app_free (PolicyId, memRef);
            return(NULL);
        }

        strcpy (Label, "Value\0");
        _itoa (i+1, &Label[strlen(Label)], 10);

        if (cssm_RegReadDataStruct (regKey, Label, &PolicyId[i].FieldValue) != CSSM_OK) {
            /* Need to free memory allocated!! */
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            app_free (PolicyId, memRef);
            return(NULL);
        }
    }
    return(PolicyId);
}

CSSM_RETURN CSSMAPI cssm_RegReadTPWrapped(char *regKey,
                                          CSSM_TP_WRAPPEDPRODUCT_INFO_PTR pWrapped)
{
    char wpKey[MAX_REG];
    CSSM_RETURN Result;

	if ((regKey == NULL) || (pWrapped == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    sprintf(wpKey, "%s\\WrappedProduct", regKey);

    Result = cssm_RegReadVersion(wpKey, "WrappedStandardVersion", &pWrapped->StandardVersion.Major,
        &pWrapped->StandardVersion.Minor);
    Result |= cssm_RegReadCSSMString(wpKey, "StandardDescription", pWrapped->StandardDescription);
    Result |= cssm_RegReadCSSMString(wpKey, "ProductVendor", pWrapped->ProductVendor);
    Result |= cssm_RegReadBinary(wpKey, "ProductFlags", &pWrapped->ProductFlags, 4);

    return(Result);
}

CSSM_RETURN CSSMAPI cssm_RegReadTPSubService (char *regKey,
                                              CSSM_TPSUBSERVICE_PTR Sub,
                                              CSSM_INFO_LEVEL InfoLevel)
{
    uint32		i = 4;
    CSSM_RETURN Result;
	CSSM_RETURN	rc;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_RegReadBinary (regKey, "SubServiceID", &Sub->SubServiceId, i);
    Result |= cssm_RegReadCSSMString (regKey, "Description", Sub->Description);
    Result |= cssm_RegReadBinary (regKey, "Authentication Mechanism", &Sub->AuthenticationMechanism, i);
    Result |= cssm_RegReadBinary (regKey, "CertType", &Sub->CertType, i);
    if (Result != CSSM_OK)
        return(Result);

    if (InfoLevel != CSSM_INFO_LEVEL_SUBSERVICE) {
        if (cssm_RegReadBinary (regKey, "Number Policies",
                           &Sub->NumberOfPolicyIdentifiers, i) == CSSM_OK) {
            if (Sub->NumberOfPolicyIdentifiers > 0)
                Sub->PolicyIdentifiers = cssm_ReadField (regKey,
                                               Sub->NumberOfPolicyIdentifiers);
            else
                Sub->PolicyIdentifiers = NULL;
        } else {
            Sub->NumberOfPolicyIdentifiers = 0;
            Sub->PolicyIdentifiers = NULL;
        }
    }

    rc = cssm_RegReadTPWrapped(regKey, &Sub->WrappedProduct);
	return(rc);
}

CSSM_CSSMINFO_PTR CSSMAPI cssm_RegReadCSSMInfo ()
{
    CSSM_CSSMINFO_PTR Info;
    char regKey[MAX_REG];
    char *ID;
	char cssmID[MAX_REG];
    sint32 dataType = CSSM_CONFIG_BINARY;
    sint32 dataLength;
	uint32 numberOfSubservices;
    char AddInURL[MAX_REG];

    /* Generate the registry Section for the add in information */

    strcpy (regKey, CSSMSECTION);
	cssm_GUIDToStr(&cssm_GUID, cssmID);
	strcat(regKey, cssmID);

    if ((Info = (CSSM_CSSMINFO_PTR)app_malloc (sizeof (CSSM_CSSMINFO), memRef)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    if (cssm_RegReadCommonInfo (regKey, &Info->Version.Major,
              &Info->Version.Minor, &Info->Description, &Info->Vendor,
              &Info->ThreadSafe, &numberOfSubservices) == CSSM_FAIL) {
        app_free (Info, memRef);
        return(NULL);
    }

    if (cssm_RegReadString (regKey, "GUID", &ID) != CSSM_OK) {
        app_free (Info, memRef);
        return(NULL);
    }

    cssm_StrToGUID (ID, &Info->GUID);
    app_free (ID, memRef);

    /* Get filename and location information */
    dataLength = MAX_REG;
    dataType = CSSM_VALUE_STRING;
    if ((cssm_GetValue (regKey,"Location", (void *)AddInURL, &dataLength,
                        &dataType, CSSM_PREFERENCE_GLOBAL)) != CSSM_OK) {
        app_free (Info, memRef);
        return(NULL);
    }

    /* Fix for WINNT 3.51 not nulling the string */
    AddInURL[dataLength] = 0;
    if ((Info->Location = app_malloc (dataLength, 0)) == NULL) {
        app_free (Info, memRef);
        return(NULL);
    }

    if (strncmp(AddInURL,"file://",7) == 0) {
#ifdef WIN32
        sint16 index = 7;
        while (AddInURL[index] != 0) {            /* convert MS-DOS paths */
            if (AddInURL[index] == '/')
                AddInURL[index] = '\\';
            if (AddInURL[index] == '|')
                AddInURL[index] = ':';
            index++;
        }
        strcpy(Info->Location, &AddInURL[8]);
#else
        strcpy(Info->Location, &AddInURL[7]);
#endif
    }

    return(Info);
}


CSSM_RETURN CSSMAPI cssm_RegReadCSPCapList(char *regKey,
                                           CSSM_CSP_CAPABILITY_PTR *ppList,
                                           uint32* pNumberOfCapabilities)
{
    uint32 i, Count, four = 4;
    CSSM_CSP_CAPABILITY_PTR pList;

    *ppList = NULL;
    *pNumberOfCapabilities = 0;

   	if ((regKey == NULL) || (ppList == NULL) || (pNumberOfCapabilities == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary (regKey, "NumberOfCapabilities", &Count, four) != CSSM_OK) {
        return(CSSM_FAIL);
    }
    *pNumberOfCapabilities = Count;

    if ((pList = app_malloc (sizeof (CSSM_CONTEXT) * Count, memRef)) == NULL) {
        return(CSSM_FAIL);
    }
    *ppList = pList;

    /* Write each algorithm supported to the registry */
    for (i = 0; i < Count; i++) {
        char algRegKey[MAX_REG], szTemp[24];

        strcpy (algRegKey, regKey);
        sprintf(szTemp, "\\Capability%d", i+1);
        strcat (algRegKey, szTemp);

        if (cssm_RegReadContext (algRegKey, CSSM_PREFERENCE_GLOBAL, pList+i) != CSSM_OK) {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadCSPSWService (char *regKey,
                                              CSSM_SOFTWARE_CSPSUBSERVICE_INFO * const Info,
                                              CSSM_INFO_LEVEL InfoLevel)
{

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (InfoLevel == CSSM_INFO_LEVEL_SUBSERVICE)
    {
        Info->NumberOfCapabilities = 0;
        Info->CapabilityList = NULL;
    }
    else if (CSSM_OK != cssm_RegReadCSPCapList(regKey, &Info->CapabilityList, &Info->NumberOfCapabilities))
    {
        return(CSSM_FAIL);
    }

    if (cssm_RegReadBinary (regKey, "Reserved", &Info->Reserved, 4) != CSSM_OK) {
        CSSM_ClearError ();
        Info->Reserved = 0;
    }

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadCSPHardwareService (char *regKey,
                                                    CSSM_HARDWARE_CSPSUBSERVICE_INFO * const Info,
                                                    CSSM_INFO_LEVEL InfoLevel)


{
    char HardwareRegKey[MAX_REG];
    int size = 4;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(HardwareRegKey, regKey);
    strcat(HardwareRegKey, "\\Hardware");

    if (InfoLevel == CSSM_INFO_LEVEL_SUBSERVICE)
    {
        Info->NumberOfCapabilities = 0;
        Info->CapabilityList = NULL;
    }
    else if (CSSM_OK != cssm_RegReadCSPCapList(regKey, &Info->CapabilityList, &Info->NumberOfCapabilities))
    {
        return(CSSM_FAIL);
    }

    if (cssm_RegReadBinary (regKey, "Reserved", &Info->Reserved, size) != CSSM_OK) {
        CSSM_ClearError ();
        Info->Reserved = 0;
    }

    if (cssm_RegReadCSSMString (HardwareRegKey, "ReaderDescription", Info->ReaderDescription) != CSSM_OK) {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadCSSMString (HardwareRegKey, "ReaderVendor", Info->ReaderVendor) != CSSM_OK) {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadCSSMString (HardwareRegKey, "ReaderSerialNumber", Info->ReaderSerialNumber) != CSSM_OK) {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadVersion (HardwareRegKey, "ReaderHardwareVersion",
            &Info->ReaderHardwareVersion.Major, &Info->ReaderHardwareVersion.Minor) != CSSM_OK) {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadVersion (HardwareRegKey, "ReaderFirmwareVersion",
            &Info->ReaderFirmwareVersion.Major, &Info->ReaderFirmwareVersion.Minor) != CSSM_OK) {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadBinary (HardwareRegKey, "ReaderFlags", &Info->ReaderFlags, size))
    {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }


    if (cssm_RegReadBinary (HardwareRegKey, "ReaderCustomFlags", &Info->ReaderCustomFlags, size))
    {
        app_free (Info->CapabilityList, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadCSSMString (HardwareRegKey, "TokenDescription", Info->TokenDescription) != CSSM_OK) {
        CSSM_ClearError ();
    }

    if ((Info->TokenDescription != NULL) || (CSSM_CSP_RDR_TOKENPRESENT & Info->ReaderFlags))
    {
        uint32 Result;
        Result = cssm_RegReadCSSMString (HardwareRegKey, "TokenVendor", Info->TokenVendor) != CSSM_OK;
        Result |= cssm_RegReadCSSMString (HardwareRegKey, "TokenSerialNumber", Info->TokenSerialNumber) != CSSM_OK;
        Result |= cssm_RegReadVersion (HardwareRegKey, "TokenHardwareVersion",
            &Info->TokenHardwareVersion.Major, &Info->TokenHardwareVersion.Minor) != CSSM_OK;
        Result |= cssm_RegReadVersion (HardwareRegKey, "TokenFirmwareVersion",
            &Info->TokenFirmwareVersion.Major, &Info->TokenFirmwareVersion.Minor) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenFlags", &Info->TokenFlags, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenCustomFlags", &Info->TokenCustomFlags, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenMaxSessionCount", &Info->TokenMaxSessionCount, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenOpenedSessionCount", &Info->TokenOpenedSessionCount, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenMaxRWSessionCount", &Info->TokenMaxRWSessionCount, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenOpenedRWSessionCount", &Info->TokenOpenedRWSessionCount, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenTotalPublicMem", &Info->TokenTotalPublicMem, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenFreePublicMem", &Info->TokenFreePublicMem, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenTotalPrivateMem", &Info->TokenTotalPrivateMem, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenFreePrivateMem", &Info->TokenFreePrivateMem, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenMaxPinLen", &Info->TokenMaxPinLen, size) != CSSM_OK;
        Result |= cssm_RegReadBinary (HardwareRegKey, "TokenMinPinLen", &Info->TokenMinPinLen, size) != CSSM_OK;
        Result |= cssm_RegReadUTC (HardwareRegKey, "TokenUTCTime", Info->TokenUTCTime) != CSSM_OK;
        Result |= cssm_RegReadCSSMString (HardwareRegKey, "UserLabel", Info->UserLabel) != CSSM_OK;
        if (Result)
            CSSM_ClearError ();

        if (cssm_RegReadDataStruct (HardwareRegKey, "UserCACertificate", &Info->UserCACertificate) != CSSM_OK)
        {
            Info->UserCACertificate.Length = 0;
            Info->UserCACertificate.Data = NULL;
            CSSM_ClearError();
        }
    }

    return(CSSM_OK);
}

CSSM_RETURN cssm_ReadCSPWrapped (char *regKey, CSSM_CSP_WRAPPEDPRODUCT_INFO_PTR Wrapped)
{
    char wpKey[MAX_REG];
    uint32 j = 4;
    CSSM_RETURN Result;

	if ((regKey == NULL) || (Wrapped == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy (wpKey, regKey);
    strcat (wpKey, "\\WrappedProduct");

    Result = cssm_RegReadVersion (wpKey, "StandardVersion",
                            &Wrapped->StandardVersion.Major,
                            &Wrapped->StandardVersion.Minor);
    Result |= cssm_RegReadCSSMString (wpKey, "StandardDescription",
                              Wrapped->StandardDescription);

    Result |= cssm_RegReadVersion (wpKey, "ProductVersion",
                            &Wrapped->ProductVersion.Major,
                            &Wrapped->ProductVersion.Minor);
    Result |= cssm_RegReadCSSMString (wpKey, "ProductDescription",
                              Wrapped->ProductDescription);
    Result |= cssm_RegReadCSSMString (wpKey, "ProductVendor",
                              Wrapped->ProductVendor);
    Result |= cssm_RegReadBinary (wpKey, "ProductFlags", &Wrapped->ProductFlags, j);

    return(Result);
}

CSSM_RETURN CSSMAPI cssm_RegReadCSPSubService (char *regKey,
                                              CSSM_CSPSUBSERVICE_PTR Sub,
                                              CSSM_INFO_LEVEL InfoLevel)
{
    uint32		i = 4;
    CSSM_RETURN Result;
	CSSM_RETURN	rc;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_RegReadBinary (regKey, "SubServiceID", &Sub->SubServiceId, i);
    Result |= cssm_RegReadCSSMString (regKey, "Description", Sub->Description);
    Result |= cssm_RegReadBinary (regKey, "CspFlags", &Sub->CspFlags, i);
    Result |= cssm_RegReadBinary (regKey, "CspCustomFlags", &Sub->CspCustomFlags, i);
    Result |= cssm_RegReadBinary (regKey, "AccessFlags", &Sub->AccessFlags, i);
    Result |= cssm_RegReadBinary (regKey, "CspType", &Sub->CspType, i);
    if (Result != CSSM_OK)
        return(Result);

    switch (Sub->CspType) {
        case CSSM_CSP_SOFTWARE :
            if (cssm_RegReadCSPSWService (regKey, &Sub->SoftwareCspSubService, InfoLevel) != CSSM_OK) {
                return(CSSM_FAIL);
            }
        break;

        case CSSM_CSP_HARDWARE :
            if (cssm_RegReadCSPHardwareService (regKey, &Sub->HardwareCspSubService, InfoLevel) != CSSM_OK) {
                return(CSSM_FAIL);
            }
        break;
    }

    rc = cssm_ReadCSPWrapped (regKey, &Sub->WrappedProduct);
	return(rc);
}

CSSM_RETURN CSSMAPI cssm_RegReadCLWrapped(char *regKey,
                                          CSSM_CL_WRAPPEDPRODUCT_INFO_PTR pWP)

{
    uint32 i;
    CSSM_RETURN Result;
    char wpKey[MAX_REG];

	if ((regKey == NULL) || (pWP == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(wpKey, regKey);
    strcat(wpKey, "\\WrappedProduct");

    Result = cssm_RegReadBinary(wpKey, "NumberOfEncoderProducts", &pWP->NumberOfEncoderProducts, 4);
    Result |= cssm_RegReadBinary(wpKey, "NumberOfCAProducts", &pWP->NumberOfCAProducts, 4);

    if (Result != CSSM_OK)
        return(Result);

    if (pWP->NumberOfEncoderProducts > 0)
    {
        pWP->EmbeddedEncoderProducts = (CSSM_CL_ENCODER_PRODUCTINFO_PTR) app_malloc(
            sizeof(CSSM_CL_ENCODER_PRODUCTINFO) * pWP->NumberOfEncoderProducts,memRef);
        if (pWP->EmbeddedEncoderProducts == NULL)
            return(CSSM_FAIL);

        for (i = 0; i < pWP->NumberOfEncoderProducts; i++)
        {
            CSSM_CL_ENCODER_PRODUCTINFO_PTR EEP = &pWP->EmbeddedEncoderProducts[i];
            char szTemp[MAX_REG];
            sprintf(szTemp, "%s\\WrappedEncoderProduct%d", wpKey, i+1);

            Result = cssm_RegReadVersion(szTemp, "StandardVersion", &EEP->StandardVersion.Major,
                    &EEP->StandardVersion.Minor);
            Result |= cssm_RegReadCSSMString(szTemp, "StandardDescription", EEP->StandardDescription);
            Result |= cssm_RegReadVersion(szTemp, "ProductVersion", &EEP->ProductVersion.Major,
                    &EEP->ProductVersion.Minor);
            Result |= cssm_RegReadCSSMString(szTemp, "ProductDescription", EEP->ProductDescription);
            Result |= cssm_RegReadCSSMString(szTemp, "ProductVendor", EEP->ProductVendor);
            Result |= cssm_RegReadBinary(szTemp, "CertType", &EEP->CertType, 4);
            Result |= cssm_RegReadBinary(szTemp, "ProductFlags", &EEP->ProductFlags, 4);

            if (Result != CSSM_OK)
            {
                app_free(pWP->EmbeddedEncoderProducts, memRef);
                return(Result);
            }
        }
    }
    else
        pWP->EmbeddedEncoderProducts = NULL;

    if (pWP->NumberOfCAProducts > 0)
    {
        pWP->AccessibleCAProducts = (CSSM_CL_CA_PRODUCTINFO_PTR) app_malloc(
            sizeof(CSSM_CL_CA_PRODUCTINFO) * pWP->NumberOfCAProducts,memRef);
        if (pWP->AccessibleCAProducts == NULL)
        {
            app_free(pWP->EmbeddedEncoderProducts, memRef);
            return(CSSM_FAIL);
        }

        for (i = 0; i < pWP->NumberOfCAProducts; i++)
        {
            uint32 j;
            CSSM_CL_CA_PRODUCTINFO_PTR CAP = &pWP->AccessibleCAProducts[i];
            char szTemp[MAX_REG];
            sprintf(szTemp, "%s\\WrappedCAProduct%d", wpKey, i+1);

            Result = cssm_RegReadVersion(szTemp, "StandardVersion", &CAP->StandardVersion.Major,
                    &CAP->StandardVersion.Minor);
            Result |= cssm_RegReadCSSMString(szTemp, "StandardDescription", CAP->StandardDescription);
            Result |= cssm_RegReadVersion(szTemp, "ProductVersion", &CAP->ProductVersion.Major,
                    &CAP->ProductVersion.Minor);
            Result |= cssm_RegReadCSSMString(szTemp, "ProductDescription", CAP->ProductDescription);
            Result |= cssm_RegReadCSSMString(szTemp, "ProductVendor", CAP->ProductVendor);
            Result |= cssm_RegReadBinary(szTemp, "CertType", &CAP->CertType, 4);
            Result |= cssm_RegReadBinary(szTemp, "AdditionalServiceFlags", &CAP->AdditionalServiceFlags, 4);
            Result |= cssm_RegReadBinary(szTemp, "NumberOfCertClasses", &CAP->NumberOfCertClasses, 4);

            if (Result != CSSM_OK)
            {
                app_free(pWP->EmbeddedEncoderProducts, memRef);
                app_free(pWP->AccessibleCAProducts, memRef);
                return(Result);
            }

            if (CAP->NumberOfCertClasses > 0)
            {
                CAP->CertClasses = (CSSM_CL_CA_CERT_CLASSINFO_PTR)
                    app_malloc(sizeof(CSSM_CL_CA_CERT_CLASSINFO) * CAP->NumberOfCertClasses,memRef);
                if (CAP->CertClasses == NULL)
                {
                    app_free(pWP->EmbeddedEncoderProducts, memRef);
                    app_free(pWP->AccessibleCAProducts, memRef);
                    return(CSSM_FAIL);
                }

                for (j = 0; j < CAP->NumberOfCertClasses; j++)
                {
                    char Label[48];
                    CSSM_CL_CA_CERT_CLASSINFO_PTR pClass = &CAP->CertClasses[j];
                    sprintf(Label, "CertClassName%d", j+1);
                    Result = cssm_RegReadCSSMString(szTemp, Label, pClass->CertClassName);
                    sprintf(Label, "CACert%d", j+1);
                    Result |= cssm_RegReadDataStruct(szTemp, Label, &pClass->CACert);

                    if (Result != CSSM_OK)
                    {
                        app_free(CAP->CertClasses, memRef);
                        app_free(pWP->EmbeddedEncoderProducts, memRef);
                        app_free(pWP->AccessibleCAProducts, memRef);
                        return(CSSM_FAIL);
                    }
                }
            }
            else
                CAP->CertClasses = NULL;
        }
    }
    else
        pWP->AccessibleCAProducts = NULL;

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadCLSubService (char *regKey,
                                              CSSM_CLSUBSERVICE_PTR Sub,
                                              CSSM_INFO_LEVEL InfoLevel)
{
    uint32 i = 0xffffff, size = 4;
    CSSM_RETURN Result;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}


    Result = cssm_RegReadBinary (regKey, "SubServiceID", &Sub->SubServiceId, size);
    Result |= cssm_RegReadCSSMString (regKey, "Description", Sub->Description);
    Result |= cssm_RegReadBinary (regKey, "CertType", &Sub->CertType, size);
    Result |= cssm_RegReadBinary (regKey, "CertEncoding", &Sub->CertEncoding, size);
    Result |= cssm_RegReadBinary (regKey, "Authentication Mechanism",
            &Sub->AuthenticationMechanism, size);

    if (Result != CSSM_OK)
        return(Result);

    if (InfoLevel == CSSM_INFO_LEVEL_SUBSERVICE)
    {
        Sub->NumberOfTemplateFields = 0;
        Sub->CertTemplates = NULL;
        Sub->NumberOfTranslationTypes = 0;
        Sub->CertTranslationTypes = NULL;
        return(CSSM_OK);
    }

    if (cssm_RegReadBinary (regKey, "NumberOfTemplateFields", &Sub->NumberOfTemplateFields, size) != CSSM_OK) {
        return(CSSM_FAIL);
    }

    if (Sub->NumberOfTemplateFields > 0)
    {
        /* Read each template entry to the registry */
        if ((Sub->CertTemplates = app_malloc (sizeof (CSSM_OID) * Sub->NumberOfTemplateFields, memRef)) == NULL) {
            return(CSSM_FAIL);
        }

        for (i = 0; i < Sub->NumberOfTemplateFields; i++) {
            char algRegKey[MAX_REG], Label[MAX_REG];

            strcpy (algRegKey, regKey);
            strcat (algRegKey, "\\");
            strcat (algRegKey, "CertTemplates");

            strcpy (Label, "OID\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            if (cssm_RegReadDataStruct (algRegKey, Label, &Sub->CertTemplates[i]) != CSSM_OK) {
                uint32 j;
                for (j = 0; j < i; j++)
                    app_free(Sub->CertTemplates[j].Data, memRef);
                app_free (Sub->CertTemplates, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
        Sub->CertTemplates = NULL;

    if (cssm_RegReadBinary (regKey, "NumberOfTranslationTypes", &Sub->NumberOfTranslationTypes, size) != CSSM_OK) {
        return(CSSM_FAIL);
    }

    if (Sub->NumberOfTranslationTypes > 0)
    {
        /* Read each algorithm supported to the registry */
        if ((Sub->CertTranslationTypes = app_malloc (sizeof (CSSM_CERT_TYPE) *
                Sub->NumberOfTranslationTypes, memRef)) == NULL) {
            return(CSSM_FAIL);
        }

        for (i = 0; i < Sub->NumberOfTranslationTypes; i++) {
            char algRegKey[MAX_REG], Label[MAX_REG];

            strcpy (algRegKey, regKey);
            strcat (algRegKey, "\\");
            strcat (algRegKey, "CertTypes");

            strcpy (Label, "Type\0");
            _itoa (i+1, &Label[strlen(Label)], 10);

            if (cssm_RegReadBinary (algRegKey, Label, &Sub->CertTranslationTypes[i], size) != CSSM_OK) {
                uint32 j;
                for (j = 0; j < Sub->NumberOfTemplateFields; j++)
                    app_free(Sub->CertTemplates[j].Data, memRef);
                app_free (Sub->CertTemplates, memRef);
                app_free (Sub->CertTranslationTypes, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
        Sub->CertTranslationTypes = NULL;


    cssm_RegReadCLWrapped(regKey, &Sub->WrappedProduct);

    return(CSSM_OK);
}

CSSM_RETURN cssm_RegReadDLWrapped (char *regKey,
                                   CSSM_DL_WRAPPEDPRODUCT_INFO_PTR const WrappedProduct)
{
    char wpKey[MAX_REG];

	if ((regKey == NULL) || (WrappedProduct == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    strcpy(wpKey, regKey);
    strcat(wpKey, "\\WrappedProduct");

    if (cssm_RegReadVersion (wpKey, "StandardVersion", &WrappedProduct->StandardVersion.Major,
            &WrappedProduct->StandardVersion.Minor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegReadCSSMString(wpKey, "StandardDescription", WrappedProduct->StandardDescription) != CSSM_OK)
        return(CSSM_FAIL);

    if (cssm_RegReadVersion (wpKey, "ProductVersion", &WrappedProduct->ProductVersion.Major,
            &WrappedProduct->ProductVersion.Minor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegReadCSSMString(wpKey, "ProductDescription", WrappedProduct->ProductDescription) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegReadCSSMString(wpKey, "ProductVendor", WrappedProduct->ProductVendor) != CSSM_OK)
        return(CSSM_FAIL);
    if (cssm_RegReadBinary(wpKey, "ProductFlags", &WrappedProduct->ProductFlags, 4) != CSSM_OK)
        return(CSSM_FAIL);

    return(CSSM_OK);
}


CSSM_RETURN CSSMAPI cssm_RegReadDLDataStoreName(char *regKey,
                                                 CSSM_NAME_LIST_PTR NameList)
{
    uint32 i;

	if ((regKey == NULL) || (NameList == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary(regKey, "NumStrings", &NameList->NumStrings, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (NameList->NumStrings > 0)
    {
        NameList->String = (char **) app_malloc(sizeof(char *) * NameList->NumStrings, memRef);
        if (NameList->String == NULL)
        {
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        for (i = 0; i < NameList->NumStrings; i++)
        {
            char Label[32];
            sprintf(Label, "String%d", i);

            if (cssm_RegReadString (regKey, Label, &NameList->String[i]) != CSSM_OK)
            {
                uint32 j;
                for (j = 0; j < i; j++)
                    app_free(NameList->String[j], memRef);
                app_free(NameList->String, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
        NameList->String = NULL;

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadDLDBAttributeInfo(char *regKey,
                                                   CSSM_DB_ATTRIBUTE_INFO_PTR Info)

{

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary(regKey, "AttributeNameFormat", &Info->AttributeNameFormat, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }
    if (Info->AttributeNameFormat == CSSM_DB_ATTRIBUTE_NAME_AS_STRING)
    {
        if (cssm_RegReadString(regKey, "AttributeName", &Info->AttributeName) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }
    }
    else
    {
        if (cssm_RegReadDataStruct(regKey, "AttributeID", &Info->AttributeID) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }
    }
    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadDLDBRecordAttribute(char *regKey,
                                                     CSSM_DB_RECORD_ATTRIBUTE_INFO_PTR Info)
{
    uint32 i;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary(regKey, "AttributeDataRecordType", &Info->DataRecordType, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadBinary(regKey, "NumberOfAttributes", &Info->NumberOfAttributes, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (Info->NumberOfAttributes > 0)
    {
        Info->AttributeInfo = (CSSM_DB_ATTRIBUTE_INFO_PTR)
            app_malloc(Info->NumberOfAttributes * sizeof(CSSM_DB_ATTRIBUTE_INFO), memRef);

        if (Info->AttributeInfo == NULL)
        {
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        for (i = 0; i < Info->NumberOfAttributes; i++)
        {
            char LocalKey[MAX_REG];

            strcpy (LocalKey, regKey);
            strcat (LocalKey, "\\Attribute");
            _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);

            if (cssm_RegReadDLDBAttributeInfo(LocalKey, &Info->AttributeInfo[i]) != CSSM_OK)
            {
                app_free(Info->AttributeInfo,memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
        Info->AttributeInfo = NULL;

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadDLDBRecordIndex(char *regKey,
                                                 CSSM_DB_RECORD_INDEX_INFO_PTR Info)
{
    uint32 i;

	if ((regKey == NULL) || (Info == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary(regKey, "IndexDataRecordType", &Info->DataRecordType, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadBinary(regKey, "NumberOfIndexes", &Info->NumberOfIndexes, 4) != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (Info->NumberOfIndexes > 0)
    {
        Info->IndexInfo = (CSSM_DB_INDEX_INFO_PTR)
            app_malloc(Info->NumberOfIndexes * sizeof(CSSM_DB_INDEX_INFO), memRef);

        if (Info->IndexInfo == NULL)
        {
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        for (i = 0; i < Info->NumberOfIndexes; i++)
        {
            char LocalKey[MAX_REG];

            strcpy (LocalKey, regKey);
            strcat (LocalKey, "\\Index");
            _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);

            if (cssm_RegReadBinary(LocalKey, "IndexType", &Info->IndexInfo[i].IndexType, 4) != CSSM_OK)
            {
                app_free(Info->IndexInfo, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            }

            if (cssm_RegReadBinary(LocalKey, "IndexedDataLocation", &Info->IndexInfo[i].IndexedDataLocation, 4) != CSSM_OK)
            {
                app_free(Info->IndexInfo, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            }

            if (cssm_RegReadDLDBAttributeInfo(LocalKey, &Info->IndexInfo[i].Info) != CSSM_OK)
            {
                app_free(Info->IndexInfo, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            }
        }
    }
    else
        Info->IndexInfo = NULL;


    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadDLDataStoreInfo(char *regKey,
                                                CSSM_DBINFO_PTR DSInfo)
{

	if ((regKey == NULL) || (DSInfo == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    if (cssm_RegReadBinary(regKey, "NumberOfRecordTypes", &DSInfo->NumberOfRecordTypes, 4) != CSSM_OK)
        return(CSSM_FAIL);

    if (DSInfo->NumberOfRecordTypes > 0)
    {
        uint32 cType;

        if (cssm_RegReadBinary(regKey, "AuthenticationMechanism", &DSInfo->AuthenticationMechanism, 4) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        if (cssm_RegReadBinary(regKey, "RecordSigningImplemented", &DSInfo->RecordSigningImplemented, 4) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        if (cssm_RegReadBinary (regKey,"SigningCsp", &DSInfo->SigningCsp, sizeof(CSSM_GUID)) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        if (cssm_RegReadBinary(regKey, "IsLocal", &DSInfo->IsLocal, 4) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        if (cssm_RegReadDataStruct(regKey, "SigningCertificate", &DSInfo->SigningCertificate) != CSSM_OK)
        {
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        if (cssm_RegReadString(regKey, "AccessPath", &DSInfo->AccessPath) != CSSM_OK)
        {
            app_free(DSInfo->SigningCertificate.Data, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
            return(CSSM_FAIL);
        }

        DSInfo->DefaultParsingModules = (CSSM_DB_PARSING_MODULE_INFO_PTR)
            app_malloc(DSInfo->NumberOfRecordTypes * sizeof(CSSM_DB_PARSING_MODULE_INFO), memRef);
        if (DSInfo->DefaultParsingModules == NULL)
        {
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            app_free(DSInfo->SigningCertificate.Data, memRef);
            app_free(DSInfo->AccessPath, memRef);
            return(CSSM_FAIL);
        }
        DSInfo->RecordAttributeNames = (CSSM_DB_RECORD_ATTRIBUTE_INFO_PTR)
            app_malloc(DSInfo->NumberOfRecordTypes * sizeof(CSSM_DB_RECORD_ATTRIBUTE_INFO), memRef);
        if (DSInfo->RecordAttributeNames == NULL)
        {
            app_free(DSInfo->DefaultParsingModules, memRef);
            app_free(DSInfo->SigningCertificate.Data, memRef);
            app_free(DSInfo->AccessPath, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        DSInfo->RecordIndexes = (CSSM_DB_RECORD_INDEX_INFO_PTR)
            app_malloc(DSInfo->NumberOfRecordTypes * sizeof(CSSM_DB_RECORD_INDEX_INFO), memRef);

        if (DSInfo->RecordIndexes == NULL)
        {
            app_free(DSInfo->DefaultParsingModules, memRef);
            app_free(DSInfo->RecordAttributeNames, memRef);
            app_free(DSInfo->SigningCertificate.Data, memRef);
            app_free(DSInfo->AccessPath, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        for (cType = 0; cType < DSInfo->NumberOfRecordTypes; cType++)
        {
            char Label[MAX_REG];

            strcpy (Label, regKey);
            strcat (Label, "\\RecordType");
            _itoa (cType+1, &Label[strlen (Label)], 10);

            if ((cssm_RegReadBinary (Label,"ParsingModule", &DSInfo->DefaultParsingModules[cType], sizeof(CSSM_DB_PARSING_MODULE_INFO)) != CSSM_OK) ||
                    (cssm_RegReadDLDBRecordAttribute(Label, &DSInfo->RecordAttributeNames[cType]) != CSSM_OK) ||
                    (cssm_RegReadDLDBRecordIndex(Label, &DSInfo->RecordIndexes[cType]) != CSSM_OK))
            {
                app_free(DSInfo->DefaultParsingModules, memRef);
                app_free(DSInfo->RecordAttributeNames, memRef);
                app_free(DSInfo->RecordIndexes, memRef);
                app_free(DSInfo->SigningCertificate.Data, memRef);
                app_free(DSInfo->AccessPath, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }
    else
    {
        DSInfo->DefaultParsingModules = NULL;
        DSInfo->RecordAttributeNames = NULL;
        DSInfo->RecordIndexes = NULL;
        DSInfo->AuthenticationMechanism = 0;
        DSInfo->RecordSigningImplemented = 0;
        DSInfo->SigningCertificate.Length = 0;
        DSInfo->SigningCertificate.Data = NULL;
        DSInfo->IsLocal = 0;
        DSInfo->AccessPath = NULL;
    }
    // Reserved is not being written/read
    DSInfo->Reserved = NULL;

    return(CSSM_OK);
}

CSSM_RETURN CSSMAPI cssm_RegReadDLSubService (char *regKey,
                                              CSSM_DLSUBSERVICE_PTR Sub,
                                              CSSM_INFO_LEVEL InfoLevel)
{
    uint32 cnt;
    CSSM_DB_CONJUNCTIVE_PTR Conj;
    CSSM_RETURN Result;

	if ((regKey == NULL) || (Sub == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    Result = cssm_RegReadBinary (regKey, "SubServiceID", &Sub->SubServiceId, 4);
    Result |= cssm_RegReadCSSMString (regKey, "Description", Sub->Description);
    Result |= cssm_RegReadBinary (regKey, "Type", &Sub->Type, 4);
    Result |= cssm_RegReadDLWrapped (regKey, &Sub->WrappedProduct);
    Result |= cssm_RegReadBinary (regKey, "Authentication Mechanism", &Sub->AuthenticationMechanism, 4);
    Result |= cssm_RegReadBinary (regKey, "QueryLimitsSupported", &Sub->QueryLimitsSupported, 4);

    if (Result != CSSM_OK)
        return(Result);

    if (InfoLevel == CSSM_INFO_LEVEL_SUBSERVICE)
    {
        Sub->Attributes.Pkcs11Attributes = NULL;
        Sub->NumberOfRelOperatorTypes = 0;
        Sub->RelOperatorTypes = NULL;
        Sub->NumberOfConjOperatorTypes = 0;
        Sub->ConjOperatorTypes = NULL;
        return(CSSM_OK);
    }

    switch (Sub->Type) {
        case CSSM_DL_PKCS11 :
            if ((Sub->Attributes.Pkcs11Attributes = app_malloc (
                       sizeof (struct cssm_dl_pkcs11_attributes), memRef)) == NULL) {
                return(CSSM_FAIL);
            }

            if (cssm_RegReadBinary (regKey, "Attributes", &Sub->Attributes.Pkcs11Attributes->DeviceAccessFlags, 4) != CSSM_OK) {
                app_free (Sub->Attributes.Pkcs11Attributes, memRef);
                return(CSSM_FAIL);
            }
            break;

        default:
            Sub->Attributes.Pkcs11Attributes = NULL;
            break;
    }

    if (cssm_RegReadBinary (regKey, "NumberOfRelOperators",
                             &Sub->NumberOfRelOperatorTypes, 4) != CSSM_OK) {
        app_free (Sub->Attributes.Pkcs11Attributes, memRef);
        return(CSSM_FAIL);
    }

    if (Sub->NumberOfRelOperatorTypes <= 0)
        Sub->RelOperatorTypes = NULL;
    else
    {
        if ((Sub->RelOperatorTypes = app_malloc (sizeof (CSSM_DB_OPERATOR) * Sub->NumberOfRelOperatorTypes, memRef)) == NULL) {
            if (Sub->Type == CSSM_DL_PKCS11)
                app_free (Sub->Attributes.Pkcs11Attributes, memRef);
            return(CSSM_FAIL);
        }

        for (cnt = 0; cnt < Sub->NumberOfRelOperatorTypes; cnt++) {
            char LocalKey[MAX_REG];
            char Label[MAX_REG];

            strcpy (LocalKey, regKey);
            strcat (LocalKey, "\\RelOperators");
            strcpy (Label, "Operator");
            _itoa (cnt+1, &Label[strlen (Label)], 10);

            if (cssm_RegReadBinary (LocalKey, Label, &Sub->RelOperatorTypes[cnt], 4) != CSSM_OK) {
                app_free (Sub->RelOperatorTypes, memRef);
                if (Sub->Type == CSSM_DL_PKCS11)
                    app_free (Sub->Attributes.Pkcs11Attributes, memRef);
                return(CSSM_FAIL);
            }
        }
    }

    if (cssm_RegReadBinary (regKey, "NumberOfConjOperators",
                         &Sub->NumberOfConjOperatorTypes, 4) != CSSM_OK) {
        app_free (Sub->RelOperatorTypes, memRef);
        if (Sub->Type == CSSM_DL_PKCS11)
            app_free (Sub->Attributes.Pkcs11Attributes, memRef);
        return(CSSM_FAIL);
    }

    if (Sub->NumberOfConjOperatorTypes <= 0)
        Sub->ConjOperatorTypes = NULL;
    else
    {
        if ((Sub->ConjOperatorTypes = app_malloc (sizeof (CSSM_DB_CONJUNCTIVE) * Sub->NumberOfConjOperatorTypes, memRef)) == NULL) {
            app_free (Sub->RelOperatorTypes, memRef);
            if (Sub->Type == CSSM_DL_PKCS11)
                app_free (Sub->Attributes.Pkcs11Attributes, memRef);
            return(CSSM_FAIL);
        }

        Conj = Sub->ConjOperatorTypes;
        for (cnt = 0; cnt < Sub->NumberOfConjOperatorTypes; cnt++) {
            char LocalKey[MAX_REG];
            char Label[MAX_REG];

            strcpy (LocalKey, regKey);
            strcat (LocalKey, "\\ConjOperators");
            strcpy (Label, "Operator");
            _itoa (cnt+1, &Label[strlen (Label)], 10);

            if (cssm_RegReadBinary (LocalKey, Label, Conj, 4) != CSSM_OK) {
                app_free (Sub->ConjOperatorTypes, memRef);
                app_free (Sub->RelOperatorTypes, memRef);
                if (Sub->Type == CSSM_DL_PKCS11)
                    app_free (Sub->Attributes.Pkcs11Attributes, memRef);
                return(CSSM_FAIL);
            }

            Conj++;
        }
    }

    if (cssm_RegReadBinary (regKey, "NumberOfDataStores", &Sub->NumberOfDataStores, 4) != CSSM_OK)
    {
        app_free (Sub->ConjOperatorTypes, memRef);
        app_free (Sub->RelOperatorTypes, memRef);
        if (Sub->Type == CSSM_DL_PKCS11)
            app_free (Sub->Attributes.Pkcs11Attributes, memRef);
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(CSSM_FAIL);
    }

    if (Sub->NumberOfDataStores <= 0 ||
                        Sub->NumberOfDataStores == CSSM_DB_DATASTORES_UNKNOWN)
    {
        Sub->DataStoreNames = NULL;
        Sub->DataStoreInfo = NULL;
    }
    else
    {
        Sub->DataStoreNames = (CSSM_NAME_LIST_PTR)
            app_malloc(sizeof(CSSM_NAME_LIST) * Sub->NumberOfDataStores, memRef);

        if (Sub->DataStoreNames == NULL)
        {
            app_free (Sub->ConjOperatorTypes, memRef);
            app_free (Sub->RelOperatorTypes, memRef);
            if (Sub->Type == CSSM_DL_PKCS11)
                app_free (Sub->Attributes.Pkcs11Attributes, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }

        Sub->DataStoreInfo = (CSSM_DBINFO_PTR)
            app_malloc(sizeof(CSSM_DBINFO) * Sub->NumberOfDataStores, memRef);

        if (Sub->DataStoreInfo == NULL)
        {
            app_free(Sub->ConjOperatorTypes, memRef);
            app_free(Sub->RelOperatorTypes, memRef);
            if (Sub->Type == CSSM_DL_PKCS11)
                app_free (Sub->Attributes.Pkcs11Attributes, memRef);
            app_free(Sub->DataStoreNames, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(CSSM_FAIL);
        }


        for (cnt = 0; cnt < Sub->NumberOfDataStores; cnt++)
        {
            char Label[MAX_REG];

            strcpy (Label, regKey);
            strcat (Label, "\\DataStoreNum");
            _itoa (cnt+1, &Label[strlen (Label)], 10);

            if ((cssm_RegReadDLDataStoreName(Label, &Sub->DataStoreNames[cnt]) != CSSM_OK) ||
               (cssm_RegReadDLDataStoreInfo(Label, &Sub->DataStoreInfo[cnt]) != CSSM_OK))
            {
                app_free(Sub->ConjOperatorTypes, memRef);
                app_free(Sub->RelOperatorTypes, memRef);
                app_free(Sub->DataStoreNames, memRef);
                app_free(Sub->DataStoreInfo, memRef);
                CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
                return(CSSM_FAIL);
            }
        }
    }

    if ((Sub->Reserved = app_malloc (sizeof (CSSM_DATA), memRef)) == NULL) {
        app_free (Sub->RelOperatorTypes, memRef);
        if (Sub->Type == CSSM_DL_PKCS11)
            app_free (Sub->Attributes.Pkcs11Attributes, memRef);
        return(CSSM_FAIL);
    }

    if (cssm_RegReadDataStruct (regKey, "Reserved", Sub->Reserved) != CSSM_OK) {
        // This code may want to be changed in the future so that we know why failure occured
        CSSM_ClearError ();
        app_free(Sub->Reserved, memRef);
        Sub->Reserved = NULL;
    }

    return(CSSM_OK);
}


CSSM_RETURN cssm_RegReadService(char *regKey, uint32 ServiceType,
                                uint32 SubServiceID,
                                uint32 InfoLevel,
                                CSSM_SERVICE_INFO_PTR ServicePtr)
{
    char LocalKey[MAX_REG];
    uint32 MatchingSub;
    CSSM_RETURN ret;
    uint32 i;
    uint32 NumMatch = 0;
    uint32 NumberOfSubServices = 0;                     /* Number of sub services in SubServiceList */

	if ((regKey == NULL) || (ServicePtr == NULL))
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FAIL);
	}

    ServicePtr->NumberOfSubServices = 0;
    ServicePtr->Reserved = NULL;

    ret = cssm_RegReadCSSMString(regKey, "Description", ServicePtr->Description);
    ret |= cssm_RegReadBinary (regKey, "Flags", &ServicePtr->Flags, 4);
    ret |= cssm_RegReadBinary (regKey, "Type", &ServicePtr->Type, 4);

    if (ret != CSSM_OK)
       return(CSSM_FAIL);

    if (cssm_RegReadBinary (regKey, "NumberOfSubServices", &NumberOfSubServices, 4) != CSSM_OK)
        return(CSSM_FAIL);
    if (NumberOfSubServices == 0)
        return(CSSM_OK);

    if (SubServiceID == CSSM_ALL_SUBSERVICES)
        NumMatch = NumberOfSubServices;
    else
    {
        MatchingSub = cssm_RegFindSubServiceNum(SubServiceID, regKey, NumberOfSubServices);
        if (0 != MatchingSub)
            NumMatch = 1;
        else
        {
            // We could not find the requested subservice
            return(CSSM_FAIL);
        }
    }

    for (i = 0; i < NumMatch; i++) {
        strcpy (LocalKey, regKey);
        strcat (LocalKey, "\\SubService");
        if (SubServiceID == CSSM_ALL_SUBSERVICES)
            _itoa (i+1, &LocalKey[strlen (LocalKey)], 10);
        else
            _itoa (MatchingSub, &LocalKey[strlen (LocalKey)], 10);

        switch (ServicePtr->Type) {
            case CSSM_SERVICE_TP:
                if (i == 0)
                    if ((ServicePtr->TpSubServiceList = app_calloc (
                        sizeof (CSSM_TPSUBSERVICE) * NumMatch, 1, memRef)) == NULL) {
                        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                        return(CSSM_FAIL);
                }
                cssm_RegReadTPSubService (LocalKey, &ServicePtr->TpSubServiceList[i], InfoLevel);
            break;

            case CSSM_SERVICE_CSP:
                if (i == 0)
                    if ((ServicePtr->TpSubServiceList = app_calloc (
                        sizeof (CSSM_CSPSUBSERVICE) * NumMatch, 1, memRef)) == NULL) {
                        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                        return(CSSM_FAIL);
                }
                if (cssm_RegReadCSPSubService (LocalKey, &ServicePtr->CspSubServiceList[i], InfoLevel)
					!= CSSM_OK) {
                        return(CSSM_FAIL);
				}
            break;

            case CSSM_SERVICE_CL:
                if (i == 0)
                    if ((ServicePtr->ClSubServiceList = app_calloc (
                        sizeof (CSSM_CLSUBSERVICE) * NumMatch, 1, memRef)) == NULL) {
                        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                        return(CSSM_FAIL);
                }
                cssm_RegReadCLSubService (LocalKey, &ServicePtr->ClSubServiceList[i], InfoLevel);
            break;

            case CSSM_SERVICE_DL:
                if (i == 0)
                    if ((ServicePtr->DlSubServiceList = app_calloc (
                        sizeof (CSSM_DLSUBSERVICE) * NumMatch, 1, memRef)) == NULL) {
                        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                        return(CSSM_FAIL);
                }
                cssm_RegReadDLSubService (LocalKey, &ServicePtr->DlSubServiceList[i], InfoLevel);
            break;
        }
    }

    ServicePtr->NumberOfSubServices = NumMatch;
    return(CSSM_OK);
}


CSSM_MODULE_INFO_PTR CSSMAPI cssm_RegReadModuleInfo(const CSSM_GUID_PTR ModuleGUID,
                                                    CSSM_SERVICE_MASK UsageMask,
                                                    uint32 SubserviceID,
                                                    CSSM_INFO_LEVEL InfoLevel)
{
    uint32					Mask, NumSubs, cSubs, NumUsedSubs, cUsedSubs;
    sint32					dataSize = sizeof (int);
    sint32					dataType = CSSM_VALUE_BINARY;
    CSSM_MODULE_INFO_PTR	ModulePtr;
    char					regKey[MAX_REG];
    char					ID[MAX_REG];
    uint32					Dynamic = 0;
    CSSM_RETURN				Result;
	CSSM_MODULE_INFO_PTR	rc;

	if (ModuleGUID == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(NULL);
	}

    /* Generate the registry Section for the add in information */
    strcpy (regKey, CSSMSECTION);
    cssm_GUIDToStr (ModuleGUID, ID);
    strcat (regKey, ID);

    /* Look for dynamic capabilities */
    if ((cssm_GetValue (regKey, "Dynamic Capabilities", (void *)&Dynamic, &dataSize,
                       &dataType, CSSM_PREFERENCE_GLOBAL) == CSSM_OK) && (Dynamic == 1))
    {
        rc = cssm_dynamic_getinfo (ModuleGUID, UsageMask, SubserviceID, InfoLevel);
		return(rc);
    }

    if ((ModulePtr = app_malloc (sizeof (CSSM_MODULE_INFO), memRef)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }
    memset (ModulePtr, 0x00, sizeof (CSSM_MODULE_INFO));

    Result = cssm_RegReadVersion (regKey, "Version", &ModulePtr->Version.Major, &ModulePtr->Version.Minor);
    Result |= cssm_RegReadVersion (regKey, "CompatibleCSSMVersion", &ModulePtr->CompatibleCSSMVersion.Major,
        &ModulePtr->CompatibleCSSMVersion.Minor);
    Result |= cssm_RegReadCSSMString (regKey, "Description", ModulePtr->Description);
    Result |= cssm_RegReadCSSMString (regKey, "Vendor", ModulePtr->Vendor);
    Result |= cssm_GetValue (regKey,"Flags", (void *)&ModulePtr->Flags, &dataSize,
        &dataType, CSSM_PREFERENCE_GLOBAL);
    Result |= cssm_GetValue (regKey,"ServiceMasks",(void *)&Mask, &dataSize,
        &dataType, CSSM_PREFERENCE_GLOBAL);
    Result |= cssm_GetValue (regKey,"NumberOfServices",(void *)&NumSubs, &dataSize,
        &dataType, CSSM_PREFERENCE_GLOBAL);

    if (Result != CSSM_OK)
    {
        CSSM_SetError (&cssm_GUID, CSSM_REGISTRY_ERROR);
        return(NULL);
    }

    if (UsageMask == 0)
    {
        NumUsedSubs = NumSubs;
    }
    else
    {
        Mask &= UsageMask;

        for (NumUsedSubs = 0, cSubs = 1; cSubs <= CSSM_SERVICE_LAST; cSubs <<= 1)
            // Up to and including the largest SERVICE_MASK bit flag
        {
            if ((cSubs & Mask) != 0) NumUsedSubs++;
        }

        if (NumSubs < NumUsedSubs)
            return(NULL);
    }

    if (NumUsedSubs > 0) {
        if ((ModulePtr->ServiceList = app_malloc (NumUsedSubs * sizeof (CSSM_SERVICE_INFO),
                memRef)) == NULL) {
            app_free (ModulePtr, memRef);
            CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
            return(NULL);
        }
        memset (ModulePtr->ServiceList, 0x00, NumUsedSubs * sizeof(CSSM_SERVICE_INFO));

        for (cSubs = 0, cUsedSubs = 0; cUsedSubs < NumUsedSubs; cSubs++)
        {
            char LocalKey[MAX_REG];
            uint32 ServiceType;

            strcpy (LocalKey, regKey);
            strcat (LocalKey, "\\Service");
            _itoa (cSubs+1, &LocalKey[strlen (LocalKey)], 10);

            // Determine the Service Type
            if (cssm_GetValue (LocalKey,"Type", (void *)&ServiceType, &dataSize,
                    &dataType, CSSM_PREFERENCE_GLOBAL) != CSSM_OK)
            {
                app_free(ModulePtr->ServiceList, memRef);
                app_free(ModulePtr, memRef);
                return(NULL);
            }

            if (ServiceType & Mask) {
                if (cssm_RegReadService(LocalKey, ServiceType, SubserviceID,
                   InfoLevel, &ModulePtr->ServiceList[cUsedSubs]) != CSSM_OK) {
                    /* If this service type should be returned and there
                       was an error.  Need a better cleanup here */
                    app_free(ModulePtr->ServiceList, memRef);
                    app_free(ModulePtr, memRef);
                    return(NULL);
                }
                ModulePtr->ServiceList[cUsedSubs++].Reserved = NULL;
            }
        }
    }
    else
        ModulePtr->ServiceList = NULL;

    ModulePtr->NumberOfServices = NumUsedSubs;
    ModulePtr->ServiceMask = Mask;
    ModulePtr->Reserved = NULL;
    return(ModulePtr);
}

CSSM_BOOL CSSMAPI cssm_RegAddinIsDynamic (const CSSM_GUID_PTR GUID)
{
    char regKey[MAX_REG];
    char ID[MAX_REG];
    uint32 i;
    CSSM_BOOL isDynamic = CSSM_FALSE;

	if (GUID == NULL)
	{
		CSSM_SetError (&cssm_GUID, CSSM_INVALID_POINTER);
		return(CSSM_FALSE);
	}

    /* Generate the registry Section for the add in information */
    strcpy (regKey, CSSMSECTION);
    cssm_GUIDToStr (GUID, ID);
    strcat (regKey, ID);

    i = sizeof(isDynamic);
    if (cssm_RegReadBinary (regKey, "Dynamic Capabilities", &isDynamic, i) == CSSM_FAIL)
        return(CSSM_FALSE);
    else
        return(isDynamic);
}
