Use well-known account aliases.
[nssm.git] / account.cpp
index 9c2ff70..5e6523f 100644 (file)
@@ -103,7 +103,7 @@ int username_sid(const TCHAR *username, SID **sid, LSA_HANDLE *policy) {
   }
 
   int ret = 0;
-  if (translated_sid->Use == SidTypeWellKnownGroup && requires_password(*sid)) {
+  if (translated_sid->Use == SidTypeWellKnownGroup && ! well_known_sid(*sid)) {
     print_message(stderr, NSSM_GUI_INVALID_USERNAME, username);
     ret = 8;
   }
@@ -154,175 +154,31 @@ int is_localsystem(const TCHAR *username) {
 }
 
 /*
-  Find the canonical name for a well-known account name.
-  MUST ONLY BE USED for well-known account names.
-  Must call LocalFree() on result.
+  Get well-known alias for LocalSystem and friends.
+  Returns a pointer to a static string.  DO NOT try to free it.
 */
-TCHAR *canonical_username(const TCHAR *username) {
-  SID *user_sid;
-  TCHAR *canon;
-  size_t len;
-
-  if (is_localsystem(username)) {
-    len = (_tcslen(NSSM_LOCALSYSTEM_ACCOUNT) + 1) * sizeof(TCHAR);
-    canon = (TCHAR *) LocalAlloc(LPTR, len);
-    if (! canon) {
-      print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, NSSM_LOCALSYSTEM_ACCOUNT, _T("canonical_username"));
-      return 0;
-    }
-    memmove(canon, NSSM_LOCALSYSTEM_ACCOUNT, len);
-    _tprintf(_T("it's localsystem = %s!\n"), canon);
-    return canon;
-  }
-
-  if (! imports.CreateWellKnownSid) return 0;
-
-  if (username_sid(username, &user_sid)) return 0;
-
-  /*
-    LsaLookupSids will return the canonical username but the result won't
-    include the NT Authority part.  Thus we must look that up as well.
-  */
-  unsigned long ntsidsize = SECURITY_MAX_SID_SIZE;
-  SID *ntauth_sid = (SID *) HeapAlloc(GetProcessHeap(), 0, ntsidsize);
-  if (! ntauth_sid) {
-    HeapFree(GetProcessHeap(), 0, user_sid);
-    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("NT Authority"), _T("canonical_username"));
-    return 0;
-  }
-
-  if (! imports.CreateWellKnownSid(WinNtAuthoritySid, NULL, ntauth_sid, &ntsidsize)) {
-    HeapFree(GetProcessHeap(), 0, ntauth_sid);
-    print_message(stderr, NSSM_MESSAGE_CREATEWELLKNOWNSID_FAILED, _T("WinNtAuthoritySid"));
-    return 0;
-  }
-
-  LSA_HANDLE policy;
-  if (open_lsa_policy(&policy)) return 0;
-
-  LSA_REFERENCED_DOMAIN_LIST *translated_domains;
-  LSA_TRANSLATED_NAME *translated_names;
-
-  unsigned long n = 2;
-  PSID *sids = (PSID *) HeapAlloc(GetProcessHeap(), 0, n * sizeof(PSID));
-  sids[0] = user_sid;
-  sids[1] = ntauth_sid;
-
-  NTSTATUS status = LsaLookupSids(policy, n, (PSID *) sids, &translated_domains, &translated_names);
-  HeapFree(GetProcessHeap(), 0, user_sid);
-  HeapFree(GetProcessHeap(), 0, ntauth_sid);
-  HeapFree(GetProcessHeap(), 0, sids);
-  LsaClose(policy);
-  if (status) {
-    print_message(stderr, NSSM_MESSAGE_LSALOOKUPSIDS_FAILED);
-    return 0;
-  }
-
-  /* Look up the account name. */
-  LSA_TRANSLATED_NAME *translated_name = &(translated_names[0]);
-  if (translated_name->Use != SidTypeWellKnownGroup) {
-    print_message(stderr, NSSM_GUI_INVALID_USERNAME);
-    LsaFreeMemory(translated_domains);
-    LsaFreeMemory(translated_names);
-    return 0;
-  }
-
-  LSA_UNICODE_STRING *lsa_group = &translated_name->Name;
-
-  /* Look up NT Authority. */
-  translated_name = &(translated_names[1]);
-  if (translated_name->Use != SidTypeDomain) {
-    print_message(stderr, NSSM_GUI_INVALID_USERNAME);
-    LsaFreeMemory(translated_domains);
-    LsaFreeMemory(translated_names);
-    return 0;
-  }
-
-  /* In theory these pointers should all be valid if we got this far... */
-  LSA_TRUST_INFORMATION *trust = &translated_domains->Domains[translated_name->DomainIndex];
-  LSA_UNICODE_STRING *lsa_domain = &trust->Name;
-
-  TCHAR *domain, *group;
-  unsigned long lsa_domain_len = lsa_domain->Length;
-  unsigned long lsa_group_len = lsa_group->Length;
-  len = lsa_domain_len + lsa_group_len + 2;
-
-#ifdef UNICODE
-  domain = lsa_domain->Buffer;
-  group = lsa_group->Buffer;
-#else
-  size_t buflen;
-
-  wcstombs_s(&buflen, NULL, 0, lsa_domain->Buffer, _TRUNCATE);
-  domain = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, buflen);
-  if (! domain) {
-    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("domain"), _T("canonical_username"));
-    LsaFreeMemory(translated_domains);
-    LsaFreeMemory(translated_names);
-    return 0;
-  }
-  wcstombs_s(&buflen, (char *) domain, buflen, lsa_domain->Buffer, _TRUNCATE);
-
-  wcstombs_s(&buflen, NULL, 0, lsa_group->Buffer, _TRUNCATE);
-  group = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, buflen);
-  if (! group) {
-    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("group"), _T("canonical_username"));
-    LsaFreeMemory(translated_domains);
-    LsaFreeMemory(translated_names);
-    return 0;
-  }
-  wcstombs_s(&buflen, (char *) group, buflen, lsa_group->Buffer, _TRUNCATE);
-#endif
-
-  canon = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));
-  if (! canon) {
-    LsaFreeMemory(translated_domains);
-    LsaFreeMemory(translated_names);
-    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("canonical_username"));
-    return 0;
-  }
-
-  _sntprintf_s(canon, len, _TRUNCATE, _T("%s\\%s"), domain, group);
-
-#ifndef UNICODE
-  HeapFree(GetProcessHeap(), 0, domain);
-  HeapFree(GetProcessHeap(), 0, group);
-#endif
-
-  LsaFreeMemory(translated_domains);
-  LsaFreeMemory(translated_names);
-
-  return canon;
-}
-
-/* Does the SID type require a password? */
-int requires_password(SID *sid) {
-  if (! imports.IsWellKnownSid) return -1;
-  if (imports.IsWellKnownSid(sid, WinLocalSystemSid)) return 0;
-  if (imports.IsWellKnownSid(sid, WinLocalServiceSid)) return 0;
-  if (imports.IsWellKnownSid(sid, WinNetworkServiceSid)) return 0;;
-  return 1;
+const TCHAR *well_known_sid(SID *sid) {
+  if (! imports.IsWellKnownSid) return 0;
+  if (imports.IsWellKnownSid(sid, WinLocalSystemSid)) return NSSM_LOCALSYSTEM_ACCOUNT;
+  if (imports.IsWellKnownSid(sid, WinLocalServiceSid)) return NSSM_LOCALSERVICE_ACCOUNT;
+  if (imports.IsWellKnownSid(sid, WinNetworkServiceSid)) return NSSM_NETWORKSERVICE_ACCOUNT;
+  return 0;
 }
 
-/* Does the username require a password? */
-int requires_password(const TCHAR *username) {
-  if (str_equiv(username, NSSM_LOCALSYSTEM_ACCOUNT)) return 0;
-
+const TCHAR *well_known_username(const TCHAR *username) {
+  if (str_equiv(username, NSSM_LOCALSYSTEM_ACCOUNT)) return NSSM_LOCALSYSTEM_ACCOUNT;
   SID *sid;
   int r = username_sid(username, &sid);
   if (username_sid(username, &sid)) return 0;
 
-  int ret = 0;
-  ret = requires_password(sid);
-
+  const TCHAR *well_known = well_known_sid(sid);
   FreeSid(sid);
 
-  return ret;
+  return well_known;
 }
 
 int grant_logon_as_service(const TCHAR *username) {
   if (! username) return 0;
-  if (! requires_password(username)) return 0;
 
   /* Open Policy object. */
   LSA_OBJECT_ATTRIBUTES attributes;
@@ -340,6 +196,14 @@ int grant_logon_as_service(const TCHAR *username) {
     return 2;
   }
 
+  /*
+    Shouldn't happen because it should have been checked before callling this function.
+  */
+  if (well_known_sid(sid)) {
+    LsaClose(policy);
+    return 3;
+  }
+
   /* Check if the SID has the "Log on as a service" right. */
   LSA_UNICODE_STRING lsa_right;
   lsa_right.Buffer = NSSM_LOGON_AS_SERVICE_RIGHT;