[BRANCHES]
[reactos.git] / reactos / dll / win32 / samsrv / user.c
1 /*
2 * PROJECT: Local Security Authority Server DLL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/samsrv/user.c
5 * PURPOSE: User specific helper functions
6 * COPYRIGHT: Copyright 2013 Eric Kohl
7 */
8
9 #include "samsrv.h"
10
11 /* FUNCTIONS ***************************************************************/
12
13 NTSTATUS
14 SampOpenUserObject(IN PSAM_DB_OBJECT DomainObject,
15 IN ULONG UserId,
16 IN ACCESS_MASK DesiredAccess,
17 OUT PSAM_DB_OBJECT *UserObject)
18 {
19 WCHAR szRid[9];
20
21 TRACE("(%p %lu %lx %p)\n",
22 DomainObject, UserId, DesiredAccess, UserObject);
23
24 /* Convert the RID into a string (hex) */
25 swprintf(szRid, L"%08lX", UserId);
26
27 /* Create the user object */
28 return SampOpenDbObject(DomainObject,
29 L"Users",
30 szRid,
31 UserId,
32 SamDbUserObject,
33 DesiredAccess,
34 UserObject);
35 }
36
37
38 NTSTATUS
39 SampAddGroupMembershipToUser(IN PSAM_DB_OBJECT UserObject,
40 IN ULONG GroupId,
41 IN ULONG Attributes)
42 {
43 PGROUP_MEMBERSHIP GroupsBuffer = NULL;
44 ULONG GroupsCount = 0;
45 ULONG Length = 0;
46 ULONG i;
47 NTSTATUS Status;
48
49 TRACE("(%p %lu %lx)\n",
50 UserObject, GroupId, Attributes);
51
52 Status = SampGetObjectAttribute(UserObject,
53 L"Groups",
54 NULL,
55 NULL,
56 &Length);
57 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
58 goto done;
59
60 GroupsBuffer = midl_user_allocate(Length + sizeof(GROUP_MEMBERSHIP));
61 if (GroupsBuffer == NULL)
62 {
63 Status = STATUS_INSUFFICIENT_RESOURCES;
64 goto done;
65 }
66
67 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
68 {
69 Status = SampGetObjectAttribute(UserObject,
70 L"Groups",
71 NULL,
72 GroupsBuffer,
73 &Length);
74 if (!NT_SUCCESS(Status))
75 goto done;
76
77 GroupsCount = Length / sizeof(GROUP_MEMBERSHIP);
78 }
79
80 for (i = 0; i < GroupsCount; i++)
81 {
82 if (GroupsBuffer[i].RelativeId == GroupId)
83 {
84 Status = STATUS_MEMBER_IN_GROUP;
85 goto done;
86 }
87 }
88
89 GroupsBuffer[GroupsCount].RelativeId = GroupId;
90 GroupsBuffer[GroupsCount].Attributes = Attributes;
91 Length += sizeof(GROUP_MEMBERSHIP);
92
93 Status = SampSetObjectAttribute(UserObject,
94 L"Groups",
95 REG_BINARY,
96 GroupsBuffer,
97 Length);
98
99 done:
100 if (GroupsBuffer != NULL)
101 midl_user_free(GroupsBuffer);
102
103 return Status;
104 }
105
106
107 NTSTATUS
108 SampRemoveGroupMembershipFromUser(IN PSAM_DB_OBJECT UserObject,
109 IN ULONG GroupId)
110 {
111 PGROUP_MEMBERSHIP GroupsBuffer = NULL;
112 ULONG GroupsCount = 0;
113 ULONG Length = 0;
114 ULONG i;
115 NTSTATUS Status = STATUS_SUCCESS;
116
117 TRACE("(%p %lu)\n",
118 UserObject, GroupId);
119
120 SampGetObjectAttribute(UserObject,
121 L"Groups",
122 NULL,
123 NULL,
124 &Length);
125
126 if (Length == 0)
127 return STATUS_MEMBER_NOT_IN_GROUP;
128
129 GroupsBuffer = midl_user_allocate(Length);
130 if (GroupsBuffer == NULL)
131 {
132 Status = STATUS_INSUFFICIENT_RESOURCES;
133 goto done;
134 }
135
136 Status = SampGetObjectAttribute(UserObject,
137 L"Groups",
138 NULL,
139 GroupsBuffer,
140 &Length);
141 if (!NT_SUCCESS(Status))
142 goto done;
143
144 Status = STATUS_MEMBER_NOT_IN_GROUP;
145
146 GroupsCount = Length / sizeof(GROUP_MEMBERSHIP);
147 for (i = 0; i < GroupsCount; i++)
148 {
149 if (GroupsBuffer[i].RelativeId == GroupId)
150 {
151 Length -= sizeof(GROUP_MEMBERSHIP);
152 Status = STATUS_SUCCESS;
153
154 if (GroupsCount - i - 1 > 0)
155 {
156 CopyMemory(&GroupsBuffer[i],
157 &GroupsBuffer[i + 1],
158 (GroupsCount - i - 1) * sizeof(GROUP_MEMBERSHIP));
159 }
160
161 break;
162 }
163 }
164
165 if (!NT_SUCCESS(Status))
166 goto done;
167
168 Status = SampSetObjectAttribute(UserObject,
169 L"Groups",
170 REG_BINARY,
171 GroupsBuffer,
172 Length);
173
174 done:
175 if (GroupsBuffer != NULL)
176 midl_user_free(GroupsBuffer);
177
178 return Status;
179 }
180
181
182 NTSTATUS
183 SampGetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject,
184 IN ULONG UserId,
185 IN ULONG GroupId,
186 OUT PULONG GroupAttributes)
187 {
188 PSAM_DB_OBJECT UserObject = NULL;
189 PGROUP_MEMBERSHIP GroupsBuffer = NULL;
190 ULONG Length = 0;
191 ULONG i;
192 NTSTATUS Status;
193
194 Status = SampOpenUserObject(DomainObject,
195 UserId,
196 0,
197 &UserObject);
198 if (!NT_SUCCESS(Status))
199 {
200 return Status;
201 }
202
203 SampGetObjectAttribute(UserObject,
204 L"Groups",
205 NULL,
206 NULL,
207 &Length);
208
209 if (Length == 0)
210 return STATUS_UNSUCCESSFUL; /* FIXME */
211
212 GroupsBuffer = midl_user_allocate(Length);
213 if (GroupsBuffer == NULL)
214 {
215 Status = STATUS_INSUFFICIENT_RESOURCES;
216 goto done;
217 }
218
219 Status = SampGetObjectAttribute(UserObject,
220 L"Groups",
221 NULL,
222 GroupsBuffer,
223 &Length);
224 if (!NT_SUCCESS(Status))
225 goto done;
226
227 for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
228 {
229 if (GroupsBuffer[i].RelativeId == GroupId)
230 {
231 *GroupAttributes = GroupsBuffer[i].Attributes;
232 goto done;
233 }
234 }
235
236 done:
237 if (GroupsBuffer != NULL)
238 midl_user_free(GroupsBuffer);
239
240 if (UserObject != NULL)
241 SampCloseDbObject(UserObject);
242
243 return Status;
244 }
245
246
247 NTSTATUS
248 SampSetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject,
249 IN ULONG UserId,
250 IN ULONG GroupId,
251 IN ULONG GroupAttributes)
252 {
253 PSAM_DB_OBJECT UserObject = NULL;
254 PGROUP_MEMBERSHIP GroupsBuffer = NULL;
255 ULONG Length = 0;
256 ULONG i;
257 NTSTATUS Status;
258
259 Status = SampOpenUserObject(DomainObject,
260 UserId,
261 0,
262 &UserObject);
263 if (!NT_SUCCESS(Status))
264 {
265 return Status;
266 }
267
268 SampGetObjectAttribute(UserObject,
269 L"Groups",
270 NULL,
271 NULL,
272 &Length);
273
274 if (Length == 0)
275 return STATUS_UNSUCCESSFUL; /* FIXME */
276
277 GroupsBuffer = midl_user_allocate(Length);
278 if (GroupsBuffer == NULL)
279 {
280 Status = STATUS_INSUFFICIENT_RESOURCES;
281 goto done;
282 }
283
284 Status = SampGetObjectAttribute(UserObject,
285 L"Groups",
286 NULL,
287 GroupsBuffer,
288 &Length);
289 if (!NT_SUCCESS(Status))
290 goto done;
291
292 for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
293 {
294 if (GroupsBuffer[i].RelativeId == GroupId)
295 {
296 GroupsBuffer[i].Attributes = GroupAttributes;
297 break;
298 }
299 }
300
301 Status = SampSetObjectAttribute(UserObject,
302 L"Groups",
303 REG_BINARY,
304 GroupsBuffer,
305 Length);
306
307 done:
308 if (GroupsBuffer != NULL)
309 midl_user_free(GroupsBuffer);
310
311 if (UserObject != NULL)
312 SampCloseDbObject(UserObject);
313
314 return Status;
315 }
316
317
318 NTSTATUS
319 SampRemoveUserFromAllGroups(IN PSAM_DB_OBJECT UserObject)
320 {
321 PGROUP_MEMBERSHIP GroupsBuffer = NULL;
322 PSAM_DB_OBJECT GroupObject;
323 ULONG Length = 0;
324 ULONG i;
325 NTSTATUS Status;
326
327 SampGetObjectAttribute(UserObject,
328 L"Groups",
329 NULL,
330 NULL,
331 &Length);
332
333 if (Length == 0)
334 return STATUS_SUCCESS;
335
336 GroupsBuffer = midl_user_allocate(Length);
337 if (GroupsBuffer == NULL)
338 {
339 Status = STATUS_INSUFFICIENT_RESOURCES;
340 goto done;
341 }
342
343 Status = SampGetObjectAttribute(UserObject,
344 L"Groups",
345 NULL,
346 GroupsBuffer,
347 &Length);
348 if (!NT_SUCCESS(Status))
349 goto done;
350
351 for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
352 {
353 Status = SampOpenGroupObject(UserObject->ParentObject,
354 GroupsBuffer[i].RelativeId,
355 0,
356 &GroupObject);
357 if (!NT_SUCCESS(Status))
358 {
359 goto done;
360 }
361
362 Status = SampRemoveMemberFromGroup(GroupObject,
363 UserObject->RelativeId);
364
365 SampCloseDbObject(GroupObject);
366
367 if (!NT_SUCCESS(Status))
368 {
369 goto done;
370 }
371 }
372
373 done:
374 if (GroupsBuffer != NULL)
375 midl_user_free(GroupsBuffer);
376
377 return Status;
378 }
379
380
381 NTSTATUS
382 SampRemoveUserFromAllAliases(IN PSAM_DB_OBJECT UserObject)
383 {
384 FIXME("(%p)\n", UserObject);
385 return STATUS_SUCCESS;
386 }
387
388
389 NTSTATUS
390 SampSetUserPassword(IN PSAM_DB_OBJECT UserObject,
391 IN PENCRYPTED_NT_OWF_PASSWORD NtPassword,
392 IN BOOLEAN NtPasswordPresent,
393 IN PENCRYPTED_LM_OWF_PASSWORD LmPassword,
394 IN BOOLEAN LmPasswordPresent)
395 {
396 PENCRYPTED_NT_OWF_PASSWORD NtHistory = NULL;
397 PENCRYPTED_LM_OWF_PASSWORD LmHistory = NULL;
398 ULONG NtHistoryLength = 0;
399 ULONG LmHistoryLength = 0;
400 ULONG CurrentHistoryLength;
401 ULONG MaxHistoryLength = 3;
402 ULONG Length = 0;
403 BOOLEAN UseNtPassword;
404 BOOLEAN UseLmPassword;
405 NTSTATUS Status;
406
407 UseNtPassword =
408 ((NtPasswordPresent != FALSE) &&
409 (NtPassword != NULL) &&
410 (memcmp(NtPassword, &EmptyNtHash, sizeof(ENCRYPTED_NT_OWF_PASSWORD)) != 0));
411
412 UseLmPassword =
413 ((LmPasswordPresent != FALSE) &&
414 (LmPassword != NULL) &&
415 (memcmp(LmPassword, &EmptyLmHash, sizeof(ENCRYPTED_LM_OWF_PASSWORD)) != 0));
416
417 /* Update the NT password history only if we have a new non-empty NT password */
418 if (UseNtPassword)
419 {
420 /* Get the size of the NT history */
421 SampGetObjectAttribute(UserObject,
422 L"NTPwdHistory",
423 NULL,
424 NULL,
425 &Length);
426
427 CurrentHistoryLength = Length / sizeof(ENCRYPTED_NT_OWF_PASSWORD);
428 if (CurrentHistoryLength < MaxHistoryLength)
429 {
430 NtHistoryLength = (CurrentHistoryLength + 1) * sizeof(ENCRYPTED_NT_OWF_PASSWORD);
431 }
432 else
433 {
434 NtHistoryLength = MaxHistoryLength * sizeof(ENCRYPTED_NT_OWF_PASSWORD);
435 }
436
437 /* Allocate the history buffer */
438 NtHistory = midl_user_allocate(NtHistoryLength);
439 if (NtHistory == NULL)
440 return STATUS_INSUFFICIENT_RESOURCES;
441
442 if (Length > 0)
443 {
444 /* Get the history */
445 Status = SampGetObjectAttribute(UserObject,
446 L"NTPwdHistory",
447 NULL,
448 NtHistory,
449 &Length);
450 if (!NT_SUCCESS(Status))
451 goto done;
452 }
453
454 /* Move the old passwords down by one entry */
455 if (NtHistoryLength > sizeof(ENCRYPTED_NT_OWF_PASSWORD))
456 {
457 MoveMemory(&(NtHistory[1]),
458 &(NtHistory[0]),
459 NtHistoryLength - sizeof(ENCRYPTED_NT_OWF_PASSWORD));
460 }
461
462 /* Add the new password to the top of the history */
463 if (NtPasswordPresent)
464 {
465 CopyMemory(&(NtHistory[0]),
466 NtPassword,
467 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
468 }
469 else
470 {
471 ZeroMemory(&(NtHistory[0]),
472 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
473 }
474
475 /* Set the history */
476 Status = SampSetObjectAttribute(UserObject,
477 L"NTPwdHistory",
478 REG_BINARY,
479 (PVOID)NtHistory,
480 NtHistoryLength);
481 if (!NT_SUCCESS(Status))
482 goto done;
483 }
484
485 /* Update the LM password history only if we have a new non-empty LM password */
486 if (UseLmPassword)
487 {
488 /* Get the size of the LM history */
489 Length = 0;
490 SampGetObjectAttribute(UserObject,
491 L"LMPwdHistory",
492 NULL,
493 NULL,
494 &Length);
495
496 CurrentHistoryLength = Length / sizeof(ENCRYPTED_LM_OWF_PASSWORD);
497 if (CurrentHistoryLength < MaxHistoryLength)
498 {
499 LmHistoryLength = (CurrentHistoryLength + 1) * sizeof(ENCRYPTED_LM_OWF_PASSWORD);
500 }
501 else
502 {
503 LmHistoryLength = MaxHistoryLength * sizeof(ENCRYPTED_LM_OWF_PASSWORD);
504 }
505
506 /* Allocate the history buffer */
507 LmHistory = midl_user_allocate(LmHistoryLength);
508 if (LmHistory == NULL)
509 return STATUS_INSUFFICIENT_RESOURCES;
510
511 if (Length > 0)
512 {
513 /* Get the history */
514 Status = SampGetObjectAttribute(UserObject,
515 L"LMPwdHistory",
516 NULL,
517 LmHistory,
518 &Length);
519 if (!NT_SUCCESS(Status))
520 goto done;
521 }
522
523 /* Move the old passwords down by one entry */
524 if (LmHistoryLength > sizeof(ENCRYPTED_LM_OWF_PASSWORD))
525 {
526 MoveMemory(&(LmHistory[1]),
527 &(LmHistory[0]),
528 LmHistoryLength - sizeof(ENCRYPTED_LM_OWF_PASSWORD));
529 }
530
531 /* Add the new password to the top of the history */
532 if (LmPasswordPresent)
533 {
534 CopyMemory(&(LmHistory[0]),
535 LmPassword,
536 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
537 }
538 else
539 {
540 ZeroMemory(&(LmHistory[0]),
541 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
542 }
543
544 /* Set the LM password history */
545 Status = SampSetObjectAttribute(UserObject,
546 L"LMPwdHistory",
547 REG_BINARY,
548 (PVOID)LmHistory,
549 LmHistoryLength);
550 if (!NT_SUCCESS(Status))
551 goto done;
552 }
553
554 /* Set the new NT password */
555 if (UseNtPassword)
556 {
557 Status = SampSetObjectAttribute(UserObject,
558 L"NTPwd",
559 REG_BINARY,
560 (PVOID)NtPassword,
561 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
562 if (!NT_SUCCESS(Status))
563 goto done;
564 }
565 else
566 {
567 Status = SampSetObjectAttribute(UserObject,
568 L"NTPwd",
569 REG_BINARY,
570 &EmptyNtHash,
571 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
572 if (!NT_SUCCESS(Status))
573 goto done;
574 }
575
576 /* Set the new LM password */
577 if (UseLmPassword)
578 {
579 Status = SampSetObjectAttribute(UserObject,
580 L"LMPwd",
581 REG_BINARY,
582 (PVOID)LmPassword,
583 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
584 if (!NT_SUCCESS(Status))
585 goto done;
586 }
587 else
588 {
589 Status = SampSetObjectAttribute(UserObject,
590 L"LMPwd",
591 REG_BINARY,
592 &EmptyLmHash,
593 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
594 if (!NT_SUCCESS(Status))
595 goto done;
596 }
597
598 done:
599 if (NtHistory != NULL)
600 midl_user_free(NtHistory);
601
602 if (LmHistory != NULL)
603 midl_user_free(LmHistory);
604
605 return Status;
606 }
607
608
609 NTSTATUS
610 SampGetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject,
611 IN OUT PSAMPR_LOGON_HOURS LogonHours)
612 {
613 PUCHAR RawBuffer = NULL;
614 ULONG Length = 0;
615 ULONG BufferLength = 0;
616 NTSTATUS Status;
617
618 Status = SampGetObjectAttribute(UserObject,
619 L"LogonHours",
620 NULL,
621 NULL,
622 &Length);
623 if (Status != STATUS_BUFFER_OVERFLOW)
624 {
625 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status);
626 return Status;
627 }
628
629 Status = STATUS_SUCCESS;
630
631 if (Length == 0)
632 {
633 LogonHours->UnitsPerWeek = 0;
634 LogonHours->LogonHours = NULL;
635 }
636 else
637 {
638 RawBuffer = midl_user_allocate(Length);
639 if (RawBuffer == NULL)
640 {
641 Status = STATUS_INSUFFICIENT_RESOURCES;
642 goto done;
643 }
644
645 Status = SampGetObjectAttribute(UserObject,
646 L"LogonHours",
647 NULL,
648 (PVOID)RawBuffer,
649 &Length);
650 if (!NT_SUCCESS(Status))
651 goto done;
652
653 LogonHours->UnitsPerWeek = *((PUSHORT)RawBuffer);
654
655 BufferLength = (((ULONG)LogonHours->UnitsPerWeek) + 7) / 8;
656
657 LogonHours->LogonHours = midl_user_allocate(BufferLength);
658 if (LogonHours->LogonHours == NULL)
659 {
660 TRACE("Failed to allocate LogonHours buffer!\n");
661 Status = STATUS_INSUFFICIENT_RESOURCES;
662 goto done;
663 }
664
665 memcpy(LogonHours->LogonHours,
666 &(RawBuffer[2]),
667 BufferLength);
668 }
669
670 done:
671
672 if (RawBuffer != NULL)
673 midl_user_free(RawBuffer);
674
675 return Status;
676 }
677
678
679 NTSTATUS
680 SampSetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject,
681 IN PSAMPR_LOGON_HOURS LogonHours)
682 {
683 PUCHAR RawBuffer = NULL;
684 ULONG BufferLength;
685 ULONG Length = 0;
686 NTSTATUS Status;
687
688 if (LogonHours->UnitsPerWeek > 0)
689 {
690 BufferLength = (((ULONG)LogonHours->UnitsPerWeek) + 7) / 8;
691
692 Length = BufferLength + sizeof(USHORT);
693
694 RawBuffer = midl_user_allocate(Length);
695 if (RawBuffer == NULL)
696 {
697 Status = STATUS_INSUFFICIENT_RESOURCES;
698 goto done;
699 }
700
701 *((PUSHORT)RawBuffer) = LogonHours->UnitsPerWeek;
702
703 memcpy(&(RawBuffer[2]),
704 LogonHours->LogonHours,
705 BufferLength);
706 }
707
708 Status = SampSetObjectAttribute(UserObject,
709 L"LogonHours",
710 REG_BINARY,
711 RawBuffer,
712 Length);
713
714 done:
715 if (RawBuffer != NULL)
716 midl_user_free(RawBuffer);
717
718 return Status;
719 }
720
721 /* EOF */