2014-06-10 19:42:34 +02:00
|
|
|
|
/* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*-
|
|
|
|
|
* Copyright (C) 2005 g10 Code GmbH
|
|
|
|
|
* Copyright (C) 2001 Justin Frankel
|
|
|
|
|
*
|
|
|
|
|
* This software is provided 'as-is', without any express or implied
|
|
|
|
|
* warranty. In no event will the authors be held liable for any
|
|
|
|
|
* damages arising from the use of this software.
|
|
|
|
|
*
|
|
|
|
|
* Permission is granted to anyone to use this software for any
|
|
|
|
|
* purpose, including commercial applications, and to alter it and
|
|
|
|
|
* redistribute it freely, subject to the following restrictions:
|
|
|
|
|
*
|
|
|
|
|
* 1. The origin of this software must not be misrepresented; you must
|
|
|
|
|
* not claim that you wrote the original software. If you use this
|
|
|
|
|
* software in a product, an acknowledgment in the product
|
|
|
|
|
* documentation would be appreciated but is not required.
|
|
|
|
|
*
|
|
|
|
|
* 2. Altered source versions must be plainly marked as such, and must
|
|
|
|
|
* not be misrepresented as being the original software.
|
|
|
|
|
*
|
|
|
|
|
* 3. This notice may not be removed or altered from any source
|
|
|
|
|
* distribution.
|
|
|
|
|
************************************************************
|
|
|
|
|
* The code for the splash screen has been taken from the Splash
|
|
|
|
|
* plugin of the NSIS 2.04 distribution. That code comes without
|
2016-10-27 14:58:01 +02:00
|
|
|
|
* explicit copyright notices in the source files or author names, it
|
2014-06-10 19:42:34 +02:00
|
|
|
|
* seems that it has been written by Justin Frankel; not sure about
|
|
|
|
|
* the year, though. [wk 2005-11-28]
|
|
|
|
|
*
|
|
|
|
|
* Fixed some compiler warnings. [wk 2014-02-24].
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include "exdll.h"
|
|
|
|
|
|
|
|
|
|
static HINSTANCE g_hInstance; /* Our Instance. */
|
|
|
|
|
static HWND g_hwndParent; /* Handle of parent window or NULL. */
|
|
|
|
|
static HBITMAP g_hbm; /* Handle of the splash image. */
|
|
|
|
|
static int sleepint; /* Milliseconds to show the spals image. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Standard entry point for DLLs. */
|
|
|
|
|
int WINAPI
|
|
|
|
|
DllMain (HANDLE hinst, DWORD reason, LPVOID reserved)
|
|
|
|
|
{
|
|
|
|
|
if (reason == DLL_PROCESS_ATTACH)
|
|
|
|
|
g_hInstance = hinst;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Dummy function for testing. */
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
dummy (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
// note if you want parameters from the stack, pop them off in order.
|
|
|
|
|
// i.e. if you are called via exdll::myFunction file.dat poop.dat
|
|
|
|
|
// calling popstring() the first time would give you file.dat,
|
|
|
|
|
// and the second time would give you poop.dat.
|
|
|
|
|
// you should empty the stack of your parameters, and ONLY your
|
|
|
|
|
// parameters.
|
|
|
|
|
|
|
|
|
|
// do your stuff here
|
|
|
|
|
{
|
|
|
|
|
char buf[1024];
|
Fix use cases of snprintf.
* agent/call-pinentry.c, agent/call-scd.c, agent/command.c,
build-aux/speedo/w32/g4wihelp.c, common/get-passphrase.c,
dirmngr/dirmngr.c, g10/call-agent.c, g10/cpr.c, g10/keygen.c,
g10/openfile.c, g10/passphrase.c, scd/app-openpgp.c, scd/scdaemon.c,
sm/call-agent.c, sm/call-dirmngr.c, sm/certreqgen.c: Fix assuming C99.
--
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2016-10-21 12:04:46 +09:00
|
|
|
|
snprintf (buf, sizeof buf, "$R0=%s\r\n$R1=%s\r\n",
|
2014-06-10 19:42:34 +02:00
|
|
|
|
getuservariable(INST_R0),
|
|
|
|
|
getuservariable(INST_R1));
|
|
|
|
|
MessageBox (g_hwndParent,buf,0,MB_OK);
|
|
|
|
|
|
Fix use cases of snprintf.
* agent/call-pinentry.c, agent/call-scd.c, agent/command.c,
build-aux/speedo/w32/g4wihelp.c, common/get-passphrase.c,
dirmngr/dirmngr.c, g10/call-agent.c, g10/cpr.c, g10/keygen.c,
g10/openfile.c, g10/passphrase.c, scd/app-openpgp.c, scd/scdaemon.c,
sm/call-agent.c, sm/call-dirmngr.c, sm/certreqgen.c: Fix assuming C99.
--
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2016-10-21 12:04:46 +09:00
|
|
|
|
snprintf (buf, sizeof buf,
|
2014-06-10 19:42:34 +02:00
|
|
|
|
"autoclose =%d\r\n"
|
|
|
|
|
"all_user_var =%d\r\n"
|
|
|
|
|
"exec_error =%d\r\n"
|
|
|
|
|
"abort =%d\r\n"
|
|
|
|
|
"exec_reboot =%d\r\n"
|
|
|
|
|
"reboot_called=%d\r\n"
|
|
|
|
|
"silent =%d\r\n"
|
|
|
|
|
"instdir_error=%d\r\n"
|
|
|
|
|
"rtl =%d\r\n"
|
|
|
|
|
"errlvl =%d\r\n",
|
|
|
|
|
extra->exec_flags->autoclose,
|
|
|
|
|
extra->exec_flags->all_user_var,
|
|
|
|
|
extra->exec_flags->exec_error,
|
|
|
|
|
extra->exec_flags->abort,
|
|
|
|
|
extra->exec_flags->exec_reboot,
|
|
|
|
|
extra->exec_flags->reboot_called,
|
|
|
|
|
extra->exec_flags->silent,
|
|
|
|
|
extra->exec_flags->instdir_error,
|
|
|
|
|
extra->exec_flags->rtl,
|
|
|
|
|
extra->exec_flags->errlvl);
|
|
|
|
|
MessageBox(g_hwndParent,buf,0,MB_OK);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
runonce (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
const char *result;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
CreateMutexA (NULL, 0, getuservariable(INST_R0));
|
|
|
|
|
result = GetLastError ()? "1":"0";
|
|
|
|
|
setuservariable (INST_R0, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
playsound (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
char fname[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
if (popstring(fname, sizeof fname))
|
|
|
|
|
return;
|
|
|
|
|
PlaySound (fname, NULL, SND_ASYNC|SND_FILENAME|SND_NODEFAULT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
stopsound (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
PlaySound (NULL, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Windows procedure to control the splashimage. This one pauses the
|
|
|
|
|
execution until the sleep time is over or the user closes this
|
|
|
|
|
windows. */
|
|
|
|
|
static LRESULT CALLBACK
|
|
|
|
|
splash_wndproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
{
|
|
|
|
|
LRESULT result = 0;
|
|
|
|
|
|
|
|
|
|
switch (uMsg)
|
|
|
|
|
{
|
|
|
|
|
case WM_CREATE:
|
|
|
|
|
{
|
|
|
|
|
BITMAP bm;
|
|
|
|
|
RECT vp;
|
|
|
|
|
|
|
|
|
|
GetObject(g_hbm, sizeof(bm), (LPSTR)&bm);
|
|
|
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0);
|
|
|
|
|
SetWindowLong(hwnd,GWL_STYLE,0);
|
|
|
|
|
SetWindowPos(hwnd,NULL,
|
|
|
|
|
vp.left+(vp.right-vp.left-bm.bmWidth)/2,
|
|
|
|
|
vp.top+(vp.bottom-vp.top-bm.bmHeight)/2,
|
|
|
|
|
bm.bmWidth,bm.bmHeight,
|
|
|
|
|
SWP_NOZORDER);
|
|
|
|
|
ShowWindow(hwnd,SW_SHOW);
|
|
|
|
|
SetTimer(hwnd,1,sleepint,NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_PAINT:
|
|
|
|
|
{
|
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
|
RECT r;
|
|
|
|
|
HDC curdc=BeginPaint(hwnd,&ps);
|
|
|
|
|
HDC hdc=CreateCompatibleDC(curdc);
|
|
|
|
|
HBITMAP oldbm;
|
|
|
|
|
GetClientRect(hwnd,&r);
|
|
|
|
|
oldbm=(HBITMAP)SelectObject(hdc,g_hbm);
|
|
|
|
|
BitBlt(curdc,r.left,r.top,r.right-r.left,r.bottom-r.top,
|
|
|
|
|
hdc,0,0,SRCCOPY);
|
|
|
|
|
SelectObject(hdc,oldbm);
|
|
|
|
|
DeleteDC(hdc);
|
|
|
|
|
EndPaint(hwnd,&ps);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_CLOSE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WM_TIMER:
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
DestroyWindow(hwnd);
|
|
|
|
|
/*(fall through)*/
|
|
|
|
|
default:
|
|
|
|
|
result = DefWindowProc (hwnd, uMsg, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Display a splash screen. Call as
|
|
|
|
|
|
|
|
|
|
g4wihelp::showsplash SLEEP FNAME
|
|
|
|
|
|
|
|
|
|
With SLEEP being the time in milliseconds to show the splashscreen
|
|
|
|
|
and FNAME the complete filename of the image. As of now only BMP
|
|
|
|
|
is supported.
|
|
|
|
|
*/
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
showsplash (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
static WNDCLASS wc;
|
|
|
|
|
char sleepstr[30];
|
|
|
|
|
char fname[MAX_PATH];
|
|
|
|
|
int err = 0;
|
|
|
|
|
char *p;
|
|
|
|
|
char classname[] = "_sp";
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
if (popstring(sleepstr, sizeof sleepstr))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (popstring(fname, sizeof fname))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!*fname)
|
|
|
|
|
return; /* Nothing to do. */
|
|
|
|
|
|
|
|
|
|
for (sleepint=0, p=sleepstr; *p >= '0' && *p <= '9'; p++)
|
|
|
|
|
{
|
|
|
|
|
sleepint *= 10;
|
|
|
|
|
sleepint += *p - '0';
|
|
|
|
|
}
|
|
|
|
|
if (sleepint <= 0)
|
|
|
|
|
return; /* Nothing to do. */
|
|
|
|
|
|
|
|
|
|
wc.lpfnWndProc = splash_wndproc;
|
|
|
|
|
wc.hInstance = g_hInstance;
|
|
|
|
|
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
|
|
|
wc.lpszClassName = classname;
|
|
|
|
|
if (!RegisterClass(&wc))
|
|
|
|
|
return; /* Error. */
|
|
|
|
|
|
|
|
|
|
g_hbm = LoadImage (NULL, fname, IMAGE_BITMAP,
|
|
|
|
|
0, 0 , LR_CREATEDIBSECTION|LR_LOADFROMFILE);
|
|
|
|
|
if (g_hbm)
|
|
|
|
|
{
|
|
|
|
|
MSG msg;
|
|
|
|
|
HWND hwnd;
|
|
|
|
|
|
|
|
|
|
hwnd = CreateWindowEx (WS_EX_TOOLWINDOW, classname, classname,
|
|
|
|
|
0, 0, 0, 0, 0, (HWND)hwndParent, NULL,
|
|
|
|
|
g_hInstance, NULL);
|
|
|
|
|
|
|
|
|
|
while (IsWindow(hwnd) && GetMessage ( &msg, hwnd, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
DispatchMessage (&msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeleteObject (g_hbm);
|
|
|
|
|
g_hbm = NULL;
|
|
|
|
|
}
|
|
|
|
|
UnregisterClass (classname, g_hInstance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Service Management. */
|
|
|
|
|
|
|
|
|
|
/* Use this to report unexpected errors. FIXME: This is really not
|
|
|
|
|
very descriptive. */
|
|
|
|
|
void
|
|
|
|
|
service_error (const char *str)
|
|
|
|
|
{
|
|
|
|
|
char buf[1024];
|
Fix use cases of snprintf.
* agent/call-pinentry.c, agent/call-scd.c, agent/command.c,
build-aux/speedo/w32/g4wihelp.c, common/get-passphrase.c,
dirmngr/dirmngr.c, g10/call-agent.c, g10/cpr.c, g10/keygen.c,
g10/openfile.c, g10/passphrase.c, scd/app-openpgp.c, scd/scdaemon.c,
sm/call-agent.c, sm/call-dirmngr.c, sm/certreqgen.c: Fix assuming C99.
--
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2016-10-21 12:04:46 +09:00
|
|
|
|
snprintf (buf, sizeof (buf), "error: %s: ec=%d\r\n", str,
|
2014-06-10 19:42:34 +02:00
|
|
|
|
GetLastError ());
|
|
|
|
|
MessageBox(g_hwndParent, buf, 0, MB_OK);
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
service_create (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE sc;
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
const char *result = NULL;
|
|
|
|
|
char service_name[256];
|
|
|
|
|
char display_name[256];
|
|
|
|
|
char program[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: service_name, display_name, program. */
|
|
|
|
|
if (popstring (service_name, sizeof (service_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (!err && popstring (display_name, sizeof (display_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (!err && popstring (program, sizeof (program)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
if (sc == NULL)
|
|
|
|
|
{
|
|
|
|
|
service_error ("OpenSCManager");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service = CreateService (sc, service_name, display_name,
|
|
|
|
|
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
|
|
|
|
/* Use SERVICE_DEMAND_START for testing.
|
|
|
|
|
FIXME: Currently not configurable by caller. */
|
|
|
|
|
SERVICE_AUTO_START,
|
|
|
|
|
SERVICE_ERROR_NORMAL, program,
|
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
|
/* FIXME: Currently not configurable by caller. */
|
|
|
|
|
/* FIXME: LocalService or NetworkService
|
|
|
|
|
don't work for dirmngr right now. NOTE!
|
|
|
|
|
If you change it here, you also should
|
|
|
|
|
adjust make-msi.pl for the msi
|
|
|
|
|
installer. In the future, this should
|
|
|
|
|
be an argument to the function and then
|
|
|
|
|
the make-msi.pl script can extract it
|
|
|
|
|
from the invocation. */
|
|
|
|
|
NULL /* "NT AUTHORITY\\LocalService" */,
|
|
|
|
|
NULL);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
{
|
|
|
|
|
service_error ("CreateService");
|
|
|
|
|
CloseServiceHandle (sc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
|
|
|
|
|
result = GetLastError () ? "1":"0";
|
|
|
|
|
setuservariable (INST_R0, result);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Requires g_hwndParent to be set! */
|
|
|
|
|
SC_HANDLE
|
|
|
|
|
service_lookup (char *service_name)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE sc;
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
|
|
|
|
|
sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
if (sc == NULL)
|
|
|
|
|
{
|
|
|
|
|
service_error ("OpenSCManager");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
service = OpenService (sc, service_name, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Fail silently here. */
|
|
|
|
|
CloseServiceHandle (sc);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (sc);
|
|
|
|
|
return service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Returns status. */
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
service_query (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
const char *result = NULL;
|
|
|
|
|
char service_name[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
SERVICE_STATUS status;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: service_name argc [argv]. */
|
|
|
|
|
if (popstring (service_name, sizeof (service_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "ERROR");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service = service_lookup (service_name);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "MISSING");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = QueryServiceStatus (service, &status);
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "ERROR");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
|
|
|
|
|
switch (status.dwCurrentState)
|
|
|
|
|
{
|
|
|
|
|
case SERVICE_START_PENDING:
|
|
|
|
|
result = "START_PENDING";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_RUNNING:
|
|
|
|
|
result = "RUNNING";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_PAUSE_PENDING:
|
|
|
|
|
result = "PAUSE_PENDING";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_PAUSED:
|
|
|
|
|
result = "PAUSED";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_CONTINUE_PENDING:
|
|
|
|
|
result = "CONTINUE_PENDING";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_STOP_PENDING:
|
|
|
|
|
result = "STOP_PENDING";
|
|
|
|
|
break;
|
|
|
|
|
case SERVICE_STOPPED:
|
|
|
|
|
result = "STOPPED";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
result = "UNKNOWN";
|
|
|
|
|
}
|
|
|
|
|
setuservariable (INST_R0, result);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
service_start (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
const char *result = NULL;
|
|
|
|
|
char service_name[256];
|
|
|
|
|
char argc_str[256];
|
|
|
|
|
#define NR_ARGS 10
|
|
|
|
|
#define ARG_MAX 256
|
|
|
|
|
char argv_str[NR_ARGS][ARG_MAX];
|
|
|
|
|
const char *argv[NR_ARGS + 1];
|
|
|
|
|
int argc;
|
|
|
|
|
int i;
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: service_name argc [argv]. */
|
|
|
|
|
if (popstring (service_name, sizeof (service_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (!err && popstring (argc_str, sizeof (argc_str)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
argc = atoi (argc_str);
|
|
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
|
{
|
|
|
|
|
if (popstring (argv_str[i], ARG_MAX))
|
|
|
|
|
{
|
|
|
|
|
err = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
argv[i] = argv_str[i];
|
|
|
|
|
}
|
|
|
|
|
argv[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service = service_lookup (service_name);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
err = StartService (service, argc, argc == 0 ? NULL : argv);
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
service_error ("StartService");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "0");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
service_stop (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
const char *result = NULL;
|
|
|
|
|
char service_name[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
SERVICE_STATUS status;
|
|
|
|
|
DWORD timeout = 10000; /* 10 seconds. */
|
|
|
|
|
DWORD start_time;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: service_name argc [argv]. */
|
|
|
|
|
if (popstring (service_name, sizeof (service_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service = service_lookup (service_name);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
err = QueryServiceStatus (service, &status);
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
service_error ("QueryService");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status.dwCurrentState != SERVICE_STOPPED
|
|
|
|
|
&& status.dwCurrentState != SERVICE_STOP_PENDING)
|
|
|
|
|
{
|
|
|
|
|
err = ControlService (service, SERVICE_CONTROL_STOP, &status);
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
service_error ("ControlService");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start_time = GetTickCount ();
|
|
|
|
|
while (status.dwCurrentState != SERVICE_STOPPED)
|
|
|
|
|
{
|
|
|
|
|
Sleep (1000); /* One second. */
|
|
|
|
|
if (!QueryServiceStatus (service, &status))
|
|
|
|
|
{
|
|
|
|
|
service_error ("QueryService");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (status.dwCurrentState == SERVICE_STOPPED)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (GetTickCount () - start_time > timeout)
|
|
|
|
|
{
|
|
|
|
|
char buf[1024];
|
Fix use cases of snprintf.
* agent/call-pinentry.c, agent/call-scd.c, agent/command.c,
build-aux/speedo/w32/g4wihelp.c, common/get-passphrase.c,
dirmngr/dirmngr.c, g10/call-agent.c, g10/cpr.c, g10/keygen.c,
g10/openfile.c, g10/passphrase.c, scd/app-openpgp.c, scd/scdaemon.c,
sm/call-agent.c, sm/call-dirmngr.c, sm/certreqgen.c: Fix assuming C99.
--
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2016-10-21 12:04:46 +09:00
|
|
|
|
snprintf (buf, sizeof (buf),
|
2014-06-10 19:42:34 +02:00
|
|
|
|
"time out waiting for service %s to stop\r\n",
|
|
|
|
|
service_name);
|
|
|
|
|
MessageBox (g_hwndParent, buf, 0, MB_OK);
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
setuservariable (INST_R0, "0");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
service_delete (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
SC_HANDLE service;
|
|
|
|
|
const char *result = NULL;
|
|
|
|
|
char service_name[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: service_name argc [argv]. */
|
|
|
|
|
if (popstring (service_name, sizeof (service_name)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service = service_lookup (service_name);
|
|
|
|
|
if (service == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
err = DeleteService (service);
|
|
|
|
|
if (err == 0)
|
|
|
|
|
{
|
|
|
|
|
service_error ("DeleteService");
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CloseServiceHandle (service);
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "0");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
/* Extract config file parameters. FIXME: Not particularly robust.
|
|
|
|
|
We expect some reasonable formatting. The parser below is very
|
|
|
|
|
limited. It expects a command line option /c=FILE or /C=FILE,
|
|
|
|
|
where FILE must be enclosed in double-quotes if it contains spaces.
|
|
|
|
|
That file should contain a single section [gpg4win] and KEY=VALUE
|
|
|
|
|
pairs for each additional configuration file to install. Comments
|
|
|
|
|
are supported only on lines by themselves. VALUE can be quoted in
|
|
|
|
|
double-quotes, but does not need to be, unless it has whitespace at
|
|
|
|
|
the beginning or end. KEY can, for example, be "gpg.conf" (without
|
|
|
|
|
the quotes). */
|
|
|
|
|
void
|
|
|
|
|
config_init (char **keys, char **values, int max)
|
|
|
|
|
{
|
|
|
|
|
/* First, parse the command line. */
|
|
|
|
|
char *cmdline;
|
|
|
|
|
char *begin = NULL;
|
|
|
|
|
char *end = NULL;
|
|
|
|
|
char mark;
|
|
|
|
|
char *fname;
|
|
|
|
|
char *ptr;
|
|
|
|
|
FILE *conf;
|
|
|
|
|
|
|
|
|
|
*keys = NULL;
|
|
|
|
|
*values = NULL;
|
|
|
|
|
|
|
|
|
|
cmdline = getuservariable (INST_CMDLINE);
|
|
|
|
|
|
|
|
|
|
mark = (*cmdline == '"') ? (cmdline++, '"') : ' ';
|
|
|
|
|
while (*cmdline && *cmdline != mark)
|
|
|
|
|
cmdline++;
|
|
|
|
|
if (mark == '"' && *cmdline)
|
|
|
|
|
cmdline++;
|
|
|
|
|
while (*cmdline && *cmdline == ' ')
|
|
|
|
|
cmdline++;
|
|
|
|
|
|
|
|
|
|
while (*cmdline)
|
|
|
|
|
{
|
|
|
|
|
/* We are at the beginning of a new argument. */
|
|
|
|
|
if (cmdline[0] == '/' && (cmdline[1] == 'C' || cmdline[1] == 'c')
|
|
|
|
|
&& cmdline[2] == '=')
|
|
|
|
|
{
|
|
|
|
|
cmdline += 3;
|
|
|
|
|
begin = cmdline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (*cmdline && *cmdline != ' ')
|
|
|
|
|
{
|
|
|
|
|
/* Skip over quoted parts. */
|
|
|
|
|
if (*cmdline == '"')
|
|
|
|
|
{
|
|
|
|
|
cmdline++;
|
|
|
|
|
while (*cmdline && *cmdline != '"')
|
|
|
|
|
cmdline++;
|
|
|
|
|
if (*cmdline)
|
|
|
|
|
cmdline++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cmdline++;
|
|
|
|
|
}
|
|
|
|
|
if (begin && !end)
|
|
|
|
|
{
|
|
|
|
|
end = cmdline - 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while (*cmdline && *cmdline == ' ')
|
|
|
|
|
cmdline++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!begin || begin > end)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Strip quotes. */
|
|
|
|
|
if (*begin == '"' && *end == '"')
|
|
|
|
|
{
|
|
|
|
|
begin++;
|
|
|
|
|
end--;
|
|
|
|
|
}
|
|
|
|
|
if (begin > end)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fname = malloc (end - begin + 2);
|
|
|
|
|
if (!fname)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ptr = fname;
|
|
|
|
|
while (begin <= end)
|
|
|
|
|
*(ptr++) = *(begin++);
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
|
|
conf = fopen (fname, "r");
|
|
|
|
|
free (fname);
|
|
|
|
|
if (!conf)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (max - 1 > 0)
|
|
|
|
|
{
|
|
|
|
|
char line[256];
|
|
|
|
|
char *ptr2;
|
|
|
|
|
|
|
|
|
|
if (fgets (line, sizeof (line), conf) == NULL)
|
|
|
|
|
break;
|
|
|
|
|
ptr = &line[strlen (line)];
|
|
|
|
|
while (ptr > line && (ptr[-1] == '\n' || ptr[-1] == '\r'
|
|
|
|
|
|| ptr[-1] == ' ' || ptr[-1] == '\t'))
|
|
|
|
|
ptr--;
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
|
|
ptr = line;
|
|
|
|
|
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
|
|
|
ptr++;
|
|
|
|
|
/* Ignore comment lines. */
|
|
|
|
|
/* FIXME: Ignore section markers. */
|
|
|
|
|
if (*ptr == '\0' || *ptr == ';' || *ptr == '[')
|
|
|
|
|
continue;
|
|
|
|
|
begin = ptr;
|
|
|
|
|
while (*ptr && *ptr != '=' && *ptr != ' ' && *ptr != '\t')
|
|
|
|
|
ptr++;
|
|
|
|
|
end = ptr - 1;
|
|
|
|
|
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
|
|
|
ptr++;
|
|
|
|
|
if (*ptr != '=')
|
|
|
|
|
continue;
|
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
|
|
if (begin > end)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* We found a key. */
|
|
|
|
|
*keys = malloc (end - begin + 2);
|
|
|
|
|
if (!keys)
|
|
|
|
|
return;
|
|
|
|
|
ptr2 = *keys;
|
|
|
|
|
while (begin <= end)
|
|
|
|
|
*(ptr2++) = *(begin++);
|
|
|
|
|
*ptr2 = '\0';
|
|
|
|
|
|
|
|
|
|
*values = NULL;
|
|
|
|
|
|
|
|
|
|
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
|
|
|
ptr++;
|
|
|
|
|
begin = ptr;
|
|
|
|
|
/* In this case, end points to the byte after the value, which
|
|
|
|
|
is OK because that is '\0'. */
|
|
|
|
|
end = &line[strlen (line)];
|
|
|
|
|
if (begin > end)
|
|
|
|
|
begin = end;
|
|
|
|
|
|
|
|
|
|
/* Strip quotes. */
|
|
|
|
|
if (*begin == '"' && end[-1] == '"')
|
|
|
|
|
{
|
|
|
|
|
begin++;
|
|
|
|
|
end--;
|
|
|
|
|
*end = '\0';
|
|
|
|
|
}
|
|
|
|
|
if (begin > end)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
*values = malloc (end - begin + 1);
|
|
|
|
|
ptr2 = *values;
|
|
|
|
|
while (begin <= end)
|
|
|
|
|
*(ptr2++) = *(begin++);
|
|
|
|
|
|
|
|
|
|
keys++;
|
|
|
|
|
values++;
|
|
|
|
|
max--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose (conf);
|
|
|
|
|
*keys = NULL;
|
|
|
|
|
*values = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
config_lookup (char *key)
|
|
|
|
|
{
|
|
|
|
|
#define MAX_KEYS 128
|
|
|
|
|
static int initialised = 0;
|
|
|
|
|
static char *keys[MAX_KEYS];
|
|
|
|
|
static char *values[MAX_KEYS];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (initialised == 0)
|
|
|
|
|
{
|
|
|
|
|
initialised = 1;
|
|
|
|
|
config_init (keys, values, MAX_KEYS);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
MessageBox(g_hwndParent, "Configuration File:", 0, MB_OK);
|
|
|
|
|
i = 0;
|
|
|
|
|
while (keys[i])
|
|
|
|
|
{
|
|
|
|
|
char buf[256];
|
|
|
|
|
sprintf (buf, "%s=%s\r\n", keys[i], values[i]);
|
|
|
|
|
MessageBox (g_hwndParent, buf, 0, MB_OK);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
while (keys[i])
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp (keys[i], key))
|
|
|
|
|
return values[i];
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
config_fetch (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
char key[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
char *value;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: key. */
|
|
|
|
|
if (popstring (key, sizeof (key)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = config_lookup (key);
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, value == NULL ? "" : value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
config_fetch_bool (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
char key[256];
|
|
|
|
|
int err = 0;
|
|
|
|
|
char *value;
|
|
|
|
|
int result;
|
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: key. */
|
|
|
|
|
if (popstring (key, sizeof (key)))
|
|
|
|
|
err = 1;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = config_lookup (key);
|
|
|
|
|
if (value == NULL || *value == '\0')
|
|
|
|
|
{
|
|
|
|
|
setuservariable (INST_R0, "");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
if (!strcasecmp (value, "true")
|
|
|
|
|
|| !strcasecmp (value, "yes")
|
|
|
|
|
|| atoi (value) != 0)
|
|
|
|
|
result = 1;
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, result == 0 ? "0" : "1");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a string from the Win32 Registry or NULL in case of error.
|
|
|
|
|
Caller must release the return value. A NULL for root is an alias
|
|
|
|
|
for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
|
|
|
|
|
char *
|
|
|
|
|
read_w32_registry_string (HKEY root, const char *dir, const char *name)
|
|
|
|
|
{
|
|
|
|
|
HKEY root_key;
|
|
|
|
|
HKEY key_handle;
|
|
|
|
|
DWORD n1, nbytes, type;
|
|
|
|
|
char *result = NULL;
|
|
|
|
|
|
|
|
|
|
root_key = root;
|
|
|
|
|
if (! root_key)
|
|
|
|
|
root_key = HKEY_CURRENT_USER;
|
|
|
|
|
|
|
|
|
|
if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
|
|
|
|
|
{
|
|
|
|
|
if (root)
|
|
|
|
|
return NULL; /* no need for a RegClose, so return direct */
|
|
|
|
|
/* It seems to be common practise to fall back to HKLM. */
|
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
|
|
|
|
|
return NULL; /* still no need for a RegClose, so return direct */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nbytes = 1;
|
|
|
|
|
if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
|
|
|
|
|
if (root)
|
|
|
|
|
goto leave;
|
|
|
|
|
/* Try to fallback to HKLM also vor a missing value. */
|
|
|
|
|
RegCloseKey (key_handle);
|
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
|
|
|
|
|
return NULL; /* Nope. */
|
|
|
|
|
if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = malloc( (n1=nbytes+1) );
|
|
|
|
|
|
|
|
|
|
if( !result )
|
|
|
|
|
goto leave;
|
|
|
|
|
if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
|
|
|
|
|
free(result); result = NULL;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
result[nbytes] = 0; /* make sure it is really a string */
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
RegCloseKey( key_handle );
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define ENV_HK HKEY_LOCAL_MACHINE
|
|
|
|
|
#define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \
|
|
|
|
|
"Session Manager\\Environment"
|
|
|
|
|
/* The following setting can be used for a per-user setting. */
|
2017-05-03 14:40:16 +02:00
|
|
|
|
#define ENV_HK_USER HKEY_CURRENT_USER
|
|
|
|
|
#define ENV_REG_USER "Environment"
|
2014-08-12 10:36:30 +02:00
|
|
|
|
/* Due to a bug in Windows7 (kb 2685893) we better put a lower limit
|
2014-06-10 19:42:34 +02:00
|
|
|
|
than 8191 on the maximum length of the PATH variable. Note, that
|
2014-08-12 10:36:30 +02:00
|
|
|
|
depending on the used toolchain we used to had a 259 byte limit in
|
2014-06-10 19:42:34 +02:00
|
|
|
|
the past. */
|
|
|
|
|
#define PATH_LENGTH_LIMIT 2047
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
path_add (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
char dir[PATH_LENGTH_LIMIT];
|
2017-05-03 14:40:16 +02:00
|
|
|
|
char is_user_install[2];
|
2014-06-10 19:42:34 +02:00
|
|
|
|
char *path;
|
|
|
|
|
char *path_new;
|
|
|
|
|
int path_new_size;
|
|
|
|
|
char *comp;
|
|
|
|
|
const char delims[] = ";";
|
2017-05-03 14:40:16 +02:00
|
|
|
|
int is_user;
|
2014-06-10 19:42:34 +02:00
|
|
|
|
HKEY key_handle = 0;
|
2017-05-03 14:40:16 +02:00
|
|
|
|
HKEY root_key;
|
|
|
|
|
const char *env_reg;
|
2014-06-10 19:42:34 +02:00
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "0");
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 1", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: path component. */
|
|
|
|
|
if (popstring (dir, sizeof (dir)))
|
|
|
|
|
return;
|
|
|
|
|
|
2017-05-03 14:40:16 +02:00
|
|
|
|
/* The expected stack layout: HKEY component. */
|
|
|
|
|
if (popstring (is_user_install, sizeof (is_user_install)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(is_user_install, "1"))
|
|
|
|
|
{
|
|
|
|
|
root_key = ENV_HK_USER;
|
|
|
|
|
env_reg = ENV_REG_USER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
root_key = ENV_HK;
|
|
|
|
|
env_reg = ENV_REG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path = read_w32_registry_string (root_key, env_reg, "Path");
|
2014-06-10 19:42:34 +02:00
|
|
|
|
|
|
|
|
|
if (! path)
|
|
|
|
|
{
|
2017-05-03 14:40:16 +02:00
|
|
|
|
path = strdup ("");
|
2014-06-10 19:42:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
/* Old path plus semicolon plus dir plus terminating nul. */
|
|
|
|
|
path_new_size = strlen (path) + 1 + strlen (dir) + 1;
|
|
|
|
|
if (path_new_size > PATH_LENGTH_LIMIT)
|
|
|
|
|
{
|
|
|
|
|
MessageBox (g_hwndParent, "PATH env variable too big", 0, MB_OK);
|
|
|
|
|
free (path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 4", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
path_new = malloc (path_new_size);
|
|
|
|
|
if (!path_new)
|
|
|
|
|
{
|
|
|
|
|
free (path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 5", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
strcpy (path_new, path);
|
|
|
|
|
strcat (path_new, ";");
|
|
|
|
|
strcat (path_new, dir);
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 6", 0, MB_OK); */
|
|
|
|
|
/* MessageBox (g_hwndParent, dir, 0, MB_OK); */
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 7", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
/* Check if the directory already exists in the path. */
|
|
|
|
|
comp = strtok (path, delims);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
/* MessageBox (g_hwndParent, comp, 0, MB_OK); */
|
2017-05-03 14:40:16 +02:00
|
|
|
|
if (!comp)
|
|
|
|
|
break;
|
2014-06-10 19:42:34 +02:00
|
|
|
|
|
|
|
|
|
if (!strcmp (comp, dir))
|
|
|
|
|
{
|
|
|
|
|
free (path);
|
|
|
|
|
free (path_new);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
comp = strtok (NULL, delims);
|
|
|
|
|
}
|
|
|
|
|
while (comp);
|
|
|
|
|
free (path);
|
|
|
|
|
|
2017-05-03 14:40:16 +02:00
|
|
|
|
/* Update the path key. */
|
|
|
|
|
RegCreateKey (root_key, env_reg, &key_handle);
|
2014-06-10 19:42:34 +02:00
|
|
|
|
RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
|
|
|
|
|
path_new, path_new_size);
|
|
|
|
|
RegCloseKey (key_handle);
|
|
|
|
|
SetEnvironmentVariable("PATH", path_new);
|
|
|
|
|
free (path_new);
|
|
|
|
|
|
|
|
|
|
/* MessageBox (g_hwndParent, "XXX 9", 0, MB_OK); */
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __declspec(dllexport)
|
|
|
|
|
path_remove (HWND hwndParent, int string_size, char *variables,
|
|
|
|
|
stack_t **stacktop, extra_parameters_t *extra)
|
|
|
|
|
{
|
|
|
|
|
char dir[PATH_LENGTH_LIMIT];
|
2017-05-03 14:40:16 +02:00
|
|
|
|
char is_user_install[2];
|
2014-06-10 19:42:34 +02:00
|
|
|
|
char *path;
|
|
|
|
|
char *path_new;
|
|
|
|
|
int path_new_size;
|
|
|
|
|
char *comp;
|
|
|
|
|
const char delims[] = ";";
|
|
|
|
|
HKEY key_handle = 0;
|
|
|
|
|
int changed = 0;
|
|
|
|
|
int count = 0;
|
2017-05-03 14:40:16 +02:00
|
|
|
|
HKEY root_key;
|
|
|
|
|
const char *env_reg;
|
2014-06-10 19:42:34 +02:00
|
|
|
|
|
|
|
|
|
g_hwndParent = hwndParent;
|
|
|
|
|
EXDLL_INIT();
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "0");
|
|
|
|
|
|
|
|
|
|
/* The expected stack layout: path component. */
|
|
|
|
|
if (popstring (dir, sizeof (dir)))
|
|
|
|
|
return;
|
|
|
|
|
|
2017-05-03 14:40:16 +02:00
|
|
|
|
/* The expected stack layout: HKEY component. */
|
|
|
|
|
if (popstring (is_user_install, sizeof (is_user_install)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(is_user_install, "1"))
|
|
|
|
|
{
|
|
|
|
|
root_key = ENV_HK_USER;
|
|
|
|
|
env_reg = ENV_REG_USER;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
root_key = ENV_HK;
|
|
|
|
|
env_reg = ENV_REG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path = read_w32_registry_string (root_key, env_reg, "Path");
|
|
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
|
return;
|
2014-06-10 19:42:34 +02:00
|
|
|
|
/* Old path plus semicolon plus dir plus terminating nul. */
|
|
|
|
|
path_new_size = strlen (path) + 1;
|
|
|
|
|
path_new = malloc (path_new_size);
|
|
|
|
|
if (!path_new)
|
|
|
|
|
{
|
|
|
|
|
free (path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
path_new[0] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Compose the new path. */
|
|
|
|
|
comp = strtok (path, delims);
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (comp, dir))
|
|
|
|
|
{
|
|
|
|
|
if (count != 0)
|
|
|
|
|
strcat (path_new, ";");
|
|
|
|
|
strcat (path_new, comp);
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
changed = 1;
|
|
|
|
|
|
|
|
|
|
comp = strtok (NULL, delims);
|
|
|
|
|
}
|
|
|
|
|
while (comp);
|
|
|
|
|
free (path);
|
|
|
|
|
|
|
|
|
|
if (! changed)
|
2017-06-07 15:30:14 +02:00
|
|
|
|
{
|
|
|
|
|
free (path_new);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-06-10 19:42:34 +02:00
|
|
|
|
|
|
|
|
|
/* Set a key for our CLSID. */
|
2017-05-03 14:40:16 +02:00
|
|
|
|
RegCreateKey (root_key, env_reg, &key_handle);
|
2014-06-10 19:42:34 +02:00
|
|
|
|
RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ,
|
|
|
|
|
path_new, path_new_size);
|
|
|
|
|
RegCloseKey (key_handle);
|
|
|
|
|
free (path_new);
|
|
|
|
|
|
|
|
|
|
setuservariable (INST_R0, "1");
|
|
|
|
|
}
|