Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/windows/installer/wix/custom/custom.cpp
34923 views
1
#ifdef __NMAKE__
2
3
# NMAKE portion.
4
# Build with : nmake /f custom.cpp
5
# Clean with : nmake /f custom.cpp clean
6
7
# Builds custom.dll
8
9
OUTPATH = .
10
11
# program name macros
12
CC = cl /nologo
13
14
LINK = link /nologo
15
16
RM = del
17
18
DLLFILE = $(OUTPATH)\custom.dll
19
20
DLLEXPORTS =\
21
-EXPORT:EnableAllowTgtSessionKey \
22
-EXPORT:RevertAllowTgtSessionKey \
23
-EXPORT:AbortMsiImmediate \
24
-EXPORT:UninstallNsisInstallation \
25
-EXPORT:KillRunningProcesses \
26
-EXPORT:ListRunningProcesses \
27
-EXPORT:InstallNetProvider \
28
-EXPORT:UninstallNetProvider
29
30
$(DLLFILE): $(OUTPATH)\custom.obj
31
$(LINK) /OUT:$@ /DLL $** $(DLLEXPORTS)
32
33
$(OUTPATH)\custom.obj: custom.cpp custom.h
34
$(CC) /c /Fo$@ custom.cpp
35
36
all: $(DLLFILE)
37
38
clean:
39
$(RM) $(DLLFILE)
40
$(RM) $(OUTPATH)\custom.obj
41
$(RM) $(OUTPATH)\custom.exp
42
43
!IFDEF __C_TEXT__
44
#else
45
/*
46
47
Copyright 2004,2005 by the Massachusetts Institute of Technology
48
49
All rights reserved.
50
51
Permission to use, copy, modify, and distribute this software and its
52
documentation for any purpose and without fee is hereby granted,
53
provided that the above copyright notice appear in all copies and that
54
both that copyright notice and this permission notice appear in
55
supporting documentation, and that the name of the Massachusetts
56
Institute of Technology (M.I.T.) not be used in advertising or publicity
57
pertaining to distribution of the software without specific, written
58
prior permission.
59
60
M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
61
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
62
M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
63
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
64
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
65
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
66
SOFTWARE.
67
68
*/
69
70
/**************************************************************
71
* custom.cpp : Dll implementing custom action to install Kerberos for Windows
72
*
73
* The functions in this file are for use as entry points
74
* for calls from MSI only. The specific MSI parameters
75
* are noted in the comments section of each of the
76
* functions.
77
*
78
* rcsid: $Id$
79
**************************************************************/
80
81
#pragma unmanaged
82
83
// Only works for Win2k and above
84
#define _WIN32_WINNT 0x500
85
#include "custom.h"
86
#include <shellapi.h>
87
88
// linker stuff
89
#pragma comment(lib, "msi")
90
#pragma comment(lib, "advapi32")
91
#pragma comment(lib, "shell32")
92
#pragma comment(lib, "user32")
93
94
void ShowMsiError( MSIHANDLE hInstall, DWORD errcode, DWORD param ){
95
MSIHANDLE hRecord;
96
97
hRecord = MsiCreateRecord(3);
98
MsiRecordClearData(hRecord);
99
MsiRecordSetInteger(hRecord, 1, errcode);
100
MsiRecordSetInteger(hRecord, 2, param);
101
102
MsiProcessMessage( hInstall, INSTALLMESSAGE_ERROR, hRecord );
103
104
MsiCloseHandle( hRecord );
105
}
106
107
static void ShowMsiErrorEx(MSIHANDLE hInstall, DWORD errcode, LPTSTR str,
108
DWORD param )
109
{
110
MSIHANDLE hRecord;
111
112
hRecord = MsiCreateRecord(3);
113
MsiRecordClearData(hRecord);
114
MsiRecordSetInteger(hRecord, 1, errcode);
115
MsiRecordSetString(hRecord, 2, str);
116
MsiRecordSetInteger(hRecord, 3, param);
117
118
MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);
119
120
MsiCloseHandle(hRecord);
121
}
122
123
#define LSA_KERBEROS_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos"
124
#define LSA_KERBEROS_PARM_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Parameters"
125
#define KFW_CLIENT_KEY "SOFTWARE\\MIT\\Kerberos\\Client\\"
126
#define SESSKEY_VALUE_NAME "AllowTGTSessionKey"
127
128
#define SESSBACKUP_VALUE_NAME "AllowTGTSessionKeyBackup"
129
#define SESSXPBACKUP_VALUE_NAME "AllowTGTSessionKeyBackupXP"
130
131
132
/* Set the AllowTGTSessionKey registry keys on install. Called as a deferred custom action. */
133
MSIDLLEXPORT EnableAllowTgtSessionKey( MSIHANDLE hInstall ) {
134
return SetAllowTgtSessionKey( hInstall, TRUE );
135
}
136
137
/* Unset the AllowTGTSessionKey registry keys on uninstall. Called as a deferred custom action. */
138
MSIDLLEXPORT RevertAllowTgtSessionKey( MSIHANDLE hInstall ) {
139
return SetAllowTgtSessionKey( hInstall, FALSE );
140
}
141
142
UINT SetAllowTgtSessionKey( MSIHANDLE hInstall, BOOL pInstall ) {
143
TCHAR tchVersionString[1024];
144
TCHAR tchVersionKey[2048];
145
DWORD size;
146
DWORD type;
147
DWORD value;
148
HKEY hkKfwClient = NULL;
149
HKEY hkLsaKerberos = NULL;
150
HKEY hkLsaKerberosParm = NULL;
151
UINT rv;
152
DWORD phase = 0;
153
154
// construct the backup key path
155
size = sizeof(tchVersionString) / sizeof(TCHAR);
156
rv = MsiGetProperty( hInstall, _T("CustomActionData"), tchVersionString, &size );
157
if(rv != ERROR_SUCCESS) {
158
if(pInstall) {
159
ShowMsiError( hInstall, ERR_CUSTACTDATA, rv );
160
return rv;
161
} else {
162
return ERROR_SUCCESS;
163
}
164
}
165
166
_tcscpy( tchVersionKey, _T( KFW_CLIENT_KEY ) );
167
_tcscat( tchVersionKey, tchVersionString );
168
169
phase = 1;
170
171
rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, tchVersionKey, 0, ((pInstall)?KEY_WRITE:KEY_READ), &hkKfwClient );
172
if(rv != ERROR_SUCCESS)
173
goto cleanup;
174
175
phase = 2;
176
177
rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberos );
178
if(rv != ERROR_SUCCESS)
179
goto cleanup;
180
181
phase = 3;
182
183
rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_PARM_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberosParm );
184
if(rv != ERROR_SUCCESS) {
185
hkLsaKerberosParm = NULL;
186
}
187
188
if(pInstall) {
189
// backup the existing values
190
if(hkLsaKerberosParm) {
191
phase = 4;
192
193
size = sizeof(value);
194
rv = RegQueryValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
195
if(rv != ERROR_SUCCESS)
196
value = 0;
197
198
phase = 5;
199
rv = RegSetValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
200
if(rv != ERROR_SUCCESS)
201
goto cleanup;
202
}
203
204
phase = 6;
205
size = sizeof(value);
206
rv = RegQueryValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
207
if(rv != ERROR_SUCCESS)
208
value = 0;
209
210
phase = 7;
211
rv = RegSetValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
212
if(rv != ERROR_SUCCESS)
213
goto cleanup;
214
215
// and now write the actual values
216
phase = 8;
217
value = 1;
218
rv = RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
219
if(rv != ERROR_SUCCESS)
220
goto cleanup;
221
222
if(hkLsaKerberosParm) {
223
phase = 9;
224
value = 1;
225
rv = RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
226
if(rv != ERROR_SUCCESS)
227
goto cleanup;
228
}
229
230
} else { // uninstalling
231
// Don't fail no matter what goes wrong. This is also a rollback action.
232
if(hkLsaKerberosParm) {
233
size = sizeof(value);
234
rv = RegQueryValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
235
if(rv != ERROR_SUCCESS)
236
value = 0;
237
238
RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
239
}
240
241
size = sizeof(value);
242
rv = RegQueryValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
243
if(rv != ERROR_SUCCESS)
244
value = 0;
245
246
RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
247
248
RegDeleteValue( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ) );
249
RegDeleteValue( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ) );
250
}
251
252
// all done
253
rv = ERROR_SUCCESS;
254
255
cleanup:
256
if(rv != ERROR_SUCCESS && pInstall) {
257
ShowMsiError(hInstall, 4005, phase);
258
}
259
if(hkKfwClient) RegCloseKey( hkKfwClient );
260
if(hkLsaKerberos) RegCloseKey( hkLsaKerberos );
261
if(hkLsaKerberosParm) RegCloseKey( hkLsaKerberosParm );
262
263
return rv;
264
}
265
266
/* Abort the installation (called as an immediate custom action) */
267
MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE hInstall ) {
268
DWORD rv;
269
DWORD dwSize = 0;
270
LPTSTR sReason = NULL;
271
LPTSTR sFormatted = NULL;
272
MSIHANDLE hRecord = NULL;
273
LPTSTR cAbortReason = _T("ABORTREASON");
274
275
rv = MsiGetProperty( hInstall, cAbortReason, _T(""), &dwSize );
276
if(rv != ERROR_MORE_DATA) goto _cleanup;
277
278
sReason = new TCHAR[ ++dwSize ];
279
280
rv = MsiGetProperty( hInstall, cAbortReason, sReason, &dwSize );
281
282
if(rv != ERROR_SUCCESS) goto _cleanup;
283
284
hRecord = MsiCreateRecord(3);
285
MsiRecordClearData(hRecord);
286
MsiRecordSetString(hRecord, 0, sReason);
287
288
dwSize = 0;
289
290
rv = MsiFormatRecord(hInstall, hRecord, "", &dwSize);
291
if(rv != ERROR_MORE_DATA) goto _cleanup;
292
293
sFormatted = new TCHAR[ ++dwSize ];
294
295
rv = MsiFormatRecord(hInstall, hRecord, sFormatted, &dwSize);
296
297
if(rv != ERROR_SUCCESS) goto _cleanup;
298
299
MsiCloseHandle(hRecord);
300
301
hRecord = MsiCreateRecord(3);
302
MsiRecordClearData(hRecord);
303
MsiRecordSetInteger(hRecord, 1, ERR_ABORT);
304
MsiRecordSetString(hRecord,2, sFormatted);
305
MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);
306
307
_cleanup:
308
if(sFormatted) delete sFormatted;
309
if(hRecord) MsiCloseHandle( hRecord );
310
if(sReason) delete sReason;
311
312
return ~ERROR_SUCCESS;
313
}
314
315
/* Kill specified processes that are running on the system */
316
/* Uses the custom table KillProcess. Called as an immediate action. */
317
318
#define MAX_KILL_PROCESSES 255
319
#define FIELD_SIZE 256
320
321
struct _KillProc {
322
TCHAR * image;
323
TCHAR * desc;
324
BOOL found;
325
DWORD pid;
326
};
327
328
#define RV_BAIL if(rv != ERROR_SUCCESS) goto _cleanup
329
330
MSIDLLEXPORT KillRunningProcesses( MSIHANDLE hInstall ) {
331
return KillRunningProcessesWorker( hInstall, TRUE );
332
}
333
334
/* When listing running processes, we populate the ListBox table with
335
values associated with the property 'KillableProcesses'. If we
336
actually find any processes worth killing, then we also set the
337
'FoundProcceses' property to '1'. Otherwise we set it to ''.
338
*/
339
340
MSIDLLEXPORT ListRunningProcesses( MSIHANDLE hInstall ) {
341
return KillRunningProcessesWorker( hInstall, FALSE );
342
}
343
344
UINT KillRunningProcessesWorker( MSIHANDLE hInstall, BOOL bKill )
345
{
346
UINT rv = ERROR_SUCCESS;
347
_KillProc * kpList;
348
int nKpList = 0;
349
int i;
350
int rowNum = 1;
351
DWORD size;
352
BOOL found = FALSE;
353
354
MSIHANDLE hDatabase = NULL;
355
MSIHANDLE hView = NULL;
356
MSIHANDLE hViewInsert = NULL;
357
MSIHANDLE hRecord = NULL;
358
MSIHANDLE hRecordInsert = NULL;
359
360
HANDLE hSnapshot = NULL;
361
362
PROCESSENTRY32 pe;
363
364
kpList = new _KillProc[MAX_KILL_PROCESSES];
365
memset(kpList, 0, sizeof(*kpList) * MAX_KILL_PROCESSES);
366
367
hDatabase = MsiGetActiveDatabase( hInstall );
368
if( hDatabase == NULL ) {
369
rv = GetLastError();
370
goto _cleanup;
371
}
372
373
// If we are only going to list out the processes, delete all the existing
374
// entries first.
375
376
if(!bKill) {
377
378
rv = MsiDatabaseOpenView( hDatabase,
379
_T( "DELETE FROM `ListBox` WHERE `ListBox`.`Property` = 'KillableProcesses'" ),
380
&hView); RV_BAIL;
381
382
rv = MsiViewExecute( hView, NULL ); RV_BAIL;
383
384
MsiCloseHandle( hView );
385
386
hView = NULL;
387
388
rv = MsiDatabaseOpenView( hDatabase,
389
_T( "SELECT * FROM `ListBox` WHERE `Property` = 'KillableProcesses'" ),
390
&hViewInsert); RV_BAIL;
391
392
MsiViewExecute(hViewInsert, NULL);
393
394
hRecordInsert = MsiCreateRecord(4);
395
396
if(hRecordInsert == NULL) {
397
rv = GetLastError();
398
goto _cleanup;
399
}
400
}
401
402
// Open a view
403
rv = MsiDatabaseOpenView( hDatabase,
404
_T( "SELECT `Image`,`Desc` FROM `KillProcess`" ),
405
&hView); RV_BAIL;
406
407
rv = MsiViewExecute( hView, NULL ); RV_BAIL;
408
409
do {
410
rv = MsiViewFetch( hView, &hRecord );
411
if(rv != ERROR_SUCCESS) {
412
if(hRecord)
413
MsiCloseHandle(hRecord);
414
hRecord = NULL;
415
break;
416
}
417
418
kpList[nKpList].image = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].image[0] = _T('\0');
419
kpList[nKpList].desc = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].desc[0] = _T('\0');
420
nKpList++;
421
422
size = FIELD_SIZE;
423
rv = MsiRecordGetString(hRecord, 1, kpList[nKpList-1].image, &size); RV_BAIL;
424
425
size = FIELD_SIZE;
426
rv = MsiRecordGetString(hRecord, 2, kpList[nKpList-1].desc, &size); RV_BAIL;
427
428
MsiCloseHandle(hRecord);
429
} while(nKpList < MAX_KILL_PROCESSES);
430
431
hRecord = NULL;
432
433
// now we have all the processes in the array. Check if they are running.
434
435
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
436
if(hSnapshot == INVALID_HANDLE_VALUE) {
437
rv = GetLastError();
438
goto _cleanup;
439
}
440
441
pe.dwSize = sizeof( PROCESSENTRY32 );
442
443
if(!Process32First( hSnapshot, &pe )) {
444
// technically we should at least find the MSI process, but we let this pass
445
rv = ERROR_SUCCESS;
446
goto _cleanup;
447
}
448
449
do {
450
for(i=0; i<nKpList; i++) {
451
if(!_tcsicmp( kpList[i].image, pe.szExeFile )) {
452
// got one
453
if(bKill) {
454
// try to kill the process
455
HANDLE hProcess = NULL;
456
457
// If we encounter an error, instead of bailing
458
// out, we continue on to the next process. We
459
// may not have permission to kill all the
460
// processes we want to kill anyway. If there are
461
// any files that we want to replace that is in
462
// use, Windows Installer will schedule a reboot.
463
// Also, it's not like we have an exhaustive list
464
// of all the programs that use Kerberos anyway.
465
466
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
467
if(hProcess == NULL) {
468
rv = GetLastError();
469
break;
470
}
471
472
if(!TerminateProcess(hProcess, 0)) {
473
rv = GetLastError();
474
CloseHandle(hProcess);
475
break;
476
}
477
478
CloseHandle(hProcess);
479
480
} else {
481
TCHAR buf[256];
482
483
// we are supposed to just list out the processes
484
rv = MsiRecordClearData( hRecordInsert ); RV_BAIL;
485
rv = MsiRecordSetString( hRecordInsert, 1, _T("KillableProcesses"));
486
rv = MsiRecordSetInteger( hRecordInsert, 2, rowNum++ ); RV_BAIL;
487
_itot( rowNum, buf, 10 );
488
rv = MsiRecordSetString( hRecordInsert, 3, buf ); RV_BAIL;
489
if(_tcslen(kpList[i].desc)) {
490
rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].desc ); RV_BAIL;
491
} else {
492
rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].image ); RV_BAIL;
493
}
494
MsiViewModify(hViewInsert, MSIMODIFY_INSERT_TEMPORARY, hRecordInsert); RV_BAIL;
495
496
found = TRUE;
497
}
498
break;
499
}
500
}
501
} while( Process32Next( hSnapshot, &pe ) );
502
503
if(!bKill) {
504
// set the 'FoundProcceses' property
505
if(found) {
506
MsiSetProperty( hInstall, _T("FoundProcesses"), _T("1"));
507
} else {
508
MsiSetProperty( hInstall, _T("FoundProcesses"), _T(""));
509
}
510
}
511
512
// Finally:
513
rv = ERROR_SUCCESS;
514
515
_cleanup:
516
517
if(hRecordInsert) MsiCloseHandle(hRecordInsert);
518
if(hViewInsert) MsiCloseHandle(hView);
519
520
if(hSnapshot && hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot);
521
522
while(nKpList) {
523
nKpList--;
524
delete kpList[nKpList].image;
525
delete kpList[nKpList].desc;
526
}
527
delete kpList;
528
529
if(hRecord) MsiCloseHandle(hRecord);
530
if(hView) MsiCloseHandle(hView);
531
532
if(hDatabase) MsiCloseHandle(hDatabase);
533
534
if(rv != ERROR_SUCCESS) {
535
ShowMsiError(hInstall, ERR_PROC_LIST, rv);
536
}
537
538
return rv;
539
}
540
541
static bool IsNSISInstalled()
542
{
543
HKEY nsisKfwKey = NULL;
544
HRESULT res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
545
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion"
546
"\\Uninstall\\Kerberos for Windows",
547
0,
548
KEY_READ | KEY_WOW64_32KEY,
549
&nsisKfwKey);
550
if (res != ERROR_SUCCESS)
551
return FALSE;
552
553
RegCloseKey(nsisKfwKey);
554
return TRUE;
555
}
556
557
static HANDLE NSISUninstallShellExecute(LPTSTR pathUninstall)
558
{
559
SHELLEXECUTEINFO sei;
560
ZeroMemory ( &sei, sizeof(sei) );
561
562
sei.cbSize = sizeof(sei);
563
sei.hwnd = GetForegroundWindow();
564
sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI |
565
SEE_MASK_NOCLOSEPROCESS;
566
sei.lpVerb = _T("runas"); // run as administrator
567
sei.lpFile = pathUninstall;
568
sei.lpParameters = _T("");
569
sei.nShow = SW_SHOWNORMAL;
570
571
if (!ShellExecuteEx(&sei)) {
572
// FAILED! TODO: report details?
573
}
574
return sei.hProcess;
575
}
576
577
static HANDLE NSISUninstallCreateProcess(LPTSTR pathUninstall)
578
{
579
STARTUPINFO sInfo;
580
PROCESS_INFORMATION pInfo;
581
pInfo.hProcess = NULL;
582
pInfo.hThread = NULL;
583
584
// Create a process for the uninstaller
585
sInfo.cb = sizeof(sInfo);
586
sInfo.lpReserved = NULL;
587
sInfo.lpDesktop = _T("");
588
sInfo.lpTitle = _T("NSIS Uninstaller for Kerberos for Windows");
589
sInfo.dwX = 0;
590
sInfo.dwY = 0;
591
sInfo.dwXSize = 0;
592
sInfo.dwYSize = 0;
593
sInfo.dwXCountChars = 0;
594
sInfo.dwYCountChars = 0;
595
sInfo.dwFillAttribute = 0;
596
sInfo.dwFlags = 0;
597
sInfo.wShowWindow = 0;
598
sInfo.cbReserved2 = 0;
599
sInfo.lpReserved2 = 0;
600
sInfo.hStdInput = 0;
601
sInfo.hStdOutput = 0;
602
sInfo.hStdError = 0;
603
604
if (!CreateProcess(pathUninstall,
605
_T("Uninstall /S"),
606
NULL,
607
NULL,
608
FALSE,
609
CREATE_SUSPENDED,
610
NULL,
611
NULL,
612
&sInfo,
613
&pInfo)) {
614
// failure; could grab info, but we should be able to recover by
615
// using NSISUninstallShellExecute...
616
} else {
617
// success
618
// start up the thread
619
ResumeThread(pInfo.hThread);
620
// done with thread handle
621
CloseHandle(pInfo.hThread);
622
}
623
return pInfo.hProcess;
624
}
625
626
627
/* Uninstall NSIS */
628
MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall )
629
{
630
DWORD rv = ERROR_SUCCESS;
631
DWORD lastError;
632
// lookup the NSISUNINSTALL property value
633
LPTSTR cNsisUninstall = _T("UPGRADENSIS");
634
LPTSTR strPathUninst = NULL;
635
DWORD dwSize = 0;
636
HANDLE hProcess = NULL;
637
HANDLE hIo = NULL;
638
HANDLE hJob = NULL;
639
640
rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize );
641
if(rv != ERROR_MORE_DATA) goto _cleanup;
642
643
strPathUninst = new TCHAR[ ++dwSize ];
644
645
rv = MsiGetProperty(hInstall, cNsisUninstall, strPathUninst, &dwSize);
646
if(rv != ERROR_SUCCESS) goto _cleanup;
647
648
hProcess = NSISUninstallCreateProcess(strPathUninst);
649
if (hProcess == NULL) // expected when run on UAC-limited account
650
hProcess = NSISUninstallShellExecute(strPathUninst);
651
652
if (hProcess == NULL) {
653
// still no uninstall process? ick...
654
lastError = GetLastError();
655
rv = 40;
656
goto _cleanup;
657
}
658
// note that it is not suffiecient to wait for the initial process to
659
// finish; there is a whole process tree that we need to wait for. sigh.
660
JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp;
661
acp.CompletionKey = 0;
662
hJob = CreateJobObject(NULL, _T("NSISUninstallObject"));
663
if(!hJob) {
664
rv = 41;
665
goto _cleanup;
666
}
667
668
hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
669
if(!hIo) {
670
rv = 42;
671
goto _cleanup;
672
}
673
674
acp.CompletionPort = hIo;
675
676
SetInformationJobObject(hJob,
677
JobObjectAssociateCompletionPortInformation,
678
&acp,
679
sizeof(acp));
680
681
AssignProcessToJobObject(hJob, hProcess);
682
683
DWORD msgId;
684
ULONG_PTR unusedCompletionKey;
685
LPOVERLAPPED unusedOverlapped;
686
for (;;) {
687
if (!GetQueuedCompletionStatus(hIo,
688
&msgId,
689
&unusedCompletionKey,
690
&unusedOverlapped,
691
INFINITE)) {
692
Sleep(1000);
693
} else if (msgId == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
694
break;
695
}
696
}
697
698
_cleanup:
699
if (hProcess) CloseHandle(hProcess);
700
if (hIo) CloseHandle(hIo);
701
if (hJob) CloseHandle(hJob);
702
703
if (IsNSISInstalled()) {
704
// uninstall failed: maybe user cancelled uninstall, or something else
705
// went wrong...
706
if (rv == ERROR_SUCCESS)
707
rv = 43;
708
} else {
709
// Maybe something went wrong, but it doesn't matter as long as nsis
710
// is gone now...
711
rv = ERROR_SUCCESS;
712
}
713
714
if (rv == 40) {
715
// CreateProcess() / ShellExecute() errors get extra data
716
ShowMsiErrorEx(hInstall, ERR_NSS_FAILED_CP, strPathUninst, lastError);
717
} else if (rv != ERROR_SUCCESS) {
718
ShowMsiError(hInstall, ERR_NSS_FAILED, rv);
719
}
720
721
if (strPathUninst) delete strPathUninst;
722
return rv;
723
}
724
725
/* Check and add or remove networkprovider key value
726
str : target string
727
str2: string to add/remove
728
bInst: == 1 if string should be added to target if not already there,
729
otherwise remove string from target if present.
730
*/
731
int npi_CheckAndAddRemove( LPTSTR str, LPTSTR str2, int bInst ) {
732
733
LPTSTR target, charset, match;
734
int ret=0;
735
736
target = new TCHAR[lstrlen(str)+3];
737
lstrcpy(target,_T(","));
738
lstrcat(target,str);
739
lstrcat(target,_T(","));
740
charset = new TCHAR[lstrlen(str2)+3];
741
lstrcpy(charset,_T(","));
742
lstrcat(charset,str2);
743
lstrcat(charset,_T(","));
744
745
match = _tcsstr(target, charset);
746
747
if ((match) && (bInst)) {
748
ret = INP_ERR_PRESENT;
749
goto cleanup;
750
}
751
752
if ((!match) && (!bInst)) {
753
ret = INP_ERR_ABSENT;
754
goto cleanup;
755
}
756
757
if (bInst) // && !match
758
{
759
lstrcat(str, _T(","));
760
lstrcat(str, str2);
761
ret = INP_ERR_ADDED;
762
goto cleanup;
763
}
764
765
// if (!bInst) && (match)
766
{
767
lstrcpy(str+(match-target),match+lstrlen(str2)+2);
768
str[lstrlen(str)-1]=_T('\0');
769
ret = INP_ERR_REMOVED;
770
goto cleanup;
771
}
772
773
cleanup:
774
775
delete target;
776
delete charset;
777
return ret;
778
}
779
780
/* Sets the registry keys required for the functioning of the network provider */
781
782
DWORD InstNetProvider(MSIHANDLE hInstall, int bInst) {
783
LPTSTR strOrder;
784
HKEY hkOrder;
785
LONG rv;
786
DWORD dwSize;
787
HANDLE hProcHeap;
788
789
strOrder = (LPTSTR) 0;
790
791
CHECK(rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, STR_KEY_ORDER, 0, KEY_READ | KEY_WRITE, &hkOrder ));
792
793
dwSize = 0;
794
CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, NULL, &dwSize ) );
795
796
strOrder = new TCHAR[ (dwSize + STR_SERVICE_LEN + 4) * sizeof(TCHAR) ];
797
798
CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, (LPBYTE) strOrder, &dwSize));
799
800
strOrder[dwSize] = '\0'; /* reg strings are not always nul terminated */
801
802
npi_CheckAndAddRemove( strOrder, STR_SERVICE , bInst);
803
804
dwSize = (lstrlen( strOrder ) + 1) * sizeof(TCHAR);
805
806
CHECK(rv = RegSetValueEx( hkOrder, STR_VAL_ORDER, NULL, REG_SZ, (LPBYTE) strOrder, dwSize ));
807
808
/* everything else should be set by the MSI tables */
809
rv = ERROR_SUCCESS;
810
_cleanup:
811
812
if( rv != ERROR_SUCCESS ) {
813
ShowMsiError( hInstall, ERR_NPI_FAILED, rv );
814
}
815
816
if(strOrder) delete strOrder;
817
818
return rv;
819
}
820
821
MSIDLLEXPORT InstallNetProvider( MSIHANDLE hInstall ) {
822
return InstNetProvider( hInstall, 1 );
823
}
824
825
MSIDLLEXPORT UninstallNetProvider( MSIHANDLE hInstall) {
826
return InstNetProvider( hInstall, 0 );
827
}
828
829
#endif
830
#ifdef __NMAKE__
831
!ENDIF
832
#endif
833
834