/* SCCSID: fwk/cssm/install/install_cssm.c, dss_cdsa_fwk, fwk_rel3, dss_980403 1.5 4/13/98 10:45:14 */
/* ***************************************************************** *
 * 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.                                                        *
 * ***************************************************************** */

/*****************************************************************************
 *
 * COMPONENT_NAME: CSSM
 *
 * (C) COPYRIGHT International Business Machines Corp. 1997
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 */

/* 
 * FILE: install_cssm.c
 *
 * A CSSM-independent program that emulates module installation for CSSM.
 */

#include "cssm.h"
#include "cssmport.h"
#include "internal.h"	// MAX_REG
#include "vendor.h"		// CSSMSECTION

#define	MAX_PATH_LEN	512

#define NUMBEROFSERVICES 1

#define CSSM_PREFERENCE_GLOBAL	0
#define CSSM_PREFERENCE_LOCAL	1

// GUID for installing CSSM
CSSM_GUID cssm_GUID = { 0x53ba1c39, 0xf3c1, 0x51cf, { 0x59, 0x72, 0x14, 0xac, 0x0, 0xb1, 0x89, 0x1d } };

CSSM_MODULE_INFO				CssmModuleInfo;
CSSM_SERVICE_INFO				CssmServiceInfo;



//===============================================================================
//
// CSSM-less module management functions
//
//===============================================================================

/*---------------------------------------------------------------
 *
 *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
 *-------------------------------------------------------------*/
static
CSSM_RETURN CSSMAPI cssm_RegWriteVersion (char *regKey, char *Label,
                                  uint32 VerMajor, uint32 VerMinor)
{
    char Version[MAX_REG];

    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) {
        fprintf(stderr, "Could not write CSSM version to registry\n");
        return (CSSM_FAIL);
    }
    return (CSSM_OK);
}

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

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

// Write a string to the Registry without trucating it.
static
CSSM_RETURN cssm_RegWriteString (char *RegKey, char *Label, char *Data)
{
    if (cssm_SetValue (RegKey, Label, (uint8 *)Data, strlen(Data) + 1,
                         CSSM_VALUE_STRING,CSSM_PREFERENCE_GLOBAL) != CSSM_OK) {
        return (CSSM_FAIL);
    }
    return (CSSM_OK);
}

static
CSSM_RETURN CSSMAPI cssm_RegWriteCommonInfo (char *regKey, 
                                             CSSM_VERSION Version,
                                             char *Description,
                                             char *Vendor,
                                             CSSM_BOOL ThreadSafe,
                                             uint32 NumberOfSubServices)
{
    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);
}

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

    if (Info == NULL) {
		fprintf(stderr, "Invalid Info pointer\n");
        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);
}

static
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;

    /* 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);

    /* 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)
	{
		fprintf(stderr, "Module service mask is not CSSM_SERVICE_CSSM\n");
        return CSSM_FAIL;
	}
    else
        return cssm_RegWriteCSSMInfo (regKey, ModuleDescription, GUID);
}

/*---------------------------------------------------------------
 *
 *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
 *-------------------------------------------------------------*/
static
void CSSMAPI cssm_GUIDToStr (const CSSM_GUID_PTR GUID, char *ID)
{

    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]);
}

/*---------------------------------------------------------------
 *
 *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
 *-------------------------------------------------------------*/
