/* SCCSID: fwk/port/port.c, dss_cdsa_fwk, fwk_rel3, dss_980413 1.44 4/13/98 11:18:43 */
/* ***************************************************************** *
 * 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:   PORT.C
 *
 */
/*
 * (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 <stdarg.h>
#include <string.h>

#include <stdlib.h>
#include <time.h>

#if defined (WIN32)
#include <direct.h>     /* getcwd */
#endif

#include "cssm.h"
#include "cssmport.h"

#ifdef SOCKETS_DEPENDENCY
#if defined(WIN32)
#include <winsock.h>
#endif
#endif /* SOCKETS_DEPENDENCY */

/*-----------------------------------------------------------------------------
 * Manifest constants and macros
 *---------------------------------------------------------------------------*/

#if defined (WIN32)
#define MAX_REG 256
static CSSM_RETURN CSSMAPI RegWipeKey(CSSM_HKEY hkey, char *szSubKey);
#endif

/*-----------------------------------------------------------------------------
 * Variable declarations
 *---------------------------------------------------------------------------*/

/* Mutex used to synchronize porting layer access to system registry */
static CSSM_MUTEX		registryLock		= 0;

/* Initialized flag */
static CSSM_BOOL		port_initialized	= CSSM_FALSE;

/*-----------------------------------------------------------------------------
 * Functions
 *---------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
 * Name: cssm_port_init
 *
 * Description: Prepares this library for use by an application. 
 * 
 * Parameters: None. 
 *
 * Returns:
 * CSSM_OK if the library was successfully initialized
 * CSSM_FAIL if an error occured
 *
 * Error Codes: None.
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_port_init()
{
	if (!port_initialized) {
	    if (registryLock == 0) {
			registryLock = (CSSM_MUTEX)cssm_CreateMutex("RegistryLock");
			if (registryLock == 0) {
				CSSM_SetError(&port_guid, CSSM_CANT_CREATE_MUTEX);
				return(CSSM_FAIL);
			}
		}
		port_initialized = CSSM_TRUE;
	} /* if !port_initialized */

    return(CSSM_OK);
}


/*-----------------------------------------------------------------------------
 * Name: cssm_port_terminate
 *
 * Description: Performs the necessary cleanup. 
 * 
 * Parameters: None. 
 *
 * Returns:
 * CSSM_OK if successfully completed
 * CSSM_FAIL if an error occured
 *
 * Error Codes: None.
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_port_terminate()
{
   if (registryLock) {
        cssm_CloseMutex((void *)registryLock);
		registryLock=0;
   }

   port_initialized = CSSM_FALSE;

   return(CSSM_OK);
}

/* Registry routines */

/*-----------------------------------------------------------------------------
 * Name: cssm_SetValue
 *
 * Description:  Sets a value for Name under Section in the registry
 * 
 * Parameters: 
 * Section (input): Name of the section in the configuration file that 
 *          will contain the entry.  May include a path to mimic 
 *          registry paths such as "CSSM\AddIn\blah". This will 
 *          map directly to the section name in Windows 3.1 and 
 *          to the registry path under Win32, but can be easily 
 *          adapted for other platforms.
 * Name (input):    Name of the value to set in the specified section.
 * Value (input):   Void pointer to the data to write to the configuration 
 *                  file/database.
 * ValueLength (input): Length of the data to write to the registry. 
 * ValueType (input):   Indicator to the type of data that is being written 
 *          to the configuration file. Valid types are 
 *          CSSM_CONFIG_STRING and CSSM_CONFIG_BINARY. Binary 
 *          values should converted to an ASCII representation of 
 *          the data before being written into a text registry. 
 *          They are stored as-is in the Win32 registry
 * PersonalPref (input):Boolean indicator as to whether the value should be 
 *          written to the system configuration data or to that 
 *          of the user. Valid values: CSSM_CONFIG_GLOBAL and 
 *          CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_CREATE_KEY - Unable to create a key for Section
 * CSSM_CANT_SET_VALUE - Unable to set the value for Name under Section
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_SetValue(char *Section, char *Name, void *Value, 
                        sint32 ValueLength, sint32 ValueType, sint32 PersonalPref)
{
    
#if defined (WIN32)

    CSSM_HKEY hkey=NULL;
    uint32 ret_val, status = CSSM_OK;

   if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
		// error set in lock mutex
	   return(CSSM_FAIL);
   }

   if (PersonalPref)
    {
        if (RegCreateKeyEx(HKEY_CURRENT_USER, Section, 0, 0, REG_OPTION_NON_VOLATILE, 
                        KEY_ALL_ACCESS, NULL, &hkey, &ret_val) != ERROR_SUCCESS)
        {
			status= CSSM_CANT_CREATE_KEY;
			goto Finally;
        }
    }
    else
    {
        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, Section, 0, 0, REG_OPTION_NON_VOLATILE, 
                        KEY_ALL_ACCESS, NULL, &hkey, &ret_val) != ERROR_SUCCESS)
        {
			status= CSSM_CANT_CREATE_KEY;
			goto Finally;
        }
    }
    
    ValueType = (ValueType == CSSM_VALUE_BINARY) ? REG_BINARY : REG_SZ;
    if (RegSetValueEx(hkey, Name, 0, ValueType, Value, ValueLength) != ERROR_SUCCESS)
    {
			status= CSSM_CANT_SET_VALUE;
			goto Finally;
    }

Finally:
	if (hkey !=NULL) {
		RegCloseKey(hkey);
	}
    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		status = CSSM_UNLOCK_MUTEX_FAILED;
	}
	if (status != CSSM_OK) {
		CSSM_SetError(&port_guid, status);
		return(CSSM_FAIL);
	}
  
	return(CSSM_OK);;
  
	
	  
#elif defined (WIN31)

    CSSM_HKEY hkey;
    uint32 ret_val;

    /* Can also do with INI files instead of registry */

    if (PersonalPref)
    {
        if (RegCreateKey(HKEY_CURRENT_USER, Section, &hkey) != ERROR_SUCCESS)
        {
            CSSM_SetError(&port_guid, CSSM_CANT_CREATE_KEY);
            return(CSSM_FAIL);
        }
    }
    else
    {
        if (RegCreateKey(HKEY_LOCAL_MACHINE, Section, &hkey) != ERROR_SUCCESS)
        {
            CSSM_SetError(&port_guid, CSSM_CANT_CREATE_KEY);
            return(CSSM_FAIL);
        }
    }
    
    if (ValueType == CSSM_CONFIG_BINARY)
    {
        /* translate binary data to text */
    }
    if (RegSetValue(hkey, Name, CSSM_CONFIG_STRING, Value, ValueLength) != ERROR_SUCCESS)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_SET_VALUE);
        return(CSSM_FAIL);
    }
	RegCloseKey(hkey);
    return(CSSM_OK);
