Use close_handle().
[nssm.git] / account.cpp
index 60d1fc6..cb7fcdb 100644 (file)
@@ -2,6 +2,10 @@
 \r
 #include <sddl.h>\r
 \r
+#ifndef STATUS_SUCCESS\r
+#define STATUS_SUCCESS ERROR_SUCCESS\r
+#endif\r
+\r
 extern imports_t imports;\r
 \r
 /* Open Policy object. */\r
@@ -10,7 +14,7 @@ int open_lsa_policy(LSA_HANDLE *policy) {
   ZeroMemory(&attributes, sizeof(attributes));\r
 \r
   NTSTATUS status = LsaOpenPolicy(0, &attributes, POLICY_ALL_ACCESS, policy);\r
-  if (status) {\r
+  if (status != STATUS_SUCCESS) {\r
     print_message(stderr, NSSM_MESSAGE_LSAOPENPOLICY_FAILED, error_string(LsaNtStatusToWinError(status)));\r
     return 1;\r
   }\r
@@ -62,34 +66,22 @@ int username_sid(const TCHAR *username, SID **sid, LSA_HANDLE *policy) {
   }\r
 \r
   LSA_UNICODE_STRING lsa_username;\r
-#ifdef UNICODE\r
-  lsa_username.Buffer = (wchar_t *) expanded;\r
-  lsa_username.Length = (unsigned short) _tcslen(expanded) * sizeof(TCHAR);\r
-  lsa_username.MaximumLength = lsa_username.Length + sizeof(TCHAR);\r
-#else\r
-  size_t buflen;\r
-  mbstowcs_s(&buflen, NULL, 0, expanded, _TRUNCATE);\r
-  lsa_username.MaximumLength = (unsigned short) buflen * sizeof(wchar_t);\r
-  lsa_username.Length = lsa_username.MaximumLength - sizeof(wchar_t);\r
-  lsa_username.Buffer = (wchar_t *) HeapAlloc(GetProcessHeap(), 0, lsa_username.MaximumLength);\r
-  if (lsa_username.Buffer) mbstowcs_s(&buflen, lsa_username.Buffer, lsa_username.MaximumLength, expanded, _TRUNCATE);\r
-  else {\r
+  int ret = to_utf16(expanded, &lsa_username.Buffer, (unsigned long *) &lsa_username.Length);\r
+  HeapFree(GetProcessHeap(), 0, expanded);\r
+  if (ret) {\r
     if (policy == &handle) LsaClose(handle);\r
-    HeapFree(GetProcessHeap(), 0, expanded);\r
     print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("LSA_UNICODE_STRING"), _T("username_sid()"));\r
     return 4;\r
   }\r
-#endif\r
+  lsa_username.Length *= sizeof(wchar_t);\r
+  lsa_username.MaximumLength = lsa_username.Length + sizeof(wchar_t);\r
 \r
   LSA_REFERENCED_DOMAIN_LIST *translated_domains;\r
   LSA_TRANSLATED_SID *translated_sid;\r
   NTSTATUS status = LsaLookupNames(*policy, 1, &lsa_username, &translated_domains, &translated_sid);\r
-#ifndef UNICODE\r
   HeapFree(GetProcessHeap(), 0, lsa_username.Buffer);\r
-#endif\r
-  HeapFree(GetProcessHeap(), 0, expanded);\r
   if (policy == &handle) LsaClose(handle);\r
-  if (status) {\r
+  if (status != STATUS_SUCCESS) {\r
     LsaFreeMemory(translated_domains);\r
     LsaFreeMemory(translated_sid);\r
     print_message(stderr, NSSM_MESSAGE_LSALOOKUPNAMES_FAILED, username, error_string(LsaNtStatusToWinError(status)));\r
@@ -97,10 +89,12 @@ int username_sid(const TCHAR *username, SID **sid, LSA_HANDLE *policy) {
   }\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
@@ -139,7 +133,7 @@ int username_sid(const TCHAR *username, SID **sid, LSA_HANDLE *policy) {
     else *sub = translated_sid->RelativeId;\r
   }\r
 \r
-  int ret = 0;\r
+  ret = 0;\r
   if (translated_sid->Use == SidTypeWellKnownGroup && ! well_known_sid(*sid)) {\r
     print_message(stderr, NSSM_GUI_INVALID_USERNAME, username);\r
     ret = 10;\r
@@ -166,7 +160,7 @@ int canonicalise_username(const TCHAR *username, TCHAR **canon) {
   LSA_REFERENCED_DOMAIN_LIST *translated_domains;\r
   LSA_TRANSLATED_NAME *translated_name;\r
   NTSTATUS status = LsaLookupSids(policy, 1, &sids, &translated_domains, &translated_name);\r
-  if (status) {\r
+  if (status != STATUS_SUCCESS) {\r
     LsaFreeMemory(translated_domains);\r
     LsaFreeMemory(translated_name);\r
     print_message(stderr, NSSM_MESSAGE_LSALOOKUPSIDS_FAILED, error_string(LsaNtStatusToWinError(status)));\r
@@ -190,21 +184,14 @@ int canonicalise_username(const TCHAR *username, TCHAR **canon) {
   memmove((char *) lsa_canon.Buffer + trust->Name.Length, L"\\", sizeof(wchar_t));\r
   memmove((char *) lsa_canon.Buffer + trust->Name.Length + sizeof(wchar_t), translated_name->Name.Buffer, translated_name->Name.Length);\r
 \r
-#ifdef UNICODE\r
-  *canon = lsa_canon.Buffer;\r
-#else\r
-  size_t buflen;\r
-  wcstombs_s(&buflen, NULL, 0, lsa_canon.Buffer, _TRUNCATE);\r
-  *canon = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, buflen);\r
-  if (! *canon) {\r
+  unsigned long canonlen;\r
+  if (from_utf16(lsa_canon.Buffer, canon, &canonlen)) {\r
     LsaFreeMemory(translated_domains);\r
     LsaFreeMemory(translated_name);\r
     print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("username_sid"));\r
     return 10;\r
   }\r
-  wcstombs_s(&buflen, *canon, buflen, lsa_canon.Buffer, _TRUNCATE);\r
   HeapFree(GetProcessHeap(), 0, lsa_canon.Buffer);\r
-#endif\r
 \r
   LsaFreeMemory(translated_domains);\r
   LsaFreeMemory(translated_name);\r
@@ -247,6 +234,31 @@ int is_localsystem(const TCHAR *username) {
   return ret;\r
 }\r
 \r
+/* Build the virtual account name. */\r
+TCHAR *virtual_account(const TCHAR *service_name) {\r
+  size_t len = _tcslen(NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN) + _tcslen(service_name) + 2;\r
+  TCHAR *name = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));\r
+  if (! name) {\r
+    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("name"), _T("virtual_account"));\r
+    return 0;\r
+  }\r
+\r
+  _sntprintf_s(name, len, _TRUNCATE, _T("%s\\%s"), NSSM_VIRTUAL_SERVICE_ACCOUNT_DOMAIN, service_name);\r
+  return name;\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
+  TCHAR *canon = virtual_account(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
@@ -307,7 +319,7 @@ int grant_logon_as_service(const TCHAR *username) {
   LSA_UNICODE_STRING *rights;\r
   unsigned long count = ~0;\r
   status = LsaEnumerateAccountRights(policy, sid, &rights, &count);\r
-  if (status) {\r
+  if (status != STATUS_SUCCESS) {\r
     /*\r
       If the account has no rights set LsaEnumerateAccountRights() will return\r
       STATUS_OBJECT_NAME_NOT_FOUND and set count to 0.\r
@@ -336,7 +348,7 @@ int grant_logon_as_service(const TCHAR *username) {
   status = LsaAddAccountRights(policy, sid, &lsa_right, 1);\r
   FreeSid(sid);\r
   LsaClose(policy);\r
-  if (status) {\r
+  if (status != STATUS_SUCCESS) {\r
     print_message(stderr, NSSM_MESSAGE_LSAADDACCOUNTRIGHTS_FAILED, error_string(LsaNtStatusToWinError(status)));\r
     return 5;\r
   }\r