Set log on details in the GUI.
authorIain Patterson <me@iain.cx>
Sun, 22 Dec 2013 12:05:48 +0000 (12:05 +0000)
committerIain Patterson <me@iain.cx>
Sun, 22 Dec 2013 12:05:48 +0000 (12:05 +0000)
The GUI can now set service logon and desktop interactive details.

ChangeLog.txt
README.txt
gui.cpp
messages.mc
nssm.rc
resource.h
service.cpp
service.h

index 8bd2dd0..911aa4d 100644 (file)
@@ -6,8 +6,8 @@ Changes since 2.21
   * Unqualified path names are now relative to the
     application startup directory when redirecting I/O.
 
-  * NSSM can now set the service display name, description
-    and startup type.
+  * NSSM can now set the service display name, description,
+    startup type and log on details.
 
 Changes since 2.20
 ------------------
index 8be1383..d650970 100644 (file)
@@ -55,8 +55,8 @@ AppEnvironment.
 \r
 Since version 2.22, NSSM can rotate existing output files when redirecting I/O.\r
 \r
-Since version 2.22, NSSM can set service display name, description and startup\r
-type.\r
+Since version 2.22, NSSM can set service display name, description, startup\r
+type and log on details.\r
 \r
 \r
 Usage\r
diff --git a/gui.cpp b/gui.cpp
index ef4b450..80d74ef 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -1,6 +1,6 @@
 #include "nssm.h"\r
 \r
-static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
+static enum { NSSM_TAB_APPLICATION, NSSM_TAB_DETAILS, NSSM_TAB_LOGON, NSSM_TAB_SHUTDOWN, NSSM_TAB_EXIT, NSSM_TAB_IO, NSSM_TAB_ROTATION, NSSM_TAB_ENVIRONMENT, NSSM_NUM_TABS };\r
 static HWND tablist[NSSM_NUM_TABS];\r
 static int selected_tab;\r
 \r
@@ -49,7 +49,7 @@ void centre_window(HWND window) {
 \r
   /* Find window size */\r
   if (! GetWindowRect(window, &size)) return;\r
-  \r
+\r
   /* Find desktop window */\r
   desktop = GetDesktopWindow();\r
   if (! desktop) return;\r
@@ -80,6 +80,12 @@ static inline void set_timeout_enabled(unsigned long control, unsigned long depe
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_SHUTDOWN], dependent), enabled);\r
 }\r
 \r
+static inline void set_logon_enabled(unsigned char enabled) {\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), enabled);\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), enabled);\r
+  EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), enabled);\r
+}\r
+\r
 static inline void set_rotation_enabled(unsigned char enabled) {\r
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_SECONDS), enabled);\r
   EnableWindow(GetDlgItem(tablist[NSSM_TAB_ROTATION], IDC_ROTATE_BYTES_LOW), enabled);\r