#endif
}


 
/*-----------------------------------------------------------------------------
 * Name: cssm_GetValue
 *
 * Description:  Gets a value for Name under Section in the registry
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file that 
 *                              contains the entry.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * Name (input)             :   Name of the value to get in the specified section.
 * Value (output)           :   Void pointer to the data to read from the configuration 
 *                              file/database.
 * ValueLength (output)     :   Length of the data to read from the registry. 
 * ValueType (output)       :   Indicator to the type of data that is being read 
 *                              from the configuration file. Valid types are 
 *                              CSSM_CONFIG_STRING and CSSM_CONFIG_BINARY. Binary 
 *                              values should converted to an ASCII representation of 
 *                              the data before being written into a text registry. 
 *                              They are stored as-is in the Win32 registry
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              read from the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open a key for Section
 * CSSM_CANT_SET_VALUE - Unable to get the value for Name under Section
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_GetValue(char *Section, char *Name, void *Value, 
          sint32 *ValueLength, sint32 *ValueType, sint32 PersonalPref)
{

#if defined (WIN32)
    
    CSSM_HKEY hkey=NULL;
	uint32	status = CSSM_OK;


    if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
       	return(CSSM_FAIL);
    }

    if (PersonalPref)
    {
        if (RegOpenKeyEx(HKEY_CURRENT_USER, Section, 0, KEY_ALL_ACCESS, &hkey) != ERROR_SUCCESS)
        {
            status = CSSM_CANT_OPEN_KEY;
            goto Finally;
        }
    }
    else
    {
        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, Section, 0, KEY_ALL_ACCESS, &hkey) != ERROR_SUCCESS)
        {
            status = CSSM_CANT_OPEN_KEY;
            goto Finally;
        }

    }
    if (RegQueryValueEx(hkey, Name, NULL, ValueType, Value, 
                            ValueLength) != ERROR_SUCCESS)
    {
        status = CSSM_CANT_GET_VALUE;
        goto Finally;
    }
    *ValueType = (*ValueType == REG_BINARY) ? CSSM_VALUE_BINARY : CSSM_VALUE_STRING;

Finally:
    if(hkey !=NULL) {
		RegCloseKey(hkey);
	}
    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		status = CSSM_UNLOCK_MUTEX_FAILED;
	}
	if (status != CSSM_OK) {
		CSSM_SetError(&port_guid, status);
		return(CSSM_FAIL);
	}
    return(CSSM_OK);

#elif defined (WIN31)

    CSSM_HKEY hkey;

    if (PersonalPref)
    {
        if (RegOpenKey(HKEY_CURRENT_USER, Section, &hkey) != ERROR_SUCCESS)
        {
            CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
            return(CSSM_FAIL);
        }
    }
    else
    {
        if (RegOpenKey(HKEY_LOCAL_MACHINE, Section, &hkey) != ERROR_SUCCESS)
        {
            CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
            return(CSSM_FAIL);
        }
    }

    if (RegQueryValue(hkey, Name, Value, ValueLength) != ERROR_SUCCESS)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_VALUE);
        return(CSSM_FAIL);
    }
    *ValueType = CSSM_VALUE_STRING;
    RegCloseKey(hkey);
    return(CSSM_OK);
#endif
}


/*-----------------------------------------------------------------------------
 * Name: cssm_DeleteSection
 *
 * Description:  Deletes a  Section in the registry
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file to
 *                              delete.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              written to the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_ENUM_KEY - Unable to enumerate the key for section
 * CSSM_CANT_DELETE_KEY - Unable to delte the key for section
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_DeleteSection(char * Section, sint32 PersonalPref)
{
		
#if defined (WIN32) || (WIN31)
	
	CSSM_RETURN	status = CSSM_OK;

    if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
        return(CSSM_FAIL);
    }
    if (PersonalPref)
    {
        if (RegWipeKey(HKEY_CURRENT_USER, Section) != CSSM_OK)
        {
			status = CSSM_FAIL;
        }
    }
    else
    {
        if (RegWipeKey(HKEY_LOCAL_MACHINE, Section) != CSSM_OK)
        {
			status = CSSM_FAIL;
        }
    }

    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		status = CSSM_FAIL; /* error code is set in unlock mutex fn */
	}

	
	return(status);
    
#endif

}

