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
11 /* FUNCTIONS ***************************************************************/
14 SampOpenUserObject(IN PSAM_DB_OBJECT DomainObject
,
16 IN ACCESS_MASK DesiredAccess
,
17 OUT PSAM_DB_OBJECT
*UserObject
)
21 TRACE("(%p %lu %lx %p)\n",
22 DomainObject
, UserId
, DesiredAccess
, UserObject
);
24 /* Convert the RID into a string (hex) */
25 swprintf(szRid
, L
"%08lX", UserId
);
27 /* Create the user object */
28 return SampOpenDbObject(DomainObject
,
39 SampAddGroupMembershipToUser(IN PSAM_DB_OBJECT UserObject
,
43 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
44 ULONG GroupsCount
= 0;
49 TRACE("(%p %lu %lx)\n",
50 UserObject
, GroupId
, Attributes
);
52 Status
= SampGetObjectAttribute(UserObject
,
57 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
60 GroupsBuffer
= midl_user_allocate(Length
+ sizeof(GROUP_MEMBERSHIP
));
61 if (GroupsBuffer
== NULL
)
63 Status
= STATUS_INSUFFICIENT_RESOURCES
;
67 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
69 Status
= SampGetObjectAttribute(UserObject
,
74 if (!NT_SUCCESS(Status
))
77 GroupsCount
= Length
/ sizeof(GROUP_MEMBERSHIP
);
80 for (i
= 0; i
< GroupsCount
; i
++)
82 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
84 Status
= STATUS_MEMBER_IN_GROUP
;
89 GroupsBuffer
[GroupsCount
].RelativeId
= GroupId
;
90 GroupsBuffer
[GroupsCount
].Attributes
= Attributes
;
91 Length
+= sizeof(GROUP_MEMBERSHIP
);
93 Status
= SampSetObjectAttribute(UserObject
,
100 if (GroupsBuffer
!= NULL
)
101 midl_user_free(GroupsBuffer
);
108 SampRemoveGroupMembershipFromUser(IN PSAM_DB_OBJECT UserObject
,
111 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
112 ULONG GroupsCount
= 0;
115 NTSTATUS Status
= STATUS_SUCCESS
;
118 UserObject
, GroupId
);
120 SampGetObjectAttribute(UserObject
,
127 return STATUS_MEMBER_NOT_IN_GROUP
;
129 GroupsBuffer
= midl_user_allocate(Length
);
130 if (GroupsBuffer
== NULL
)
132 Status
= STATUS_INSUFFICIENT_RESOURCES
;
136 Status
= SampGetObjectAttribute(UserObject
,
141 if (!NT_SUCCESS(Status
))
144 Status
= STATUS_MEMBER_NOT_IN_GROUP
;
146 GroupsCount
= Length
/ sizeof(GROUP_MEMBERSHIP
);
147 for (i
= 0; i
< GroupsCount
; i
++)
149 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
151 Length
-= sizeof(GROUP_MEMBERSHIP
);
152 Status
= STATUS_SUCCESS
;
154 if (GroupsCount
- i
- 1 > 0)
156 CopyMemory(&GroupsBuffer
[i
],
157 &GroupsBuffer
[i
+ 1],
158 (GroupsCount
- i
- 1) * sizeof(GROUP_MEMBERSHIP
));
165 if (!NT_SUCCESS(Status
))
168 Status
= SampSetObjectAttribute(UserObject
,
175 if (GroupsBuffer
!= NULL
)
176 midl_user_free(GroupsBuffer
);
183 SampGetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject
,
186 OUT PULONG GroupAttributes
)
188 PSAM_DB_OBJECT UserObject
= NULL
;
189 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
194 Status
= SampOpenUserObject(DomainObject
,
198 if (!NT_SUCCESS(Status
))
203 SampGetObjectAttribute(UserObject
,
210 return STATUS_UNSUCCESSFUL
; /* FIXME */
212 GroupsBuffer
= midl_user_allocate(Length
);
213 if (GroupsBuffer
== NULL
)
215 Status
= STATUS_INSUFFICIENT_RESOURCES
;
219 Status
= SampGetObjectAttribute(UserObject
,
224 if (!NT_SUCCESS(Status
))
227 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
229 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
231 *GroupAttributes
= GroupsBuffer
[i
].Attributes
;
237 if (GroupsBuffer
!= NULL
)
238 midl_user_free(GroupsBuffer
);
240 if (UserObject
!= NULL
)
241 SampCloseDbObject(UserObject
);
248 SampSetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject
,
251 IN ULONG GroupAttributes
)
253 PSAM_DB_OBJECT UserObject
= NULL
;
254 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
259 Status
= SampOpenUserObject(DomainObject
,
263 if (!NT_SUCCESS(Status
))
268 SampGetObjectAttribute(UserObject
,
275 return STATUS_UNSUCCESSFUL
; /* FIXME */
277 GroupsBuffer
= midl_user_allocate(Length
);
278 if (GroupsBuffer
== NULL
)
280 Status
= STATUS_INSUFFICIENT_RESOURCES
;
284 Status
= SampGetObjectAttribute(UserObject
,
289 if (!NT_SUCCESS(Status
))
292 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
294 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
296 GroupsBuffer
[i
].Attributes
= GroupAttributes
;
301 Status
= SampSetObjectAttribute(UserObject
,
308 if (GroupsBuffer
!= NULL
)
309 midl_user_free(GroupsBuffer
);
311 if (UserObject
!= NULL
)
312 SampCloseDbObject(UserObject
);
319 SampRemoveUserFromAllGroups(IN PSAM_DB_OBJECT UserObject
)
321 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
322 PSAM_DB_OBJECT GroupObject
;
327 SampGetObjectAttribute(UserObject
,
334 return STATUS_SUCCESS
;
336 GroupsBuffer
= midl_user_allocate(Length
);
337 if (GroupsBuffer
== NULL
)
339 Status
= STATUS_INSUFFICIENT_RESOURCES
;
343 Status
= SampGetObjectAttribute(UserObject
,
348 if (!NT_SUCCESS(Status
))
351 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
353 Status
= SampOpenGroupObject(UserObject
->ParentObject
,
354 GroupsBuffer
[i
].RelativeId
,
357 if (!NT_SUCCESS(Status
))
362 Status
= SampRemoveMemberFromGroup(GroupObject
,
363 UserObject
->RelativeId
);
364 if (Status
== STATUS_MEMBER_NOT_IN_GROUP
)
365 Status
= STATUS_SUCCESS
;
367 SampCloseDbObject(GroupObject
);
369 if (!NT_SUCCESS(Status
))
375 /* Remove all groups from the Groups attribute */
376 Status
= SampSetObjectAttribute(UserObject
,
383 if (GroupsBuffer
!= NULL
)
384 midl_user_free(GroupsBuffer
);
391 SampRemoveUserFromAllAliases(IN PSAM_DB_OBJECT UserObject
)
393 FIXME("(%p)\n", UserObject
);
394 return STATUS_SUCCESS
;
399 SampSetUserPassword(IN PSAM_DB_OBJECT UserObject
,
400 IN PENCRYPTED_NT_OWF_PASSWORD NtPassword
,
401 IN BOOLEAN NtPasswordPresent
,
402 IN PENCRYPTED_LM_OWF_PASSWORD LmPassword
,
403 IN BOOLEAN LmPasswordPresent
)
405 PENCRYPTED_NT_OWF_PASSWORD NtHistory
= NULL
;
406 PENCRYPTED_LM_OWF_PASSWORD LmHistory
= NULL
;
407 ULONG NtHistoryLength
= 0;
408 ULONG LmHistoryLength
= 0;
409 ULONG CurrentHistoryLength
;
410 ULONG MaxHistoryLength
= 3;
412 BOOLEAN UseNtPassword
;
413 BOOLEAN UseLmPassword
;
417 ((NtPasswordPresent
!= FALSE
) &&
418 (NtPassword
!= NULL
) &&
419 (memcmp(NtPassword
, &EmptyNtHash
, sizeof(ENCRYPTED_NT_OWF_PASSWORD
)) != 0));
422 ((LmPasswordPresent
!= FALSE
) &&
423 (LmPassword
!= NULL
) &&
424 (memcmp(LmPassword
, &EmptyLmHash
, sizeof(ENCRYPTED_LM_OWF_PASSWORD
)) != 0));
426 /* Update the NT password history only if we have a new non-empty NT password */
429 /* Get the size of the NT history */
430 SampGetObjectAttribute(UserObject
,
436 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
437 if (CurrentHistoryLength
< MaxHistoryLength
)
439 NtHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
443 NtHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
446 /* Allocate the history buffer */
447 NtHistory
= midl_user_allocate(NtHistoryLength
);
448 if (NtHistory
== NULL
)
449 return STATUS_INSUFFICIENT_RESOURCES
;
453 /* Get the history */
454 Status
= SampGetObjectAttribute(UserObject
,
459 if (!NT_SUCCESS(Status
))
463 /* Move the old passwords down by one entry */
464 if (NtHistoryLength
> sizeof(ENCRYPTED_NT_OWF_PASSWORD
))
466 MoveMemory(&(NtHistory
[1]),
468 NtHistoryLength
- sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
471 /* Add the new password to the top of the history */
472 if (NtPasswordPresent
)
474 CopyMemory(&(NtHistory
[0]),
476 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
480 ZeroMemory(&(NtHistory
[0]),
481 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
484 /* Set the history */
485 Status
= SampSetObjectAttribute(UserObject
,
490 if (!NT_SUCCESS(Status
))
494 /* Update the LM password history only if we have a new non-empty LM password */
497 /* Get the size of the LM history */
499 SampGetObjectAttribute(UserObject
,
505 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
506 if (CurrentHistoryLength
< MaxHistoryLength
)
508 LmHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
512 LmHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
515 /* Allocate the history buffer */
516 LmHistory
= midl_user_allocate(LmHistoryLength
);
517 if (LmHistory
== NULL
)
518 return STATUS_INSUFFICIENT_RESOURCES
;
522 /* Get the history */
523 Status
= SampGetObjectAttribute(UserObject
,
528 if (!NT_SUCCESS(Status
))
532 /* Move the old passwords down by one entry */
533 if (LmHistoryLength
> sizeof(ENCRYPTED_LM_OWF_PASSWORD
))
535 MoveMemory(&(LmHistory
[1]),
537 LmHistoryLength
- sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
540 /* Add the new password to the top of the history */
541 if (LmPasswordPresent
)
543 CopyMemory(&(LmHistory
[0]),
545 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
549 ZeroMemory(&(LmHistory
[0]),
550 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
553 /* Set the LM password history */
554 Status
= SampSetObjectAttribute(UserObject
,
559 if (!NT_SUCCESS(Status
))
563 /* Set the new NT password */
566 Status
= SampSetObjectAttribute(UserObject
,
570 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
571 if (!NT_SUCCESS(Status
))
576 Status
= SampSetObjectAttribute(UserObject
,
580 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
581 if (!NT_SUCCESS(Status
))
585 /* Set the new LM password */
588 Status
= SampSetObjectAttribute(UserObject
,
592 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
593 if (!NT_SUCCESS(Status
))
598 Status
= SampSetObjectAttribute(UserObject
,
602 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
603 if (!NT_SUCCESS(Status
))
608 if (NtHistory
!= NULL
)
609 midl_user_free(NtHistory
);
611 if (LmHistory
!= NULL
)
612 midl_user_free(LmHistory
);
619 SampGetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
620 IN OUT PSAMPR_LOGON_HOURS LogonHours
)
622 PUCHAR RawBuffer
= NULL
;
624 ULONG BufferLength
= 0;
627 Status
= SampGetObjectAttribute(UserObject
,
632 if (Status
!= STATUS_BUFFER_OVERFLOW
)
634 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status
);
638 Status
= STATUS_SUCCESS
;
642 LogonHours
->UnitsPerWeek
= 0;
643 LogonHours
->LogonHours
= NULL
;
647 RawBuffer
= midl_user_allocate(Length
);
648 if (RawBuffer
== NULL
)
650 Status
= STATUS_INSUFFICIENT_RESOURCES
;
654 Status
= SampGetObjectAttribute(UserObject
,
659 if (!NT_SUCCESS(Status
))
662 LogonHours
->UnitsPerWeek
= *((PUSHORT
)RawBuffer
);
664 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
666 LogonHours
->LogonHours
= midl_user_allocate(BufferLength
);
667 if (LogonHours
->LogonHours
== NULL
)
669 TRACE("Failed to allocate LogonHours buffer!\n");
670 Status
= STATUS_INSUFFICIENT_RESOURCES
;
674 memcpy(LogonHours
->LogonHours
,
681 if (RawBuffer
!= NULL
)
682 midl_user_free(RawBuffer
);
689 SampSetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
690 IN PSAMPR_LOGON_HOURS LogonHours
)
692 PUCHAR RawBuffer
= NULL
;
697 if (LogonHours
->UnitsPerWeek
> 0)
699 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
701 Length
= BufferLength
+ sizeof(USHORT
);
703 RawBuffer
= midl_user_allocate(Length
);
704 if (RawBuffer
== NULL
)
706 Status
= STATUS_INSUFFICIENT_RESOURCES
;
710 *((PUSHORT
)RawBuffer
) = LogonHours
->UnitsPerWeek
;
712 memcpy(&(RawBuffer
[2]),
713 LogonHours
->LogonHours
,
717 Status
= SampSetObjectAttribute(UserObject
,
724 if (RawBuffer
!= NULL
)
725 midl_user_free(RawBuffer
);