2007-08-04 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Sat, 4 Aug 2007 03:20:40 +0000 (03:20 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Sat, 4 Aug 2007 03:20:40 +0000 (03:20 +0000)
* src/g4wihelp.c (service_error, service_create, service_lookup,
service_start, service_stop, service_delete): New functions.
* src/inst-dirmngr.nsi: Register and start the service.
* src/uninst-dirmngr.nsi: Stop and unregister the service.

* src/inst-sections.nsi: Add dirmngr as dependency for gnupg2, and
w32pth as dependency for dirmngr.

* src/Makefile.am (gpg4win_pkg_gnupg2_configure): Add
--with-pth-prefix.

ChangeLog
src/Makefile.am
src/g4wihelp.c
src/inst-dirmngr.nsi
src/inst-sections.nsi
src/uninst-dirmngr.nsi

index 0294ce9..101d438 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-08-04  Marcus Brinkmann  <marcus@g10code.de>
+
+       * src/g4wihelp.c (service_error, service_create, service_lookup,
+       service_start, service_stop, service_delete): New functions.
+       * src/inst-dirmngr.nsi: Register and start the service.
+       * src/uninst-dirmngr.nsi: Stop and unregister the service.
+
+       * src/inst-sections.nsi: Add dirmngr as dependency for gnupg2, and
+       w32pth as dependency for dirmngr.
+
+       * src/Makefile.am (gpg4win_pkg_gnupg2_configure): Add
+       --with-pth-prefix.
+
 2007-07-10  Werner Koch  <wk@g10code.com>
 
        Released 1.1.1.
index 9eaf6b5..6948e75 100644 (file)
@@ -125,7 +125,8 @@ gpg4win_pkg_dirmngr_configure = \
   --with-gpg-error-prefix=$(idir) \
   --with-ksba-prefix=$(idir) \
   --with-libgcrypt-prefix=$(idir) \
-  --with-libassuan-prefix=$(idir)
+  --with-libassuan-prefix=$(idir) \
+  --with-pth-prefix=$(idir)
 
 gpg4win_pkg_gnupg2_configure = \
   --with-gpg-error-prefix=$(idir) \
index 7afb859..51dd04b 100644 (file)
@@ -266,3 +266,314 @@ showsplash (HWND hwndParent, int string_size, char *variables,
     }
   UnregisterClass (classname, g_hInstance);
 }
+
+\f
+/* Service Management.  */
+
+/* Use this to report unexpected errors.  FIXME: This is really not
+   very descriptive.  */
+void
+service_error (const char *str)
+{
+  char buf[1024];
+  snprintf (buf, sizeof (buf) - 1, "error: %s: ec=%d\r\n", str,
+           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,
+                          /* FIXME: As long as we are debugging... */
+                          SERVICE_DEMAND_START /* SERVICE_AUTO_START */,
+                          SERVICE_ERROR_NORMAL, program,
+                          NULL, NULL, NULL,
+                          NULL /* FIXME: "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];
+  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, 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;
+
+  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 = ControlService (service, SERVICE_CONTROL_STOP, &status);
+  if (err == 0)
+    {
+      service_error ("ControlService");
+      CloseServiceHandle (service);
+      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;
+}
+
index fbdffe9..e91b2ef 100644 (file)
@@ -33,8 +33,37 @@ Section "-dirmngr" SEC_dirmngr
 !ifdef SOURCES
   File "${gpg4win_pkg_dirmngr}"
 !else
+  Var /GLOBAL DirMngrStatus
+  g4wihelp::service_query "DirMngr"
+  StrCpy $DirMngrStatus $R0
+
+  StrCmp $DirMngrStatus "MISSING" dirmngr_stopped
+  # Try to stop the daemon in case it is running.
+  g4wihelp::service_stop "DirMngr"
+dirmngr_stopped:
+
   File "${prefix}/bin/dirmngr.exe"
+  File "${prefix}/bin/dirmngr-client.exe"
+  File "${prefix}/libexec/dirmngr_ldap.exe"
+
+  # We need to create the cache directory, as this is not
+  # automatically created by dirmngr.  Actually, the default should be
+  # different.  FIXME.
+  CreateDirectory "$INSTDIR\cache"
+
+  # FIXME: Error checking.  Also, check if --service really reaches
+  # the service both times.
+
+  StrCmp $DirMngrStatus "MISSING" 0 dirmngr_created
+    # Create the service.
+    g4wihelp::service_create "DirMngr" "DirMngr" '"$INSTDIR\dirmngr.exe" --service'
+dirmngr_created:
+
+  # We only start the dirmngr if it was running before.
+  StrCmp $DirMngrStatus "RUNNING" 0 dirmngr_restarted
+  # Start the service.
+  g4wihelp::service_start "DirMngr" "1" "\"$INSTDIR\dirmngr.exe\""
+dirmngr_restarted:
 
 !endif
 SectionEnd
-
index c2252ff..da937dc 100644 (file)
@@ -332,6 +332,7 @@ Function CalcDepends
   !insertmacro SelectSection ${SEC_w32pth}
   !insertmacro SelectSection ${SEC_zlib}
   !insertmacro SelectSection ${SEC_pinentry}
+  !insertmacro SelectSection ${SEC_dirmngr}
   skip_gnupg2:
 !endif
 
@@ -462,6 +463,7 @@ Function CalcDepends
   !insertmacro SelectSection ${SEC_libksba}
   !insertmacro SelectSection ${SEC_libassuan}
   !insertmacro SelectSection ${SEC_libgpg_error}
+  !insertmacro SelectSection ${SEC_w32pth}
   skip_dirmngr:
 !endif
 
index 90a1d72..b32b543 100644 (file)
@@ -31,7 +31,23 @@ Section "-un.dirmngr"
   Push "${gpg4win_pkg_dirmngr}"
   Call un.SourceDelete
 !else
+  # We need to stop before delete.
+  Var /GLOBAL DirMngrUninstStatus
+  g4wihelp::service_query "DirMngr"
+  StrCpy $DirMngrUninstStatus $R0
+  StrCmp $DirMngrUninstStatus "MISSING" dirmngr_uninst_deleted
+  StrCmp $DirMngrUninstStatus "RUNNING" 0 dirmngr_uninst_stopped
+  # Try to stop the daemon in case it is running.
+  g4wihelp::service_stop "DirMngr"
+dirmngr_uninst_stopped:
+  g4wihelp::service_delete "DirMngr"
+dirmngr_uninst_deleted:
+
   Delete "$INSTDIR\dirmngr.exe"
+  Delete "$INSTDIR\dirmngr-client.exe"
+  Delete "$INSTDIR\dirmngr_ldap.exe"
+  RMDir "$INSTDIR\cache"
+  RMDir "$INSTDIR"
 
 !endif
 SectionEnd