/*-----------------------------------------------------------------------------
 * Name: RegWipeKey
 *
 * Description:  Recursively deletes a  Section in the registry
 *				 Note that the caller of this function should
 *				 lock before calling
 * 
 * Parameters: 
 * hkey (input)         :   HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE
 * szSubKey (input)     :   Key to delete
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_ENUM_KEY - Unable to enumerate the key for section
 * CSSM_CANT_DELETE_KEY - Unable to delte the key for section
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI RegWipeKey(CSSM_HKEY hkey, char *szSubKey) 
{


#if defined (WIN32)

    CSSM_HKEY htempkey;
    char keyname[MAX_REG];
    char tempkeyname[MAX_REG];
    uint32 keynamelength;
    sint32 index = 0;
    sint32 regResult;
    sint32 done = 0;

    do 
    {
         /* open the key for enumeration */
        regResult = RegOpenKeyEx(hkey, szSubKey, 0, KEY_ALL_ACCESS, &htempkey);
        if (regResult != ERROR_SUCCESS)
        {
            CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
            return(CSSM_FAIL);
        }

        keynamelength = MAX_REG;
        regResult = RegEnumKeyEx(htempkey, 0, keyname, &keynamelength, 
                                     0, NULL, NULL, NULL);
        RegCloseKey(htempkey);

        if (regResult != ERROR_NO_MORE_ITEMS && regResult == ERROR_SUCCESS) 
        {
            strcpy(tempkeyname,szSubKey);
            strcat(tempkeyname,"\\");
            strcat(tempkeyname,keyname);

            regResult = RegWipeKey(hkey,tempkeyname);
            if (regResult == CSSM_FAIL)
                done = 1;
        } 
        else if (regResult == ERROR_NO_MORE_ITEMS)
        {
            done = 1;
        }
        else
        {
            CSSM_SetError(&port_guid, CSSM_CANT_ENUM_KEY);
            return(CSSM_FAIL);
        }
    } while (!done);

    /* Nuke the requested key */
    regResult = RegDeleteKey(hkey,szSubKey);
    if (regResult != ERROR_SUCCESS)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_DELETE_KEY);
        return(CSSM_FAIL);
    }

    return(CSSM_OK);
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetSectionList
 *
 * Description:  Get a list of the sections under the specified section
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file to
 *                              delete.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * list (output)            :   List of subsections
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              written to the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_ENUM_KEY - Unable to enumerate the key for section
 * CSSM_CANT_QUERY_KEY - Unable to query the key for section
 *---------------------------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_GetSectionList(char *section, CSSM_REG_LIST_PTR list, sint32 PersonalPref) 
{
    
#if defined (WIN32)


    CSSM_HKEY hkey=NULL;
    sint32 numkeys;
    char name[MAX_REG];
    uint32 namelength;
    sint32 index;
    sint32 regResult;
	uint32	status = CSSM_OK;
    

    if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
		return(CSSM_FAIL);
    }

    if (PersonalPref) 
    {
        regResult = RegOpenKeyEx(HKEY_CURRENT_USER, section, 0, KEY_ALL_ACCESS, &hkey);
    } 
    else 
    {
        regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, section, 0, KEY_ALL_ACCESS, &hkey);
    }
    if (regResult != ERROR_SUCCESS) 
    {
		status = CSSM_CANT_OPEN_KEY;
        goto Finally;
    }

    /* Get the count of keys */
    regResult = RegQueryInfoKey(hkey, NULL, NULL, NULL, &numkeys,
                                NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    if (regResult != ERROR_SUCCESS) 
    {
		status = CSSM_CANT_QUERY_KEY;
        goto Finally;
    }

    /* Allocate memory for the names */
    if ((*list = cssm_malloc((sizeof(char *) * (numkeys + 1)), NULL)) == NULL) 
    {
		status = CSSM_MALLOC_FAILED;
        goto Finally;
    }
    cssm_memset(*list,0,sizeof(char *) * (numkeys + 1));

    /* Enumerate the keys and place in string list */
    for (index = 0; index < numkeys; index++) 
    {
        namelength = MAX_REG;
        regResult = RegEnumKeyEx(hkey, index, name, &namelength, NULL, NULL, NULL,  NULL);
        if (regResult != ERROR_SUCCESS) 
        {
            char * *ppChar;

            (*list)[index] = NULL;
            RegCloseKey(hkey);
            ppChar = *list;
            while (*ppChar)
                cssm_free((*ppChar)++, NULL);

	        status = CSSM_CANT_ENUM_KEY;
            goto Finally;
        }

        /* Allocate memory for the name string */
        if (((*list)[index] = cssm_malloc((namelength + 1), NULL)) == NULL) 
        {
            char * *ppChar;
            
            (*list)[index] = NULL;
            RegCloseKey(hkey);
            ppChar = *list;
            while (*ppChar)
                cssm_free((*ppChar)++, NULL);
			
			status = CSSM_MALLOC_FAILED;
        	goto Finally;
        }

        /* Copy the CSP name into the new storage area */
        strcpy((*list)[index],name);
    }
    (*list)[index] = NULL;
Finally:

    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		status = CSSM_UNLOCK_MUTEX_FAILED;
	}
    if (hkey != NULL) {
		RegCloseKey(hkey);
	}
	if (status != CSSM_OK) {
		CSSM_SetError(&port_guid, status);
		return(CSSM_FAIL);
	}

    return(CSSM_OK);
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetValueList
 *
 * Description:  Get a list of the values under the specified section
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file to
 *                              delete.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * list (output)            :   List of values
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              written to the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_ENUM_KEY - Unable to enumerate the key for section
 * CSSM_CANT_QUERY_KEY - Unable to query the key for section
 *---------------------------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_GetValueList(char *section, CSSM_REG_LIST_PTR list, sint32 PersonalPref) 
{


#if defined (WIN32)
    CSSM_HKEY hkey;
    sint32 numkeys;
    char name[MAX_REG];
    uint32 namelength;
    sint32 index;
    sint32 regResult;
    

     if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
		return(CSSM_FAIL);
    }

	 if (PersonalPref) 
    {
        regResult = RegOpenKeyEx(HKEY_CURRENT_USER, section, 0, KEY_ALL_ACCESS, &hkey);
    } 
    else 
    {
        regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, section, 0, KEY_ALL_ACCESS, &hkey);
    }
    if (regResult != ERROR_SUCCESS) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }

    /* Get the count of values */
    regResult = RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL,
                                &numkeys, NULL, NULL, NULL, NULL);
    if (regResult != ERROR_SUCCESS) 
    {
        RegCloseKey(hkey);
        CSSM_SetError(&port_guid, CSSM_CANT_QUERY_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }

    /* Allocate memory for the names */
    if ((*list = cssm_malloc((sizeof(char *) * (numkeys + 1)), NULL)) == NULL) 
    {
        RegCloseKey(hkey);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }
    cssm_memset(*list,0,sizeof(char *) * (numkeys + 1));

    /* Enumerate the values and place in string list */
    for (index = 0; index < numkeys; index++) 
    {
        namelength = MAX_REG;
        regResult = RegEnumValue(hkey, index, name, &namelength, NULL, NULL, NULL, NULL);
        if (regResult != ERROR_SUCCESS) 
        {
            char * *ppChar;

            (*list)[index] = NULL;
            RegCloseKey(hkey);
            ppChar = *list;
            while (*ppChar)
                cssm_free((*ppChar)++, NULL);

	        RegCloseKey(hkey);
            CSSM_SetError(&port_guid, CSSM_CANT_ENUM_KEY);
	        cssm_UnlockMutex((void *) registryLock);
            return(CSSM_FAIL);
        }

        /* Allocate memory for the name string */
        if (((*list)[index] = cssm_malloc((namelength + 1), NULL)) == NULL) 
        {
            char * *ppChar;
            
            (*list)[index] = NULL;
            RegCloseKey(hkey);
            ppChar = *list;
            while (*ppChar)
                cssm_free((*ppChar)++, NULL);

            cssm_UnlockMutex((void *) registryLock);
	        return(CSSM_FAIL);
        }

        /* Copy the CSP name into the new storage area */
        strcpy((*list)[index],name);
    }
    (*list)[index] = NULL;

    RegCloseKey(hkey);
    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		return(CSSM_FAIL);
	}
    return(CSSM_OK);
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetValueCount
 *
 * Description:  Gets the number of values under the specified section
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file to
 *                              delete.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * count (output)           :   Number of values under section
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              written to the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_QUERY_KEY - Unable to query the key for section
 *---------------------------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_GetValueCount(char *section, sint32 *count, sint32 PersonalPref) 
{
#if defined (WIN32)

    CSSM_HKEY hkey;
    sint32 numkeys;
    sint32 regResult;

    if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
		return(CSSM_FAIL);
    }
   
    if (PersonalPref) 
    {
        regResult = RegOpenKeyEx(HKEY_CURRENT_USER, section, 0, KEY_ALL_ACCESS, &hkey);
    } 
    else 
    {
        regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, section, 0, KEY_ALL_ACCESS, &hkey);
    }
    if (regResult != ERROR_SUCCESS) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }

    /* Get the count of values */
    regResult = RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL, 
                                &numkeys, NULL, NULL, NULL, NULL);
    RegCloseKey(hkey);
    if (regResult != ERROR_SUCCESS) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_QUERY_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }
    *count = numkeys;

    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		return(CSSM_FAIL);
	}
    return(CSSM_OK);
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetSectionCount
 *
 * Description:  Gets the number of sections under the specified section
 * 
 * Parameters: 
 * Section (input)          :   Name of the section in the configuration file to
 *                              delete.  May include a path to mimic 
 *                              registry paths such as "CSSM\AddIn\blah". This will 
 *                              map directly to the section name in Windows 3.1 and 
 *                              to the registry path under Win32, but can be easily 
 *                              adapted for other platforms.
 * count (output)           :   Number of subsections under section
 * PersonalPref (input)     :   Boolean indicator as to whether the value should be 
 *                              written to the system configuration data or to that 
 *                              of the user. Valid values are CSSM_CONFIG_GLOBAL and 
 *                              CSSM_CONFIG_PERSONAL
 *
 * Returns:
 * CSSM_OK if the operation was successful
 * CSSM_FAIL if an error occured
 *
 * Error Codes:
 * CSSM_CANT_OPEN_KEY - Unable to open the key for section 
 * CSSM_CANT_QUERY_KEY - Unable to query the key for section
 *---------------------------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_GetSectionCount(char *section, sint32 *count, sint32 PersonalPref) 
{
#if defined (WIN32)

    CSSM_HKEY hkey;
    sint32 numkeys;
    sint32 regResult;
    
    
    if ( cssm_LockMutex((void *)registryLock, INFINITE) != CSSM_MUTEX_LOCKED) {
		return(CSSM_FAIL);
    }
	if (PersonalPref) 
    {
        regResult = RegOpenKeyEx(HKEY_CURRENT_USER, section, 0, KEY_ALL_ACCESS, &hkey);
    } 
    else 
    {
        regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, section, 0, KEY_ALL_ACCESS, &hkey);
    }
    if (regResult != ERROR_SUCCESS) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_OPEN_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }

    /* Get the count of values */
    regResult = RegQueryInfoKey(hkey, NULL, NULL, NULL, &numkeys,
                                NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    RegCloseKey(hkey);
    if (regResult != ERROR_SUCCESS) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_QUERY_KEY);
        cssm_UnlockMutex((void *) registryLock);
        return(CSSM_FAIL);
    }
    *count = numkeys;

    if (cssm_UnlockMutex((void *) registryLock) != CSSM_MUTEX_UNLOCKED) {
		return(CSSM_FAIL);
	}
    return(CSSM_OK);
#endif
}


/* Memory allocation, pointer, and string routines */

/*-----------------------------------------------------------------------------
 * Name: cssm_malloc
 *
 * Description:  Allocates a memory block of the requested size
 * 
 * Parameters: 
 * mem_size (input)       : Number of bytes of memory to allocate
 * allocRef (input)       : Reference to the heap allocated from
 *
 * Returns:
 * Pointer to allocated memory. 
 * NULL if an error condition occurred. 
 * 
 * Error Codes:
 * CSSM_MALLOC_FAILED
 *---------------------------------------------------------------------------*/

void * cssm_malloc (uint32  mem_size, void* allocRef)
{
  /* Asssume all allocations from the same heap - ignore allocRef */
  void *mem_ptr;

  mem_ptr = calloc(mem_size,1);

    if (mem_ptr == NULL) {
        CSSM_SetError(&port_guid, CSSM_MALLOC_FAILED);
        return(NULL);
    }
    else {
        return(mem_ptr);
    }
}


/*-----------------------------------------------------------------------------
 * Name: cssm_calloc
 *
 * Description:  Allocates a memory block of the requested size and
 *               initializes all elements to zero
 * 
 * Parameters: 
 * num_elem (input)       : Number of elements to allocate
 * num_bytes (input)      : Size of each element to allocate
 * allocRef               : Reference to the heap in which memory is allocated
 *
 * Returns:
 * Pointer to allocated memory. 
 * NULL if an error condition occurred. 
 * 
 * Error Codes:
 * CSSM_CALLOC_FAILED
 *---------------------------------------------------------------------------*/

