4 /*****************************************************************************\
7 * Author : Sue Richeson *
8 * Author : Chris Koeritz *
10 *******************************************************************************
11 * Copyright (c) 1999-$now By Author. This program is free software; you can *
12 * redistribute it and/or modify it under the terms of the GNU General Public *
13 * License as published by the Free Software Foundation; either version 2 of *
14 * the License or (at your option) any later version. This is online at: *
15 * http://www.fsf.org/copyleft/gpl.html *
16 * Please send any updates to: fred@gruntose.com *
17 \*****************************************************************************/
21 #include "nt_security.h"
22 #include "win32_security.h"
24 #include <basis/astring.h>
28 // LSA success status value.
29 #ifndef STATUS_SUCCESS
30 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
33 nt_security::nt_security()
34 : m_sDirServiceProvider(NULL_POINTER)
36 // Eventually, construction of nt_security should determine if WinNT://
37 // or LDAP://, etc is the service provider and set a private member variable
38 // with the appropriate distinguished name qualifier.
39 m_sDirServiceProvider = new astring("WinNT://");
41 //---------------------------------------------------------------------------
44 nt_security::~nt_security()
46 if (m_sDirServiceProvider)
47 delete m_sDirServiceProvider;
51 //---------------------------------------------------------------------------
53 bool nt_security::iequalsUsername(astring name1, astring name2)
55 return normalizeUsername(name1) == normalizeUsername(name2);
58 const astring &nt_security::normalizeUsername(astring &username)
60 username.replace_all('/', '\\');
61 username.replace_all('|', ':');
66 //---------------------------------------------------------------------------
68 astring nt_security::DomainBinding(const astring &domain)
70 astring tempstring = *m_sDirServiceProvider + domain;
73 //---------------------------------------------------------------------------
76 astring nt_security::DomainUserBinding(const astring &domain, const astring &user_name)
78 astring tempstring = *m_sDirServiceProvider + domain + astring("/") + user_name;
81 //---------------------------------------------------------------------------
83 // This piece of code is borrowed from the following July 1999 MSDN article
84 // HOWTO: Look Up Current User Name and Domain Name
86 //NOTE: It has been modified for inclusion in this class and it is NT-specific.
88 bool nt_security::GetUserAndDomainName(astring &UserName, astring &DomainName)
90 return win32_security::GetUserAndDomainName(UserName, DomainName);
94 //---------------------------------------------------------------------------
95 // The following routines were taken from the lsapriv sample application by
96 // Scott Field on the MSDN January 2001.
97 //---------------------------------------------------------------------------
99 /*---------------------------------------------------------------------------
100 This function attempts to obtain a SID representing the supplied
101 account on the supplied system.
103 If the function succeeds, the return value is the SID. A buffer is
104 allocated which contains the SID representing the supplied account.
105 This buffer should be freed when it is no longer needed by calling
106 HeapFree(GetProcessHeap(), 0, buffer)
108 If the function fails, the return SID is NULL.
110 Scott Field (sfield) 12-Jul-95
111 Sue Richeson 27-FEB-2001 Mods for use in LightLink.
112 Chris Koeritz 02-JAN-2008 changed some more for use within hoople.
113 ---------------------------------------------------------------------------*/
115 PSID nt_security::GetUserSID(const astring &user_name)
118 char * ReferencedDomain = NULL;
119 DWORD cbSid = 128; // initial allocation attempt
120 DWORD cchReferencedDomain = 16; // initial allocation size
122 bool bSuccess = false;
126 // initial memory allocations
128 psid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid);
131 ReferencedDomain = (char *)HeapAlloc(GetProcessHeap(), 0, cchReferencedDomain * sizeof(TCHAR));
132 if (ReferencedDomain != NULL)
134 // Obtain the SID of the specified account on the specified system.
137 while (!LookupAccountName(NULL, // machine to lookup account on
138 to_unicode_temp(user_name), // account to lookup
139 psid, // SID of interest
140 &cbSid, // size of SID
141 to_unicode_temp(ReferencedDomain), // domain where found.
142 &cchReferencedDomain,
145 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
149 psid = (PSID)HeapReAlloc(GetProcessHeap(), 0, psid, cbSid);
152 ReferencedDomain = (char *)HeapReAlloc(GetProcessHeap(), 0,
154 cchReferencedDomain * sizeof(TCHAR));
155 if (ReferencedDomain == NULL)
173 } // if ReferencedDomain
181 // Cleanup and indicate failure, if appropriate.
183 if (ReferencedDomain != NULL)
184 HeapFree(GetProcessHeap(), 0, ReferencedDomain);
190 HeapFree(GetProcessHeap(), 0, psid);
197 //---------------------------------------------------------------------------
200 DWORD nt_security::OpenPolicy(const astring &serverName, DWORD DesiredAccess, PLSA_HANDLE pPolicyHandle)
202 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
206 // Always initialize the object attributes to all zeroes.
208 ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
210 transcode_to_utf16 temp_server(serverName);
211 LSA_UNICODE_STRING server;
212 server.Buffer = (PWSTR)(UTF16 *)temp_server;
213 server.Length = serverName.length() * (int)sizeof(UTF16);
214 server.MaximumLength = (serverName.length() +1) * (int)sizeof(UTF16);
216 // Attempt to open the policy.
217 Status = LsaOpenPolicy(&server, &ObjectAttributes, DesiredAccess, pPolicyHandle);
218 if (STATUS_SUCCESS != Status)
220 winerror = LsaNtStatusToWinError(Status);
221 ClosePolicy(pPolicyHandle);
227 //---------------------------------------------------------------------------
230 void nt_security::ClosePolicy(PLSA_HANDLE policyHandle)
232 if (policyHandle != NULL)
233 LsaClose(policyHandle);
235 //---------------------------------------------------------------------------
239 void nt_security::InitLsaString(LPWSTR inString, PLSA_UNICODE_STRING LsaString)
243 if (inString == NULL)
245 LsaString->Buffer = NULL;
246 LsaString->Length = 0;
247 LsaString->MaximumLength = 0;
251 StringLength = wcslen(inString);
252 LsaString->Buffer = inString;
253 LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
254 LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
257 //---------------------------------------------------------------------------
260 DWORD nt_security::SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle, // open policy handle
261 PSID AccountSid, // SID to grant privilege to
262 const astring &PrivilegeName, // privilege to grant (Unicode)
263 bool bEnable) // enable or disable
268 // Create a LSA_UNICODE_STRING for the privilege name.
270 transcode_to_utf16 temp_priv(PrivilegeName);
271 LSA_UNICODE_STRING privs;
272 privs.Buffer = (PWSTR)(UTF16 *)temp_priv;
273 privs.Length = PrivilegeName.length() * (int)sizeof(UTF16);
274 privs.MaximumLength = (PrivilegeName.length() +1) * (int)sizeof(UTF16);
276 // grant or revoke the privilege, accordingly
280 Status = LsaAddAccountRights(PolicyHandle, // open policy handle
281 AccountSid, // target SID
282 &privs, // privileges
283 1); // privilege count
287 Status = LsaRemoveAccountRights(PolicyHandle, // open policy handle
288 AccountSid, // target SID
289 FALSE, // do not disable all rights
290 &privs, // privileges
291 1); // privilege count
294 if (Status == STATUS_SUCCESS)
298 winerror = LsaNtStatusToWinError(Status);
302 //---------------------------------------------------------------------------
305 DWORD nt_security::SetPrivilegeOnUser(const astring &domain,
307 const astring &privilege,
310 LSA_HANDLE policyHandle;
314 // Open the policy on the target machine.
316 winerror = OpenPolicy(domain, (POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES), &policyHandle);
320 // Obtain the SID of the user/group.
321 // Note that we could target a specific machine, but we don't.
322 // Specifying NULL for target machine searches for the SID in the
323 // following order: well-known, Built-in and local, primary domain,
326 psid = GetUserSID(user);
329 ClosePolicy(&policyHandle);
330 return ERROR_NO_SUCH_USER;
333 // Grant the SeServiceLogonRight to users represented by psid.
335 winerror = SetPrivilegeOnAccount(policyHandle, psid, privilege, bEnable);
337 // Close the policy handle.
339 ClosePolicy(&policyHandle);
342 // Free memory allocated for SID.
345 HeapFree(GetProcessHeap(), 0, psid);
350 DWORD nt_security::AddUserToGroup(const astring &user_name, const astring &group_name)
352 LOCALGROUP_MEMBERS_INFO_3 lgmi3;
354 DWORD totalEntries = 1;
355 NET_API_STATUS nStatus;
357 // fwprintf(stderr, L"Usage: %s ServerName GroupName MemberAccountName-(DomainName\\AccountName)\n", argv[0]);
359 // Set up the LOCALGROUP_MEMBERS_INFO_3 structure.
360 // Assign the member account name in form of DomainName\AccountName
361 transcode_to_utf16 temp_user(user_name);
362 lgmi3.lgrmi3_domainandname = (LPWSTR)(UTF16 *)temp_user;
364 // Call the NetLocalGroupAddMembers() function, specifying level 3.
365 // Level 0 can use SID
366 transcode_to_utf16 temp_group(group_name);
367 nStatus = NetLocalGroupAddMembers(L"", (LPWSTR)(UTF16 *)temp_group, dwLevel,
368 (LPBYTE)&lgmi3, totalEntries);
370 //printf("got error code %d\n" , nStatus);
372 if (nStatus == ERROR_MEMBER_IN_ALIAS) nStatus = 0; // not an error.