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