void * cssm_calloc (uint32  num_elem, uint32  num_bytes, void* allocRef)
{
  /* Assume all allocations from one heap - ignore allocRef */
    void *ptr;

    ptr = calloc(num_elem, num_bytes);

    if (ptr == NULL) {
        CSSM_SetError(&port_guid, CSSM_CALLOC_FAILED);
        return(NULL);
    } 
	else {
        return(ptr);
    }
}

/*-----------------------------------------------------------------------------
 * Name: cssm_free
 *
 * Description:  Frees an allocated memory block
 * 
 * Parameters: 
 * mem_ptr (input)       : Pointer to allocated memory
 * allocRef (input)      : Reference to the heap where the memory was allocated
 *
 * Returns:
 * CSSM_OK if call is successful 
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/

void cssm_free (void *mem_ptr, void* allocRef)
{
  /* Assume all allocations are from the same heap - ignore allocRef */
  if (mem_ptr!= NULL) {
	  free(mem_ptr);
  }

  mem_ptr = NULL;
  
  return;
}

/*-----------------------------------------------------------------------------
 * Name: cssm_realloc
 *
 * Description:  Re-allocates a memory block of the requested size
 * 
 * Parameters: 
 * old_ptr (input)        : Pointer to old memory block
 * num_bytes (input)      : Size of memory block to allocate
 * allocRef (input)       : Reference to heap where memory to be reallocated
 *                          is currently allocated
 *
 * Returns:
 * Pointer to allocated memory. 
 * NULL if an error condition occurred or memory was freed, see comments. 
 * 
 * Error Codes:
 * CSSM_REALLOC_FAILED
 *
 * Comments: 
 *  If the pointer passed in is NULL, cssm_realloc behaves like cssm_malloc. 
 *  The return value is NULL if the size is zero and the buffer argument is 
 *  not NULL, or if there is not enough available memory to expand the block 
 *  to the given size. In the first case, the original block is freed. In the 
 *  second, the original block is unchanged.
 *---------------------------------------------------------------------------*/
void * cssm_realloc (void *old_ptr, uint32  num_bytes, void* allocRef)
{
  /* Assume all alocations are fromm the same heap - ignore allocRef */
    void *new_ptr;

    new_ptr = realloc(old_ptr, num_bytes);

    if (new_ptr == NULL && num_bytes != 0)
    {
      CSSM_SetError(&port_guid, CSSM_REALLOC_FAILED);
      return(NULL);
    }
    else
    {
      CSSM_ClearError();
      return(new_ptr);
    }

}


/*-----------------------------------------------------------------------------
 * Name: cssm_memset
 *
 * Description:  Initializes all elements of a memory block to a value
 * 
 * Parameters: 
 * ptr (input)       : Pointer to memory block
 * vlaue (input)     : Value to initialize memory to
 * num_bytes (input) : Number of bytes of memory to initialize
 *
 * Returns:
 * Ptr to memory (same as pointer passed in)
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
void * cssm_memset (void *ptr, sint32 value, uint32  num_bytes )
{

    memset(ptr, value, num_bytes);
    return(ptr);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_memcpy
 *
 * Description:  Copies contents of one memory block to another
 * 
 * Parameters: 
 * dest_ptr (input)       : Pointer to destination memory block
 * src_ptr (input)        : Pointer to source memory block
 * num_bytes (input)      : Number of bytes of memory to copy
 *
 * Returns:
 * Ptr to memory (same as pointer passed in)
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
void * cssm_memcpy (void *dest_ptr, void *src_ptr, uint32  num_bytes )
{

    memcpy(dest_ptr, src_ptr, num_bytes);
    return(dest_ptr);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_memmove
 *
 * Description:  Copies contents of one memory block to another -
 *                  handles overlapping memory regions
 * 
 * Parameters: 
 * dest_ptr (input)       : Pointer to destination memory block
 * src_ptr (input)        : Pointer to source memory block
 * num_bytes (input)      : Number of bytes of memory to copy
 *
 * Returns:
 * Ptr to memory (same as pointer passed in)
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
void * cssm_memmove (void *dest_ptr, void *src_ptr, uint32  num_bytes )
{

    memmove(dest_ptr, src_ptr, num_bytes);
    return(dest_ptr);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_memcmp
 *
 * Description:  Compares the contents of two memory blocks
 * 
 * Parameters: 
 * ptr1 (input)        : Pointer to first memory block
 * ptr2 (input)        : Pointer to second memory block
 * count (input)       : Number of bytes of memory to compare
 *
 * Returns:
 * < 0          ptr1 less than ptr2
 * 0            ptr1 identical to ptr2
 * > 0          ptr1 greater than ptr2
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
sint32 cssm_memcmp (void *ptr1, void *ptr2, uint32  count)
{
    return(memcmp(ptr1, ptr2, count));
}


/*-----------------------------------------------------------------------------
 * Name: cssm_IsBadStrPtr
 *
 * Description: On Windows platforms, cssm_IsBadStrPtr verifies that the 
 *              calling process has read access to a range of memory pointed 
 *              to by a string pointer.  On all platforms, this function will
 *              check that the pointer passed consists of printable character
 *              bytes.
 * 
 * Parameters: 
 * str (input)           : Pointer to a string
 * length (input)        : Length of pointer to check
 *
 * Returns:
 * CSSM_TRUE - string pointer is bad
 * CSSM_FALSE - string pointer is okay
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
CSSM_BOOL CSSMAPI cssm_IsBadStrPtr (const char *str, uint32 length)
{
    uint32 i;

#if defined(WIN32)

    if (IsBadStringPtr(str, length))
        return(CSSM_TRUE);
    

#endif
    if(strlen(str)!=length)
        return(CSSM_TRUE);
    
    /* check that all characters are printable */
    for(i=0; i < strlen(str); i++)
    {
        if (!(isprint(str[i])))
            return(CSSM_TRUE);
    }

    return(CSSM_FALSE);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_IsBadCodePtr
 *
 * Description:  On Windows platforms, cssm_IsBadCodePtr determines whether 
 *               the calling process has read access to the memory at the 
 *               specified address.  On other platforms, cssm_IsBadCodePtr 
 *               may simply ensure that the pointer is not NULL
 * 
 * Parameters: 
 * code_ptr (input)           : Pointer to a piece of code
 *
 * Returns:
 * CSSM_TRUE - code pointer is bad
 * CSSM_FALSE - code pointer is okay
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
CSSM_BOOL CSSMAPI cssm_IsBadCodePtr(CSSM_CALLBACK code_ptr)
{

#if defined(WIN32)

    if (IsBadCodePtr((CSSM_PROC_ADDR)code_ptr))
        return(CSSM_TRUE);
    return(CSSM_FALSE);

#else

    if (code_ptr == NULL)
        return(CSSM_TRUE);

    return(CSSM_FALSE);

#endif

}

/*-----------------------------------------------------------------------------
 * Name: cssm_IsBadReadPtr
 *
 * Description:  On Windows platforms, cssm_IsBadReadPtr verifies that the 
 *               calling process has read access to the specified range
 *               of memory.  On other platforms, cssm_IsBadStrPtr 
 *               may simply ensure that the pointer is not NULL
 * 
 * Parameters: 
 * str (input)           : Pointer 
 * length (input)        : Length of pointer to check
 *
 * Returns:
 * CSSM_TRUE - pointer is bad
 * CSSM_FALSE - pointer is okay
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
CSSM_BOOL CSSMAPI cssm_IsBadReadPtr (const void *ptr, uint32 length)
{

#if defined(WIN32)

    if ( (IsBadReadPtr(ptr, length)) || (length==0) || (ptr == NULL) )
        return(CSSM_TRUE);

    return(CSSM_FALSE);

#else

    if ((ptr == NULL) || (length==0))
        return(CSSM_TRUE);

    return(CSSM_FALSE);

#endif

}

/*-----------------------------------------------------------------------------
 * Name: cssm_IsBadWritePtr
 *
 * Description:  On Windows platforms, cssm_IsBadWritePtr verifies that the 
 *               calling process has write access to the specified range
 *               of memory.  On other platforms, cssm_IsBadStrPtr 
 *               may simply ensure that the pointer is not NULL
 * 
 * Parameters: 
 * str (input)           : Pointer 
 * length (input)        : Length of pointer to check
 *
 * Returns:
 * CSSM_TRUE - pointer is bad
 * CSSM_FALSE - pointer is okay
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
CSSM_BOOL CSSMAPI cssm_IsBadWritePtr (void *ptr, uint32 length)
{

#if defined(WIN32)

    if (IsBadWritePtr(ptr, length) || (length==0) || (ptr==NULL))
        return(CSSM_TRUE);

    return(CSSM_FALSE);

#else

    if ((ptr == NULL) || (length==0))
        return(CSSM_TRUE);

    return(CSSM_FALSE);

#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_strlwr
 *
 * Description:  Converts a string to all lowercase
 * 
 * Parameters: 
 * str (input)           : Pointer to a string
 *
 * Returns:
 * Pointer to a string - same pointer that was passed in.
 * 
 * Error Codes:
 * None
 *---------------------------------------------------------------------------*/