@@ -146,6 +152,112 @@ int install(HWND window) {
     service->startup = (unsigned long) SendMessage(combo, CB_GETCURSEL, 0, 0);\r
     if (service->startup == CB_ERR) service->startup = 0;\r
 \r
+    /* Get logon stuff. */\r
+    if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+      if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+        service->type |= SERVICE_INTERACTIVE_PROCESS;\r
+      }\r
+    }\r
+    else {\r
+      /* Username. */\r
+      service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
+      if (! service->usernamelen) {\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_USERNAME);\r
+        return 6;\r
+      }\r
+      service->usernamelen++;\r
+\r
+      service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
+      if (! service->username) {\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
+        return 6;\r
+      }\r
+      if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username, (int) service->usernamelen)) {\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_USERNAME);\r
+        return 6;\r
+      }\r
+\r
+      /* Password. */\r
+      service->passwordlen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), WM_GETTEXTLENGTH, 0, 0);\r
+      if (! service->passwordlen) {\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
+        return 6;\r
+      }\r
+      if (SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), WM_GETTEXTLENGTH, 0, 0) != service->passwordlen) {\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
+        return 6;\r
+      }\r
+      service->passwordlen++;\r
+\r
+      /* Temporary buffer for password validation. */\r
+      TCHAR *password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
+      if (! password) {\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password confirmation"), _T("install()"));\r
+        return 6;\r
+      }\r
+\r
+      /* Actual password buffer. */\r
+      service->password = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->passwordlen * sizeof(TCHAR));\r
+      if (! service->password) {\r
+        HeapFree(GetProcessHeap(), 0, password);\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("password"), _T("install()"));\r
+        return 6;\r
+      }\r
+\r
+      /* Get first password. */\r
+      if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1, service->password, (int) service->passwordlen)) {\r
+        HeapFree(GetProcessHeap(), 0, password);\r
+        SecureZeroMemory(service->password, service->passwordlen);\r
+        HeapFree(GetProcessHeap(), 0, service->password);\r
+        service->password = 0;\r
+        service->passwordlen = 0;\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
+        return 6;\r
+      }\r
+\r
+      /* Get confirmation. */\r
+      if (! GetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2, password, (int) service->passwordlen)) {\r
+        SecureZeroMemory(password, service->passwordlen);\r
+        HeapFree(GetProcessHeap(), 0, password);\r
+        SecureZeroMemory(service->password, service->passwordlen);\r
+        HeapFree(GetProcessHeap(), 0, service->password);\r
+        service->password = 0;\r
+        service->passwordlen = 0;\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_INVALID_PASSWORD);\r
+        return 6;\r
+      }\r
+\r
+      /* Compare. */\r
+      if (_tcsncmp(password, service->password, service->passwordlen)) {\r
+        popup_message(MB_OK | MB_ICONEXCLAMATION, NSSM_GUI_MISSING_PASSWORD);\r
+        SecureZeroMemory(password, service->passwordlen);\r
+        HeapFree(GetProcessHeap(), 0, password);\r
+        SecureZeroMemory(service->password, service->passwordlen);\r
+        HeapFree(GetProcessHeap(), 0, service->password);\r
+        service->password = 0;\r
+        service->passwordlen = 0;\r
+        HeapFree(GetProcessHeap(), 0, service->username);\r
+        service->username = 0;\r
+        service->usernamelen = 0;\r
+        return 6;\r
+      }\r
+    }\r
+\r
     /* Get stop method stuff. */\r
     check_stop_method(service, NSSM_STOP_METHOD_CONSOLE, IDC_METHOD_CONSOLE);\r
     check_stop_method(service, NSSM_STOP_METHOD_WINDOW, IDC_METHOD_WINDOW);\r
