"LocalSystem" aka "System" aka "NT Authority\System"\r
"LocalService" aka "Local Service" aka "NT Authority\Local Service"\r
"NetworkService" aka "Network Service" aka "NT Authority\Network Service"\r
+ Virtual service account "NT Service\<servicename>"\r
\r
\r
The Start parameter is used to query or set the startup type of the service.\r
Thanks to David Bremner for general tidyups.\r
Thanks to Nabil Redmann for suggesting redirecting hooks' output.\r
Thanks to Bader Aldurai for suggesting the process tree.\r
+Thanks to Christian Long for suggesting virtual accounts.\r
\r
Licence\r
-------\r
}\r
\r
if (translated_sid->Use != SidTypeUser && translated_sid->Use != SidTypeWellKnownGroup) {\r
- LsaFreeMemory(translated_domains);\r
- LsaFreeMemory(translated_sid);\r
- print_message(stderr, NSSM_GUI_INVALID_USERNAME, username);\r
- return 6;\r
+ if (translated_sid->Use != SidTypeUnknown || _tcsnicmp(NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN _T("\\"), username, _tcslen(NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN) + 1)) {\r
+ LsaFreeMemory(translated_domains);\r
+ LsaFreeMemory(translated_sid);\r
+ print_message(stderr, NSSM_GUI_INVALID_USERNAME, username);\r
+ return 6;\r
+ }\r
}\r
\r
LSA_TRUST_INFORMATION *trust = &translated_domains->Domains[translated_sid->DomainIndex];\r
return ret;\r
}\r
\r
+/* Does the username represent a virtual account for the service? */\r
+int is_virtual_account(const TCHAR *service_name, const TCHAR *username) {\r
+ if (! imports.IsWellKnownSid) return 0;\r
+ if (! service_name) return 0;\r
+ if (! username) return 0;\r
+\r
+ size_t len = _tcslen(NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN) + _tcslen(service_name) + 2;\r
+ TCHAR *canon = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));\r
+ if (! canon) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("is_virtual_account"));\r
+ return 0;\r
+ }\r
+ _sntprintf_s(canon, len, _TRUNCATE, _T("%s\\%s"), NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN, service_name);\r
+ int ret = str_equiv(canon, username);\r
+ HeapFree(GetProcessHeap(), 0, canon);\r
+ return ret;\r
+}\r
+\r
/*\r
Get well-known alias for LocalSystem and friends.\r
Returns a pointer to a static string. DO NOT try to free it.\r
/* Other well-known accounts which can start a service without a password. */\r
#define NSSM_LOCALSERVICE_ACCOUNT _T("NT Authority\\LocalService")\r
#define NSSM_NETWORKSERVICE_ACCOUNT _T("NT Authority\\NetworkService")\r
+/* Virtual service accounts. */\r
+#define NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN _T("NT Service")\r
/* This is explicitly a wide string. */\r
#define NSSM_LOGON_AS_SERVICE_RIGHT L"SeServiceLogonRight"\r
\r
int username_equiv(const TCHAR *, const TCHAR *);\r
int canonicalise_username(const TCHAR *, TCHAR **);\r
int is_localsystem(const TCHAR *);\r
+int is_virtual_account(const TCHAR *, const TCHAR *);\r
const TCHAR *well_known_sid(SID *);\r
const TCHAR *well_known_username(const TCHAR *);\r
int grant_logon_as_service(const TCHAR *);\r
return dialog(templ, parent, function, 0);\r
}\r
\r
+static inline void set_logon_enabled(unsigned char interact_enabled, unsigned char credentials_enabled) {\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), interact_enabled);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), credentials_enabled);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), credentials_enabled);\r
+ EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), credentials_enabled);\r
+}\r
+\r
int nssm_gui(int resource, nssm_service_t *service) {\r
/* Create window */\r
HWND dlg = dialog(MAKEINTRESOURCE(resource), 0, nssm_dlg, (LPARAM) service);\r
\r
/* Log on tab. */\r
if (service->username) {\r
- CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_ACCOUNT);\r
- SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
- EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_INTERACT), 0);\r
- EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), 1);\r
- EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD1), 1);\r
- EnableWindow(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_PASSWORD2), 1);\r
+ if (is_virtual_account(service->name, service->username)) {\r
+ CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_VIRTUAL_SERVICE);\r
+ set_logon_enabled(0, 0);\r
+ }\r
+ else {\r
+ CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_ACCOUNT);\r
+ SetDlgItemText(tablist[NSSM_TAB_LOGON], IDC_USERNAME, service->username);\r
+ set_logon_enabled(0, 1);\r
+ }\r
}\r
else {\r
- CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
+ CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_VIRTUAL_SERVICE, IDC_LOCALSYSTEM);\r
if (service->type & SERVICE_INTERACTIVE_PROCESS) SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_INTERACT, BM_SETCHECK, BST_CHECKED, 0);\r
}\r
\r
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_INTERACT), ! 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_affinity_enabled(unsigned char enabled) {\r
EnableWindow(GetDlgItem(tablist[NSSM_TAB_PROCESS], IDC_AFFINITY), enabled);\r
}\r
service->password = 0;\r
service->passwordlen = 0;\r
}\r
+ else if (SendDlgItemMessage(tablist[NSSM_TAB_LOGON], IDC_VIRTUAL_SERVICE, BM_GETCHECK, 0, 0) & BST_CHECKED) {\r
+ if (service->username) HeapFree(GetProcessHeap(), 0, service->username);\r
+ service->usernamelen = _tcslen(NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN) + _tcslen(service->name) + 2;\r
+ service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->usernamelen * sizeof(TCHAR));\r
+ if (! service->username) {\r
+ popup_message(window, MB_OK | MB_ICONEXCLAMATION, NSSM_EVENT_OUT_OF_MEMORY, _T("account name"), _T("install()"));\r
+ return 6;\r
+ }\r
+ _sntprintf_s(service->username, service->usernamelen, _TRUNCATE, _T("%s\\%s"), NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN, service->name);\r
+ service->password = 0;\r
+ service->passwordlen = 0;\r
+ }\r
else {\r
/* Username. */\r
service->usernamelen = SendMessage(GetDlgItem(tablist[NSSM_TAB_LOGON], IDC_USERNAME), WM_GETTEXTLENGTH, 0, 0);\r
\r
/* Log on. */\r
case IDC_LOCALSYSTEM:\r
- set_logon_enabled(0);\r
+ set_logon_enabled(1, 0);\r
+ break;\r
+\r
+ case IDC_VIRTUAL_SERVICE:\r
+ set_logon_enabled(0, 0);\r
break;\r
\r
case IDC_ACCOUNT:\r
- set_logon_enabled(1);\r
+ set_logon_enabled(0, 1);\r
break;\r
\r
/* Affinity. */\r
\r
/* Set defaults. */\r
CheckRadioButton(tablist[NSSM_TAB_LOGON], IDC_LOCALSYSTEM, IDC_ACCOUNT, IDC_LOCALSYSTEM);\r
- set_logon_enabled(0);\r
+ set_logon_enabled(1, 0);\r
\r
/* Dependencies tab. */\r
tab.pszText = message_string(NSSM_GUI_TAB_DEPENDENCIES);\r
#define IDC_HOOK 1050\r
#define IDC_BROWSE_HOOK 1051\r
#define IDC_REDIRECT_HOOK 1052\r
+#define IDC_VIRTUAL_SERVICE 1053\r
\r
// Next default values for new objects\r
// \r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_NEXT_RESOURCE_VALUE 117\r
#define _APS_NEXT_COMMAND_VALUE 40001\r
-#define _APS_NEXT_CONTROL_VALUE 1053\r
+#define _APS_NEXT_CONTROL_VALUE 1054\r
#define _APS_NEXT_SYMED_VALUE 101\r
#endif\r
#endif\r
TCHAR *username = 0;\r
TCHAR *canon = 0;\r
TCHAR *password = 0;\r
+ boolean virtual_account = false;\r
if (service->usernamelen) {\r
username = service->username;\r
- if (canonicalise_username(username, &canon)) return 5;\r
- if (service->passwordlen) password = service->password;\r
+ if (is_virtual_account(service->name, username)) {\r
+ virtual_account = true;\r
+ canon = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (service->usernamelen + 1) * sizeof(TCHAR));\r
+ if (! canon) {\r
+ print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("edit_service()"));\r
+ return 5;\r
+ }\r
+ memmove(canon, username, (service->usernamelen + 1) * sizeof(TCHAR));\r
+ }\r
+ else {\r
+ if (canonicalise_username(username, &canon)) return 5;\r
+ if (service->passwordlen) password = service->password;\r
+ }\r
}\r
else if (editing) username = canon = NSSM_LOCALSYSTEM_ACCOUNT;\r
\r
- if (well_known_username(canon)) password = _T("");\r
- else {\r
- if (grant_logon_as_service(canon)) {\r
- if (canon != username) HeapFree(GetProcessHeap(), 0, canon);\r
- print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);\r
- return 5;\r
+ if (! virtual_account) {\r
+ if (well_known_username(canon)) password = _T("");\r
+ else {\r
+ if (grant_logon_as_service(canon)) {\r
+ if (canon != username) HeapFree(GetProcessHeap(), 0, canon);\r
+ print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);\r
+ return 5;\r
+ }\r
}\r
}\r
\r
That means the username is actually passed in the additional parameter.\r
*/\r
bool localsystem = false;\r
+ bool virtual_account = false;\r
TCHAR *username = NSSM_LOCALSYSTEM_ACCOUNT;\r
TCHAR *password = 0;\r
if (additional) {\r
username = (TCHAR *) well_known;\r
password = _T("");\r
}\r
+ else if (is_virtual_account(service_name, username)) virtual_account = true;\r
else if (! password) {\r
/* We need a password if the account requires it. */\r
print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);\r
HeapFree(GetProcessHeap(), 0, qsc);\r
}\r
\r
- if (! well_known) {\r
+ if (! well_known && ! virtual_account) {\r
if (grant_logon_as_service(username)) {\r
if (passwordsize) SecureZeroMemory(password, passwordsize);\r
print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);\r