char * CSSMAPI cssm_strlwr (char * str)
{
#if defined(WIN32)

    _strlwr(str);
    return(str);

#else 

    char *p;

	for(p = str; p < str + strlen( str ); p++)
    {
        *p = tolower(*p);
    }
    
    return(str);

#endif

}


/* File I/O Routines */

/*----------------------------------------------------------
 *Name: CSSM_fwrite
 *
 *Description: Writes the contents of 'buffer' to the file 
 *  pointed to by 'stream' one byte at a time.  The file should
 *  have been opened in binary mode.
 * 
 *Parameters:
 *  buffer (input) - pointer to data to be written
 *  size (input) - size of each item to be written
 *  num (input) - number of items to be written
 *  stream (input) - pointer to a file opened in binary mode
 * 
 *Returns: 
 *  CSSM_OK - The write was successfully completed
 *  CSSM_FAIL - A problem was encountered during the write.
 *     Call cssm_GetError for more info.
 * 
 *Error Codess:
 *  CSSM_INVALID_FILE_PTR
 *  CSSM_BAD_PTR_PASSED
 *  CSSM_FWRITE_FAILED
 *--------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_fwrite (void *buffer, uint32 size, uint32  num, FILE *stream )
{
    
    uint32  num_written, total_size, i;
    

    if (stream == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_FILE_PTR);
        return(CSSM_FAIL);
    }

    total_size = size * num;

    if (cssm_IsBadReadPtr(buffer, total_size))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(CSSM_FAIL);
    }
    
    for (i = 0; i < total_size; i++)
    {
    
        num_written = fwrite(buffer, 1, 1, stream);

        if (num_written != 1)
        {
            CSSM_SetError(&port_guid, CSSM_FWRITE_FAILED);
            return(CSSM_FAIL);
        }
            
        buffer = (uint8 *) buffer + sizeof(uint8);
    }
    return(CSSM_OK);
}

/*----------------------------------------------------------
 *Name: CSSM_fread
 *
 *Description: Reads the contents of the file pointed to by 
 *  'stream' to 'buffer' one byte at a time.  The file should
 *  have been opened in binary mode.
 * 
 *Parameters:
 *  buffer (output) - pointer to area to place data
 *  size (input) - size of each item to be read
 *  num (input) - number of items to be read
 *  stream (input) - pointer to a file opened in binary mode
 * 
 *Returns: 
 *  CSSM_OK - The read was successfully completed
 *  CSSM_FAIL - A problem was encountered during the read.
 *     Call CSSM_GetError for more info.
 * 
 *Error Codes:
 *  CSSM_INVALID_FILE_PTR - 'stream' is NULL
 *  CSSM_BAD_PTR_PASSED - 'buffer' is not valid for writing data to
 *  CSSM_FREAD_FAILED - can't read from file
 *  CSSM_END_OF_FILE - end of file encountered before all requested
 *    data was read.  caller can determine severity of this error
 *--------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_fread (void *buffer, uint32 size, uint32  num, FILE *stream )
{

    uint32  num_read, total_size, i;

    if (stream == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_FILE_PTR);
        return(CSSM_FAIL);
    }

    total_size = size * num;

    if (cssm_IsBadWritePtr(buffer, total_size))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(CSSM_FAIL);
    }
    
    for (i = 0; i < total_size; i++)
    {
        num_read = fread(buffer, 1, 1, stream);
        
        if (num_read != 1)
        {
            if (feof(stream))
            {
                /* May not be an error case, less data in the file
                   then expected */
                CSSM_SetError(&port_guid, CSSM_END_OF_FILE);
                return(CSSM_FAIL);
            }
            else
            {
                CSSM_SetError(&port_guid, CSSM_FREAD_FAILED);
                return(CSSM_FAIL);
            }
        }
            
        buffer = (uint8 *) buffer + sizeof(uint8);
    }
    return(CSSM_OK);
    
}

/*----------------------------------------------------------
 *Name: CSSM_GetLength
 *
 *Description: Returns the length of the file pointed to by 'stream'
 * 
 *Parameters:
 *  stream (input) - pointer to a file 
 * 
 *Returns: 
 *  -1:  Error encountered.  Call CSSM_GetError for more info
 *  0 <= file_size:  Size of file
 * 
 *Error Codes:
 *  CSSM_CANT_FSEEK
 *  CSSM_INVALID_FILE_PTR
 *--------------------------------------------------------*/

sint32 CSSMAPI cssm_GetLength (FILE *stream) 
{

    sint32 bytes;
    sint32 current_pos;

    // Check that file pointer passed is valid

    if (stream == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_FILE_PTR);
        return(CSSM_FAIL);
    }

    // Record current file cursor position
    current_pos = ftell(stream);

    // Verify current position is valid, if not set to 0
    if(current_pos < 0)
        current_pos = 0;

    // Seek to the end of the file
    if (fseek(stream, 0, SEEK_END))
    {
        CSSM_SetError(&port_guid, CSSM_CANT_FSEEK);
        return(-1);
    }

    // Record position (at end of file)
    bytes = ftell(stream);

    // Verify the end of file position found is valid (not negative)
    if (bytes == -1)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_FILE_PTR);
        return(-1);
    }

    // Return file pointer to original position
    fseek(stream, current_pos, SEEK_SET);
    
    // Return file length
    return(bytes + 1);
    
}

/* Misc */

#ifdef SOCKETS_DEPENDENCY
/*-----------------------------------------------------------------------------
 * Name: cssm_GetIdentificationInfo
 *
 * Description:  Gets current user identification information that is useful 
 *               across systems.
 * 
 * Parameters: 
 * info (input)                : Pointer 
 * size (input)                : Length of string pointer
 *
 * Returns:
 * Pointer to string containing identification information
 * NULL if an error occured.
 * 
 * Error Codes:
 * CSSM_GET_IDENTIFICATION_INFO_FAILED - could not get required information
 * CSSM_BAD_PTR_PASSED - input pointer is not valid
 *---------------------------------------------------------------------------*/

char * CSSMAPI cssm_GetIdentificationInfo(char *info, uint32  size)
{

#	define MAX_INFO_LEN			1024
	static CSSM_BOOL			sockets_initialized = CSSM_FALSE;
	char						username[MAX_INFO_LEN];
	char						tmpbuf[MAX_INFO_LEN];
	char						outbuf[MAX_INFO_LEN];
	struct hostent				*hostentry;
	int							i;

	outbuf[0] = '\0';

    if (cssm_IsBadWritePtr(info, size))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }

	// get name of current user

	if (cssm_GetUserName(username, MAX_INFO_LEN) == NULL)
	{
		// error already set
		return(NULL);
	}

	sprintf(tmpbuf, "USER=%s", username);
	strcat(outbuf, tmpbuf);

#ifdef WIN32
	//
	// Initialize sockets for gethostname() and gethostbyname()
	//
	if (!sockets_initialized)
	{
		WORD wVersionRequested;  
		WSADATA wsaData; 

		wVersionRequested = MAKEWORD(1, 1); 
		
		if (WSAStartup(wVersionRequested, &wsaData) != 0)
			return(NULL);
	}
