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
9 /* INCLUDES ****************************************************************/
13 WINE_DEFAULT_DEBUG_CHANNEL(samsrv
);
16 /* FUNCTIONS ***************************************************************/
19 SampOpenUserObject(IN PSAM_DB_OBJECT DomainObject
,
21 IN ACCESS_MASK DesiredAccess
,
22 OUT PSAM_DB_OBJECT
*UserObject
)
26 TRACE("(%p %lu %lx %p)\n",
27 DomainObject
, UserId
, DesiredAccess
, UserObject
);
29 /* Convert the RID into a string (hex) */
30 swprintf(szRid
, L
"%08lX", UserId
);
32 /* Create the user object */
33 return SampOpenDbObject(DomainObject
,
44 SampAddGroupMembershipToUser(IN PSAM_DB_OBJECT UserObject
,
48 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
49 ULONG GroupsCount
= 0;
54 TRACE("(%p %lu %lx)\n",
55 UserObject
, GroupId
, Attributes
);
57 Status
= SampGetObjectAttribute(UserObject
,
62 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
65 GroupsBuffer
= midl_user_allocate(Length
+ sizeof(GROUP_MEMBERSHIP
));
66 if (GroupsBuffer
== NULL
)
68 Status
= STATUS_INSUFFICIENT_RESOURCES
;
72 if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
74 Status
= SampGetObjectAttribute(UserObject
,
79 if (!NT_SUCCESS(Status
))
82 GroupsCount
= Length
/ sizeof(GROUP_MEMBERSHIP
);
85 for (i
= 0; i
< GroupsCount
; i
++)
87 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
89 Status
= STATUS_MEMBER_IN_GROUP
;
94 GroupsBuffer
[GroupsCount
].RelativeId
= GroupId
;
95 GroupsBuffer
[GroupsCount
].Attributes
= Attributes
;
96 Length
+= sizeof(GROUP_MEMBERSHIP
);
98 Status
= SampSetObjectAttribute(UserObject
,
105 if (GroupsBuffer
!= NULL
)
106 midl_user_free(GroupsBuffer
);
113 SampRemoveGroupMembershipFromUser(IN PSAM_DB_OBJECT UserObject
,
116 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
117 ULONG GroupsCount
= 0;
120 NTSTATUS Status
= STATUS_SUCCESS
;
123 UserObject
, GroupId
);
125 SampGetObjectAttribute(UserObject
,
132 return STATUS_MEMBER_NOT_IN_GROUP
;
134 GroupsBuffer
= midl_user_allocate(Length
);
135 if (GroupsBuffer
== NULL
)
137 Status
= STATUS_INSUFFICIENT_RESOURCES
;
141 Status
= SampGetObjectAttribute(UserObject
,
146 if (!NT_SUCCESS(Status
))
149 Status
= STATUS_MEMBER_NOT_IN_GROUP
;
151 GroupsCount
= Length
/ sizeof(GROUP_MEMBERSHIP
);
152 for (i
= 0; i
< GroupsCount
; i
++)
154 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
156 Length
-= sizeof(GROUP_MEMBERSHIP
);
157 Status
= STATUS_SUCCESS
;
159 if (GroupsCount
- i
- 1 > 0)
161 CopyMemory(&GroupsBuffer
[i
],
162 &GroupsBuffer
[i
+ 1],
163 (GroupsCount
- i
- 1) * sizeof(GROUP_MEMBERSHIP
));
170 if (!NT_SUCCESS(Status
))
173 Status
= SampSetObjectAttribute(UserObject
,
180 if (GroupsBuffer
!= NULL
)
181 midl_user_free(GroupsBuffer
);
188 SampGetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject
,
191 OUT PULONG GroupAttributes
)
193 PSAM_DB_OBJECT UserObject
= NULL
;
194 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
199 Status
= SampOpenUserObject(DomainObject
,
203 if (!NT_SUCCESS(Status
))
208 SampGetObjectAttribute(UserObject
,
215 return STATUS_UNSUCCESSFUL
; /* FIXME */
217 GroupsBuffer
= midl_user_allocate(Length
);
218 if (GroupsBuffer
== NULL
)
220 Status
= STATUS_INSUFFICIENT_RESOURCES
;
224 Status
= SampGetObjectAttribute(UserObject
,
229 if (!NT_SUCCESS(Status
))
232 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
234 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
236 *GroupAttributes
= GroupsBuffer
[i
].Attributes
;
242 if (GroupsBuffer
!= NULL
)
243 midl_user_free(GroupsBuffer
);
245 if (UserObject
!= NULL
)
246 SampCloseDbObject(UserObject
);
253 SampSetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject
,
256 IN ULONG GroupAttributes
)
258 PSAM_DB_OBJECT UserObject
= NULL
;
259 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
264 Status
= SampOpenUserObject(DomainObject
,
268 if (!NT_SUCCESS(Status
))
273 SampGetObjectAttribute(UserObject
,
280 return STATUS_UNSUCCESSFUL
; /* FIXME */
282 GroupsBuffer
= midl_user_allocate(Length
);
283 if (GroupsBuffer
== NULL
)
285 Status
= STATUS_INSUFFICIENT_RESOURCES
;
289 Status
= SampGetObjectAttribute(UserObject
,
294 if (!NT_SUCCESS(Status
))
297 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
299 if (GroupsBuffer
[i
].RelativeId
== GroupId
)
301 GroupsBuffer
[i
].Attributes
= GroupAttributes
;
306 Status
= SampSetObjectAttribute(UserObject
,
313 if (GroupsBuffer
!= NULL
)
314 midl_user_free(GroupsBuffer
);
316 if (UserObject
!= NULL
)
317 SampCloseDbObject(UserObject
);
324 SampRemoveUserFromAllGroups(IN PSAM_DB_OBJECT UserObject
)
326 PGROUP_MEMBERSHIP GroupsBuffer
= NULL
;
327 PSAM_DB_OBJECT GroupObject
;
332 SampGetObjectAttribute(UserObject
,
339 return STATUS_SUCCESS
;
341 GroupsBuffer
= midl_user_allocate(Length
);
342 if (GroupsBuffer
== NULL
)
344 Status
= STATUS_INSUFFICIENT_RESOURCES
;
348 Status
= SampGetObjectAttribute(UserObject
,
353 if (!NT_SUCCESS(Status
))
356 for (i
= 0; i
< (Length
/ sizeof(GROUP_MEMBERSHIP
)); i
++)
358 Status
= SampOpenGroupObject(UserObject
->ParentObject
,
359 GroupsBuffer
[i
].RelativeId
,
362 if (!NT_SUCCESS(Status
))
367 Status
= SampRemoveMemberFromGroup(GroupObject
,
368 UserObject
->RelativeId
);
370 SampCloseDbObject(GroupObject
);
372 if (!NT_SUCCESS(Status
))
379 if (GroupsBuffer
!= NULL
)
380 midl_user_free(GroupsBuffer
);
387 SampRemoveUserFromAllAliases(IN PSAM_DB_OBJECT UserObject
)
389 FIXME("(%p)\n", UserObject
);
390 return STATUS_SUCCESS
;
395 SampSetUserPassword(IN PSAM_DB_OBJECT UserObject
,
396 IN PENCRYPTED_NT_OWF_PASSWORD NtPassword
,
397 IN BOOLEAN NtPasswordPresent
,
398 IN PENCRYPTED_LM_OWF_PASSWORD LmPassword
,
399 IN BOOLEAN LmPasswordPresent
)
401 PENCRYPTED_NT_OWF_PASSWORD NtHistory
= NULL
;
402 PENCRYPTED_LM_OWF_PASSWORD LmHistory
= NULL
;
403 ULONG NtHistoryLength
= 0;
404 ULONG LmHistoryLength
= 0;
405 ULONG CurrentHistoryLength
;
406 ULONG MaxHistoryLength
= 3;
408 BOOLEAN UseNtPassword
;
409 BOOLEAN UseLmPassword
;
413 ((NtPasswordPresent
!= FALSE
) &&
414 (NtPassword
!= NULL
) &&
415 (memcmp(NtPassword
, &EmptyNtHash
, sizeof(ENCRYPTED_NT_OWF_PASSWORD
)) != 0));
418 ((LmPasswordPresent
!= FALSE
) &&
419 (LmPassword
!= NULL
) &&
420 (memcmp(LmPassword
, &EmptyLmHash
, sizeof(ENCRYPTED_LM_OWF_PASSWORD
)) != 0));
422 /* Update the NT password history only if we have a new non-empty NT password */
425 /* Get the size of the NT history */
426 SampGetObjectAttribute(UserObject
,
432 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
433 if (CurrentHistoryLength
< MaxHistoryLength
)
435 NtHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
439 NtHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_NT_OWF_PASSWORD
);
442 /* Allocate the history buffer */
443 NtHistory
= midl_user_allocate(NtHistoryLength
);
444 if (NtHistory
== NULL
)
445 return STATUS_INSUFFICIENT_RESOURCES
;
449 /* Get the history */
450 Status
= SampGetObjectAttribute(UserObject
,
455 if (!NT_SUCCESS(Status
))
459 /* Move the old passwords down by one entry */
460 if (NtHistoryLength
> sizeof(ENCRYPTED_NT_OWF_PASSWORD
))
462 MoveMemory(&(NtHistory
[1]),
464 NtHistoryLength
- sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
467 /* Add the new password to the top of the history */
468 if (NtPasswordPresent
)
470 CopyMemory(&(NtHistory
[0]),
472 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
476 ZeroMemory(&(NtHistory
[0]),
477 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
480 /* Set the history */
481 Status
= SampSetObjectAttribute(UserObject
,
486 if (!NT_SUCCESS(Status
))
490 /* Update the LM password history only if we have a new non-empty LM password */
493 /* Get the size of the LM history */
495 SampGetObjectAttribute(UserObject
,
501 CurrentHistoryLength
= Length
/ sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
502 if (CurrentHistoryLength
< MaxHistoryLength
)
504 LmHistoryLength
= (CurrentHistoryLength
+ 1) * sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
508 LmHistoryLength
= MaxHistoryLength
* sizeof(ENCRYPTED_LM_OWF_PASSWORD
);
511 /* Allocate the history buffer */
512 LmHistory
= midl_user_allocate(LmHistoryLength
);
513 if (LmHistory
== NULL
)
514 return STATUS_INSUFFICIENT_RESOURCES
;
518 /* Get the history */
519 Status
= SampGetObjectAttribute(UserObject
,
524 if (!NT_SUCCESS(Status
))
528 /* Move the old passwords down by one entry */
529 if (LmHistoryLength
> sizeof(ENCRYPTED_LM_OWF_PASSWORD
))
531 MoveMemory(&(LmHistory
[1]),
533 LmHistoryLength
- sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
536 /* Add the new password to the top of the history */
537 if (LmPasswordPresent
)
539 CopyMemory(&(LmHistory
[0]),
541 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
545 ZeroMemory(&(LmHistory
[0]),
546 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
549 /* Set the LM password history */
550 Status
= SampSetObjectAttribute(UserObject
,
555 if (!NT_SUCCESS(Status
))
559 /* Set the new NT password */
562 Status
= SampSetObjectAttribute(UserObject
,
566 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
567 if (!NT_SUCCESS(Status
))
572 Status
= SampSetObjectAttribute(UserObject
,
576 sizeof(ENCRYPTED_NT_OWF_PASSWORD
));
577 if (!NT_SUCCESS(Status
))
581 /* Set the new LM password */
584 Status
= SampSetObjectAttribute(UserObject
,
588 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
589 if (!NT_SUCCESS(Status
))
594 Status
= SampSetObjectAttribute(UserObject
,
598 sizeof(ENCRYPTED_LM_OWF_PASSWORD
));
599 if (!NT_SUCCESS(Status
))
604 if (NtHistory
!= NULL
)
605 midl_user_free(NtHistory
);
607 if (LmHistory
!= NULL
)
608 midl_user_free(LmHistory
);
615 SampGetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
616 IN OUT PSAMPR_LOGON_HOURS LogonHours
)
618 PUCHAR RawBuffer
= NULL
;
620 ULONG BufferLength
= 0;
623 Status
= SampGetObjectAttribute(UserObject
,
628 if (Status
!= STATUS_BUFFER_OVERFLOW
)
630 TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status
);
634 Status
= STATUS_SUCCESS
;
638 LogonHours
->UnitsPerWeek
= 0;
639 LogonHours
->LogonHours
= NULL
;
643 RawBuffer
= midl_user_allocate(Length
);
644 if (RawBuffer
== NULL
)
646 Status
= STATUS_INSUFFICIENT_RESOURCES
;
650 Status
= SampGetObjectAttribute(UserObject
,
655 if (!NT_SUCCESS(Status
))
658 LogonHours
->UnitsPerWeek
= *((PUSHORT
)RawBuffer
);
660 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
662 LogonHours
->LogonHours
= midl_user_allocate(BufferLength
);
663 if (LogonHours
->LogonHours
== NULL
)
665 TRACE("Failed to allocate LogonHours buffer!\n");
666 Status
= STATUS_INSUFFICIENT_RESOURCES
;
670 memcpy(LogonHours
->LogonHours
,
677 if (RawBuffer
!= NULL
)
678 midl_user_free(RawBuffer
);
685 SampSetLogonHoursAttrbute(IN PSAM_DB_OBJECT UserObject
,
686 IN PSAMPR_LOGON_HOURS LogonHours
)
688 PUCHAR RawBuffer
= NULL
;
693 if (LogonHours
->UnitsPerWeek
> 0)
695 BufferLength
= (((ULONG
)LogonHours
->UnitsPerWeek
) + 7) / 8;
697 Length
= BufferLength
+ sizeof(USHORT
);
699 RawBuffer
= midl_user_allocate(Length
);
700 if (RawBuffer
== NULL
)
702 Status
= STATUS_INSUFFICIENT_RESOURCES
;
706 *((PUSHORT
)RawBuffer
) = LogonHours
->UnitsPerWeek
;
708 memcpy(&(RawBuffer
[2]),
709 LogonHours
->LogonHours
,
713 Status
= SampSetObjectAttribute(UserObject
,
720 if (RawBuffer
!= NULL
)
721 midl_user_free(RawBuffer
);