ユーザーに「サービスとしてログオン」権限を付与する
特定のサービスをユーザーアカウントで起動しようとすると、ユーザーにサービス権限がないことが問題になることがある。特にVistaでは、Administratorsに所属していてもこの権限がないので、いろいろとやっかいだ。
これを解決するために、
// espresso3389というユーザーにサービス起動の権限を付与する addSeServiceLogonRightToUser("espresso3389");
という感じで使える関数を作成してみた。
#include <windows.h> #include <sddl.h> #include <iads.h> #include <ntsecapi.h> #include <vector> #include "atlbase.h" #include "atlstr.h" using namespace ATL; // アカウント名からSIDと所属ドメイン名を取得する PSID lookupAccountName(LPCTSTR pszName, CString& domainName, std::vector<BYTE>& buf) { DWORD domNameSize = 0; DWORD dwSidSize = 0; SID_NAME_USE snu; LookupAccountName(NULL, pszName, NULL, &dwSidSize, NULL, &domNameSize, &snu); if(dwSidSize && domNameSize) { buf.resize(dwSidSize); PSID psid = (PSID)&buf[0]; LookupAccountName(NULL, pszName, psid, &dwSidSize, domainName.GetBufferSetLength(domNameSize), &domNameSize, &snu); return psid; } return NULL; } // 指定のユーザーに指定の権限を付与する bool addAccountRight(LPCTSTR pszName, LPCTSTR right) { std::vector<BYTE> buf; CString domainName; PSID psid = lookupAccountName(pszName, domainName, buf); if(!psid) { return false; } CStringW rightW = CT2W(right); LSA_HANDLE handle; LSA_OBJECT_ATTRIBUTES objAttr; ZeroMemory(&objAttr, sizeof(objAttr)); NTSTATUS status = LsaOpenPolicy( NULL, &objAttr, POLICY_ALL_ACCESS, &handle); if(status) { SetLastError(LsaNtStatusToWinError(status)); return false; } USHORT size = (USHORT)rightW.GetLength() * 2; LSA_UNICODE_STRING rights = {size, size, (LPWSTR)(LPCWSTR)rightW}; status = LsaAddAccountRights(handle, psid, &rights, 1); if(status) { DWORD err = LsaNtStatusToWinError(status); LsaClose(handle); SetLastError(err); return false; } LsaClose(handle); return true; } // 指定のユーザーにSeServiceLogonRightを付与する bool addSeServiceLogonRightToUser(LPCTSTR pszName) { return addAccountRight(pszName, _T("SeServiceLogonRight")); }
後に気づいたが、同様のコードが、KB132958: How To Manage User Privileges Programmatically in Windows NTにある。
補足
サービスの起動に失敗した場合、イベントログに下のようなわかりやすいログが残る。
FoobarService サービスで、現在構成されているパスワードで .\espresso3389 としてログオンできませんでした。次のエラーが原因です: ログオンの失敗: このユーザーには、要求されたログオンの種類がこのコンピュータ上で許可されていません。 サービス: FoobarService ドメインとアカウント: .\espresso3389 サービス アカウントに、必要なユーザー権限である "サービスとしてログオン" がありません。 ユーザーの対処 コンピュータ上でこのサービス アカウントに "サービスとしてログオン" を割り当ててください。これは、ローカル セキュリティ設定 (Secpol.msc) を使用して実行できます。このコンピュータがクラスタ内のノードである場合は、ユーザー権限がクラスタ内のすべてのノード上のクラスタ サービス アカウントに割り当てられていることを確認してください。 ユーザー権限をこのサービス アカウントに既に割り当て済みにもかかわらず、ユーザー権限が削除されているように見える場合は、このノードと関連付けられたグループ ポリシー オブジェクトによって権限が削除されている可能性があるかどうかを、ドメイン管理者に問い合わせてください。
これを見ればわかるように、手作業でもよければ、Secpol.mscを使って権限を付与できる。