#endif

	// get name and network address information for the current machine

	if (gethostname(tmpbuf, MAX_INFO_LEN) != 0) 
	{
		printf("could not get hostname\n");
		return(NULL);
	}

	if ((hostentry = gethostbyname(tmpbuf)) == NULL) 
	{
		printf("could not get hostentry\n");
		return(NULL);
	}

	sprintf(tmpbuf, "/HOST=%s", hostentry->h_name);
	strcat(outbuf, tmpbuf);

	if (hostentry->h_addrtype == PF_INET)
	{
		for (i = 0; hostentry->h_addr_list[i] != NULL; i++)
		{
			struct in_addr address;

			memcpy((void *)&address.s_addr,
			       (void *)hostentry->h_addr_list[i],
			       sizeof(address.s_addr));

			sprintf(tmpbuf, "/ADDRESS=%s", inet_ntoa(address));
			strcat(outbuf, tmpbuf);
		}
	}

	if (size < strlen(outbuf) + 1) {
		return(NULL);
	}

	// copy structure
	strcpy(info, outbuf);

	return(info);
}
#endif // SOCKETS_DEPENDENCY

/*-----------------------------------------------------------------------------
 * Name: cssm_GetUserName
 *
 * Description:  Gets the name of the current user
 * 
 * Parameters: 
 * user_name (input)           : Pointer 
 * size (input)                : Length of string pointer
 *
 * Returns:
 * Pointer to string containing user's name.
 * NULL if an error occured.
 * 
 * Error Codes:
 * CSSM_CANT_GET_USER_NAME - unable to get the user's name
 * CSSM_BAD_PTR_PASSED - user_name pointer is not valid
 *---------------------------------------------------------------------------*/
char * CSSMAPI cssm_GetUserName(char *user_name, uint32 size) 
{


    if (cssm_IsBadWritePtr(user_name, size)) {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }
    if (GetUserName(user_name, &size)) {
        return(user_name);
    } 
    else {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_USER_NAME);
        return(NULL);
    }
}

/*-----------------------------------------------------------------------------
 * Name: cssm_getcwd
 *
 * Description:  Gets the current working directory
 * 
 * Parameters: 
 * dir (input)                 : Pointer 
 * size (input)                : Length of string pointer
 *
 * Returns:
 * Pointer to string containing directory name.
 * NULL if an error occured.
 * 
 * Error Codes:
 * CSSM_GET_CWD_FAILED - unable to get the current working directory
 * CSSM_BAD_PTR_PASSED - dir pointer is not valid
 *---------------------------------------------------------------------------*/

char * CSSMAPI cssm_getcwd(char *dir, uint32  size)
{

    char *tmp, *ptr;

    if (cssm_IsBadWritePtr(dir, size))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }

    if ((tmp = getcwd(dir, size)) == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_GETCWD_FAILED);
        return(NULL);
    }
    else
    {
        /* modify based on platform */
        while ((ptr = strchr(tmp, '\\')) != NULL)
        {
            *ptr = '/';
        }
        strcpy(dir, tmp);
        return(dir);
    }

}


/*-----------------------------------------------------------------------------
 * Name: cssm_getenv
 *
 * Description:  Gets the value of the specified environment variable
 * 
 * Parameters: 
 * env_var (input)           : Pointer 
 *
 * Returns:
 * Pointer to string containing value of environment value
 * NULL if an error occured.
 * 
 * Error Codes:
 * CSSM_ENV_VAR_NOT_FOUND - specified environment variable not found
 * CSSM_BAD_PTR_PASSED - env_var pointer is not valid
 *---------------------------------------------------------------------------*/
char * CSSMAPI cssm_getenv(char *env_var)
{

    uint32  ret_val;
    char *ptr;

    if (cssm_IsBadReadPtr(env_var, strlen(env_var)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }
    ret_val = GetEnvironmentVariable(env_var, ptr, 0);
    if (ret_val == 0)
    {
        CSSM_SetError(&port_guid, CSSM_ENV_VAR_NOT_FOUND);
        return(NULL);
    }

    ptr = (char *) cssm_malloc(ret_val, NULL);
    if (ptr == NULL)
        return(NULL);
    GetEnvironmentVariable(env_var, ptr, ret_val);
    return(ptr);

}

/* Dynamic Library Loading routines */

/*-----------------------------------------------------------------------------
 * Name: cssm_LoadLibrary
 *
 * Description:  Loads a dynamically linked library
 * 
 * Parameters: 
 * LibraryPathName (input)      :  Path name of library
 *
 * Returns:
 * Handle to the loaded library
 * NULL if an error occurs
 * 
 * Error Codes:
 * CSSM_LOAD_LIBRARY_FAILED - Unable to load the specified library
 * CSSM_BAD_PTR_PASSED - LibraryPathName pointer is not valid
 *---------------------------------------------------------------------------*/
CSSM_LIB_HANDLE CSSMAPI cssm_LoadLibrary(char *LibraryPathName)
{

#if defined(WIN32)

    HINSTANCE tmp;

    if (cssm_IsBadReadPtr(LibraryPathName, strlen(LibraryPathName)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }

    /* LoadLibrary will call DllMain() to init */
    if ((tmp = LoadLibrary(LibraryPathName)) == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_LOAD_LIBRARY_FAILED);
    }

    return(tmp);

#endif //WIN32
}


/*-----------------------------------------------------------------------------
 * Name: cssm_FreeLibrary
 *
 * Description:  Frees a dynamically linked library
 * 
 * Parameters: 
 * handle (input)   :  Handle of loaded library 
 *
 * Returns:
 * CSSM_OK if the operation is successful
 * CSSM_FAIL if there is an error
 * 
 * Error Codes:
 * CSSM_FREE_LIBRARY_FAILED - Unable to free the specified library
 * CSSM_INVALID_LIB_HANDLE - Handle for library is invalid
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_FreeLibrary(CSSM_LIB_HANDLE handle)
{

#if defined(WIN32)

    if (handle == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_LIB_HANDLE);
        return(CSSM_FAIL);
    }

    if (FreeLibrary((HMODULE)handle) == TRUE)
    {
        return(CSSM_OK);
    }

    CSSM_SetError(&port_guid, CSSM_FREE_LIBRARY_FAILED);
    return(CSSM_FAIL);

#endif //WIN32
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetProcAddress
 *
 * Description:  Returns the address of the specified function
 * 
 * Parameters: 
 * handle (input)       :  Handle for a loaded library
 * func_name (input)    :  Name of function to get the address for
 *
 * Returns:
 * Address of the specified function
 * NULL if an error occurs
 * 
 * Error Codes:
 * CSSM_CANT_GET_PROC_ADDRESS - Unable to get the procedure address
 * CSSM_BAD_MODULE_HANDLE - handle is invalid
 * CSSM_BAD_PTR_PASSED - func_name ptr is invalid
 *---------------------------------------------------------------------------*/
CSSM_PROC_ADDR CSSMAPI cssm_GetProcAddress(CSSM_MODULE handle, char * func_name)
{


#if defined (WIN32)

    FARPROC func_addr;

    if (handle == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_MODULE_HANDLE);
        return(NULL);
    }

    if (cssm_IsBadReadPtr(func_name, strlen(func_name)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }

    func_addr = GetProcAddress(handle, func_name);
    
    if (func_addr == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_PROC_ADDR);
    }
    
    return(func_addr);

#endif //WIN32
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetModuleHandle
 *
 * Description:  Returns the handle of the specified module
 * 
 * Parameters: 
 * module_name - Name of file to return a handle to
 *
 * Returns:
 * Handle to the specified module
 * NULL if an error occurs
 * 
 * Error Codes:
 * CSSM_CANT_GET_MODULE_HANDLE - Unable to load the specified library
 * CSSM_BAD_PTR_PASSED - module_name pointer is not valid
 *---------------------------------------------------------------------------*/
CSSM_MODULE CSSMAPI cssm_GetModuleHandle(char *module_name)
{

#if defined (WIN32)
    
    HMODULE module;

    if (cssm_IsBadReadPtr(module_name, strlen(module_name)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(NULL);
    }

    module = GetModuleHandle(module_name);
    
    if (module == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_MODULE_HANDLE);
    }
    
    return(module);

#endif //WIN32
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetModuleFileName
 *
 * Description:  Gets the filename of the specifed module
 * 
 * Parameters: 
 * module (input)   : Handle of a module
 * filename (output)    : Name of file
 * buf_length (input)   : Lenght of filename buffer
 *
 * Returns:
 * CSSM_OK if successful
 * CSSM_FAIL if an error occured
 * 
 * Error Codes:
 * CSSM_CANT_GET_MODULE_FILENAME - Unable to get the module filename
 * CSSM_BAD_PTR_PASSED - LibraryPathName pointer is not valid
 * CSSM_BAD_MODULE_HANDLE - module handle is invalid
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_GetModuleFileName(CSSM_MODULE module, char *filename, sint32 buf_length)
{

#if defined (WIN32)

    sint32  ret_val;

    if (module == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_MODULE_HANDLE);
        return(CSSM_FAIL);
    }

    if (cssm_IsBadReadPtr(filename, strlen(filename)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(CSSM_FAIL);
    }

    ret_val = GetModuleFileName(module, filename, buf_length);

    if (ret_val == 0)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_MODULE_FILE_NAME);
        return(CSSM_FAIL);
    }

    return(CSSM_OK);

#else

#if 0
    if (dlnam(module, filename, buf_length)<0)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_GET_MODULE_FILE_NAME);
        return(CSSM_FAIL);
    }

    return(CSSM_OK);