@@ -429,6 +541,15 @@ INT_PTR CALLBACK tab_dlg(HWND tab, UINT message, WPARAM w, LPARAM l) {
           browse(dlg, buffer, OFN_NOVALIDATE, NSSM_GUI_BROWSE_FILTER_DIRECTORIES, 0);\r
           break;\r
 \r
+        /* Log on. */\r
+        case IDC_LOCALSYSTEM:\r
+          set_logon_enabled(0);\r
+          break;\r
+\r
+        case IDC_ACCOUNT:\r
+          set_logon_enabled(1);\r
+          break;\r
+\r
         /* Shutdown methods. */\r
         case IDC_METHOD_CONSOLE:\r
           set_timeout_enabled(LOWORD(w), IDC_KILL_CONSOLE);\r
@@ -521,6 +642,17 @@ INT_PTR CALLBACK install_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       SendMessage(combo, CB_INSERTSTRING, NSSM_STARTUP_DISABLED, (LPARAM) message_string(NSSM_GUI_STARTUP_DISABLED));\r
       SendMessage(combo, CB_SETCURSEL, NSSM_STARTUP_AUTOMATIC, 0);\r
 \r
+      /* Logon tab. */\r
+      tab.pszText = message_string(NSSM_GUI_TAB_LOGON);\r
+      tab.cchTextMax = (int) _tcslen(tab.pszText);\r
+      SendMessage(tabs, TCM_INSERTITEM, NSSM_TAB_LOGON, (LPARAM) &tab);\r
+      tablist[NSSM_TAB_LOGON] = CreateDialog(0, MAKEINTRESOURCE(IDD_LOGON), window, tab_dlg);\r
+      ShowWindow(tablist[NSSM_TAB_LOGON], SW_HIDE);\r
+\r
+      /* Set defaults. */\r
+      CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
+      set_logon_enabled(0);\r
+\r
       /* Shutdown tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_SHUTDOWN);\r
       tab.cchTextMax = (int) _tcslen(tab.pszText);\r
index 427905e..4304d98 100644 (file)
@@ -297,6 +297,58 @@ Nessuna opzione valida specificata!
 .
 
 MessageId = +1
+SymbolicName = NSSM_GUI_MISSING_USERNAME
+Severity = Informational
+Language = English
+Missing account name!
+.
+Language = French
+Missing account name!
+.
+Language = Italian
+Missing account name!
+.
+
+MessageId = +1
+SymbolicName = NSSM_GUI_INVALID_USERNAME
+Severity = Informational
+Language = English
+Invalid account name!
+.
+Language = French
+Invalid account name!
+.
+Language = Italian
+Invalid account name!
+.
+
+MessageId = +1
+SymbolicName = NSSM_GUI_MISSING_PASSWORD
+Severity = Informational
+Language = English
+Missing or mismatched password(s)!
+.
+Language = French
+Missing or mismatched password(s)!
+.
+Language = Italian
+Missing or mismatched password(s)!
+.
+
+MessageId = +1
+SymbolicName = NSSM_GUI_INVALID_PASSWORD
+Severity = Informational
+Language = English
+Invalid password!
+.
+Language = French
+Invalid password!
+.
+Language = Italian
+Invalid password!
+.
+
+MessageId = +1
 SymbolicName = NSSM_GUI_INVALID_DISPLAYNAME
 Severity = Informational
 Language = English
@@ -511,6 +563,19 @@ Details%0
 .
 
 MessageId = +1
+SymbolicName = NSSM_GUI_TAB_LOGON
+Severity = Informational
+Language = English
+Log on%0
+.
+Language = French
+Log on%0
+.
+Language = Italian
+Log on%0
+.
+
+MessageId = +1
 SymbolicName = NSSM_GUI_TAB_SHUTDOWN
 Severity = Informational
 Language = English
diff --git a/nssm.rc b/nssm.rc
index 62b6508..5c21be3 100644 (file)
--- a/nssm.rc
+++ b/nssm.rc
@@ -119,6 +119,22 @@ FONT 8, "MS Sans Serif"
 }\r
 \r
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
+IDD_LOGON DIALOG 9, 20, 261, 75\r
+STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
+FONT 8, "MS Sans Serif"\r
+{\r
+    GROUPBOX        "Log on as", IDC_STATIC, 7, 7, 251, 68\r
+    AUTORADIOBUTTON "Local System account", IDC_LOCALSYSTEM, 13, 18, 86, 8\r
+    AUTOCHECKBOX    "Allow service to interact with desktop", IDC_INTERACT, 101, 18, 133, 8\r
+    AUTORADIOBUTTON "This account:", IDC_ACCOUNT, 13, 32, 59, 8\r
+    EDITTEXT        IDC_USERNAME, 75, 30, 178, 12, ES_AUTOHSCROLL\r
+    LTEXT           "Password:", IDC_STATIC, 25, 46, 32, 8, SS_LEFT\r
+    EDITTEXT        IDC_PASSWORD1, 75, 44, 178, 12, ES_AUTOHSCROLL | ES_PASSWORD\r
+    LTEXT           "Confirm:", IDC_STATIC, 25, 60, 26, 8, SS_LEFT\r
+    EDITTEXT        IDC_PASSWORD2, 75, 58, 178, 12, ES_AUTOHSCROLL | ES_PASSWORD\r
+}\r
+\r
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
 IDD_SHUTDOWN DIALOG 9, 20, 261, 75\r
 STYLE DS_SHELLFONT | WS_VISIBLE | WS_CHILD | DS_CONTROL\r
 FONT 8, "MS Sans Serif"\r
index accc4b7..6964003 100644 (file)
@@ -8,11 +8,12 @@
 #define IDD_REMOVE                      103\r
 #define IDD_APPLICATION                 104\r
 #define IDD_DETAILS                     105\r
-#define IDD_IO                          106\r
-#define IDD_ROTATION                    107\r
-#define IDD_APPEXIT                     108\r
-#define IDD_SHUTDOWN                    109\r
-#define IDD_ENVIRONMENT                 110\r
+#define IDD_LOGON                       106\r
+#define IDD_IO                          107\r
+#define IDD_ROTATION                    108\r
+#define IDD_APPEXIT                     109\r
+#define IDD_SHUTDOWN                    110\r
+#define IDD_ENVIRONMENT                 111\r
 #define IDC_PATH                        1000\r
 #define IDC_TAB1                        1001\r
 #define IDC_CANCEL                      1002\r
 #define IDC_DISPLAYNAME                 1031\r
 #define IDC_DESCRIPTION                 1032\r
 #define IDC_STARTUP                     1033\r
+#define IDC_LOCALSYSTEM                 1034\r
+#define IDC_INTERACT                    1035\r
+#define IDC_ACCOUNT                     1036\r
+#define IDC_USERNAME                    1037\r
+#define IDC_PASSWORD1                   1038\r
+#define IDC_PASSWORD2                   1039\r
 \r
 // Next default values for new objects\r
 // \r
 #ifdef APSTUDIO_INVOKED\r
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
-#define _APS_NEXT_RESOURCE_VALUE        111\r
+#define _APS_NEXT_RESOURCE_VALUE        112\r
 #define _APS_NEXT_COMMAND_VALUE         40001\r
-#define _APS_NEXT_CONTROL_VALUE         1034\r
+#define _APS_NEXT_CONTROL_VALUE         1040\r
 #define _APS_NEXT_SYMED_VALUE           101\r
 #endif\r
 #endif\r
index 5b75a41..57dc7a2 100644 (file)
@@ -36,6 +36,7 @@ SC_HANDLE open_service_manager() {
 void set_nssm_service_defaults(nssm_service_t *service) {\r
   if (! service) return;\r
 \r
+  service->type = SERVICE_WIN32_OWN_PROCESS;\r
   service->stdin_sharing = NSSM_STDIN_SHARING;\r
   service->stdin_disposition = NSSM_STDIN_DISPOSITION;\r
   service->stdin_flags = NSSM_STDIN_FLAGS;\r
@@ -62,6 +63,11 @@ nssm_service_t *alloc_nssm_service() {
 /* Free memory for a service. */\r
 void cleanup_nssm_service(nssm_service_t *service) {\r
   if (! service) return;\r
+  if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
+  if (service->password) {\r
+    SecureZeroMemory(service->password, service->passwordlen);\r
+    HeapFree(GetProcessHeap(), 0, service->password);\r
+  }\r
   if (service->env) HeapFree(GetProcessHeap(), 0, service->env);\r
   if (service->env_extra) HeapFree(GetProcessHeap(), 0, service->env_extra);\r
   if (service->handle) CloseServiceHandle(service->handle);\r
@@ -145,6 +151,13 @@ int install_service(nssm_service_t *service) {
   TCHAR command[MAX_PATH];\r
   GetModuleFileName(0, command, _countof(command));\r
 \r
+  /*\r
+    The only two valid flags for service type are SERVICE_WIN32_OWN_PROCESS\r
+    and SERVICE_INTERACTIVE_PROCESS.\r
+  */\r
+  service->type &= SERVICE_INTERACTIVE_PROCESS;\r
+  service->type |= SERVICE_WIN32_OWN_PROCESS;\r
+\r
   /* Startup type. */\r
   unsigned long startup;\r
   switch (service->startup) {\r
@@ -157,7 +170,7 @@ int install_service(nssm_service_t *service) {
   if (! service->displayname[0]) _sntprintf_s(service->displayname, _countof(service->displayname), _TRUNCATE, _T("%s"), service->name);\r
 \r
   /* Create the service */\r
-  service->handle = CreateService(services, service->name, service->displayname, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, startup, SERVICE_ERROR_NORMAL, command, 0, 0, 0, 0, 0);\r
+  service->handle = CreateService(services, service->name, service->displayname, SC_MANAGER_ALL_ACCESS, service->type, startup, SERVICE_ERROR_NORMAL, command, 0, 0, 0, service->username, service->password);\r
   if (! service->handle) {\r
     print_message(stderr, NSSM_MESSAGE_CREATESERVICE_FAILED);\r
     CloseServiceHandle(services);\r
index 474f365..dc1715b 100644 (file)
--- a/service.h
+++ b/service.h
@@ -22,6 +22,11 @@ typedef struct {
   TCHAR displayname[SERVICE_DISPLAYNAME_LENGTH];\r
   TCHAR description[VALUE_LENGTH];\r
   unsigned long startup;\r
+  TCHAR *username;\r
+  size_t usernamelen;\r
+  TCHAR *password;\r
+  size_t passwordlen;\r
+  unsigned long type;\r
   TCHAR exe[EXE_LENGTH];\r
   TCHAR flags[VALUE_LENGTH];\r
   TCHAR dir[MAX_PATH];\r