working on getting the run as service tool to work again.
[feisty_meow.git] / nucleus / library / security / nt_security.cpp
1
2
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : nt_security                                                       *
7 *  Author : Sue Richeson                                                      *
8 *  Author : Chris Koeritz                                                     *
9 *                                                                             *
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 \*****************************************************************************/
18
19 #ifdef __WIN32__
20
21 #include "nt_security.h"
22 #include "win32_security.h"
23
24 #include <basis/astring.h>
25
26 #include <lm.h>
27
28 // LSA success status value.
29 #ifndef STATUS_SUCCESS
30   #define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
31 #endif
32
33 nt_security::nt_security()
34 : m_sDirServiceProvider(NIL)
35 {
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://");
40 }
41 //---------------------------------------------------------------------------
42
43
44 nt_security::~nt_security()
45 {
46   if (m_sDirServiceProvider)
47     delete m_sDirServiceProvider;
48 }
49
50
51 //---------------------------------------------------------------------------
52
53 bool nt_security::iequalsUsername(astring name1, astring name2)
54 {
55     return normalizeUsername(name1) == normalizeUsername(name2);
56 }
57
58 const astring &nt_security::normalizeUsername(astring &username)
59 {
60     username.replace_all('/', '\\');
61     username.replace_all('|', ':');
62     username.to_lower();
63     return username;
64 }
65
66   //---------------------------------------------------------------------------
67
68 astring nt_security::DomainBinding(const astring &domain)
69 {
70   astring tempstring = *m_sDirServiceProvider + domain;
71   return (tempstring);
72 }
73 //---------------------------------------------------------------------------
74
75
76 astring nt_security::DomainUserBinding(const astring &domain, const astring &user_name)
77 {
78   astring tempstring = *m_sDirServiceProvider + domain + astring("/") + user_name;
79   return (tempstring);
80 }
81 //---------------------------------------------------------------------------
82
83 // This piece of code is borrowed from the following July 1999 MSDN article
84 //     HOWTO: Look Up Current User Name and Domain Name
85 //     ID: Q155698 
86 //NOTE: It has been modified for inclusion in this class and it is NT-specific.
87
88 bool nt_security::GetUserAndDomainName(astring &UserName, astring &DomainName)
89 {
90   return win32_security::GetUserAndDomainName(UserName, DomainName);
91 }
92
93
94 //---------------------------------------------------------------------------
95 // The following routines were taken from the lsapriv sample application by
96 // Scott Field on the MSDN January 2001.
97 //---------------------------------------------------------------------------
98
99 /*---------------------------------------------------------------------------
100 This function attempts to obtain a SID representing the supplied
101 account on the supplied system.
102
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)
107
108 If the function fails, the return SID is NULL.
109
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 ---------------------------------------------------------------------------*/
114
115 PSID nt_security::GetUserSID(const astring &user_name)
116 {
117     PSID psid = NULL;
118     char * ReferencedDomain = NULL;
119     DWORD cbSid = 128;    // initial allocation attempt
120     DWORD cchReferencedDomain = 16; // initial allocation size
121     SID_NAME_USE peUse;
122     bool bSuccess = false;
123
124     try 
125     {   //
126         // initial memory allocations
127         //
128         psid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid);
129         if (psid != NULL)
130         {
131             ReferencedDomain = (char *)HeapAlloc(GetProcessHeap(), 0, cchReferencedDomain * sizeof(TCHAR));
132             if (ReferencedDomain != NULL)
133             {
134                 // Obtain the SID of the specified account on the specified system.
135                 //
136                 bSuccess = true;
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,
143                     &peUse)) 
144                 {
145                     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 
146                     {
147                         // reallocate memory
148                         //
149                         psid = (PSID)HeapReAlloc(GetProcessHeap(), 0, psid, cbSid);
150                         if(psid != NULL)
151                         {
152                             ReferencedDomain = (char *)HeapReAlloc(GetProcessHeap(), 0,
153                                                                    ReferencedDomain,
154                                                                    cchReferencedDomain * sizeof(TCHAR));
155                             if (ReferencedDomain == NULL)
156                             {
157                                 break;
158                                 bSuccess = false;
159                             }
160                         }
161                         else
162                         {
163                             break;
164                             bSuccess = false;
165                         }
166                     }
167                     else
168                     {
169                         break;
170                         bSuccess = false;
171                     }
172                 } // end while
173             } // if ReferencedDomain
174         } // if psid
175     }
176     catch(...) 
177     {
178         bSuccess = false;
179     }
180
181     // Cleanup and indicate failure, if appropriate.
182     //
183     if (ReferencedDomain != NULL)
184         HeapFree(GetProcessHeap(), 0, ReferencedDomain);
185
186     if (!bSuccess) 
187     {
188         if (psid != NULL) 
189         {
190             HeapFree(GetProcessHeap(), 0, psid);
191             psid = NULL;
192         }
193     }
194
195     return psid;
196 }
197 //---------------------------------------------------------------------------
198
199
200 DWORD nt_security::OpenPolicy(const astring &serverName, DWORD DesiredAccess, PLSA_HANDLE pPolicyHandle)
201 {
202     LSA_OBJECT_ATTRIBUTES ObjectAttributes;
203     NTSTATUS Status;
204     DWORD winerror = 0;
205
206     // Always initialize the object attributes to all zeroes.
207     //
208     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
209
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);
215
216     // Attempt to open the policy.
217     Status = LsaOpenPolicy(&server, &ObjectAttributes, DesiredAccess, pPolicyHandle);
218     if (STATUS_SUCCESS != Status)
219     {
220         winerror = LsaNtStatusToWinError(Status);
221         ClosePolicy(pPolicyHandle);
222         return winerror;
223     }
224     else
225         return winerror;
226 }
227 //---------------------------------------------------------------------------
228
229
230 void nt_security::ClosePolicy(PLSA_HANDLE policyHandle)
231 {
232     if (policyHandle != NULL)
233         LsaClose(policyHandle);
234 }
235 //---------------------------------------------------------------------------
236
237
238 /*
239 void nt_security::InitLsaString(LPWSTR inString, PLSA_UNICODE_STRING LsaString)
240 {
241     DWORD StringLength;
242
243     if (inString == NULL) 
244     {
245         LsaString->Buffer = NULL;
246         LsaString->Length = 0;
247         LsaString->MaximumLength = 0;
248         return;
249     }
250
251     StringLength = wcslen(inString);
252     LsaString->Buffer = inString;
253     LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
254     LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
255 }
256 */
257 //---------------------------------------------------------------------------
258
259
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
264 {
265     NTSTATUS Status;
266     DWORD winerror = 0;
267
268     // Create a LSA_UNICODE_STRING for the privilege name.
269     //
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);
275
276     // grant or revoke the privilege, accordingly
277     //
278     if (bEnable) 
279     {
280         Status = LsaAddAccountRights(PolicyHandle,       // open policy handle
281                                      AccountSid,         // target SID
282                                      &privs,   // privileges
283                                      1);                 // privilege count
284     }
285     else 
286     {
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
292     }
293
294     if (Status == STATUS_SUCCESS)
295         return winerror;
296     else
297     {
298         winerror = LsaNtStatusToWinError(Status);
299         return winerror;
300     }
301 }
302 //---------------------------------------------------------------------------
303
304
305 DWORD nt_security::SetPrivilegeOnUser(const astring &domain,
306                                          const astring &user,
307                                          const astring &privilege,
308                                          bool bEnable)
309 {
310     LSA_HANDLE policyHandle;
311     PSID psid = NULL;
312     DWORD winerror = 0;
313
314     // Open the policy on the target machine.
315     //
316     winerror = OpenPolicy(domain, (POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES), &policyHandle);
317     if (winerror != 0)
318         return winerror;
319
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,
324     // trusted domains.
325     //
326     psid = GetUserSID(user);
327     if (psid == NULL)
328     {
329         ClosePolicy(&policyHandle);
330         return ERROR_NO_SUCH_USER;
331     }
332
333     // Grant the SeServiceLogonRight to users represented by psid.
334     //
335     winerror = SetPrivilegeOnAccount(policyHandle, psid, privilege, bEnable);
336
337     // Close the policy handle.
338     //
339     ClosePolicy(&policyHandle);
340
341     //
342     // Free memory allocated for SID.
343     //
344     if (psid != NULL) 
345         HeapFree(GetProcessHeap(), 0, psid);
346
347     return winerror;
348 }
349
350 DWORD nt_security::AddUserToGroup(const astring &user_name, const astring &group_name)
351 {
352    LOCALGROUP_MEMBERS_INFO_3 lgmi3;
353    DWORD dwLevel = 3;
354    DWORD totalEntries = 1;
355    NET_API_STATUS nStatus;
356
357 // fwprintf(stderr, L"Usage: %s ServerName GroupName MemberAccountName-(DomainName\\AccountName)\n", argv[0]);
358
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;
363
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);
369
370 //printf("got error code %d\n" , nStatus);
371
372    if (nStatus == ERROR_MEMBER_IN_ALIAS) nStatus = 0;  // not an error.
373
374    return nStatus;
375 }
376
377 #endif  //win32
378
379
380