#endif

#endif //WIN32

}

/* Synchronization / Mutex Routines */

/*-----------------------------------------------------------------------------
 * Name: cssm_CreateMutex
 *
 * Description:  creates a mutex object
 * 
 * Parameters: 
 * name (input)         :       Name of mutex 
 *
 * Returns:
 * Pointer to the mutex object
 * NULL if an error occurent
 * 
 * Error Codes:
 * CSSM_CANT_CREATE_MUTEX - Unable to create the mutex
 * CSSM_BAD_PTR_PASSED - name pointer is not valid
 *---------------------------------------------------------------------------*/

void * CSSMAPI cssm_CreateMutex (char *name )
{
#if defined (WIN32)
    HANDLE mhandle;
    static SECURITY_DESCRIPTOR sd = {0};
	static SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), &sd,TRUE};

	InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);

	if (name != NULL) {
		if (cssm_IsBadReadPtr(name, strlen(name)))
		{
			CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
			return(NULL);
		}
	}

    mhandle = CreateMutex(&sa, FALSE, name);

    if (mhandle == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_CANT_CREATE_MUTEX);
    }
     
    return(mhandle);
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_LockMutex
 *
 * Description:  locks a mutex object
 * 
 * Parameters: 
 * mutex (input)            :       Pointer to mutex object
 * timeout (input)          :       Length of time to wait on mutex 
 *
 * Returns:
 * CSSM_MUTEX_LOCKED - Mutex successfully locked
 * CSSM_MUTEX_BUSY - Mutex is busy, cannot lock
 * CSSM_MUTEX_ERROR - See error codes
 * 
 * Error Codes:
 * CSSM_LOCK_MUTEX_FAILED - Unable to lock the mutex
 * CSSM_INVALID_MUTEX_PTR - mutex pointer is not valid
 *---------------------------------------------------------------------------*/

CSSM_MUTEX CSSMAPI cssm_LockMutex (void *mutex, sint32 timeout)
{

#if defined(WIN32)

    uint32 ret_val;

    if (mutex == NULL)
        {
        CSSM_SetError(&port_guid, CSSM_INVALID_MUTEX_PTR);
        return(CSSM_MUTEX_ERROR);
    }

    ret_val = WaitForSingleObject(mutex, timeout);
    
    if (ret_val == WAIT_FAILED)
    {
        CSSM_SetError(&port_guid, CSSM_LOCK_MUTEX_FAILED);
        return(CSSM_MUTEX_ERROR);
    }
    else
    {
        if (ret_val == WAIT_OBJECT_0 || ret_val == WAIT_ABANDONED)
        {
            return(CSSM_MUTEX_LOCKED);
        }
        else if (ret_val == WAIT_TIMEOUT)
        {
            return(CSSM_MUTEX_BUSY);
        }
        else
        {
            CSSM_SetError(&port_guid, CSSM_LOCK_MUTEX_FAILED);
            return(CSSM_MUTEX_ERROR);
        }
    }
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_TrylockMutex
 *
 * Description:  Try to lock a mutex object
 * 
 * Parameters: 
 * mutex (input)            :       Pointer to mutex object
 *
 * Returns:
 * CSSM_MUTEX_LOCKED - Mutex successfully locked
 * CSSM_MUTEX_BUSY - Mutex is busy, cannot lock
 * CSSM_MUTEX_ERROR - See error codes
 * 
 * Error Codes:
 * CSSM_TRYLOCK_MUTEX_FAILED - Unable to lock the mutex
 * CSSM_INVALID_MUTEX_PTR - mutex pointer is not valid
 *---------------------------------------------------------------------------*/

CSSM_MUTEX CSSMAPI cssm_TrylockMutex (void *mutex)
{

#if defined (WIN32)

    uint32 ret_val;

    if (mutex == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_MUTEX_PTR);
        return(CSSM_MUTEX_ERROR);
    }

    ret_val = WaitForSingleObject(mutex, CSSM_ZERO_WAIT);
    
    if (ret_val == WAIT_FAILED)
    {
        CSSM_SetError(&port_guid, CSSM_TRYLOCK_MUTEX_FAILED);
        return(CSSM_MUTEX_ERROR);
    }
    else
    {
        if (ret_val == WAIT_OBJECT_0 || ret_val == WAIT_ABANDONED)
        {
            return(CSSM_MUTEX_LOCKED);
        }
        else if (ret_val == WAIT_TIMEOUT)
        {
            return(CSSM_MUTEX_BUSY);
        }
        else
        {
            CSSM_SetError(&port_guid, CSSM_TRYLOCK_MUTEX_FAILED);
            return(CSSM_MUTEX_ERROR);
        }
    }
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_UnlockMutex
 *
 * Description: unlocks a mutex object
 * 
 * Parameters: 
 * mutex (input)            :       Pointer to mutex object
 *
 * Returns:
 * CSSM_MUTEX_UNLOCKED - Mutex successfully unlocked
 * CSSM_MUTEX_ERROR - See error codes
 * 
 * Error Codes:
 * CSSM_UNLOCK_MUTEX_FAILED - Unable to lock the mutex
 * CSSM_INVALID_MUTEX_PTR - mutex pointer is not valid
 *---------------------------------------------------------------------------*/

CSSM_MUTEX CSSMAPI cssm_UnlockMutex (void *mutex)
{
    

#if defined (WIN32)

    if (mutex == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_MUTEX_PTR);
        return(CSSM_MUTEX_ERROR);
    }

    if (ReleaseMutex(mutex))
    {
        return(CSSM_MUTEX_UNLOCKED);
    }
    else
    {
        CSSM_SetError(&port_guid, CSSM_UNLOCK_MUTEX_FAILED);
        return(CSSM_MUTEX_ERROR);
    }
#endif
}

/*-----------------------------------------------------------------------------
 * Name: cssm_CloseMutex
 *
 * Description:  Closes and destorys a mutex object
 * 
 * Parameters: 
 * mutex (input)            :       Pointer to mutex object
 *
 * Returns:
 * CSSM_OK if successful
 * CSSM_FAIL if an error occurred
 * 
 * Error Codes:
 * CSSM_CANT_CLOSE_MUTEX - Unable to lock the mutex
 * CSSM_INVALID_MUTEX_PTR - mutex pointer is not valid
 *---------------------------------------------------------------------------*/

CSSM_RETURN CSSMAPI cssm_CloseMutex (void *mutex)
{
	CSSM_BOOL SuccessfulClose = CSSM_FALSE;

#ifdef PORT_DEBUG
	printf("port: cssm_CloseMutex: mutex = %d\n", mutex);
#endif

#if defined (WIN32)

    if (mutex == NULL) {
        CSSM_SetError(&port_guid, CSSM_INVALID_MUTEX_PTR);
        return(CSSM_FAIL);
    }

    if (CloseHandle(mutex))
		SuccessfulClose = CSSM_TRUE;
#endif

	if (SuccessfulClose == CSSM_TRUE) {
        return(CSSM_OK);
    }
    else {
        CSSM_SetError(&port_guid, CSSM_CANT_CLOSE_MUTEX);
        return(CSSM_FAIL);
    }
}