static
CSSM_RETURN CSSMAPI cssm_RegRemoveModule (const CSSM_GUID_PTR GUID)
{
    char regKey[MAX_REG];
    char ID[MAX_REG];

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

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


/*---------------------------------------------------------------
 *
 *Name: cssm_ModuleInstall
 *
 *Description:
 *   Internal function that installs only CSSM information into
 *   the registry.
 *
 *Parameters: 
 *   ModuleName (input) - name of addin module
 *   ModuleFileName (input) - name of file that implements addin module
 *   ModulePathName (input) -  path to file of addin module
 *   GUID (input) -  GUID of addin module
 *   ModuleDescription (input) -  Description of addin module
 *   Reserved1 (input) -  Reserved data
 *   Reserved2 (input) -  Reserved data
 *
 *Returns:
 *   CSSM_FAIL - unable to complete update to registry
 *   CSSM_OK - registry has updated information
 *
 *-------------------------------------------------------------*/
static
CSSM_RETURN CSSMAPI cssm_ModuleInstall (
                                 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)
{
    /* Make sure all pointer are valid */
    if (cssm_IsBadReadPtr(ModuleName, 1)) {
        return (CSSM_FAIL);
    }

    if (cssm_IsBadStrPtr(ModuleName,strlen(ModuleName))) {
        return (CSSM_FAIL);
    }

    if (cssm_IsBadReadPtr(ModuleFileName, 1)) {
        return (CSSM_FAIL);
    }
    if (cssm_IsBadStrPtr(ModuleFileName,strlen(ModuleFileName))) {
        return (CSSM_FAIL);
    }

    if (cssm_IsBadReadPtr(ModulePathName, 1)) {
        return (CSSM_FAIL);
    }
    if (cssm_IsBadStrPtr(ModulePathName,strlen(ModulePathName))) {
        return (CSSM_FAIL);
    }

    if (cssm_IsBadReadPtr(GUID, sizeof(CSSM_GUID_PTR))) {
        return (CSSM_FAIL);
    }

    if (cssm_IsBadReadPtr(ModuleDescription, sizeof(CSSM_MODULE_INFO_PTR))) {

        return (CSSM_FAIL);
    }

    /* update registry with the add in information */
    return (cssm_RegWriteModule (ModuleName, ModuleFileName, ModulePathName,
                               GUID, ModuleDescription, Reserved1, Reserved2));
}

/*----------------------------------------------------------
 *Name: cssm_ModuleUninstall
 *
 *Description:
 * Remove an add-in from visibilty by the CSSM.
 *
 *Parameters: 
 * GUID (input) - GUID that describes the add-in
 *
 *Returns: 
 * CSSM_OK - call is successful
 * CSSM_INVALID_POINTER - invalid pointer
 *--------------------------------------------------------*/
static
CSSM_RETURN CSSMAPI cssm_ModuleUninstall (const CSSM_GUID_PTR GUID) 
{
    /* Check validity of pointers */
    if (cssm_IsBadReadPtr(GUID, sizeof (CSSM_GUID))) {
		fprintf(stderr, "Invalid GUID pointer\n");
        return (CSSM_FAIL);
    }

    /* Clean up internal structures */
    return (cssm_RegRemoveModule (GUID));
}

//===============================================================================
//
// CSSM information functions
//
//===============================================================================

//
// GetModuleGUID -
//

static
CSSM_RETURN GetModuleGUID(CSSM_GUID **ModuleGUID)
{
	*ModuleGUID = &cssm_GUID;
	return (CSSM_OK);
}

/*****************************************************************************
 * Function: GetModuleInfo
 * 
 * Sets up ModuleInfo data structure.
 *
 * Input: ModuleInfo - pointer to location where the pointer to the ModuleInfo 
 *					   data structure will be stored
 *
 * Output: ModuleInfo
 *
 * Returns: CSSM_OK or CSSM_FAIL
 *
 */
static
CSSM_RETURN GetModuleInfo(CSSM_MODULE_INFO **ModuleInfo)
{

	//
	// Set up ModuleInfo
	//

	CssmModuleInfo.Version.Major = CSSM_MAJOR;
	CssmModuleInfo.Version.Minor = CSSM_MINOR;

	CssmModuleInfo.CompatibleCSSMVersion.Major = CSSM_MAJOR;
	CssmModuleInfo.CompatibleCSSMVersion.Minor = CSSM_MINOR;
 
	strcpy(CssmModuleInfo.Description, 
		   "Common Security Services Framework"); 
	
	strcpy(CssmModuleInfo.Vendor, "IBM Corporation"); 
	
	CssmModuleInfo.Flags = CSSM_MODULE_THREADSAFE |
		                    CSSM_MODULE_EXPORTABLE;

	CssmModuleInfo.ServiceMask = CSSM_SERVICE_CSSM;
	CssmModuleInfo.NumberOfServices = NUMBEROFSERVICES;
	CssmModuleInfo.ServiceList = &CssmServiceInfo;
	
	CssmModuleInfo.Reserved = NULL;

	//
	// Set up ServiceInfo for CSP
	//

	strcpy(CssmServiceInfo.Description, 
		   "Common Security Services Framework"); 

	CssmServiceInfo.Type = CSSM_SERVICE_CSSM;
	CssmServiceInfo.Flags = 0;
	CssmServiceInfo.NumberOfSubServices = 0;
	CssmServiceInfo.SubServiceList = NULL;
	CssmServiceInfo.Reserved = NULL;

	//
	// Return ModuleInfo
	//

	*ModuleInfo = &CssmModuleInfo;
	return (CSSM_OK);
}

//
// FreeModuleInfo -
//

static
CSSM_RETURN FreeModuleInfo(CSSM_MODULE_INFO **ModuleInfo)
{
	return (CSSM_OK);
}

static void 
Usage(char **argv)
{
	printf("%s <addin filename> <addin directory> 'install'|'uninstall'\n", argv[0]);
	printf("  Installs the named addin.\n");
	printf("  If no arguments are given, you will be prompted\n");
}

static CSSM_RETURN 
ProcessArgs(int argc, char **argv, char *NameString, char *FileString, char *DirString, char *ActionString)
{
	CSSM_RETURN rc;
	CSSM_BOOL				Prompt = FALSE;

	rc = CSSM_OK;

	// Process arguments

	if (argc == 4)
	{
		strcpy(FileString,		argv[1]);
		strcpy(DirString,		argv[2]);
		strcpy(ActionString,	argv[3]);
	}
	else if (argc == 1)
	{
		Prompt = TRUE;
	}
	else
	{
		Usage(argv);
		rc = CSSM_FAIL;
	}

	// Prompt if necessary

	if (Prompt == TRUE) {
		printf("addin directory?\n");
        fflush(stdin); 
		gets(DirString);

		printf("addin filename? \n");
        fflush(stdin); 
		gets(FileString);

		printf("action? [install|uninstall]\n");
        fflush(stdin); 
		gets(ActionString);
	}

	// Note: currently we will not prompt for name to minimize user input
	// and equate it to the string given for the filename
	strcpy(NameString, FileString);

	if (rc != CSSM_FAIL)
           rc = cssm_port_init();

	return rc;
}

static CSSM_RETURN 
GetModuleInfoAndGUID(CSSM_MODULE_INFO **ModuleInfo, CSSM_GUID **ModuleGUID)
{
	CSSM_RETURN	rc = CSSM_OK;

	// Get module info; this function must be implemented by the addin provider

	rc = GetModuleInfo(ModuleInfo);
	
	if (rc != CSSM_OK)
	{
		printf("GetModuleInfo failed\n");
	}

	// Get module GUID; this function must be implemented by the addin provider

	if (rc == CSSM_OK)
	{
		rc = GetModuleGUID(ModuleGUID);
	}
	
	if (rc != CSSM_OK)
	{
		printf("GetModuleGUID failed\n");
	}

	return rc;
}

int main(int argc, char **argv)
{
	CSSM_RETURN				rc = CSSM_OK;
	char					NameString[MAX_PATH_LEN];
	char 					FileString[MAX_PATH_LEN];
	char 					DirString[MAX_PATH_LEN];
	char					ActionString[MAX_PATH_LEN];
	CSSM_MODULE_INFO		*ModuleInfo;
	CSSM_GUID				*ModuleGUID;

	// Process arguments

	rc = ProcessArgs(argc, argv, NameString, FileString, 
					 DirString, ActionString);

	if (rc == CSSM_OK)
	{
		rc = GetModuleInfoAndGUID(&ModuleInfo, &ModuleGUID);
	}

	// Perform appropriate install/uninstall action

	if (rc == CSSM_OK)
	{
		if (strcmp(ActionString, "install") == 0)
		{
			rc = cssm_ModuleInstall (NameString, FileString, DirString,
									 ModuleGUID, ModuleInfo, 
									 NULL, NULL);
		}
		else if (strcmp(ActionString, "uninstall") == 0)
		{
			rc = cssm_ModuleUninstall (ModuleGUID);
		}
	}

	if (rc != CSSM_OK)
	{
		printf("Exiting with rc = %d\n", rc);
	}

	return rc;
}

