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
);
365 SampCloseDbObject(GroupObject
);
367 if (!NT_SUCCESS(Status
))
374 if (GroupsBuffer
!= NULL
)
375 midl_user_free(GroupsBuffer
);
382 SampRemoveUserFromAllAliases(IN PSAM_DB_OBJECT UserObject
)
384 FIXME("(%p)\n", UserObject
);
385 return STATUS_SUCCESS
;
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
)
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;
403 BOOLEAN UseNtPassword
;
404 BOOLEAN UseLmPassword
;
408 ((NtPasswordPresent
!= FALSE
) &&
409 (NtPassword
!= NULL
) &&
410 (memcmp(NtPassword
, &EmptyNtHash
, sizeof(ENCRYPTED_NT_OWF_PASSWORD
)) != 0));
413 ((LmPasswordPresent
!= FALSE
) &&
414 (LmPassword
!= NULL
) &&
415 (memcmp(LmPassword
, &EmptyLmHash
, sizeof(ENCRYPTED_LM_OWF_PASSWORD
)) != 0));
417 /* Update the NT password history only if we have a new non-empty NT password */
420 /* Get the size of the NT history */
421 SampGetObjectAttribute(UserObject
,
427 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
428 if (CurrentHistoryLength
< MaxHistoryLength
)
430 NtHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
434 NtHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
437 /* Allocate the history buffer */
438 NtHistory
= midl_user_allocate(NtHistoryLength
);
439 if (NtHistory
== NULL
)
440 return STATUS_INSUFFICIENT_RESOURCES
;
444 /* Get the history */
445 Status
= SampGetObjectAttribute(UserObject
,
450 if (!NT_SUCCESS(Status
))
454 /* Move the old passwords down by one entry */
455 if (NtHistoryLength
> sizeof(ENCRYPTED_NT_OWF_PASSWORD
))
457 MoveMemory(&(NtHistory
[1]),
459 NtHistoryLength
- sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
462 /* Add the new password to the top of the history */
463 if (NtPasswordPresent
)
465 CopyMemory(&(NtHistory
[0]),
467 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
471 ZeroMemory(&(NtHistory
[0]),
472 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
475 /* Set the history */
476 Status
= SampSetObjectAttribute(UserObject
,
481 if (!NT_SUCCESS(Status
))
485 /* Update the LM password history only if we have a new non-empty LM password */
488 /* Get the size of the LM history */
490 SampGetObjectAttribute(UserObject
,
496 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
497 if (CurrentHistoryLength
< MaxHistoryLength
)
499 LmHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
503 LmHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
506 /* Allocate the history buffer */
507 LmHistory
= midl_user_allocate(LmHistoryLength
);
508 if (LmHistory
== NULL
)
509 return STATUS_INSUFFICIENT_RESOURCES
;
513 /* Get the history */
514 Status
= SampGetObjectAttribute(UserObject
,
519 if (!NT_SUCCESS(Status
))
523 /* Move the old passwords down by one entry */
524 if (LmHistoryLength
> sizeof(ENCRYPTED_LM_OWF_PASSWORD
))
526 MoveMemory(&(LmHistory
[1]),
528 LmHistoryLength
- sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
531 /* Add the new password to the top of the history */
532 if (LmPasswordPresent
)
534 CopyMemory(&(LmHistory
[0]),
536 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
540 ZeroMemory(&(LmHistory
[0]),
541 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
544 /* Set the LM password history */
545 Status
= SampSetObjectAttribute(UserObject
,
550 if (!NT_SUCCESS(Status
))
554 /* Set the new NT password */
557 Status
= SampSetObjectAttribute(UserObject
,
561 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
562 if (!NT_SUCCESS(Status
))
567 Status
= SampSetObjectAttribute(UserObject
,
571 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
572 if (!NT_SUCCESS(Status
))
576 /* Set the new LM password */
579 Status
= SampSetObjectAttribute(UserObject
,
583 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
584 if (!NT_SUCCESS(Status
))
589 Status
= SampSetObjectAttribute(UserObject
,
593 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
594 if (!NT_SUCCESS(Status
))
599 if (NtHistory
!= NULL
)
600 midl_user_free(NtHistory
);
602 if (LmHistory
!= NULL
)
603 midl_user_free(LmHistory
);
610 SampGetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
611 IN OUT PSAMPR_LOGON_HOURS LogonHours
)
613 PUCHAR RawBuffer
= NULL
;
615 ULONG BufferLength
= 0;
618 Status
= SampGetObjectAttribute(UserObject
,
623 if (Status
!= STATUS_BUFFER_OVERFLOW
)
625 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status
);
629 Status
= STATUS_SUCCESS
;
633 LogonHours
->UnitsPerWeek
= 0;
634 LogonHours
->LogonHours
= NULL
;
638 RawBuffer
= midl_user_allocate(Length
);
639 if (RawBuffer
== NULL
)
641 Status
= STATUS_INSUFFICIENT_RESOURCES
;
645 Status
= SampGetObjectAttribute(UserObject
,
650 if (!NT_SUCCESS(Status
))
653 LogonHours
->UnitsPerWeek
= *((PUSHORT
)RawBuffer
);
655 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
657 LogonHours
->LogonHours
= midl_user_allocate(BufferLength
);
658 if (LogonHours
->LogonHours
== NULL
)
660 TRACE("Failed to allocate LogonHours buffer!\n");
661 Status
= STATUS_INSUFFICIENT_RESOURCES
;
665 memcpy(LogonHours
->LogonHours
,
672 if (RawBuffer
!= NULL
)
673 midl_user_free(RawBuffer
);
680 SampSetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
681 IN PSAMPR_LOGON_HOURS LogonHours
)
683 PUCHAR RawBuffer
= NULL
;
688 if (LogonHours
->UnitsPerWeek
> 0)
690 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
692 Length
= BufferLength
+ sizeof(USHORT
);
694 RawBuffer
= midl_user_allocate(Length
);
695 if (RawBuffer
== NULL
)
697 Status
= STATUS_INSUFFICIENT_RESOURCES
;
701 *((PUSHORT
)RawBuffer
) = LogonHours
->UnitsPerWeek
;
703 memcpy(&(RawBuffer
[2]),
704 LogonHours
->LogonHours
,
708 Status
= SampSetObjectAttribute(UserObject
,
715 if (RawBuffer
!= NULL
)
716 midl_user_free(RawBuffer
);