/* Shared Memory File Functions */
/*-----------------------------------------------------------------------------
 * Name: cssm_CreateMemoryFile
 *
 * Description:  Create and open a shared memory file
 * 
 * Parameters: 
 * name (input)     :  Name of shared memory file
 * perms (input)    :  Permissions to open the file (read or read/write)
 *
 * Returns:
 * handle of shared file
 * NULL if an error occurs
 * 
 * Error Codes:
 * CSSM_BAD_PTR_PASSED - name ptr is invalid
 * CSSM_INVALID_PERMS - perms are not a valid value
 * CSSM_CANT_CREATE_SHARED_MEMORY_FILE - unable to create the shared memory file
 *---------------------------------------------------------------------------*/

CSSM_SHARED_FILE CSSMAPI cssm_CreateMemoryFile (char * name, sint32 perms)
{

    CSSM_SHARED_FILE file_handle;

    if (cssm_IsBadReadPtr(name, strlen(name)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(CSSM_INVALID_FILE_HANDLE);
    }

    if (perms != CSSM_CREATE_READWRITE && perms != CSSM_CREATE_READ)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_PERMS);
        return(CSSM_INVALID_FILE_HANDLE);
    }

#if defined (WIN32)

    if ((file_handle = CreateFileMapping((CSSM_SHARED_FILE)-1, NULL,
      perms, 0, 0, name)) == 
      CSSM_INVALID_FILE_HANDLE)
#endif
    {
        CSSM_SetError(&port_guid, CSSM_CANT_CREATE_SHARED_MEMORY_FILE);
    }
    return(file_handle);
}


/*-----------------------------------------------------------------------------
 * Name: cssm_OpenMemoryFile
 *
 * Description:  open a shared memory file
 * 
 * Parameters: 
 * name (input)     :  Name of shared memory file
 * perms (input)    :  Permissions to open the file (read or read/write)
 *
 * Returns:
 * handle of shared file
 * NULL if an error occurs
 * 
 * Error Codes:
 * CSSM_BAD_PTR_PASSED - name ptr is invalid
 * CSSM_INVALID_PERMS - perms are not a valid value
 * CSSM_CANT_OPNE_SHARED_MEMORY_FILE - unable to open the shared memory file
 *---------------------------------------------------------------------------*/
CSSM_SHARED_FILE CSSMAPI cssm_OpenMemoryFile (char * name, sint32 perms)
{

    CSSM_SHARED_FILE file_handle;

    if (cssm_IsBadReadPtr(name, strlen(name)))
    {
        CSSM_SetError(&port_guid, CSSM_BAD_PTR_PASSED);
        return(CSSM_INVALID_FILE_HANDLE);
    }

    if (perms != CSSM_CREATE_READWRITE && perms != CSSM_CREATE_READ)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_PERMS);
        return(CSSM_INVALID_FILE_HANDLE);
    }

#if defined (WIN32)
    file_handle = OpenFileMapping(perms, TRUE, name);
#endif
    if (file_handle == CSSM_INVALID_FILE_HANDLE) 
    {
        CSSM_SetError(&port_guid, CSSM_CANT_OPEN_SHARED_MEMORY_FILE);
    }
    return(file_handle);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_MapMemoryFile
 *
 * Description:  map a shared memory file
 * 
 * Parameters: 
 * handle (input)   :  Handle of shared memory file
 * perms (input)    :  Permissions to open the file (read or read/write)
 *
 * Returns:
 * Address of mapped view of file
 * NULL if an error occured
 * 
 * Error Codes:
 * CSSM_BAD_FILE_HANDLE - handle parameter is invalid
 * CSSM_INVALID_PERMS - perms are not a valid value
 * CSSM_CANT_MAP_SHARED_MEMORY_FILE - unable to map the shared memory file
 *---------------------------------------------------------------------------*/
void * CSSMAPI cssm_MapMemoryFile (CSSM_SHARED_FILE handle, sint32 perms)
{
    void *ptr;

    if (handle == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_FILE_HANDLE);
        return(NULL);
    }

    if (perms != CSSM_MAP_READWRITE && perms != CSSM_MAP_READ)
    {
        CSSM_SetError(&port_guid, CSSM_INVALID_PERMS);
        return(NULL);
    }

#if defined (WIN32)
    if ((ptr = MapViewOfFile(handle, perms, 0, 0, 0)) == NULL)
#endif
    {
        CSSM_SetError(&port_guid, CSSM_CANT_MAP_SHARED_MEMORY_FILE);
        return(NULL);
    }

    return(ptr);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_UnmapMemoryFile
 *
 * Description:  unmap a shared memory file
 * 
 * Parameters: 
 * file_addr (input)    :   Address of mapped file
 *
 * Returns:
 * CSSM_OK  if operation is successful
 * CSSM_FAIL if error occurred
 * 
 * Error Codes:
 * CSSM_BAD_UNMAP_SHARED_MEMORY_FILE - unable to unmap the shared memory file
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_UnmapMemoryFile (void *file_addr)
{

    if (file_addr == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_FILE_ADDR);
        return(CSSM_FAIL);
    }
#if defined (WIN32)
       if (UnmapViewOfFile(file_addr))
        return(CSSM_OK);
#endif

    CSSM_SetError(&port_guid, CSSM_CANT_UNMAP_SHARED_MEMORY_FILE);
    return(CSSM_FAIL);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_FlushMemoryFile
 *
 * Description:  flush a shared memory file
 * 
 * Parameters: 
 * file_addr (input)    :   Address of mapped file 
 *
 * Returns:
 * CSSM_OK if the operation is successful
 * CSSM_FAIL if an error occured
 * 
 * Error Codes:
 * CSSM_BAD_FILE_ADDR - file_addr parameter is invalid
 * CSSM_CANT_FLUSH_SHARED_MEMORY_FILE - unable to flush the shared memory file
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_FlushMemoryFile (void *file_addr)
{

    if (file_addr == NULL)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_FILE_ADDR);
        return(CSSM_FAIL);
    }
#if defined (WIN32)
    if (FlushViewOfFile(file_addr, 0))
        return(CSSM_OK);
#endif
    CSSM_SetError(&port_guid, CSSM_CANT_FLUSH_SHARED_MEMORY_FILE);
    return(CSSM_FAIL);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_CloseMemoryFile
 *
 * Description:  close a shared memory file
 * 
 * Parameters: 
 * handle (input)   :  Handle of shared memory file
 *
 * Returns:
 * CSSM_OK if successful
 * CSSM_FAIL if an error occurred
 *
 * Error Codes:
 * CSSM_BAD_FILE_HANDLE - handle parameter is invalid
 * CSSM_CANT_CLOSE_SHARED_MEMORY_FILE - unable to map the shared memory file
 *---------------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_CloseMemoryFile (CSSM_SHARED_FILE handle)
{

    if (handle == CSSM_INVALID_FILE_HANDLE)
    {
        CSSM_SetError(&port_guid, CSSM_BAD_FILE_HANDLE);
        return(CSSM_FAIL);
    }

#if defined (WIN32)

    if (CloseHandle(handle))
        return(CSSM_OK);

#endif

    CSSM_SetError(&port_guid, CSSM_CANT_CLOSE_SHARED_MEMORY_FILE);
    return(CSSM_FAIL);
}

/*-----------------------------------------------------------------------------
 * Name: cssm_GetTime
 *
 * Description: retrieves the system time in milliseconds. Suitable for making 
 *   elapsed time computation only. 
 *
 * Parameters: None.
 * 
 * Returns:
 *    - time in milliseconds. 
 *    
 *---------------------------------------------------------------------------*/

uint32 CSSMAPI cssm_GetTime ()
{
#if defined (WIN32)
	uint32	rc;
    rc = timeGetTime();
	return(rc);
#endif
}
