Path: blob/main/crypto/krb5/src/windows/installer/wix/custom/custom.cpp
34923 views
#ifdef __NMAKE__12# NMAKE portion.3# Build with : nmake /f custom.cpp4# Clean with : nmake /f custom.cpp clean56# Builds custom.dll78OUTPATH = .910# program name macros11CC = cl /nologo1213LINK = link /nologo1415RM = del1617DLLFILE = $(OUTPATH)\custom.dll1819DLLEXPORTS =\20-EXPORT:EnableAllowTgtSessionKey \21-EXPORT:RevertAllowTgtSessionKey \22-EXPORT:AbortMsiImmediate \23-EXPORT:UninstallNsisInstallation \24-EXPORT:KillRunningProcesses \25-EXPORT:ListRunningProcesses \26-EXPORT:InstallNetProvider \27-EXPORT:UninstallNetProvider2829$(DLLFILE): $(OUTPATH)\custom.obj30$(LINK) /OUT:$@ /DLL $** $(DLLEXPORTS)3132$(OUTPATH)\custom.obj: custom.cpp custom.h33$(CC) /c /Fo$@ custom.cpp3435all: $(DLLFILE)3637clean:38$(RM) $(DLLFILE)39$(RM) $(OUTPATH)\custom.obj40$(RM) $(OUTPATH)\custom.exp4142!IFDEF __C_TEXT__43#else44/*4546Copyright 2004,2005 by the Massachusetts Institute of Technology4748All rights reserved.4950Permission to use, copy, modify, and distribute this software and its51documentation for any purpose and without fee is hereby granted,52provided that the above copyright notice appear in all copies and that53both that copyright notice and this permission notice appear in54supporting documentation, and that the name of the Massachusetts55Institute of Technology (M.I.T.) not be used in advertising or publicity56pertaining to distribution of the software without specific, written57prior permission.5859M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING60ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL61M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR62ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,63WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,64ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS65SOFTWARE.6667*/6869/**************************************************************70* custom.cpp : Dll implementing custom action to install Kerberos for Windows71*72* The functions in this file are for use as entry points73* for calls from MSI only. The specific MSI parameters74* are noted in the comments section of each of the75* functions.76*77* rcsid: $Id$78**************************************************************/7980#pragma unmanaged8182// Only works for Win2k and above83#define _WIN32_WINNT 0x50084#include "custom.h"85#include <shellapi.h>8687// linker stuff88#pragma comment(lib, "msi")89#pragma comment(lib, "advapi32")90#pragma comment(lib, "shell32")91#pragma comment(lib, "user32")9293void ShowMsiError( MSIHANDLE hInstall, DWORD errcode, DWORD param ){94MSIHANDLE hRecord;9596hRecord = MsiCreateRecord(3);97MsiRecordClearData(hRecord);98MsiRecordSetInteger(hRecord, 1, errcode);99MsiRecordSetInteger(hRecord, 2, param);100101MsiProcessMessage( hInstall, INSTALLMESSAGE_ERROR, hRecord );102103MsiCloseHandle( hRecord );104}105106static void ShowMsiErrorEx(MSIHANDLE hInstall, DWORD errcode, LPTSTR str,107DWORD param )108{109MSIHANDLE hRecord;110111hRecord = MsiCreateRecord(3);112MsiRecordClearData(hRecord);113MsiRecordSetInteger(hRecord, 1, errcode);114MsiRecordSetString(hRecord, 2, str);115MsiRecordSetInteger(hRecord, 3, param);116117MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);118119MsiCloseHandle(hRecord);120}121122#define LSA_KERBEROS_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos"123#define LSA_KERBEROS_PARM_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Parameters"124#define KFW_CLIENT_KEY "SOFTWARE\\MIT\\Kerberos\\Client\\"125#define SESSKEY_VALUE_NAME "AllowTGTSessionKey"126127#define SESSBACKUP_VALUE_NAME "AllowTGTSessionKeyBackup"128#define SESSXPBACKUP_VALUE_NAME "AllowTGTSessionKeyBackupXP"129130131/* Set the AllowTGTSessionKey registry keys on install. Called as a deferred custom action. */132MSIDLLEXPORT EnableAllowTgtSessionKey( MSIHANDLE hInstall ) {133return SetAllowTgtSessionKey( hInstall, TRUE );134}135136/* Unset the AllowTGTSessionKey registry keys on uninstall. Called as a deferred custom action. */137MSIDLLEXPORT RevertAllowTgtSessionKey( MSIHANDLE hInstall ) {138return SetAllowTgtSessionKey( hInstall, FALSE );139}140141UINT SetAllowTgtSessionKey( MSIHANDLE hInstall, BOOL pInstall ) {142TCHAR tchVersionString[1024];143TCHAR tchVersionKey[2048];144DWORD size;145DWORD type;146DWORD value;147HKEY hkKfwClient = NULL;148HKEY hkLsaKerberos = NULL;149HKEY hkLsaKerberosParm = NULL;150UINT rv;151DWORD phase = 0;152153// construct the backup key path154size = sizeof(tchVersionString) / sizeof(TCHAR);155rv = MsiGetProperty( hInstall, _T("CustomActionData"), tchVersionString, &size );156if(rv != ERROR_SUCCESS) {157if(pInstall) {158ShowMsiError( hInstall, ERR_CUSTACTDATA, rv );159return rv;160} else {161return ERROR_SUCCESS;162}163}164165_tcscpy( tchVersionKey, _T( KFW_CLIENT_KEY ) );166_tcscat( tchVersionKey, tchVersionString );167168phase = 1;169170rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, tchVersionKey, 0, ((pInstall)?KEY_WRITE:KEY_READ), &hkKfwClient );171if(rv != ERROR_SUCCESS)172goto cleanup;173174phase = 2;175176rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberos );177if(rv != ERROR_SUCCESS)178goto cleanup;179180phase = 3;181182rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_PARM_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberosParm );183if(rv != ERROR_SUCCESS) {184hkLsaKerberosParm = NULL;185}186187if(pInstall) {188// backup the existing values189if(hkLsaKerberosParm) {190phase = 4;191192size = sizeof(value);193rv = RegQueryValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );194if(rv != ERROR_SUCCESS)195value = 0;196197phase = 5;198rv = RegSetValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));199if(rv != ERROR_SUCCESS)200goto cleanup;201}202203phase = 6;204size = sizeof(value);205rv = RegQueryValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );206if(rv != ERROR_SUCCESS)207value = 0;208209phase = 7;210rv = RegSetValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));211if(rv != ERROR_SUCCESS)212goto cleanup;213214// and now write the actual values215phase = 8;216value = 1;217rv = RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));218if(rv != ERROR_SUCCESS)219goto cleanup;220221if(hkLsaKerberosParm) {222phase = 9;223value = 1;224rv = RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));225if(rv != ERROR_SUCCESS)226goto cleanup;227}228229} else { // uninstalling230// Don't fail no matter what goes wrong. This is also a rollback action.231if(hkLsaKerberosParm) {232size = sizeof(value);233rv = RegQueryValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );234if(rv != ERROR_SUCCESS)235value = 0;236237RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));238}239240size = sizeof(value);241rv = RegQueryValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );242if(rv != ERROR_SUCCESS)243value = 0;244245RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));246247RegDeleteValue( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ) );248RegDeleteValue( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ) );249}250251// all done252rv = ERROR_SUCCESS;253254cleanup:255if(rv != ERROR_SUCCESS && pInstall) {256ShowMsiError(hInstall, 4005, phase);257}258if(hkKfwClient) RegCloseKey( hkKfwClient );259if(hkLsaKerberos) RegCloseKey( hkLsaKerberos );260if(hkLsaKerberosParm) RegCloseKey( hkLsaKerberosParm );261262return rv;263}264265/* Abort the installation (called as an immediate custom action) */266MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE hInstall ) {267DWORD rv;268DWORD dwSize = 0;269LPTSTR sReason = NULL;270LPTSTR sFormatted = NULL;271MSIHANDLE hRecord = NULL;272LPTSTR cAbortReason = _T("ABORTREASON");273274rv = MsiGetProperty( hInstall, cAbortReason, _T(""), &dwSize );275if(rv != ERROR_MORE_DATA) goto _cleanup;276277sReason = new TCHAR[ ++dwSize ];278279rv = MsiGetProperty( hInstall, cAbortReason, sReason, &dwSize );280281if(rv != ERROR_SUCCESS) goto _cleanup;282283hRecord = MsiCreateRecord(3);284MsiRecordClearData(hRecord);285MsiRecordSetString(hRecord, 0, sReason);286287dwSize = 0;288289rv = MsiFormatRecord(hInstall, hRecord, "", &dwSize);290if(rv != ERROR_MORE_DATA) goto _cleanup;291292sFormatted = new TCHAR[ ++dwSize ];293294rv = MsiFormatRecord(hInstall, hRecord, sFormatted, &dwSize);295296if(rv != ERROR_SUCCESS) goto _cleanup;297298MsiCloseHandle(hRecord);299300hRecord = MsiCreateRecord(3);301MsiRecordClearData(hRecord);302MsiRecordSetInteger(hRecord, 1, ERR_ABORT);303MsiRecordSetString(hRecord,2, sFormatted);304MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);305306_cleanup:307if(sFormatted) delete sFormatted;308if(hRecord) MsiCloseHandle( hRecord );309if(sReason) delete sReason;310311return ~ERROR_SUCCESS;312}313314/* Kill specified processes that are running on the system */315/* Uses the custom table KillProcess. Called as an immediate action. */316317#define MAX_KILL_PROCESSES 255318#define FIELD_SIZE 256319320struct _KillProc {321TCHAR * image;322TCHAR * desc;323BOOL found;324DWORD pid;325};326327#define RV_BAIL if(rv != ERROR_SUCCESS) goto _cleanup328329MSIDLLEXPORT KillRunningProcesses( MSIHANDLE hInstall ) {330return KillRunningProcessesWorker( hInstall, TRUE );331}332333/* When listing running processes, we populate the ListBox table with334values associated with the property 'KillableProcesses'. If we335actually find any processes worth killing, then we also set the336'FoundProcceses' property to '1'. Otherwise we set it to ''.337*/338339MSIDLLEXPORT ListRunningProcesses( MSIHANDLE hInstall ) {340return KillRunningProcessesWorker( hInstall, FALSE );341}342343UINT KillRunningProcessesWorker( MSIHANDLE hInstall, BOOL bKill )344{345UINT rv = ERROR_SUCCESS;346_KillProc * kpList;347int nKpList = 0;348int i;349int rowNum = 1;350DWORD size;351BOOL found = FALSE;352353MSIHANDLE hDatabase = NULL;354MSIHANDLE hView = NULL;355MSIHANDLE hViewInsert = NULL;356MSIHANDLE hRecord = NULL;357MSIHANDLE hRecordInsert = NULL;358359HANDLE hSnapshot = NULL;360361PROCESSENTRY32 pe;362363kpList = new _KillProc[MAX_KILL_PROCESSES];364memset(kpList, 0, sizeof(*kpList) * MAX_KILL_PROCESSES);365366hDatabase = MsiGetActiveDatabase( hInstall );367if( hDatabase == NULL ) {368rv = GetLastError();369goto _cleanup;370}371372// If we are only going to list out the processes, delete all the existing373// entries first.374375if(!bKill) {376377rv = MsiDatabaseOpenView( hDatabase,378_T( "DELETE FROM `ListBox` WHERE `ListBox`.`Property` = 'KillableProcesses'" ),379&hView); RV_BAIL;380381rv = MsiViewExecute( hView, NULL ); RV_BAIL;382383MsiCloseHandle( hView );384385hView = NULL;386387rv = MsiDatabaseOpenView( hDatabase,388_T( "SELECT * FROM `ListBox` WHERE `Property` = 'KillableProcesses'" ),389&hViewInsert); RV_BAIL;390391MsiViewExecute(hViewInsert, NULL);392393hRecordInsert = MsiCreateRecord(4);394395if(hRecordInsert == NULL) {396rv = GetLastError();397goto _cleanup;398}399}400401// Open a view402rv = MsiDatabaseOpenView( hDatabase,403_T( "SELECT `Image`,`Desc` FROM `KillProcess`" ),404&hView); RV_BAIL;405406rv = MsiViewExecute( hView, NULL ); RV_BAIL;407408do {409rv = MsiViewFetch( hView, &hRecord );410if(rv != ERROR_SUCCESS) {411if(hRecord)412MsiCloseHandle(hRecord);413hRecord = NULL;414break;415}416417kpList[nKpList].image = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].image[0] = _T('\0');418kpList[nKpList].desc = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].desc[0] = _T('\0');419nKpList++;420421size = FIELD_SIZE;422rv = MsiRecordGetString(hRecord, 1, kpList[nKpList-1].image, &size); RV_BAIL;423424size = FIELD_SIZE;425rv = MsiRecordGetString(hRecord, 2, kpList[nKpList-1].desc, &size); RV_BAIL;426427MsiCloseHandle(hRecord);428} while(nKpList < MAX_KILL_PROCESSES);429430hRecord = NULL;431432// now we have all the processes in the array. Check if they are running.433434hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );435if(hSnapshot == INVALID_HANDLE_VALUE) {436rv = GetLastError();437goto _cleanup;438}439440pe.dwSize = sizeof( PROCESSENTRY32 );441442if(!Process32First( hSnapshot, &pe )) {443// technically we should at least find the MSI process, but we let this pass444rv = ERROR_SUCCESS;445goto _cleanup;446}447448do {449for(i=0; i<nKpList; i++) {450if(!_tcsicmp( kpList[i].image, pe.szExeFile )) {451// got one452if(bKill) {453// try to kill the process454HANDLE hProcess = NULL;455456// If we encounter an error, instead of bailing457// out, we continue on to the next process. We458// may not have permission to kill all the459// processes we want to kill anyway. If there are460// any files that we want to replace that is in461// use, Windows Installer will schedule a reboot.462// Also, it's not like we have an exhaustive list463// of all the programs that use Kerberos anyway.464465hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);466if(hProcess == NULL) {467rv = GetLastError();468break;469}470471if(!TerminateProcess(hProcess, 0)) {472rv = GetLastError();473CloseHandle(hProcess);474break;475}476477CloseHandle(hProcess);478479} else {480TCHAR buf[256];481482// we are supposed to just list out the processes483rv = MsiRecordClearData( hRecordInsert ); RV_BAIL;484rv = MsiRecordSetString( hRecordInsert, 1, _T("KillableProcesses"));485rv = MsiRecordSetInteger( hRecordInsert, 2, rowNum++ ); RV_BAIL;486_itot( rowNum, buf, 10 );487rv = MsiRecordSetString( hRecordInsert, 3, buf ); RV_BAIL;488if(_tcslen(kpList[i].desc)) {489rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].desc ); RV_BAIL;490} else {491rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].image ); RV_BAIL;492}493MsiViewModify(hViewInsert, MSIMODIFY_INSERT_TEMPORARY, hRecordInsert); RV_BAIL;494495found = TRUE;496}497break;498}499}500} while( Process32Next( hSnapshot, &pe ) );501502if(!bKill) {503// set the 'FoundProcceses' property504if(found) {505MsiSetProperty( hInstall, _T("FoundProcesses"), _T("1"));506} else {507MsiSetProperty( hInstall, _T("FoundProcesses"), _T(""));508}509}510511// Finally:512rv = ERROR_SUCCESS;513514_cleanup:515516if(hRecordInsert) MsiCloseHandle(hRecordInsert);517if(hViewInsert) MsiCloseHandle(hView);518519if(hSnapshot && hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot);520521while(nKpList) {522nKpList--;523delete kpList[nKpList].image;524delete kpList[nKpList].desc;525}526delete kpList;527528if(hRecord) MsiCloseHandle(hRecord);529if(hView) MsiCloseHandle(hView);530531if(hDatabase) MsiCloseHandle(hDatabase);532533if(rv != ERROR_SUCCESS) {534ShowMsiError(hInstall, ERR_PROC_LIST, rv);535}536537return rv;538}539540static bool IsNSISInstalled()541{542HKEY nsisKfwKey = NULL;543HRESULT res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,544"SOFTWARE\\Microsoft\\Windows\\CurrentVersion"545"\\Uninstall\\Kerberos for Windows",5460,547KEY_READ | KEY_WOW64_32KEY,548&nsisKfwKey);549if (res != ERROR_SUCCESS)550return FALSE;551552RegCloseKey(nsisKfwKey);553return TRUE;554}555556static HANDLE NSISUninstallShellExecute(LPTSTR pathUninstall)557{558SHELLEXECUTEINFO sei;559ZeroMemory ( &sei, sizeof(sei) );560561sei.cbSize = sizeof(sei);562sei.hwnd = GetForegroundWindow();563sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI |564SEE_MASK_NOCLOSEPROCESS;565sei.lpVerb = _T("runas"); // run as administrator566sei.lpFile = pathUninstall;567sei.lpParameters = _T("");568sei.nShow = SW_SHOWNORMAL;569570if (!ShellExecuteEx(&sei)) {571// FAILED! TODO: report details?572}573return sei.hProcess;574}575576static HANDLE NSISUninstallCreateProcess(LPTSTR pathUninstall)577{578STARTUPINFO sInfo;579PROCESS_INFORMATION pInfo;580pInfo.hProcess = NULL;581pInfo.hThread = NULL;582583// Create a process for the uninstaller584sInfo.cb = sizeof(sInfo);585sInfo.lpReserved = NULL;586sInfo.lpDesktop = _T("");587sInfo.lpTitle = _T("NSIS Uninstaller for Kerberos for Windows");588sInfo.dwX = 0;589sInfo.dwY = 0;590sInfo.dwXSize = 0;591sInfo.dwYSize = 0;592sInfo.dwXCountChars = 0;593sInfo.dwYCountChars = 0;594sInfo.dwFillAttribute = 0;595sInfo.dwFlags = 0;596sInfo.wShowWindow = 0;597sInfo.cbReserved2 = 0;598sInfo.lpReserved2 = 0;599sInfo.hStdInput = 0;600sInfo.hStdOutput = 0;601sInfo.hStdError = 0;602603if (!CreateProcess(pathUninstall,604_T("Uninstall /S"),605NULL,606NULL,607FALSE,608CREATE_SUSPENDED,609NULL,610NULL,611&sInfo,612&pInfo)) {613// failure; could grab info, but we should be able to recover by614// using NSISUninstallShellExecute...615} else {616// success617// start up the thread618ResumeThread(pInfo.hThread);619// done with thread handle620CloseHandle(pInfo.hThread);621}622return pInfo.hProcess;623}624625626/* Uninstall NSIS */627MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall )628{629DWORD rv = ERROR_SUCCESS;630DWORD lastError;631// lookup the NSISUNINSTALL property value632LPTSTR cNsisUninstall = _T("UPGRADENSIS");633LPTSTR strPathUninst = NULL;634DWORD dwSize = 0;635HANDLE hProcess = NULL;636HANDLE hIo = NULL;637HANDLE hJob = NULL;638639rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize );640if(rv != ERROR_MORE_DATA) goto _cleanup;641642strPathUninst = new TCHAR[ ++dwSize ];643644rv = MsiGetProperty(hInstall, cNsisUninstall, strPathUninst, &dwSize);645if(rv != ERROR_SUCCESS) goto _cleanup;646647hProcess = NSISUninstallCreateProcess(strPathUninst);648if (hProcess == NULL) // expected when run on UAC-limited account649hProcess = NSISUninstallShellExecute(strPathUninst);650651if (hProcess == NULL) {652// still no uninstall process? ick...653lastError = GetLastError();654rv = 40;655goto _cleanup;656}657// note that it is not suffiecient to wait for the initial process to658// finish; there is a whole process tree that we need to wait for. sigh.659JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp;660acp.CompletionKey = 0;661hJob = CreateJobObject(NULL, _T("NSISUninstallObject"));662if(!hJob) {663rv = 41;664goto _cleanup;665}666667hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);668if(!hIo) {669rv = 42;670goto _cleanup;671}672673acp.CompletionPort = hIo;674675SetInformationJobObject(hJob,676JobObjectAssociateCompletionPortInformation,677&acp,678sizeof(acp));679680AssignProcessToJobObject(hJob, hProcess);681682DWORD msgId;683ULONG_PTR unusedCompletionKey;684LPOVERLAPPED unusedOverlapped;685for (;;) {686if (!GetQueuedCompletionStatus(hIo,687&msgId,688&unusedCompletionKey,689&unusedOverlapped,690INFINITE)) {691Sleep(1000);692} else if (msgId == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {693break;694}695}696697_cleanup:698if (hProcess) CloseHandle(hProcess);699if (hIo) CloseHandle(hIo);700if (hJob) CloseHandle(hJob);701702if (IsNSISInstalled()) {703// uninstall failed: maybe user cancelled uninstall, or something else704// went wrong...705if (rv == ERROR_SUCCESS)706rv = 43;707} else {708// Maybe something went wrong, but it doesn't matter as long as nsis709// is gone now...710rv = ERROR_SUCCESS;711}712713if (rv == 40) {714// CreateProcess() / ShellExecute() errors get extra data715ShowMsiErrorEx(hInstall, ERR_NSS_FAILED_CP, strPathUninst, lastError);716} else if (rv != ERROR_SUCCESS) {717ShowMsiError(hInstall, ERR_NSS_FAILED, rv);718}719720if (strPathUninst) delete strPathUninst;721return rv;722}723724/* Check and add or remove networkprovider key value725str : target string726str2: string to add/remove727bInst: == 1 if string should be added to target if not already there,728otherwise remove string from target if present.729*/730int npi_CheckAndAddRemove( LPTSTR str, LPTSTR str2, int bInst ) {731732LPTSTR target, charset, match;733int ret=0;734735target = new TCHAR[lstrlen(str)+3];736lstrcpy(target,_T(","));737lstrcat(target,str);738lstrcat(target,_T(","));739charset = new TCHAR[lstrlen(str2)+3];740lstrcpy(charset,_T(","));741lstrcat(charset,str2);742lstrcat(charset,_T(","));743744match = _tcsstr(target, charset);745746if ((match) && (bInst)) {747ret = INP_ERR_PRESENT;748goto cleanup;749}750751if ((!match) && (!bInst)) {752ret = INP_ERR_ABSENT;753goto cleanup;754}755756if (bInst) // && !match757{758lstrcat(str, _T(","));759lstrcat(str, str2);760ret = INP_ERR_ADDED;761goto cleanup;762}763764// if (!bInst) && (match)765{766lstrcpy(str+(match-target),match+lstrlen(str2)+2);767str[lstrlen(str)-1]=_T('\0');768ret = INP_ERR_REMOVED;769goto cleanup;770}771772cleanup:773774delete target;775delete charset;776return ret;777}778779/* Sets the registry keys required for the functioning of the network provider */780781DWORD InstNetProvider(MSIHANDLE hInstall, int bInst) {782LPTSTR strOrder;783HKEY hkOrder;784LONG rv;785DWORD dwSize;786HANDLE hProcHeap;787788strOrder = (LPTSTR) 0;789790CHECK(rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, STR_KEY_ORDER, 0, KEY_READ | KEY_WRITE, &hkOrder ));791792dwSize = 0;793CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, NULL, &dwSize ) );794795strOrder = new TCHAR[ (dwSize + STR_SERVICE_LEN + 4) * sizeof(TCHAR) ];796797CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, (LPBYTE) strOrder, &dwSize));798799strOrder[dwSize] = '\0'; /* reg strings are not always nul terminated */800801npi_CheckAndAddRemove( strOrder, STR_SERVICE , bInst);802803dwSize = (lstrlen( strOrder ) + 1) * sizeof(TCHAR);804805CHECK(rv = RegSetValueEx( hkOrder, STR_VAL_ORDER, NULL, REG_SZ, (LPBYTE) strOrder, dwSize ));806807/* everything else should be set by the MSI tables */808rv = ERROR_SUCCESS;809_cleanup:810811if( rv != ERROR_SUCCESS ) {812ShowMsiError( hInstall, ERR_NPI_FAILED, rv );813}814815if(strOrder) delete strOrder;816817return rv;818}819820MSIDLLEXPORT InstallNetProvider( MSIHANDLE hInstall ) {821return InstNetProvider( hInstall, 1 );822}823824MSIDLLEXPORT UninstallNetProvider( MSIHANDLE hInstall) {825return InstNetProvider( hInstall, 0 );826}827828#endif829#ifdef __NMAKE__830!ENDIF831#endif832833834