[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Security Account Manager (SAM) Server
4 * FILE: reactos/dll/win32/samsrv/samrpc.c
5 * PURPOSE: RPC interface functions
6 *
7 * PROGRAMMERS: Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "samsrv.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
15
16 /* GLOBALS *******************************************************************/
17
18 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
19
20 static GENERIC_MAPPING ServerMapping =
21 {
22 SAM_SERVER_READ,
23 SAM_SERVER_WRITE,
24 SAM_SERVER_EXECUTE,
25 SAM_SERVER_ALL_ACCESS
26 };
27
28 static GENERIC_MAPPING DomainMapping =
29 {
30 DOMAIN_READ,
31 DOMAIN_WRITE,
32 DOMAIN_EXECUTE,
33 DOMAIN_ALL_ACCESS
34 };
35
36 static GENERIC_MAPPING AliasMapping =
37 {
38 ALIAS_READ,
39 ALIAS_WRITE,
40 ALIAS_EXECUTE,
41 ALIAS_ALL_ACCESS
42 };
43
44 static GENERIC_MAPPING GroupMapping =
45 {
46 GROUP_READ,
47 GROUP_WRITE,
48 GROUP_EXECUTE,
49 GROUP_ALL_ACCESS
50 };
51
52 static GENERIC_MAPPING UserMapping =
53 {
54 USER_READ,
55 USER_WRITE,
56 USER_EXECUTE,
57 USER_ALL_ACCESS
58 };
59
60 PGENERIC_MAPPING pServerMapping = &ServerMapping;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 static
66 LARGE_INTEGER
67 SampAddRelativeTimeToTime(IN LARGE_INTEGER AbsoluteTime,
68 IN LARGE_INTEGER RelativeTime)
69 {
70 LARGE_INTEGER NewTime;
71
72 NewTime.QuadPart = AbsoluteTime.QuadPart - RelativeTime.QuadPart;
73
74 if (NewTime.QuadPart < 0)
75 NewTime.QuadPart = 0;
76
77 return NewTime;
78 }
79
80
81 VOID
82 SampStartRpcServer(VOID)
83 {
84 RPC_STATUS Status;
85
86 TRACE("SampStartRpcServer() called\n");
87
88 Status = RpcServerUseProtseqEpW(L"ncacn_np",
89 10,
90 L"\\pipe\\samr",
91 NULL);
92 if (Status != RPC_S_OK)
93 {
94 WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
95 return;
96 }
97
98 Status = RpcServerRegisterIf(samr_v1_0_s_ifspec,
99 NULL,
100 NULL);
101 if (Status != RPC_S_OK)
102 {
103 WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
104 return;
105 }
106
107 Status = RpcServerListen(1, 20, TRUE);
108 if (Status != RPC_S_OK)
109 {
110 WARN("RpcServerListen() failed (Status %lx)\n", Status);
111 return;
112 }
113
114 TRACE("SampStartRpcServer() done\n");
115 }
116
117
118 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
119 {
120 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
121 }
122
123
124 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
125 {
126 HeapFree(GetProcessHeap(), 0, ptr);
127 }
128
129
130 void __RPC_USER SAMPR_HANDLE_rundown(SAMPR_HANDLE hHandle)
131 {
132 }
133
134
135 /* Function 0 */
136 NTSTATUS
137 NTAPI
138 SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
139 OUT SAMPR_HANDLE *ServerHandle,
140 IN ACCESS_MASK DesiredAccess)
141 {
142 PSAM_DB_OBJECT ServerObject;
143 NTSTATUS Status;
144
145 TRACE("SamrConnect(%p %p %lx)\n",
146 ServerName, ServerHandle, DesiredAccess);
147
148 RtlAcquireResourceShared(&SampResource,
149 TRUE);
150
151 /* Map generic access rights */
152 RtlMapGenericMask(&DesiredAccess,
153 &ServerMapping);
154
155 /* Open the Server Object */
156 Status = SampOpenDbObject(NULL,
157 NULL,
158 L"SAM",
159 0,
160 SamDbServerObject,
161 DesiredAccess,
162 &ServerObject);
163 if (NT_SUCCESS(Status))
164 *ServerHandle = (SAMPR_HANDLE)ServerObject;
165
166 RtlReleaseResource(&SampResource);
167
168 TRACE("SamrConnect done (Status 0x%08lx)\n", Status);
169
170 return Status;
171 }
172
173
174 /* Function 1 */
175 NTSTATUS
176 NTAPI
177 SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle)
178 {
179 PSAM_DB_OBJECT DbObject;
180 NTSTATUS Status = STATUS_SUCCESS;
181
182 TRACE("SamrCloseHandle(%p)\n", SamHandle);
183
184 RtlAcquireResourceShared(&SampResource,
185 TRUE);
186
187 Status = SampValidateDbObject(*SamHandle,
188 SamDbIgnoreObject,
189 0,
190 &DbObject);
191 if (Status == STATUS_SUCCESS)
192 {
193 Status = SampCloseDbObject(DbObject);
194 *SamHandle = NULL;
195 }
196
197 RtlReleaseResource(&SampResource);
198
199 TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
200
201 return Status;
202 }
203
204
205 /* Function 2 */
206 NTSTATUS
207 NTAPI
208 SamrSetSecurityObject(IN SAMPR_HANDLE ObjectHandle,
209 IN SECURITY_INFORMATION SecurityInformation,
210 IN PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
211 {
212 UNIMPLEMENTED;
213 return STATUS_NOT_IMPLEMENTED;
214 }
215
216
217 /* Function 3 */
218 NTSTATUS
219 NTAPI
220 SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
221 IN SECURITY_INFORMATION SecurityInformation,
222 OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
223 {
224 UNIMPLEMENTED;
225 return STATUS_NOT_IMPLEMENTED;
226 }
227
228
229 /* Function 4 */
230 NTSTATUS
231 NTAPI
232 SamrShutdownSamServer(IN SAMPR_HANDLE ServerHandle)
233 {
234 PSAM_DB_OBJECT ServerObject;
235 NTSTATUS Status;
236
237 TRACE("(%p)\n", ServerHandle);
238
239 RtlAcquireResourceShared(&SampResource,
240 TRUE);
241
242 /* Validate the server handle */
243 Status = SampValidateDbObject(ServerHandle,
244 SamDbServerObject,
245 SAM_SERVER_SHUTDOWN,
246 &ServerObject);
247
248 RtlReleaseResource(&SampResource);
249
250 if (!NT_SUCCESS(Status))
251 return Status;
252
253 /* Shut the server down */
254 RpcMgmtStopServerListening(0);
255
256 return STATUS_SUCCESS;
257 }
258
259
260 /* Function 5 */
261 NTSTATUS
262 NTAPI
263 SamrLookupDomainInSamServer(IN SAMPR_HANDLE ServerHandle,
264 IN PRPC_UNICODE_STRING Name,
265 OUT PRPC_SID *DomainId)
266 {
267 PSAM_DB_OBJECT ServerObject;
268 HANDLE DomainsKeyHandle = NULL;
269 HANDLE DomainKeyHandle = NULL;
270 WCHAR DomainKeyName[64];
271 ULONG Index;
272 WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
273 UNICODE_STRING DomainName;
274 ULONG Length;
275 BOOL Found = FALSE;
276 NTSTATUS Status;
277
278 TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
279 ServerHandle, Name, DomainId);
280
281 RtlAcquireResourceShared(&SampResource,
282 TRUE);
283
284 /* Validate the server handle */
285 Status = SampValidateDbObject(ServerHandle,
286 SamDbServerObject,
287 SAM_SERVER_LOOKUP_DOMAIN,
288 &ServerObject);
289 if (!NT_SUCCESS(Status))
290 goto done;
291
292 *DomainId = NULL;
293
294 Status = SampRegOpenKey(ServerObject->KeyHandle,
295 L"Domains",
296 KEY_READ,
297 &DomainsKeyHandle);
298 if (!NT_SUCCESS(Status))
299 goto done;
300
301 Index = 0;
302 while (Found == FALSE)
303 {
304 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
305 Index,
306 64,
307 DomainKeyName);
308 if (!NT_SUCCESS(Status))
309 {
310 if (Status == STATUS_NO_MORE_ENTRIES)
311 Status = STATUS_NO_SUCH_DOMAIN;
312 break;
313 }
314
315 TRACE("Domain key name: %S\n", DomainKeyName);
316
317 Status = SampRegOpenKey(DomainsKeyHandle,
318 DomainKeyName,
319 KEY_READ,
320 &DomainKeyHandle);
321 if (NT_SUCCESS(Status))
322 {
323 Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
324 Status = SampRegQueryValue(DomainKeyHandle,
325 L"Name",
326 NULL,
327 (PVOID)&DomainNameString,
328 &Length);
329 if (NT_SUCCESS(Status))
330 {
331 TRACE("Domain name: %S\n", DomainNameString);
332
333 RtlInitUnicodeString(&DomainName,
334 DomainNameString);
335 if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
336 {
337 TRACE("Found it!\n");
338 Found = TRUE;
339
340 Status = SampRegQueryValue(DomainKeyHandle,
341 L"SID",
342 NULL,
343 NULL,
344 &Length);
345 if (NT_SUCCESS(Status))
346 {
347 *DomainId = midl_user_allocate(Length);
348
349 SampRegQueryValue(DomainKeyHandle,
350 L"SID",
351 NULL,
352 (PVOID)*DomainId,
353 &Length);
354
355 Status = STATUS_SUCCESS;
356 break;
357 }
358 }
359 }
360
361 SampRegCloseKey(&DomainKeyHandle);
362 }
363
364 Index++;
365 }
366
367 done:
368 SampRegCloseKey(&DomainKeyHandle);
369 SampRegCloseKey(&DomainsKeyHandle);
370
371 RtlReleaseResource(&SampResource);
372
373 return Status;
374 }
375
376
377 /* Function 6 */
378 NTSTATUS
379 NTAPI
380 SamrEnumerateDomainsInSamServer(IN SAMPR_HANDLE ServerHandle,
381 IN OUT unsigned long *EnumerationContext,
382 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
383 IN ULONG PreferedMaximumLength,
384 OUT PULONG CountReturned)
385 {
386 PSAM_DB_OBJECT ServerObject;
387 WCHAR DomainKeyName[64];
388 HANDLE DomainsKeyHandle = NULL;
389 HANDLE DomainKeyHandle = NULL;
390 ULONG EnumIndex;
391 ULONG EnumCount;
392 ULONG RequiredLength;
393 ULONG DataLength;
394 ULONG i;
395 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
396 NTSTATUS Status;
397
398 TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
399 ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
400 CountReturned);
401
402 RtlAcquireResourceShared(&SampResource,
403 TRUE);
404
405 /* Validate the server handle */
406 Status = SampValidateDbObject(ServerHandle,
407 SamDbServerObject,
408 SAM_SERVER_ENUMERATE_DOMAINS,
409 &ServerObject);
410 if (!NT_SUCCESS(Status))
411 goto done;
412
413 Status = SampRegOpenKey(ServerObject->KeyHandle,
414 L"Domains",
415 KEY_READ,
416 &DomainsKeyHandle);
417 if (!NT_SUCCESS(Status))
418 goto done;
419
420 EnumIndex = *EnumerationContext;
421 EnumCount = 0;
422 RequiredLength = 0;
423
424 while (TRUE)
425 {
426 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
427 EnumIndex,
428 64 * sizeof(WCHAR),
429 DomainKeyName);
430 if (!NT_SUCCESS(Status))
431 break;
432
433 TRACE("EnumIndex: %lu\n", EnumIndex);
434 TRACE("Domain key name: %S\n", DomainKeyName);
435
436 Status = SampRegOpenKey(DomainsKeyHandle,
437 DomainKeyName,
438 KEY_READ,
439 &DomainKeyHandle);
440 TRACE("SampRegOpenKey returned %08lX\n", Status);
441 if (NT_SUCCESS(Status))
442 {
443 DataLength = 0;
444 Status = SampRegQueryValue(DomainKeyHandle,
445 L"Name",
446 NULL,
447 NULL,
448 &DataLength);
449 TRACE("SampRegQueryValue returned %08lX\n", Status);
450 if (NT_SUCCESS(Status))
451 {
452 TRACE("Data length: %lu\n", DataLength);
453
454 if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
455 break;
456
457 RequiredLength += (DataLength + sizeof(UNICODE_STRING));
458 EnumCount++;
459 }
460
461 SampRegCloseKey(&DomainKeyHandle);
462 }
463
464 EnumIndex++;
465 }
466
467 TRACE("EnumCount: %lu\n", EnumCount);
468 TRACE("RequiredLength: %lu\n", RequiredLength);
469
470 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
471 if (EnumBuffer == NULL)
472 {
473 Status = STATUS_INSUFFICIENT_RESOURCES;
474 goto done;
475 }
476
477 EnumBuffer->EntriesRead = EnumCount;
478 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
479 if (EnumBuffer->Buffer == NULL)
480 {
481 Status = STATUS_INSUFFICIENT_RESOURCES;
482 goto done;
483 }
484
485 EnumIndex = *EnumerationContext;
486 for (i = 0; i < EnumCount; i++, EnumIndex++)
487 {
488 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
489 EnumIndex,
490 64 * sizeof(WCHAR),
491 DomainKeyName);
492 if (!NT_SUCCESS(Status))
493 break;
494
495 TRACE("EnumIndex: %lu\n", EnumIndex);
496 TRACE("Domain key name: %S\n", DomainKeyName);
497
498 Status = SampRegOpenKey(DomainsKeyHandle,
499 DomainKeyName,
500 KEY_READ,
501 &DomainKeyHandle);
502 TRACE("SampRegOpenKey returned %08lX\n", Status);
503 if (NT_SUCCESS(Status))
504 {
505 DataLength = 0;
506 Status = SampRegQueryValue(DomainKeyHandle,
507 L"Name",
508 NULL,
509 NULL,
510 &DataLength);
511 TRACE("SampRegQueryValue returned %08lX\n", Status);
512 if (NT_SUCCESS(Status))
513 {
514 EnumBuffer->Buffer[i].RelativeId = 0;
515 EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
516 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
517 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
518 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
519 {
520 SampRegCloseKey(&DomainKeyHandle);
521 Status = STATUS_INSUFFICIENT_RESOURCES;
522 goto done;
523 }
524
525 Status = SampRegQueryValue(DomainKeyHandle,
526 L"Name",
527 NULL,
528 EnumBuffer->Buffer[i].Name.Buffer,
529 &DataLength);
530 TRACE("SampRegQueryValue returned %08lX\n", Status);
531 if (NT_SUCCESS(Status))
532 {
533 TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
534 }
535 }
536
537 SampRegCloseKey(&DomainKeyHandle);
538
539 if (!NT_SUCCESS(Status))
540 goto done;
541 }
542 }
543
544 if (NT_SUCCESS(Status))
545 {
546 *EnumerationContext += EnumCount;
547 *Buffer = EnumBuffer;
548 *CountReturned = EnumCount;
549 }
550
551 done:
552 SampRegCloseKey(&DomainKeyHandle);
553 SampRegCloseKey(&DomainsKeyHandle);
554
555 if (!NT_SUCCESS(Status))
556 {
557 *EnumerationContext = 0;
558 *Buffer = NULL;
559 *CountReturned = 0;
560
561 if (EnumBuffer != NULL)
562 {
563 if (EnumBuffer->Buffer != NULL)
564 {
565 if (EnumBuffer->EntriesRead != 0)
566 {
567 for (i = 0; i < EnumBuffer->EntriesRead; i++)
568 {
569 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
570 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
571 }
572 }
573
574 midl_user_free(EnumBuffer->Buffer);
575 }
576
577 midl_user_free(EnumBuffer);
578 }
579 }
580
581 RtlReleaseResource(&SampResource);
582
583 return Status;
584 }
585
586
587 /* Function 7 */
588 NTSTATUS
589 NTAPI
590 SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
591 IN ACCESS_MASK DesiredAccess,
592 IN PRPC_SID DomainId,
593 OUT SAMPR_HANDLE *DomainHandle)
594 {
595 PSAM_DB_OBJECT ServerObject;
596 PSAM_DB_OBJECT DomainObject;
597 NTSTATUS Status;
598
599 TRACE("SamrOpenDomain(%p %lx %p %p)\n",
600 ServerHandle, DesiredAccess, DomainId, DomainHandle);
601
602 /* Map generic access rights */
603 RtlMapGenericMask(&DesiredAccess,
604 &DomainMapping);
605
606 RtlAcquireResourceShared(&SampResource,
607 TRUE);
608
609 /* Validate the server handle */
610 Status = SampValidateDbObject(ServerHandle,
611 SamDbServerObject,
612 SAM_SERVER_LOOKUP_DOMAIN,
613 &ServerObject);
614 if (!NT_SUCCESS(Status))
615 return Status;
616
617 /* Validate the Domain SID */
618 if ((DomainId->Revision != SID_REVISION) ||
619 (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
620 (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
621 return STATUS_INVALID_PARAMETER;
622
623 /* Open the domain object */
624 if ((DomainId->SubAuthorityCount == 1) &&
625 (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
626 {
627 /* Builtin domain object */
628 TRACE("Opening the builtin domain object.\n");
629
630 Status = SampOpenDbObject(ServerObject,
631 L"Domains",
632 L"Builtin",
633 0,
634 SamDbDomainObject,
635 DesiredAccess,
636 &DomainObject);
637 }
638 else if ((DomainId->SubAuthorityCount == 4) &&
639 (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
640 {
641 /* Account domain object */
642 TRACE("Opening the account domain object.\n");
643
644 /* FIXME: Check the account domain sub authorities!!! */
645
646 Status = SampOpenDbObject(ServerObject,
647 L"Domains",
648 L"Account",
649 0,
650 SamDbDomainObject,
651 DesiredAccess,
652 &DomainObject);
653 }
654 else
655 {
656 /* No vaild domain SID */
657 Status = STATUS_INVALID_PARAMETER;
658 }
659
660 if (NT_SUCCESS(Status))
661 *DomainHandle = (SAMPR_HANDLE)DomainObject;
662
663 RtlReleaseResource(&SampResource);
664
665 TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
666
667 return Status;
668 }
669
670
671 static NTSTATUS
672 SampQueryDomainPassword(PSAM_DB_OBJECT DomainObject,
673 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
674 {
675 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
676 SAM_DOMAIN_FIXED_DATA FixedData;
677 ULONG Length = 0;
678 NTSTATUS Status;
679
680 *Buffer = NULL;
681
682 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
683 if (InfoBuffer == NULL)
684 return STATUS_INSUFFICIENT_RESOURCES;
685
686 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
687 Status = SampGetObjectAttribute(DomainObject,
688 L"F",
689 NULL,
690 (PVOID)&FixedData,
691 &Length);
692 if (!NT_SUCCESS(Status))
693 goto done;
694
695 InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
696 InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
697 InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
698 InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
699 InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
700 InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
701 InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
702
703 *Buffer = InfoBuffer;
704
705 done:
706 if (!NT_SUCCESS(Status))
707 {
708 if (InfoBuffer != NULL)
709 {
710 midl_user_free(InfoBuffer);
711 }
712 }
713
714 return Status;
715 }
716
717
718 static NTSTATUS
719 SampGetNumberOfAccounts(PSAM_DB_OBJECT DomainObject,
720 LPCWSTR AccountType,
721 PULONG Count)
722 {
723 HANDLE AccountKeyHandle = NULL;
724 HANDLE NamesKeyHandle = NULL;
725 NTSTATUS Status;
726
727 *Count = 0;
728
729 Status = SampRegOpenKey(DomainObject->KeyHandle,
730 AccountType,
731 KEY_READ,
732 &AccountKeyHandle);
733 if (!NT_SUCCESS(Status))
734 return Status;
735
736 Status = SampRegOpenKey(AccountKeyHandle,
737 L"Names",
738 KEY_READ,
739 &NamesKeyHandle);
740 if (!NT_SUCCESS(Status))
741 goto done;
742
743 Status = SampRegQueryKeyInfo(NamesKeyHandle,
744 NULL,
745 Count);
746
747 done:
748 SampRegCloseKey(&NamesKeyHandle);
749 SampRegCloseKey(&AccountKeyHandle);
750
751 return Status;
752 }
753
754
755 static NTSTATUS
756 SampQueryDomainGeneral(PSAM_DB_OBJECT DomainObject,
757 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
758 {
759 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
760 SAM_DOMAIN_FIXED_DATA FixedData;
761 ULONG Length = 0;
762 NTSTATUS Status;
763
764 *Buffer = NULL;
765
766 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
767 if (InfoBuffer == NULL)
768 return STATUS_INSUFFICIENT_RESOURCES;
769
770 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
771 Status = SampGetObjectAttribute(DomainObject,
772 L"F",
773 NULL,
774 (PVOID)&FixedData,
775 &Length);
776 if (!NT_SUCCESS(Status))
777 goto done;
778
779 InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
780 InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
781 InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
782 InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
783 InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
784 InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
785 InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
786
787 /* Get the OemInformation string */
788 Status = SampGetObjectAttributeString(DomainObject,
789 L"OemInformation",
790 &InfoBuffer->General.OemInformation);
791 if (!NT_SUCCESS(Status))
792 {
793 TRACE("Status 0x%08lx\n", Status);
794 goto done;
795 }
796
797 /* Get the Name string */
798 Status = SampGetObjectAttributeString(DomainObject,
799 L"Name",
800 &InfoBuffer->General.DomainName);
801 if (!NT_SUCCESS(Status))
802 {
803 TRACE("Status 0x%08lx\n", Status);
804 goto done;
805 }
806
807 /* Get the ReplicaSourceNodeName string */
808 Status = SampGetObjectAttributeString(DomainObject,
809 L"ReplicaSourceNodeName",
810 &InfoBuffer->General.ReplicaSourceNodeName);
811 if (!NT_SUCCESS(Status))
812 {
813 TRACE("Status 0x%08lx\n", Status);
814 goto done;
815 }
816
817 /* Get the number of Users in the Domain */
818 Status = SampGetNumberOfAccounts(DomainObject,
819 L"Users",
820 &InfoBuffer->General.UserCount);
821 if (!NT_SUCCESS(Status))
822 {
823 TRACE("Status 0x%08lx\n", Status);
824 goto done;
825 }
826
827 /* Get the number of Groups in the Domain */
828 Status = SampGetNumberOfAccounts(DomainObject,
829 L"Groups",
830 &InfoBuffer->General.GroupCount);
831 if (!NT_SUCCESS(Status))
832 {
833 TRACE("Status 0x%08lx\n", Status);
834 goto done;
835 }
836
837 /* Get the number of Aliases in the Domain */
838 Status = SampGetNumberOfAccounts(DomainObject,
839 L"Aliases",
840 &InfoBuffer->General.AliasCount);
841 if (!NT_SUCCESS(Status))
842 {
843 TRACE("Status 0x%08lx\n", Status);
844 goto done;
845 }
846
847 *Buffer = InfoBuffer;
848
849 done:
850 if (!NT_SUCCESS(Status))
851 {
852 if (InfoBuffer != NULL)
853 {
854 if (InfoBuffer->General.OemInformation.Buffer != NULL)
855 midl_user_free(InfoBuffer->General.OemInformation.Buffer);
856
857 if (InfoBuffer->General.DomainName.Buffer != NULL)
858 midl_user_free(InfoBuffer->General.DomainName.Buffer);
859
860 if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
861 midl_user_free(InfoBuffer->General.ReplicaSourceNodeName.Buffer);
862
863 midl_user_free(InfoBuffer);
864 }
865 }
866
867 return Status;
868 }
869
870
871 static NTSTATUS
872 SampQueryDomainLogoff(PSAM_DB_OBJECT DomainObject,
873 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
874 {
875 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
876 SAM_DOMAIN_FIXED_DATA FixedData;
877 ULONG Length = 0;
878 NTSTATUS Status;
879
880 *Buffer = NULL;
881
882 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
883 if (InfoBuffer == NULL)
884 return STATUS_INSUFFICIENT_RESOURCES;
885
886 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
887 Status = SampGetObjectAttribute(DomainObject,
888 L"F",
889 NULL,
890 (PVOID)&FixedData,
891 &Length);
892 if (!NT_SUCCESS(Status))
893 goto done;
894
895 InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
896 InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
897
898 *Buffer = InfoBuffer;
899
900 done:
901 if (!NT_SUCCESS(Status))
902 {
903 if (InfoBuffer != NULL)
904 {
905 midl_user_free(InfoBuffer);
906 }
907 }
908
909 return Status;
910 }
911
912
913 static NTSTATUS
914 SampQueryDomainOem(PSAM_DB_OBJECT DomainObject,
915 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
916 {
917 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
918 NTSTATUS Status;
919
920 *Buffer = NULL;
921
922 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
923 if (InfoBuffer == NULL)
924 return STATUS_INSUFFICIENT_RESOURCES;
925
926 /* Get the OemInformation string */
927 Status = SampGetObjectAttributeString(DomainObject,
928 L"OemInformation",
929 &InfoBuffer->Oem.OemInformation);
930 if (!NT_SUCCESS(Status))
931 {
932 TRACE("Status 0x%08lx\n", Status);
933 goto done;
934 }
935
936 *Buffer = InfoBuffer;
937
938 done:
939 if (!NT_SUCCESS(Status))
940 {
941 if (InfoBuffer != NULL)
942 {
943 if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
944 midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
945
946 midl_user_free(InfoBuffer);
947 }
948 }
949
950 return Status;
951 }
952
953
954 static NTSTATUS
955 SampQueryDomainName(PSAM_DB_OBJECT DomainObject,
956 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
957 {
958 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
959 NTSTATUS Status;
960
961 *Buffer = NULL;
962
963 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
964 if (InfoBuffer == NULL)
965 return STATUS_INSUFFICIENT_RESOURCES;
966
967 /* Get the Name string */
968 Status = SampGetObjectAttributeString(DomainObject,
969 L"Name",
970 &InfoBuffer->Name.DomainName);
971 if (!NT_SUCCESS(Status))
972 {
973 TRACE("Status 0x%08lx\n", Status);
974 goto done;
975 }
976
977 *Buffer = InfoBuffer;
978
979 done:
980 if (!NT_SUCCESS(Status))
981 {
982 if (InfoBuffer != NULL)
983 {
984 if (InfoBuffer->Name.DomainName.Buffer != NULL)
985 midl_user_free(InfoBuffer->Name.DomainName.Buffer);
986
987 midl_user_free(InfoBuffer);
988 }
989 }
990
991 return Status;
992 }
993
994
995 static NTSTATUS
996 SampQueryDomainReplication(PSAM_DB_OBJECT DomainObject,
997 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
998 {
999 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1000 NTSTATUS Status;
1001
1002 *Buffer = NULL;
1003
1004 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1005 if (InfoBuffer == NULL)
1006 return STATUS_INSUFFICIENT_RESOURCES;
1007
1008 /* Get the ReplicaSourceNodeName string */
1009 Status = SampGetObjectAttributeString(DomainObject,
1010 L"ReplicaSourceNodeName",
1011 &InfoBuffer->Replication.ReplicaSourceNodeName);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 TRACE("Status 0x%08lx\n", Status);
1015 goto done;
1016 }
1017
1018 *Buffer = InfoBuffer;
1019
1020 done:
1021 if (!NT_SUCCESS(Status))
1022 {
1023 if (InfoBuffer != NULL)
1024 {
1025 if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
1026 midl_user_free(InfoBuffer->Replication.ReplicaSourceNodeName.Buffer);
1027
1028 midl_user_free(InfoBuffer);
1029 }
1030 }
1031
1032 return Status;
1033 }
1034
1035
1036 static NTSTATUS
1037 SampQueryDomainServerRole(PSAM_DB_OBJECT DomainObject,
1038 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1039 {
1040 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1041 SAM_DOMAIN_FIXED_DATA FixedData;
1042 ULONG Length = 0;
1043 NTSTATUS Status;
1044
1045 *Buffer = NULL;
1046
1047 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1048 if (InfoBuffer == NULL)
1049 return STATUS_INSUFFICIENT_RESOURCES;
1050
1051 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1052 Status = SampGetObjectAttribute(DomainObject,
1053 L"F",
1054 NULL,
1055 (PVOID)&FixedData,
1056 &Length);
1057 if (!NT_SUCCESS(Status))
1058 goto done;
1059
1060 InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
1061
1062 *Buffer = InfoBuffer;
1063
1064 done:
1065 if (!NT_SUCCESS(Status))
1066 {
1067 if (InfoBuffer != NULL)
1068 {
1069 midl_user_free(InfoBuffer);
1070 }
1071 }
1072
1073 return Status;
1074 }
1075
1076
1077 static NTSTATUS
1078 SampQueryDomainModified(PSAM_DB_OBJECT DomainObject,
1079 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1080 {
1081 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1082 SAM_DOMAIN_FIXED_DATA FixedData;
1083 ULONG Length = 0;
1084 NTSTATUS Status;
1085
1086 *Buffer = NULL;
1087
1088 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1089 if (InfoBuffer == NULL)
1090 return STATUS_INSUFFICIENT_RESOURCES;
1091
1092 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1093 Status = SampGetObjectAttribute(DomainObject,
1094 L"F",
1095 NULL,
1096 (PVOID)&FixedData,
1097 &Length);
1098 if (!NT_SUCCESS(Status))
1099 goto done;
1100
1101 InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1102 InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1103 InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1104 InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1105
1106 *Buffer = InfoBuffer;
1107
1108 done:
1109 if (!NT_SUCCESS(Status))
1110 {
1111 if (InfoBuffer != NULL)
1112 {
1113 midl_user_free(InfoBuffer);
1114 }
1115 }
1116
1117 return Status;
1118 }
1119
1120
1121 static NTSTATUS
1122 SampQueryDomainState(PSAM_DB_OBJECT DomainObject,
1123 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1124 {
1125 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1126 SAM_DOMAIN_FIXED_DATA FixedData;
1127 ULONG Length = 0;
1128 NTSTATUS Status;
1129
1130 *Buffer = NULL;
1131
1132 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1133 if (InfoBuffer == NULL)
1134 return STATUS_INSUFFICIENT_RESOURCES;
1135
1136 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1137 Status = SampGetObjectAttribute(DomainObject,
1138 L"F",
1139 NULL,
1140 (PVOID)&FixedData,
1141 &Length);
1142 if (!NT_SUCCESS(Status))
1143 goto done;
1144
1145 InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1146
1147 *Buffer = InfoBuffer;
1148
1149 done:
1150 if (!NT_SUCCESS(Status))
1151 {
1152 if (InfoBuffer != NULL)
1153 {
1154 midl_user_free(InfoBuffer);
1155 }
1156 }
1157
1158 return Status;
1159 }
1160
1161
1162 static NTSTATUS
1163 SampQueryDomainGeneral2(PSAM_DB_OBJECT DomainObject,
1164 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1165 {
1166 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1167 SAM_DOMAIN_FIXED_DATA FixedData;
1168 ULONG Length = 0;
1169 NTSTATUS Status;
1170
1171 *Buffer = NULL;
1172
1173 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1174 if (InfoBuffer == NULL)
1175 return STATUS_INSUFFICIENT_RESOURCES;
1176
1177 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1178 Status = SampGetObjectAttribute(DomainObject,
1179 L"F",
1180 NULL,
1181 (PVOID)&FixedData,
1182 &Length);
1183 if (!NT_SUCCESS(Status))
1184 goto done;
1185
1186 InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1187 InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1188 InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1189 InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1190 InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1191 InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1192 InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1193
1194 InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1195 InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1196 InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1197
1198 /* Get the OemInformation string */
1199 Status = SampGetObjectAttributeString(DomainObject,
1200 L"OemInformation",
1201 &InfoBuffer->General2.I1.OemInformation);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 TRACE("Status 0x%08lx\n", Status);
1205 goto done;
1206 }
1207
1208 /* Get the Name string */
1209 Status = SampGetObjectAttributeString(DomainObject,
1210 L"Name",
1211 &InfoBuffer->General2.I1.DomainName);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 TRACE("Status 0x%08lx\n", Status);
1215 goto done;
1216 }
1217
1218 /* Get the ReplicaSourceNodeName string */
1219 Status = SampGetObjectAttributeString(DomainObject,
1220 L"ReplicaSourceNodeName",
1221 &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1222 if (!NT_SUCCESS(Status))
1223 {
1224 TRACE("Status 0x%08lx\n", Status);
1225 goto done;
1226 }
1227
1228 /* Get the number of Users in the Domain */
1229 Status = SampGetNumberOfAccounts(DomainObject,
1230 L"Users",
1231 &InfoBuffer->General2.I1.UserCount);
1232 if (!NT_SUCCESS(Status))
1233 {
1234 TRACE("Status 0x%08lx\n", Status);
1235 goto done;
1236 }
1237
1238 /* Get the number of Groups in the Domain */
1239 Status = SampGetNumberOfAccounts(DomainObject,
1240 L"Groups",
1241 &InfoBuffer->General2.I1.GroupCount);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 TRACE("Status 0x%08lx\n", Status);
1245 goto done;
1246 }
1247
1248 /* Get the number of Aliases in the Domain */
1249 Status = SampGetNumberOfAccounts(DomainObject,
1250 L"Aliases",
1251 &InfoBuffer->General2.I1.AliasCount);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 TRACE("Status 0x%08lx\n", Status);
1255 goto done;
1256 }
1257
1258 *Buffer = InfoBuffer;
1259
1260 done:
1261 if (!NT_SUCCESS(Status))
1262 {
1263 if (InfoBuffer != NULL)
1264 {
1265 if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1266 midl_user_free(InfoBuffer->General2.I1.OemInformation.Buffer);
1267
1268 if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1269 midl_user_free(InfoBuffer->General2.I1.DomainName.Buffer);
1270
1271 if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1272 midl_user_free(InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer);
1273
1274 midl_user_free(InfoBuffer);
1275 }
1276 }
1277
1278 return Status;
1279 }
1280
1281
1282 static NTSTATUS
1283 SampQueryDomainLockout(PSAM_DB_OBJECT DomainObject,
1284 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1285 {
1286 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1287 SAM_DOMAIN_FIXED_DATA FixedData;
1288 ULONG Length = 0;
1289 NTSTATUS Status;
1290
1291 *Buffer = NULL;
1292
1293 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1294 if (InfoBuffer == NULL)
1295 return STATUS_INSUFFICIENT_RESOURCES;
1296
1297 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1298 Status = SampGetObjectAttribute(DomainObject,
1299 L"F",
1300 NULL,
1301 (PVOID)&FixedData,
1302 &Length);
1303 if (!NT_SUCCESS(Status))
1304 goto done;
1305
1306 InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1307 InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1308 InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1309
1310 *Buffer = InfoBuffer;
1311
1312 done:
1313 if (!NT_SUCCESS(Status))
1314 {
1315 if (InfoBuffer != NULL)
1316 {
1317 midl_user_free(InfoBuffer);
1318 }
1319 }
1320
1321 return Status;
1322 }
1323
1324
1325 static NTSTATUS
1326 SampQueryDomainModified2(PSAM_DB_OBJECT DomainObject,
1327 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1328 {
1329 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1330 SAM_DOMAIN_FIXED_DATA FixedData;
1331 ULONG Length = 0;
1332 NTSTATUS Status;
1333
1334 *Buffer = NULL;
1335
1336 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1337 if (InfoBuffer == NULL)
1338 return STATUS_INSUFFICIENT_RESOURCES;
1339
1340 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1341 Status = SampGetObjectAttribute(DomainObject,
1342 L"F",
1343 NULL,
1344 (PVOID)&FixedData,
1345 &Length);
1346 if (!NT_SUCCESS(Status))
1347 goto done;
1348
1349 InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1350 InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1351 InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1352 InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1353 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1354 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1355
1356 *Buffer = InfoBuffer;
1357
1358 done:
1359 if (!NT_SUCCESS(Status))
1360 {
1361 if (InfoBuffer != NULL)
1362 {
1363 midl_user_free(InfoBuffer);
1364 }
1365 }
1366
1367 return Status;
1368 }
1369
1370
1371 /* Function 8 */
1372 NTSTATUS
1373 NTAPI
1374 SamrQueryInformationDomain(IN SAMPR_HANDLE DomainHandle,
1375 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1376 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1377 {
1378 PSAM_DB_OBJECT DomainObject;
1379 ACCESS_MASK DesiredAccess;
1380 NTSTATUS Status;
1381
1382 TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1383 DomainHandle, DomainInformationClass, Buffer);
1384
1385 switch (DomainInformationClass)
1386 {
1387 case DomainPasswordInformation:
1388 case DomainLockoutInformation:
1389 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
1390 break;
1391
1392 case DomainGeneralInformation:
1393 case DomainLogoffInformation:
1394 case DomainOemInformation:
1395 case DomainNameInformation:
1396 case DomainReplicationInformation:
1397 case DomainServerRoleInformation:
1398 case DomainModifiedInformation:
1399 case DomainStateInformation:
1400 case DomainModifiedInformation2:
1401 DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
1402 break;
1403
1404 case DomainGeneralInformation2:
1405 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS |
1406 DOMAIN_READ_OTHER_PARAMETERS;
1407 break;
1408
1409 default:
1410 return STATUS_INVALID_INFO_CLASS;
1411 }
1412
1413 RtlAcquireResourceShared(&SampResource,
1414 TRUE);
1415
1416 /* Validate the server handle */
1417 Status = SampValidateDbObject(DomainHandle,
1418 SamDbDomainObject,
1419 DesiredAccess,
1420 &DomainObject);
1421 if (!NT_SUCCESS(Status))
1422 goto done;
1423
1424 switch (DomainInformationClass)
1425 {
1426 case DomainPasswordInformation:
1427 Status = SampQueryDomainPassword(DomainObject,
1428 Buffer);
1429 break;
1430
1431 case DomainGeneralInformation:
1432 Status = SampQueryDomainGeneral(DomainObject,
1433 Buffer);
1434 break;
1435
1436 case DomainLogoffInformation:
1437 Status = SampQueryDomainLogoff(DomainObject,
1438 Buffer);
1439 break;
1440
1441 case DomainOemInformation:
1442 Status = SampQueryDomainOem(DomainObject,
1443 Buffer);
1444 break;
1445
1446 case DomainNameInformation:
1447 Status = SampQueryDomainName(DomainObject,
1448 Buffer);
1449 break;
1450
1451 case DomainReplicationInformation:
1452 Status = SampQueryDomainReplication(DomainObject,
1453 Buffer);
1454 break;
1455
1456 case DomainServerRoleInformation:
1457 Status = SampQueryDomainServerRole(DomainObject,
1458 Buffer);
1459 break;
1460
1461 case DomainModifiedInformation:
1462 Status = SampQueryDomainModified(DomainObject,
1463 Buffer);
1464 break;
1465
1466 case DomainStateInformation:
1467 Status = SampQueryDomainState(DomainObject,
1468 Buffer);
1469 break;
1470
1471 case DomainGeneralInformation2:
1472 Status = SampQueryDomainGeneral2(DomainObject,
1473 Buffer);
1474 break;
1475
1476 case DomainLockoutInformation:
1477 Status = SampQueryDomainLockout(DomainObject,
1478 Buffer);
1479 break;
1480
1481 case DomainModifiedInformation2:
1482 Status = SampQueryDomainModified2(DomainObject,
1483 Buffer);
1484 break;
1485
1486 default:
1487 Status = STATUS_NOT_IMPLEMENTED;
1488 }
1489
1490 done:
1491 RtlReleaseResource(&SampResource);
1492
1493 return Status;
1494 }
1495
1496
1497 static NTSTATUS
1498 SampSetDomainPassword(PSAM_DB_OBJECT DomainObject,
1499 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1500 {
1501 SAM_DOMAIN_FIXED_DATA FixedData;
1502 ULONG Length = 0;
1503 NTSTATUS Status;
1504
1505 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1506 Status = SampGetObjectAttribute(DomainObject,
1507 L"F",
1508 NULL,
1509 (PVOID)&FixedData,
1510 &Length);
1511 if (!NT_SUCCESS(Status))
1512 goto done;
1513
1514 FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1515 FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1516 FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1517 FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1518 FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1519 FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1520 FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1521
1522 Status = SampSetObjectAttribute(DomainObject,
1523 L"F",
1524 REG_BINARY,
1525 &FixedData,
1526 Length);
1527
1528 done:
1529 return Status;
1530 }
1531
1532
1533 static NTSTATUS
1534 SampSetDomainLogoff(PSAM_DB_OBJECT DomainObject,
1535 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1536 {
1537 SAM_DOMAIN_FIXED_DATA FixedData;
1538 ULONG Length = 0;
1539 NTSTATUS Status;
1540
1541 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1542 Status = SampGetObjectAttribute(DomainObject,
1543 L"F",
1544 NULL,
1545 (PVOID)&FixedData,
1546 &Length);
1547 if (!NT_SUCCESS(Status))
1548 goto done;
1549
1550 FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1551 FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1552
1553 Status = SampSetObjectAttribute(DomainObject,
1554 L"F",
1555 REG_BINARY,
1556 &FixedData,
1557 Length);
1558
1559 done:
1560 return Status;
1561 }
1562
1563
1564 static NTSTATUS
1565 SampSetDomainServerRole(PSAM_DB_OBJECT DomainObject,
1566 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1567 {
1568 SAM_DOMAIN_FIXED_DATA FixedData;
1569 ULONG Length = 0;
1570 NTSTATUS Status;
1571
1572 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1573 Status = SampGetObjectAttribute(DomainObject,
1574 L"F",
1575 NULL,
1576 (PVOID)&FixedData,
1577 &Length);
1578 if (!NT_SUCCESS(Status))
1579 goto done;
1580
1581 FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1582
1583 Status = SampSetObjectAttribute(DomainObject,
1584 L"F",
1585 REG_BINARY,
1586 &FixedData,
1587 Length);
1588
1589 done:
1590 return Status;
1591 }
1592
1593
1594 static NTSTATUS
1595 SampSetDomainState(PSAM_DB_OBJECT DomainObject,
1596 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1597 {
1598 SAM_DOMAIN_FIXED_DATA FixedData;
1599 ULONG Length = 0;
1600 NTSTATUS Status;
1601
1602 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1603 Status = SampGetObjectAttribute(DomainObject,
1604 L"F",
1605 NULL,
1606 (PVOID)&FixedData,
1607 &Length);
1608 if (!NT_SUCCESS(Status))
1609 goto done;
1610
1611 FixedData.DomainServerState = Buffer->State.DomainServerState;
1612
1613 Status = SampSetObjectAttribute(DomainObject,
1614 L"F",
1615 REG_BINARY,
1616 &FixedData,
1617 Length);
1618
1619 done:
1620 return Status;
1621 }
1622
1623
1624 static NTSTATUS
1625 SampSetDomainLockout(PSAM_DB_OBJECT DomainObject,
1626 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1627 {
1628 SAM_DOMAIN_FIXED_DATA FixedData;
1629 ULONG Length = 0;
1630 NTSTATUS Status;
1631
1632 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1633 Status = SampGetObjectAttribute(DomainObject,
1634 L"F",
1635 NULL,
1636 (PVOID)&FixedData,
1637 &Length);
1638 if (!NT_SUCCESS(Status))
1639 goto done;
1640
1641 FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1642 FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1643 FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1644
1645 Status = SampSetObjectAttribute(DomainObject,
1646 L"F",
1647 REG_BINARY,
1648 &FixedData,
1649 Length);
1650
1651 done:
1652 return Status;
1653 }
1654
1655
1656 /* Function 9 */
1657 NTSTATUS
1658 NTAPI
1659 SamrSetInformationDomain(IN SAMPR_HANDLE DomainHandle,
1660 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1661 IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1662 {
1663 PSAM_DB_OBJECT DomainObject;
1664 ACCESS_MASK DesiredAccess;
1665 NTSTATUS Status;
1666
1667 TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1668 DomainHandle, DomainInformationClass, DomainInformation);
1669
1670 switch (DomainInformationClass)
1671 {
1672 case DomainPasswordInformation:
1673 case DomainLockoutInformation:
1674 DesiredAccess = DOMAIN_WRITE_PASSWORD_PARAMS;
1675 break;
1676
1677 case DomainLogoffInformation:
1678 case DomainOemInformation:
1679 case DomainNameInformation:
1680 DesiredAccess = DOMAIN_WRITE_OTHER_PARAMETERS;
1681 break;
1682
1683 case DomainReplicationInformation:
1684 case DomainServerRoleInformation:
1685 case DomainStateInformation:
1686 DesiredAccess = DOMAIN_ADMINISTER_SERVER;
1687 break;
1688
1689 default:
1690 return STATUS_INVALID_INFO_CLASS;
1691 }
1692
1693 RtlAcquireResourceExclusive(&SampResource,
1694 TRUE);
1695
1696 /* Validate the server handle */
1697 Status = SampValidateDbObject(DomainHandle,
1698 SamDbDomainObject,
1699 DesiredAccess,
1700 &DomainObject);
1701 if (!NT_SUCCESS(Status))
1702 goto done;
1703
1704 switch (DomainInformationClass)
1705 {
1706 case DomainPasswordInformation:
1707 Status = SampSetDomainPassword(DomainObject,
1708 DomainInformation);
1709 break;
1710
1711 case DomainLogoffInformation:
1712 Status = SampSetDomainLogoff(DomainObject,
1713 DomainInformation);
1714 break;
1715
1716 case DomainOemInformation:
1717 Status = SampSetObjectAttributeString(DomainObject,
1718 L"OemInformation",
1719 &DomainInformation->Oem.OemInformation);
1720 break;
1721
1722 case DomainNameInformation:
1723 Status = SampSetObjectAttributeString(DomainObject,
1724 L"Name",
1725 &DomainInformation->Name.DomainName);
1726 break;
1727
1728 case DomainReplicationInformation:
1729 Status = SampSetObjectAttributeString(DomainObject,
1730 L"ReplicaSourceNodeName",
1731 &DomainInformation->Replication.ReplicaSourceNodeName);
1732 break;
1733
1734 case DomainServerRoleInformation:
1735 Status = SampSetDomainServerRole(DomainObject,
1736 DomainInformation);
1737 break;
1738
1739 case DomainStateInformation:
1740 Status = SampSetDomainState(DomainObject,
1741 DomainInformation);
1742 break;
1743
1744 case DomainLockoutInformation:
1745 Status = SampSetDomainLockout(DomainObject,
1746 DomainInformation);
1747 break;
1748
1749 default:
1750 Status = STATUS_NOT_IMPLEMENTED;
1751 }
1752
1753 done:
1754 RtlReleaseResource(&SampResource);
1755
1756 return Status;
1757 }
1758
1759
1760 /* Function 10 */
1761 NTSTATUS
1762 NTAPI
1763 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1764 IN PRPC_UNICODE_STRING Name,
1765 IN ACCESS_MASK DesiredAccess,
1766 OUT SAMPR_HANDLE *GroupHandle,
1767 OUT unsigned long *RelativeId)
1768 {
1769 SAM_DOMAIN_FIXED_DATA FixedDomainData;
1770 SAM_GROUP_FIXED_DATA FixedGroupData;
1771 PSAM_DB_OBJECT DomainObject;
1772 PSAM_DB_OBJECT GroupObject;
1773 ULONG ulSize;
1774 ULONG ulRid;
1775 WCHAR szRid[9];
1776 NTSTATUS Status;
1777
1778 TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
1779 DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
1780
1781 /* Map generic access rights */
1782 RtlMapGenericMask(&DesiredAccess,
1783 &GroupMapping);
1784
1785 RtlAcquireResourceExclusive(&SampResource,
1786 TRUE);
1787
1788 /* Validate the domain handle */
1789 Status = SampValidateDbObject(DomainHandle,
1790 SamDbDomainObject,
1791 DOMAIN_CREATE_GROUP,
1792 &DomainObject);
1793 if (!NT_SUCCESS(Status))
1794 {
1795 TRACE("failed with status 0x%08lx\n", Status);
1796 goto done;
1797 }
1798
1799 /* Check the group account name */
1800 Status = SampCheckAccountName(Name, 256);
1801 if (!NT_SUCCESS(Status))
1802 {
1803 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
1804 goto done;
1805 }
1806
1807 /* Check if the group name already exists in the domain */
1808 Status = SampCheckAccountNameInDomain(DomainObject,
1809 Name->Buffer);
1810 if (!NT_SUCCESS(Status))
1811 {
1812 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
1813 Name->Buffer, Status);
1814 goto done;
1815 }
1816
1817 /* Get the fixed domain attributes */
1818 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
1819 Status = SampGetObjectAttribute(DomainObject,
1820 L"F",
1821 NULL,
1822 (PVOID)&FixedDomainData,
1823 &ulSize);
1824 if (!NT_SUCCESS(Status))
1825 {
1826 TRACE("failed with status 0x%08lx\n", Status);
1827 goto done;
1828 }
1829
1830 /* Increment the NextRid attribute */
1831 ulRid = FixedDomainData.NextRid;
1832 FixedDomainData.NextRid++;
1833
1834 /* Store the fixed domain attributes */
1835 Status = SampSetObjectAttribute(DomainObject,
1836 L"F",
1837 REG_BINARY,
1838 &FixedDomainData,
1839 ulSize);
1840 if (!NT_SUCCESS(Status))
1841 {
1842 TRACE("failed with status 0x%08lx\n", Status);
1843 goto done;
1844 }
1845
1846 TRACE("RID: %lx\n", ulRid);
1847
1848 /* Convert the RID into a string (hex) */
1849 swprintf(szRid, L"%08lX", ulRid);
1850
1851 /* Create the group object */
1852 Status = SampCreateDbObject(DomainObject,
1853 L"Groups",
1854 szRid,
1855 ulRid,
1856 SamDbGroupObject,
1857 DesiredAccess,
1858 &GroupObject);
1859 if (!NT_SUCCESS(Status))
1860 {
1861 TRACE("failed with status 0x%08lx\n", Status);
1862 goto done;
1863 }
1864
1865 /* Add the account name of the user object */
1866 Status = SampSetAccountNameInDomain(DomainObject,
1867 L"Groups",
1868 Name->Buffer,
1869 ulRid);
1870 if (!NT_SUCCESS(Status))
1871 {
1872 TRACE("failed with status 0x%08lx\n", Status);
1873 goto done;
1874 }
1875
1876 /* Initialize fixed user data */
1877 memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
1878 FixedGroupData.Version = 1;
1879 FixedGroupData.GroupId = ulRid;
1880
1881 /* Set fixed user data attribute */
1882 Status = SampSetObjectAttribute(GroupObject,
1883 L"F",
1884 REG_BINARY,
1885 (LPVOID)&FixedGroupData,
1886 sizeof(SAM_GROUP_FIXED_DATA));
1887 if (!NT_SUCCESS(Status))
1888 {
1889 TRACE("failed with status 0x%08lx\n", Status);
1890 goto done;
1891 }
1892
1893 /* Set the Name attribute */
1894 Status = SampSetObjectAttributeString(GroupObject,
1895 L"Name",
1896 Name);
1897 if (!NT_SUCCESS(Status))
1898 {
1899 TRACE("failed with status 0x%08lx\n", Status);
1900 goto done;
1901 }
1902
1903 /* Set the AdminComment attribute */
1904 Status = SampSetObjectAttributeString(GroupObject,
1905 L"AdminComment",
1906 NULL);
1907 if (!NT_SUCCESS(Status))
1908 {
1909 TRACE("failed with status 0x%08lx\n", Status);
1910 goto done;
1911 }
1912
1913 if (NT_SUCCESS(Status))
1914 {
1915 *GroupHandle = (SAMPR_HANDLE)GroupObject;
1916 *RelativeId = ulRid;
1917 }
1918
1919 done:
1920 RtlReleaseResource(&SampResource);
1921
1922 TRACE("returns with status 0x%08lx\n", Status);
1923
1924 return Status;
1925 }
1926
1927
1928 /* Function 11 */
1929 NTSTATUS
1930 NTAPI
1931 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
1932 IN OUT unsigned long *EnumerationContext,
1933 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
1934 IN unsigned long PreferedMaximumLength,
1935 OUT unsigned long *CountReturned)
1936 {
1937 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
1938 PSAM_DB_OBJECT DomainObject;
1939 HANDLE GroupsKeyHandle = NULL;
1940 HANDLE NamesKeyHandle = NULL;
1941 WCHAR GroupName[64];
1942 ULONG EnumIndex;
1943 ULONG EnumCount = 0;
1944 ULONG RequiredLength = 0;
1945 ULONG NameLength;
1946 ULONG DataLength;
1947 ULONG Rid;
1948 ULONG i;
1949 BOOLEAN MoreEntries = FALSE;
1950 NTSTATUS Status;
1951
1952 TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
1953 DomainHandle, EnumerationContext, Buffer,
1954 PreferedMaximumLength, CountReturned);
1955
1956 RtlAcquireResourceShared(&SampResource,
1957 TRUE);
1958
1959 /* Validate the domain handle */
1960 Status = SampValidateDbObject(DomainHandle,
1961 SamDbDomainObject,
1962 DOMAIN_LIST_ACCOUNTS,
1963 &DomainObject);
1964 if (!NT_SUCCESS(Status))
1965 goto done;
1966
1967 Status = SampRegOpenKey(DomainObject->KeyHandle,
1968 L"Groups",
1969 KEY_READ,
1970 &GroupsKeyHandle);
1971 if (!NT_SUCCESS(Status))
1972 goto done;
1973
1974 Status = SampRegOpenKey(GroupsKeyHandle,
1975 L"Names",
1976 KEY_READ,
1977 &NamesKeyHandle);
1978 if (!NT_SUCCESS(Status))
1979 goto done;
1980
1981 TRACE("Part 1\n");
1982
1983 EnumIndex = *EnumerationContext;
1984
1985 while (TRUE)
1986 {
1987 NameLength = 64 * sizeof(WCHAR);
1988 Status = SampRegEnumerateValue(NamesKeyHandle,
1989 EnumIndex,
1990 GroupName,
1991 &NameLength,
1992 NULL,
1993 NULL,
1994 NULL);
1995 if (!NT_SUCCESS(Status))
1996 {
1997 if (Status == STATUS_NO_MORE_ENTRIES)
1998 Status = STATUS_SUCCESS;
1999 break;
2000 }
2001
2002 TRACE("EnumIndex: %lu\n", EnumIndex);
2003 TRACE("Group name: %S\n", GroupName);
2004 TRACE("Name length: %lu\n", NameLength);
2005
2006 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2007 {
2008 MoreEntries = TRUE;
2009 break;
2010 }
2011
2012 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2013 EnumCount++;
2014
2015 EnumIndex++;
2016 }
2017
2018 TRACE("EnumCount: %lu\n", EnumCount);
2019 TRACE("RequiredLength: %lu\n", RequiredLength);
2020
2021 if (!NT_SUCCESS(Status))
2022 goto done;
2023
2024 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2025 if (EnumBuffer == NULL)
2026 {
2027 Status = STATUS_INSUFFICIENT_RESOURCES;
2028 goto done;
2029 }
2030
2031 EnumBuffer->EntriesRead = EnumCount;
2032 if (EnumCount == 0)
2033 goto done;
2034
2035 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2036 if (EnumBuffer->Buffer == NULL)
2037 {
2038 Status = STATUS_INSUFFICIENT_RESOURCES;
2039 goto done;
2040 }
2041
2042 TRACE("Part 2\n");
2043
2044 EnumIndex = *EnumerationContext;
2045 for (i = 0; i < EnumCount; i++, EnumIndex++)
2046 {
2047 NameLength = 64 * sizeof(WCHAR);
2048 DataLength = sizeof(ULONG);
2049 Status = SampRegEnumerateValue(NamesKeyHandle,
2050 EnumIndex,
2051 GroupName,
2052 &NameLength,
2053 NULL,
2054 &Rid,
2055 &DataLength);
2056 if (!NT_SUCCESS(Status))
2057 {
2058 if (Status == STATUS_NO_MORE_ENTRIES)
2059 Status = STATUS_SUCCESS;
2060 break;
2061 }
2062
2063 TRACE("EnumIndex: %lu\n", EnumIndex);
2064 TRACE("Group name: %S\n", GroupName);
2065 TRACE("Name length: %lu\n", NameLength);
2066 TRACE("RID: %lu\n", Rid);
2067
2068 EnumBuffer->Buffer[i].RelativeId = Rid;
2069
2070 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2071 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2072
2073 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2074 #if 0
2075 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2076 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2077 {
2078 Status = STATUS_INSUFFICIENT_RESOURCES;
2079 goto done;
2080 }
2081
2082 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2083 GroupName,
2084 EnumBuffer->Buffer[i].Name.Length);
2085 #endif
2086 }
2087
2088 done:
2089 if (NT_SUCCESS(Status))
2090 {
2091 *EnumerationContext += EnumCount;
2092 *Buffer = EnumBuffer;
2093 *CountReturned = EnumCount;
2094 }
2095 else
2096 {
2097 *EnumerationContext = 0;
2098 *Buffer = NULL;
2099 *CountReturned = 0;
2100
2101 if (EnumBuffer != NULL)
2102 {
2103 if (EnumBuffer->Buffer != NULL)
2104 {
2105 if (EnumBuffer->EntriesRead != 0)
2106 {
2107 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2108 {
2109 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2110 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2111 }
2112 }
2113
2114 midl_user_free(EnumBuffer->Buffer);
2115 }
2116
2117 midl_user_free(EnumBuffer);
2118 }
2119 }
2120
2121 SampRegCloseKey(&NamesKeyHandle);
2122 SampRegCloseKey(&GroupsKeyHandle);
2123
2124 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2125 Status = STATUS_MORE_ENTRIES;
2126
2127 RtlReleaseResource(&SampResource);
2128
2129 return Status;
2130 }
2131
2132
2133 /* Function 12 */
2134 NTSTATUS
2135 NTAPI
2136 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2137 IN PRPC_UNICODE_STRING Name,
2138 IN ACCESS_MASK DesiredAccess,
2139 OUT SAMPR_HANDLE *UserHandle,
2140 OUT unsigned long *RelativeId)
2141 {
2142 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2143 SAM_USER_FIXED_DATA FixedUserData;
2144 PSAM_DB_OBJECT DomainObject;
2145 PSAM_DB_OBJECT UserObject;
2146 GROUP_MEMBERSHIP GroupMembership;
2147 UCHAR LogonHours[23];
2148 ULONG ulSize;
2149 ULONG ulRid;
2150 WCHAR szRid[9];
2151 NTSTATUS Status;
2152
2153 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2154 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2155
2156 if (Name == NULL ||
2157 Name->Length == 0 ||
2158 Name->Buffer == NULL ||
2159 UserHandle == NULL ||
2160 RelativeId == NULL)
2161 return STATUS_INVALID_PARAMETER;
2162
2163 /* Map generic access rights */
2164 RtlMapGenericMask(&DesiredAccess,
2165 &UserMapping);
2166
2167 RtlAcquireResourceExclusive(&SampResource,
2168 TRUE);
2169
2170 /* Validate the domain handle */
2171 Status = SampValidateDbObject(DomainHandle,
2172 SamDbDomainObject,
2173 DOMAIN_CREATE_USER,
2174 &DomainObject);
2175 if (!NT_SUCCESS(Status))
2176 {
2177 TRACE("failed with status 0x%08lx\n", Status);
2178 goto done;
2179 }
2180
2181 /* Check the user account name */
2182 Status = SampCheckAccountName(Name, 20);
2183 if (!NT_SUCCESS(Status))
2184 {
2185 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2186 goto done;
2187 }
2188
2189 /* Check if the user name already exists in the domain */
2190 Status = SampCheckAccountNameInDomain(DomainObject,
2191 Name->Buffer);
2192 if (!NT_SUCCESS(Status))
2193 {
2194 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2195 Name->Buffer, Status);
2196 goto done;
2197 }
2198
2199 /* Get the fixed domain attributes */
2200 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2201 Status = SampGetObjectAttribute(DomainObject,
2202 L"F",
2203 NULL,
2204 (PVOID)&FixedDomainData,
2205 &ulSize);
2206 if (!NT_SUCCESS(Status))
2207 {
2208 TRACE("failed with status 0x%08lx\n", Status);
2209 goto done;
2210 }
2211
2212 /* Increment the NextRid attribute */
2213 ulRid = FixedDomainData.NextRid;
2214 FixedDomainData.NextRid++;
2215
2216 /* Store the fixed domain attributes */
2217 Status = SampSetObjectAttribute(DomainObject,
2218 L"F",
2219 REG_BINARY,
2220 &FixedDomainData,
2221 ulSize);
2222 if (!NT_SUCCESS(Status))
2223 {
2224 TRACE("failed with status 0x%08lx\n", Status);
2225 goto done;
2226 }
2227
2228 TRACE("RID: %lx\n", ulRid);
2229
2230 /* Convert the RID into a string (hex) */
2231 swprintf(szRid, L"%08lX", ulRid);
2232
2233 /* Create the user object */
2234 Status = SampCreateDbObject(DomainObject,
2235 L"Users",
2236 szRid,
2237 ulRid,
2238 SamDbUserObject,
2239 DesiredAccess,
2240 &UserObject);
2241 if (!NT_SUCCESS(Status))
2242 {
2243 TRACE("failed with status 0x%08lx\n", Status);
2244 goto done;
2245 }
2246
2247 /* Add the account name for the user object */
2248 Status = SampSetAccountNameInDomain(DomainObject,
2249 L"Users",
2250 Name->Buffer,
2251 ulRid);
2252 if (!NT_SUCCESS(Status))
2253 {
2254 TRACE("failed with status 0x%08lx\n", Status);
2255 goto done;
2256 }
2257
2258 /* Initialize fixed user data */
2259 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2260 FixedUserData.Version = 1;
2261 FixedUserData.Reserved = 0;
2262 FixedUserData.LastLogon.QuadPart = 0;
2263 FixedUserData.LastLogoff.QuadPart = 0;
2264 FixedUserData.PasswordLastSet.QuadPart = 0;
2265 FixedUserData.AccountExpires.LowPart = MAXULONG;
2266 FixedUserData.AccountExpires.HighPart = MAXLONG;
2267 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2268 FixedUserData.UserId = ulRid;
2269 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2270 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2271 USER_PASSWORD_NOT_REQUIRED |
2272 USER_NORMAL_ACCOUNT;
2273 FixedUserData.CountryCode = 0;
2274 FixedUserData.CodePage = 0;
2275 FixedUserData.BadPasswordCount = 0;
2276 FixedUserData.LogonCount = 0;
2277 FixedUserData.AdminCount = 0;
2278 FixedUserData.OperatorCount = 0;
2279
2280 /* Set fixed user data attribute */
2281 Status = SampSetObjectAttribute(UserObject,
2282 L"F",
2283 REG_BINARY,
2284 (LPVOID)&FixedUserData,
2285 sizeof(SAM_USER_FIXED_DATA));
2286 if (!NT_SUCCESS(Status))
2287 {
2288 TRACE("failed with status 0x%08lx\n", Status);
2289 goto done;
2290 }
2291
2292 /* Set the Name attribute */
2293 Status = SampSetObjectAttributeString(UserObject,
2294 L"Name",
2295 Name);
2296 if (!NT_SUCCESS(Status))
2297 {
2298 TRACE("failed with status 0x%08lx\n", Status);
2299 goto done;
2300 }
2301
2302 /* Set the FullName attribute */
2303 Status = SampSetObjectAttributeString(UserObject,
2304 L"FullName",
2305 NULL);
2306 if (!NT_SUCCESS(Status))
2307 {
2308 TRACE("failed with status 0x%08lx\n", Status);
2309 goto done;
2310 }
2311
2312 /* Set the HomeDirectory attribute */
2313 Status = SampSetObjectAttributeString(UserObject,
2314 L"HomeDirectory",
2315 NULL);
2316 if (!NT_SUCCESS(Status))
2317 {
2318 TRACE("failed with status 0x%08lx\n", Status);
2319 goto done;
2320 }
2321
2322 /* Set the HomeDirectoryDrive attribute */
2323 Status = SampSetObjectAttributeString(UserObject,
2324 L"HomeDirectoryDrive",
2325 NULL);
2326 if (!NT_SUCCESS(Status))
2327 {
2328 TRACE("failed with status 0x%08lx\n", Status);
2329 goto done;
2330 }
2331
2332 /* Set the ScriptPath attribute */
2333 Status = SampSetObjectAttributeString(UserObject,
2334 L"ScriptPath",
2335 NULL);
2336 if (!NT_SUCCESS(Status))
2337 {
2338 TRACE("failed with status 0x%08lx\n", Status);
2339 goto done;
2340 }
2341
2342 /* Set the ProfilePath attribute */
2343 Status = SampSetObjectAttributeString(UserObject,
2344 L"ProfilePath",
2345 NULL);
2346 if (!NT_SUCCESS(Status))
2347 {
2348 TRACE("failed with status 0x%08lx\n", Status);
2349 goto done;
2350 }
2351
2352 /* Set the AdminComment attribute */
2353 Status = SampSetObjectAttributeString(UserObject,
2354 L"AdminComment",
2355 NULL);
2356 if (!NT_SUCCESS(Status))
2357 {
2358 TRACE("failed with status 0x%08lx\n", Status);
2359 goto done;
2360 }
2361
2362 /* Set the UserComment attribute */
2363 Status = SampSetObjectAttributeString(UserObject,
2364 L"UserComment",
2365 NULL);
2366 if (!NT_SUCCESS(Status))
2367 {
2368 TRACE("failed with status 0x%08lx\n", Status);
2369 goto done;
2370 }
2371
2372 /* Set the WorkStations attribute */
2373 Status = SampSetObjectAttributeString(UserObject,
2374 L"WorkStations",
2375 NULL);
2376 if (!NT_SUCCESS(Status))
2377 {
2378 TRACE("failed with status 0x%08lx\n", Status);
2379 goto done;
2380 }
2381
2382 /* Set the Parameters attribute */
2383 Status = SampSetObjectAttributeString(UserObject,
2384 L"Parameters",
2385 NULL);
2386 if (!NT_SUCCESS(Status))
2387 {
2388 TRACE("failed with status 0x%08lx\n", Status);
2389 goto done;
2390 }
2391
2392 /* Set LogonHours attribute*/
2393 *((PUSHORT)LogonHours) = 168;
2394 memset(&(LogonHours[2]), 0xff, 21);
2395
2396 Status = SampSetObjectAttribute(UserObject,
2397 L"LogonHours",
2398 REG_BINARY,
2399 &LogonHours,
2400 sizeof(LogonHours));
2401 if (!NT_SUCCESS(Status))
2402 {
2403 TRACE("failed with status 0x%08lx\n", Status);
2404 goto done;
2405 }
2406
2407 /* Set Groups attribute*/
2408 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2409 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2410 SE_GROUP_ENABLED |
2411 SE_GROUP_ENABLED_BY_DEFAULT;
2412
2413 Status = SampSetObjectAttribute(UserObject,
2414 L"Groups",
2415 REG_BINARY,
2416 &GroupMembership,
2417 sizeof(GROUP_MEMBERSHIP));
2418 if (!NT_SUCCESS(Status))
2419 {
2420 TRACE("failed with status 0x%08lx\n", Status);
2421 goto done;
2422 }
2423
2424 /* Set LMPwd attribute*/
2425 Status = SampSetObjectAttribute(UserObject,
2426 L"LMPwd",
2427 REG_BINARY,
2428 &EmptyLmHash,
2429 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2430 if (!NT_SUCCESS(Status))
2431 {
2432 TRACE("failed with status 0x%08lx\n", Status);
2433 goto done;
2434 }
2435
2436 /* Set NTPwd attribute*/
2437 Status = SampSetObjectAttribute(UserObject,
2438 L"NTPwd",
2439 REG_BINARY,
2440 &EmptyNtHash,
2441 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2442 if (!NT_SUCCESS(Status))
2443 {
2444 TRACE("failed with status 0x%08lx\n", Status);
2445 goto done;
2446 }
2447
2448 /* Set LMPwdHistory attribute*/
2449 Status = SampSetObjectAttribute(UserObject,
2450 L"LMPwdHistory",
2451 REG_BINARY,
2452 NULL,
2453 0);
2454 if (!NT_SUCCESS(Status))
2455 {
2456 TRACE("failed with status 0x%08lx\n", Status);
2457 goto done;
2458 }
2459
2460 /* Set NTPwdHistory attribute*/
2461 Status = SampSetObjectAttribute(UserObject,
2462 L"NTPwdHistory",
2463 REG_BINARY,
2464 NULL,
2465 0);
2466 if (!NT_SUCCESS(Status))
2467 {
2468 TRACE("failed with status 0x%08lx\n", Status);
2469 goto done;
2470 }
2471
2472 /* FIXME: Set SecDesc attribute*/
2473
2474 if (NT_SUCCESS(Status))
2475 {
2476 *UserHandle = (SAMPR_HANDLE)UserObject;
2477 *RelativeId = ulRid;
2478 }
2479
2480 done:
2481 RtlReleaseResource(&SampResource);
2482
2483 TRACE("returns with status 0x%08lx\n", Status);
2484
2485 return Status;
2486 }
2487
2488
2489 /* Function 13 */
2490 NTSTATUS
2491 NTAPI
2492 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2493 IN OUT unsigned long *EnumerationContext,
2494 IN unsigned long UserAccountControl,
2495 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2496 IN unsigned long PreferedMaximumLength,
2497 OUT unsigned long *CountReturned)
2498 {
2499 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2500 PSAM_DB_OBJECT DomainObject;
2501 HANDLE UsersKeyHandle = NULL;
2502 HANDLE NamesKeyHandle = NULL;
2503 WCHAR UserName[64];
2504 ULONG EnumIndex;
2505 ULONG EnumCount = 0;
2506 ULONG RequiredLength = 0;
2507 ULONG NameLength;
2508 ULONG DataLength;
2509 ULONG Rid;
2510 ULONG i;
2511 BOOLEAN MoreEntries = FALSE;
2512 NTSTATUS Status;
2513
2514 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2515 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2516 PreferedMaximumLength, CountReturned);
2517
2518 RtlAcquireResourceShared(&SampResource,
2519 TRUE);
2520
2521 /* Validate the domain handle */
2522 Status = SampValidateDbObject(DomainHandle,
2523 SamDbDomainObject,
2524 DOMAIN_LIST_ACCOUNTS,
2525 &DomainObject);
2526 if (!NT_SUCCESS(Status))
2527 goto done;
2528
2529 Status = SampRegOpenKey(DomainObject->KeyHandle,
2530 L"Users",
2531 KEY_READ,
2532 &UsersKeyHandle);
2533 if (!NT_SUCCESS(Status))
2534 goto done;
2535
2536 Status = SampRegOpenKey(UsersKeyHandle,
2537 L"Names",
2538 KEY_READ,
2539 &NamesKeyHandle);
2540 if (!NT_SUCCESS(Status))
2541 goto done;
2542
2543 TRACE("Part 1\n");
2544
2545 EnumIndex = *EnumerationContext;
2546
2547 while (TRUE)
2548 {
2549 NameLength = 64 * sizeof(WCHAR);
2550 Status = SampRegEnumerateValue(NamesKeyHandle,
2551 EnumIndex,
2552 UserName,
2553 &NameLength,
2554 NULL,
2555 NULL,
2556 NULL);
2557 if (!NT_SUCCESS(Status))
2558 {
2559 if (Status == STATUS_NO_MORE_ENTRIES)
2560 Status = STATUS_SUCCESS;
2561 break;
2562 }
2563
2564 TRACE("EnumIndex: %lu\n", EnumIndex);
2565 TRACE("User name: %S\n", UserName);
2566 TRACE("Name length: %lu\n", NameLength);
2567
2568 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2569 {
2570 MoreEntries = TRUE;
2571 break;
2572 }
2573
2574 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2575 EnumCount++;
2576
2577 EnumIndex++;
2578 }
2579
2580 TRACE("EnumCount: %lu\n", EnumCount);
2581 TRACE("RequiredLength: %lu\n", RequiredLength);
2582
2583 if (!NT_SUCCESS(Status))
2584 goto done;
2585
2586 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2587 if (EnumBuffer == NULL)
2588 {
2589 Status = STATUS_INSUFFICIENT_RESOURCES;
2590 goto done;
2591 }
2592
2593 EnumBuffer->EntriesRead = EnumCount;
2594 if (EnumCount == 0)
2595 goto done;
2596
2597 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2598 if (EnumBuffer->Buffer == NULL)
2599 {
2600 Status = STATUS_INSUFFICIENT_RESOURCES;
2601 goto done;
2602 }
2603
2604 TRACE("Part 2\n");
2605
2606 EnumIndex = *EnumerationContext;
2607 for (i = 0; i < EnumCount; i++, EnumIndex++)
2608 {
2609 NameLength = 64 * sizeof(WCHAR);
2610 DataLength = sizeof(ULONG);
2611 Status = SampRegEnumerateValue(NamesKeyHandle,
2612 EnumIndex,
2613 UserName,
2614 &NameLength,
2615 NULL,
2616 &Rid,
2617 &DataLength);
2618 if (!NT_SUCCESS(Status))
2619 {
2620 if (Status == STATUS_NO_MORE_ENTRIES)
2621 Status = STATUS_SUCCESS;
2622 break;
2623 }
2624
2625 TRACE("EnumIndex: %lu\n", EnumIndex);
2626 TRACE("User name: %S\n", UserName);
2627 TRACE("Name length: %lu\n", NameLength);
2628 TRACE("RID: %lu\n", Rid);
2629
2630 EnumBuffer->Buffer[i].RelativeId = Rid;
2631
2632 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2633 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2634
2635 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2636 #if 0
2637 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2638 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2639 {
2640 Status = STATUS_INSUFFICIENT_RESOURCES;
2641 goto done;
2642 }
2643
2644 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2645 UserName,
2646 EnumBuffer->Buffer[i].Name.Length);
2647 #endif
2648 }
2649
2650 done:
2651 if (NT_SUCCESS(Status))
2652 {
2653 *EnumerationContext += EnumCount;
2654 *Buffer = EnumBuffer;
2655 *CountReturned = EnumCount;
2656 }
2657 else
2658 {
2659 *EnumerationContext = 0;
2660 *Buffer = NULL;
2661 *CountReturned = 0;
2662
2663 if (EnumBuffer != NULL)
2664 {
2665 if (EnumBuffer->Buffer != NULL)
2666 {
2667 if (EnumBuffer->EntriesRead != 0)
2668 {
2669 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2670 {
2671 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2672 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2673 }
2674 }
2675
2676 midl_user_free(EnumBuffer->Buffer);
2677 }
2678
2679 midl_user_free(EnumBuffer);
2680 }
2681 }
2682
2683 SampRegCloseKey(&NamesKeyHandle);
2684 SampRegCloseKey(&UsersKeyHandle);
2685
2686 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2687 Status = STATUS_MORE_ENTRIES;
2688
2689 RtlReleaseResource(&SampResource);
2690
2691 return Status;
2692 }
2693
2694
2695 /* Function 14 */
2696 NTSTATUS
2697 NTAPI
2698 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2699 IN PRPC_UNICODE_STRING AccountName,
2700 IN ACCESS_MASK DesiredAccess,
2701 OUT SAMPR_HANDLE *AliasHandle,
2702 OUT unsigned long *RelativeId)
2703 {
2704 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2705 PSAM_DB_OBJECT DomainObject;
2706 PSAM_DB_OBJECT AliasObject;
2707 ULONG ulSize;
2708 ULONG ulRid;
2709 WCHAR szRid[9];
2710 NTSTATUS Status;
2711
2712 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2713 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2714
2715 /* Map generic access rights */
2716 RtlMapGenericMask(&DesiredAccess,
2717 &AliasMapping);
2718
2719 RtlAcquireResourceExclusive(&SampResource,
2720 TRUE);
2721
2722 /* Validate the domain handle */
2723 Status = SampValidateDbObject(DomainHandle,
2724 SamDbDomainObject,
2725 DOMAIN_CREATE_ALIAS,
2726 &DomainObject);
2727 if (!NT_SUCCESS(Status))
2728 {
2729 TRACE("failed with status 0x%08lx\n", Status);
2730 goto done;
2731 }
2732
2733 /* Check the alias acoount name */
2734 Status = SampCheckAccountName(AccountName, 256);
2735 if (!NT_SUCCESS(Status))
2736 {
2737 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2738 goto done;
2739 }
2740
2741 /* Check if the alias name already exists in the domain */
2742 Status = SampCheckAccountNameInDomain(DomainObject,
2743 AccountName->Buffer);
2744 if (!NT_SUCCESS(Status))
2745 {
2746 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2747 AccountName->Buffer, Status);
2748 goto done;
2749 }
2750
2751 /* Get the fixed domain attributes */
2752 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2753 Status = SampGetObjectAttribute(DomainObject,
2754 L"F",
2755 NULL,
2756 (PVOID)&FixedDomainData,
2757 &ulSize);
2758 if (!NT_SUCCESS(Status))
2759 {
2760 TRACE("failed with status 0x%08lx\n", Status);
2761 goto done;
2762 }
2763
2764 /* Increment the NextRid attribute */
2765 ulRid = FixedDomainData.NextRid;
2766 FixedDomainData.NextRid++;
2767
2768 /* Store the fixed domain attributes */
2769 Status = SampSetObjectAttribute(DomainObject,
2770 L"F",
2771 REG_BINARY,
2772 &FixedDomainData,
2773 ulSize);
2774 if (!NT_SUCCESS(Status))
2775 {
2776 TRACE("failed with status 0x%08lx\n", Status);
2777 goto done;
2778 }
2779
2780 TRACE("RID: %lx\n", ulRid);
2781
2782 /* Convert the RID into a string (hex) */
2783 swprintf(szRid, L"%08lX", ulRid);
2784
2785 /* Create the alias object */
2786 Status = SampCreateDbObject(DomainObject,
2787 L"Aliases",
2788 szRid,
2789 ulRid,
2790 SamDbAliasObject,
2791 DesiredAccess,
2792 &AliasObject);
2793 if (!NT_SUCCESS(Status))
2794 {
2795 TRACE("failed with status 0x%08lx\n", Status);
2796 goto done;
2797 }
2798
2799 /* Add the account name for the alias object */
2800 Status = SampSetAccountNameInDomain(DomainObject,
2801 L"Aliases",
2802 AccountName->Buffer,
2803 ulRid);
2804 if (!NT_SUCCESS(Status))
2805 {
2806 TRACE("failed with status 0x%08lx\n", Status);
2807 goto done;
2808 }
2809
2810 /* Set the Name attribute */
2811 Status = SampSetObjectAttributeString(AliasObject,
2812 L"Name",
2813 AccountName);
2814 if (!NT_SUCCESS(Status))
2815 {
2816 TRACE("failed with status 0x%08lx\n", Status);
2817 goto done;
2818 }
2819
2820 /* Set the Description attribute */
2821 Status = SampSetObjectAttributeString(AliasObject,
2822 L"Description",
2823 NULL);
2824 if (!NT_SUCCESS(Status))
2825 {
2826 TRACE("failed with status 0x%08lx\n", Status);
2827 goto done;
2828 }
2829
2830 if (NT_SUCCESS(Status))
2831 {
2832 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2833 *RelativeId = ulRid;
2834 }
2835
2836 done:
2837 RtlReleaseResource(&SampResource);
2838
2839 TRACE("returns with status 0x%08lx\n", Status);
2840
2841 return Status;
2842 }
2843
2844
2845 /* Function 15 */
2846 NTSTATUS
2847 NTAPI
2848 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2849 IN OUT unsigned long *EnumerationContext,
2850 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2851 IN unsigned long PreferedMaximumLength,
2852 OUT unsigned long *CountReturned)
2853 {
2854 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2855 PSAM_DB_OBJECT DomainObject;
2856 HANDLE AliasesKeyHandle = NULL;
2857 HANDLE NamesKeyHandle = NULL;
2858 WCHAR AliasName[64];
2859 ULONG EnumIndex;
2860 ULONG EnumCount = 0;
2861 ULONG RequiredLength = 0;
2862 ULONG NameLength;
2863 ULONG DataLength;
2864 ULONG Rid;
2865 ULONG i;
2866 BOOLEAN MoreEntries = FALSE;
2867 NTSTATUS Status;
2868
2869 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2870 DomainHandle, EnumerationContext, Buffer,
2871 PreferedMaximumLength, CountReturned);
2872
2873 RtlAcquireResourceShared(&SampResource,
2874 TRUE);
2875
2876 /* Validate the domain handle */
2877 Status = SampValidateDbObject(DomainHandle,
2878 SamDbDomainObject,
2879 DOMAIN_LIST_ACCOUNTS,
2880 &DomainObject);
2881 if (!NT_SUCCESS(Status))
2882 goto done;
2883
2884 Status = SampRegOpenKey(DomainObject->KeyHandle,
2885 L"Aliases",
2886 KEY_READ,
2887 &AliasesKeyHandle);
2888 if (!NT_SUCCESS(Status))
2889 goto done;
2890
2891 Status = SampRegOpenKey(AliasesKeyHandle,
2892 L"Names",
2893 KEY_READ,
2894 &NamesKeyHandle);
2895 if (!NT_SUCCESS(Status))
2896 goto done;
2897
2898 TRACE("Part 1\n");
2899
2900 EnumIndex = *EnumerationContext;
2901
2902 while (TRUE)
2903 {
2904 NameLength = 64 * sizeof(WCHAR);
2905 Status = SampRegEnumerateValue(NamesKeyHandle,
2906 EnumIndex,
2907 AliasName,
2908 &NameLength,
2909 NULL,
2910 NULL,
2911 NULL);
2912 if (!NT_SUCCESS(Status))
2913 {
2914 if (Status == STATUS_NO_MORE_ENTRIES)
2915 Status = STATUS_SUCCESS;
2916 break;
2917 }
2918
2919 TRACE("EnumIndex: %lu\n", EnumIndex);
2920 TRACE("Alias name: %S\n", AliasName);
2921 TRACE("Name length: %lu\n", NameLength);
2922
2923 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2924 {
2925 MoreEntries = TRUE;
2926 break;
2927 }
2928
2929 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2930 EnumCount++;
2931
2932 EnumIndex++;
2933 }
2934
2935 TRACE("EnumCount: %lu\n", EnumCount);
2936 TRACE("RequiredLength: %lu\n", RequiredLength);
2937
2938 if (!NT_SUCCESS(Status))
2939 goto done;
2940
2941 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2942 if (EnumBuffer == NULL)
2943 {
2944 Status = STATUS_INSUFFICIENT_RESOURCES;
2945 goto done;
2946 }
2947
2948 EnumBuffer->EntriesRead = EnumCount;
2949 if (EnumCount == 0)
2950 goto done;
2951
2952 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2953 if (EnumBuffer->Buffer == NULL)
2954 {
2955 Status = STATUS_INSUFFICIENT_RESOURCES;
2956 goto done;
2957 }
2958
2959 TRACE("Part 2\n");
2960
2961 EnumIndex = *EnumerationContext;
2962 for (i = 0; i < EnumCount; i++, EnumIndex++)
2963 {
2964 NameLength = 64 * sizeof(WCHAR);
2965 DataLength = sizeof(ULONG);
2966 Status = SampRegEnumerateValue(NamesKeyHandle,
2967 EnumIndex,
2968 AliasName,
2969 &NameLength,
2970 NULL,
2971 &Rid,
2972 &DataLength);
2973 if (!NT_SUCCESS(Status))
2974 {
2975 if (Status == STATUS_NO_MORE_ENTRIES)
2976 Status = STATUS_SUCCESS;
2977 break;
2978 }
2979
2980 TRACE("EnumIndex: %lu\n", EnumIndex);
2981 TRACE("Alias name: %S\n", AliasName);
2982 TRACE("Name length: %lu\n", NameLength);
2983 TRACE("RID: %lu\n", Rid);
2984
2985 EnumBuffer->Buffer[i].RelativeId = Rid;
2986
2987 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2988 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2989
2990 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2991 #if 0
2992 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2993 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2994 {
2995 Status = STATUS_INSUFFICIENT_RESOURCES;
2996 goto done;
2997 }
2998
2999 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3000 AliasName,
3001 EnumBuffer->Buffer[i].Name.Length);
3002 #endif
3003 }
3004
3005 done:
3006 if (NT_SUCCESS(Status))
3007 {
3008 *EnumerationContext += EnumCount;
3009 *Buffer = EnumBuffer;
3010 *CountReturned = EnumCount;
3011 }
3012 else
3013 {
3014 *EnumerationContext = 0;
3015 *Buffer = NULL;
3016 *CountReturned = 0;
3017
3018 if (EnumBuffer != NULL)
3019 {
3020 if (EnumBuffer->Buffer != NULL)
3021 {
3022 if (EnumBuffer->EntriesRead != 0)
3023 {
3024 for (i = 0; i < EnumBuffer->EntriesRead; i++)
3025 {
3026 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3027 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3028 }
3029 }
3030
3031 midl_user_free(EnumBuffer->Buffer);
3032 }
3033
3034 midl_user_free(EnumBuffer);
3035 }
3036 }
3037
3038 SampRegCloseKey(&NamesKeyHandle);
3039 SampRegCloseKey(&AliasesKeyHandle);
3040
3041 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
3042 Status = STATUS_MORE_ENTRIES;
3043
3044 RtlReleaseResource(&SampResource);
3045
3046 return Status;
3047 }
3048
3049
3050 /* Function 16 */
3051 NTSTATUS
3052 NTAPI
3053 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3054 IN PSAMPR_PSID_ARRAY SidArray,
3055 OUT PSAMPR_ULONG_ARRAY Membership)
3056 {
3057 PSAM_DB_OBJECT DomainObject;
3058 HANDLE AliasesKeyHandle = NULL;
3059 HANDLE MembersKeyHandle = NULL;
3060 HANDLE MemberKeyHandle = NULL;
3061 LPWSTR MemberSidString = NULL;
3062 PULONG RidArray = NULL;
3063 ULONG MaxSidCount = 0;
3064 ULONG ValueCount;
3065 ULONG DataLength;
3066 ULONG i, j;
3067 NTSTATUS Status;
3068 WCHAR NameBuffer[9];
3069
3070 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3071 DomainHandle, SidArray, Membership);
3072
3073 RtlAcquireResourceShared(&SampResource,
3074 TRUE);
3075
3076 /* Validate the domain handle */
3077 Status = SampValidateDbObject(DomainHandle,
3078 SamDbDomainObject,
3079 DOMAIN_GET_ALIAS_MEMBERSHIP,
3080 &DomainObject);
3081 if (!NT_SUCCESS(Status))
3082 goto done;
3083
3084 Status = SampRegOpenKey(DomainObject->KeyHandle,
3085 L"Aliases",
3086 KEY_READ,
3087 &AliasesKeyHandle);
3088 TRACE("SampRegOpenKey returned %08lX\n", Status);
3089 if (!NT_SUCCESS(Status))
3090 goto done;
3091
3092 Status = SampRegOpenKey(AliasesKeyHandle,
3093 L"Members",
3094 KEY_READ,
3095 &MembersKeyHandle);
3096 TRACE("SampRegOpenKey returned %08lX\n", Status);
3097
3098 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3099 {
3100 Status = STATUS_SUCCESS;
3101 goto done;
3102 }
3103
3104 if (!NT_SUCCESS(Status))
3105 goto done;
3106
3107 for (i = 0; i < SidArray->Count; i++)
3108 {
3109 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3110 TRACE("Open %S\n", MemberSidString);
3111
3112 Status = SampRegOpenKey(MembersKeyHandle,
3113 MemberSidString,
3114 KEY_READ,
3115 &MemberKeyHandle);
3116 TRACE("SampRegOpenKey returned %08lX\n", Status);
3117 if (NT_SUCCESS(Status))
3118 {
3119 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3120 NULL,
3121 &ValueCount);
3122 if (NT_SUCCESS(Status))
3123 {
3124 TRACE("Found %lu values\n", ValueCount);
3125 MaxSidCount += ValueCount;
3126 }
3127
3128 SampRegCloseKey(&MemberKeyHandle);
3129 }
3130
3131 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3132 Status = STATUS_SUCCESS;
3133
3134 LocalFree(MemberSidString);
3135 }
3136
3137 if (MaxSidCount == 0)
3138 {
3139 Status = STATUS_SUCCESS;
3140 goto done;
3141 }
3142
3143 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3144 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3145 if (RidArray == NULL)
3146 {
3147 Status = STATUS_INSUFFICIENT_RESOURCES;
3148 goto done;
3149 }
3150
3151 for (i = 0; i < SidArray->Count; i++)
3152 {
3153 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3154 TRACE("Open %S\n", MemberSidString);
3155
3156 Status = SampRegOpenKey(MembersKeyHandle,
3157 MemberSidString,
3158 KEY_READ,
3159 &MemberKeyHandle);
3160 TRACE("SampRegOpenKey returned %08lX\n", Status);
3161 if (NT_SUCCESS(Status))
3162 {
3163 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3164 NULL,
3165 &ValueCount);
3166 if (NT_SUCCESS(Status))
3167 {
3168 TRACE("Found %lu values\n", ValueCount);
3169
3170 for (j = 0; j < ValueCount; j++)
3171 {
3172 DataLength = 9 * sizeof(WCHAR);
3173 Status = SampRegEnumerateValue(MemberKeyHandle,
3174 j,
3175 NameBuffer,
3176 &DataLength,
3177 NULL,
3178 NULL,
3179 NULL);
3180 if (NT_SUCCESS(Status))
3181 {
3182 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3183 }
3184 }
3185 }
3186
3187 SampRegCloseKey(&MemberKeyHandle);
3188 }
3189
3190 LocalFree(MemberSidString);
3191 }
3192
3193 done:
3194 SampRegCloseKey(&MembersKeyHandle);
3195 SampRegCloseKey(&MembersKeyHandle);
3196 SampRegCloseKey(&AliasesKeyHandle);
3197
3198 if (NT_SUCCESS(Status))
3199 {
3200 Membership->Count = MaxSidCount;
3201 Membership->Element = RidArray;
3202 }
3203 else
3204 {
3205 if (RidArray != NULL)
3206 midl_user_free(RidArray);
3207 }
3208
3209 RtlReleaseResource(&SampResource);
3210
3211 return Status;
3212 }
3213
3214
3215 /* Function 17 */
3216 NTSTATUS
3217 NTAPI
3218 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3219 IN ULONG Count,
3220 IN RPC_UNICODE_STRING Names[],
3221 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3222 OUT PSAMPR_ULONG_ARRAY Use)
3223 {
3224 PSAM_DB_OBJECT DomainObject;
3225 HANDLE AccountsKeyHandle = NULL;
3226 HANDLE NamesKeyHandle = NULL;
3227 ULONG MappedCount = 0;
3228 ULONG DataLength;
3229 ULONG i;
3230 ULONG RelativeId;
3231 NTSTATUS Status;
3232
3233 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3234 DomainHandle, Count, Names, RelativeIds, Use);
3235
3236 RtlAcquireResourceShared(&SampResource,
3237 TRUE);
3238
3239 /* Validate the domain handle */
3240 Status = SampValidateDbObject(DomainHandle,
3241 SamDbDomainObject,
3242 DOMAIN_LOOKUP,
3243 &DomainObject);
3244 if (!NT_SUCCESS(Status))
3245 {
3246 TRACE("failed with status 0x%08lx\n", Status);
3247 goto done;
3248 }
3249
3250 RelativeIds->Count = 0;
3251 Use->Count = 0;
3252
3253 if (Count == 0)
3254 {
3255 Status = STATUS_SUCCESS;
3256 goto done;
3257 }
3258
3259 /* Allocate the relative IDs array */
3260 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3261 if (RelativeIds->Element == NULL)
3262 {
3263 Status = STATUS_INSUFFICIENT_RESOURCES;
3264 goto done;
3265 }
3266
3267 /* Allocate the use array */
3268 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3269 if (Use->Element == NULL)
3270 {
3271 Status = STATUS_INSUFFICIENT_RESOURCES;
3272 goto done;
3273 }
3274
3275 RelativeIds->Count = Count;
3276 Use->Count = Count;
3277
3278 for (i = 0; i < Count; i++)
3279 {
3280 TRACE("Name: %S\n", Names[i].Buffer);
3281
3282 RelativeId = 0;
3283
3284 /* Lookup aliases */
3285 Status = SampRegOpenKey(DomainObject->KeyHandle,
3286 L"Aliases",
3287 KEY_READ,
3288 &AccountsKeyHandle);
3289 if (NT_SUCCESS(Status))
3290 {
3291 Status = SampRegOpenKey(AccountsKeyHandle,
3292 L"Names",
3293 KEY_READ,
3294 &NamesKeyHandle);
3295 if (NT_SUCCESS(Status))
3296 {
3297 DataLength = sizeof(ULONG);
3298 Status = SampRegQueryValue(NamesKeyHandle,
3299 Names[i].Buffer,
3300 NULL,
3301 &RelativeId,
3302 &DataLength);
3303
3304 SampRegCloseKey(&NamesKeyHandle);
3305 }
3306
3307 SampRegCloseKey(&AccountsKeyHandle);
3308 }
3309
3310 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3311 break;
3312
3313 /* Return alias account */
3314 if (NT_SUCCESS(Status) && RelativeId != 0)
3315 {
3316 TRACE("Rid: %lu\n", RelativeId);
3317 RelativeIds->Element[i] = RelativeId;
3318 Use->Element[i] = SidTypeAlias;
3319 MappedCount++;
3320 continue;
3321 }
3322
3323 /* Lookup groups */
3324 Status = SampRegOpenKey(DomainObject->KeyHandle,
3325 L"Groups",
3326 KEY_READ,
3327 &AccountsKeyHandle);
3328 if (NT_SUCCESS(Status))
3329 {
3330 Status = SampRegOpenKey(AccountsKeyHandle,
3331 L"Names",
3332 KEY_READ,
3333 &NamesKeyHandle);
3334 if (NT_SUCCESS(Status))
3335 {
3336 DataLength = sizeof(ULONG);
3337 Status = SampRegQueryValue(NamesKeyHandle,
3338 Names[i].Buffer,
3339 NULL,
3340 &RelativeId,
3341 &DataLength);
3342
3343 SampRegCloseKey(&NamesKeyHandle);
3344 }
3345
3346 SampRegCloseKey(&AccountsKeyHandle);
3347 }
3348
3349 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3350 break;
3351
3352 /* Return group account */
3353 if (NT_SUCCESS(Status) && RelativeId != 0)
3354 {
3355 TRACE("Rid: %lu\n", RelativeId);
3356 RelativeIds->Element[i] = RelativeId;
3357 Use->Element[i] = SidTypeGroup;
3358 MappedCount++;
3359 continue;
3360 }
3361
3362 /* Lookup users */
3363 Status = SampRegOpenKey(DomainObject->KeyHandle,
3364 L"Users",
3365 KEY_READ,
3366 &AccountsKeyHandle);
3367 if (NT_SUCCESS(Status))
3368 {
3369 Status = SampRegOpenKey(AccountsKeyHandle,
3370 L"Names",
3371 KEY_READ,
3372 &NamesKeyHandle);
3373 if (NT_SUCCESS(Status))
3374 {
3375 DataLength = sizeof(ULONG);
3376 Status = SampRegQueryValue(NamesKeyHandle,
3377 Names[i].Buffer,
3378 NULL,
3379 &RelativeId,
3380 &DataLength);
3381
3382 SampRegCloseKey(&NamesKeyHandle);
3383 }
3384
3385 SampRegCloseKey(&AccountsKeyHandle);
3386 }
3387
3388 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3389 break;
3390
3391 /* Return user account */
3392 if (NT_SUCCESS(Status) && RelativeId != 0)
3393 {
3394 TRACE("Rid: %lu\n", RelativeId);
3395 RelativeIds->Element[i] = RelativeId;
3396 Use->Element[i] = SidTypeUser;
3397 MappedCount++;
3398 continue;
3399 }
3400
3401 /* Return unknown account */
3402 RelativeIds->Element[i] = 0;
3403 Use->Element[i] = SidTypeUnknown;
3404 }
3405
3406 done:
3407 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3408 Status = STATUS_SUCCESS;
3409
3410 if (NT_SUCCESS(Status))
3411 {
3412 if (MappedCount == 0)
3413 Status = STATUS_NONE_MAPPED;
3414 else if (MappedCount < Count)
3415 Status = STATUS_SOME_NOT_MAPPED;
3416 }
3417 else
3418 {
3419 if (RelativeIds->Element != NULL)
3420 {
3421 midl_user_free(RelativeIds->Element);
3422 RelativeIds->Element = NULL;
3423 }
3424
3425 RelativeIds->Count = 0;
3426
3427 if (Use->Element != NULL)
3428 {
3429 midl_user_free(Use->Element);
3430 Use->Element = NULL;
3431 }
3432
3433 Use->Count = 0;
3434 }
3435
3436 RtlReleaseResource(&SampResource);
3437
3438 TRACE("Returned Status %lx\n", Status);
3439
3440 return Status;
3441 }
3442
3443
3444 /* Function 18 */
3445 NTSTATUS
3446 NTAPI
3447 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3448 IN ULONG Count,
3449 IN ULONG *RelativeIds,
3450 OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3451 OUT PSAMPR_ULONG_ARRAY Use)
3452 {
3453 PSAM_DB_OBJECT DomainObject;
3454 WCHAR RidString[9];
3455 HANDLE AccountsKeyHandle = NULL;
3456 HANDLE AccountKeyHandle = NULL;
3457 ULONG MappedCount = 0;
3458 ULONG DataLength;
3459 ULONG i;
3460 NTSTATUS Status;
3461
3462 TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3463 DomainHandle, Count, RelativeIds, Names, Use);
3464
3465 RtlAcquireResourceShared(&SampResource,
3466 TRUE);
3467
3468 /* Validate the domain handle */
3469 Status = SampValidateDbObject(DomainHandle,
3470 SamDbDomainObject,
3471 DOMAIN_LOOKUP,
3472 &DomainObject);
3473 if (!NT_SUCCESS(Status))
3474 {
3475 TRACE("failed with status 0x%08lx\n", Status);
3476 goto done;
3477 }
3478
3479 Names->Count = 0;
3480 Use->Count = 0;
3481
3482 if (Count == 0)
3483 {
3484 Status = STATUS_SUCCESS;
3485 goto done;
3486 }
3487
3488 /* Allocate the names array */
3489 Names->Element = midl_user_allocate(Count * sizeof(ULONG));
3490 if (Names->Element == NULL)
3491 {
3492 Status = STATUS_INSUFFICIENT_RESOURCES;
3493 goto done;
3494 }
3495
3496 /* Allocate the use array */
3497 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3498 if (Use->Element == NULL)
3499 {
3500 Status = STATUS_INSUFFICIENT_RESOURCES;
3501 goto done;
3502 }
3503
3504 Names->Count = Count;
3505 Use->Count = Count;
3506
3507 for (i = 0; i < Count; i++)
3508 {
3509 TRACE("RID: %lu\n", RelativeIds[i]);
3510
3511 swprintf(RidString, L"%08lx", RelativeIds[i]);
3512
3513 /* Lookup aliases */
3514 Status = SampRegOpenKey(DomainObject->KeyHandle,
3515 L"Aliases",
3516 KEY_READ,
3517 &AccountsKeyHandle);
3518 if (NT_SUCCESS(Status))
3519 {
3520 Status = SampRegOpenKey(AccountsKeyHandle,
3521 RidString,
3522 KEY_READ,
3523 &AccountKeyHandle);
3524 if (NT_SUCCESS(Status))
3525 {
3526 DataLength = 0;
3527 Status = SampRegQueryValue(AccountKeyHandle,
3528 L"Name",
3529 NULL,
3530 NULL,
3531 &DataLength);
3532 if (NT_SUCCESS(Status))
3533 {
3534 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3535 if (Names->Element[i].Buffer == NULL)
3536 Status = STATUS_INSUFFICIENT_RESOURCES;
3537
3538 if (NT_SUCCESS(Status))
3539 {
3540 Names->Element[i].MaximumLength = (USHORT)DataLength;
3541 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3542
3543 Status = SampRegQueryValue(AccountKeyHandle,
3544 L"Name",
3545 NULL,
3546 Names->Element[i].Buffer,
3547 &DataLength);
3548 }
3549 }
3550
3551 SampRegCloseKey(&AccountKeyHandle);
3552 }
3553
3554 SampRegCloseKey(&AccountsKeyHandle);
3555 }
3556
3557 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3558 break;
3559
3560 /* Return alias account */
3561 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3562 {
3563 TRACE("Name: %S\n", Names->Element[i].Buffer);
3564 Use->Element[i] = SidTypeAlias;
3565 MappedCount++;
3566 continue;
3567 }
3568
3569 /* Lookup groups */
3570 Status = SampRegOpenKey(DomainObject->KeyHandle,
3571 L"Groups",
3572 KEY_READ,
3573 &AccountsKeyHandle);
3574 if (NT_SUCCESS(Status))
3575 {
3576 Status = SampRegOpenKey(AccountsKeyHandle,
3577 RidString,
3578 KEY_READ,
3579 &AccountKeyHandle);
3580 if (NT_SUCCESS(Status))
3581 {
3582 DataLength = 0;
3583 Status = SampRegQueryValue(AccountKeyHandle,
3584 L"Name",
3585 NULL,
3586 NULL,
3587 &DataLength);
3588 if (NT_SUCCESS(Status))
3589 {
3590 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3591 if (Names->Element[i].Buffer == NULL)
3592 Status = STATUS_INSUFFICIENT_RESOURCES;
3593
3594 if (NT_SUCCESS(Status))
3595 {
3596 Names->Element[i].MaximumLength = (USHORT)DataLength;
3597 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3598
3599 Status = SampRegQueryValue(AccountKeyHandle,
3600 L"Name",
3601 NULL,
3602 Names->Element[i].Buffer,
3603 &DataLength);
3604 }
3605 }
3606
3607 SampRegCloseKey(&AccountKeyHandle);
3608 }
3609
3610 SampRegCloseKey(&AccountsKeyHandle);
3611 }
3612
3613 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3614 break;
3615
3616 /* Return group account */
3617 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3618 {
3619 TRACE("Name: %S\n", Names->Element[i].Buffer);
3620 Use->Element[i] = SidTypeGroup;
3621 MappedCount++;
3622 continue;
3623 }
3624
3625 /* Lookup users */
3626 Status = SampRegOpenKey(DomainObject->KeyHandle,
3627 L"Users",
3628 KEY_READ,
3629 &AccountsKeyHandle);
3630 if (NT_SUCCESS(Status))
3631 {
3632 Status = SampRegOpenKey(AccountsKeyHandle,
3633 RidString,
3634 KEY_READ,
3635 &AccountKeyHandle);
3636 if (NT_SUCCESS(Status))
3637 {
3638 DataLength = 0;
3639 Status = SampRegQueryValue(AccountKeyHandle,
3640 L"Name",
3641 NULL,
3642 NULL,
3643 &DataLength);
3644 if (NT_SUCCESS(Status))
3645 {
3646 TRACE("DataLength: %lu\n", DataLength);
3647
3648 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3649 if (Names->Element[i].Buffer == NULL)
3650 Status = STATUS_INSUFFICIENT_RESOURCES;
3651
3652 if (NT_SUCCESS(Status))
3653 {
3654 Names->Element[i].MaximumLength = (USHORT)DataLength;
3655 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3656
3657 Status = SampRegQueryValue(AccountKeyHandle,
3658 L"Name",
3659 NULL,
3660 Names->Element[i].Buffer,
3661 &DataLength);
3662 }
3663 }
3664
3665 SampRegCloseKey(&AccountKeyHandle);
3666 }
3667
3668 SampRegCloseKey(&AccountsKeyHandle);
3669 }
3670
3671 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3672 break;
3673
3674 /* Return user account */
3675 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3676 {
3677 TRACE("Name: %S\n", Names->Element[i].Buffer);
3678 Use->Element[i] = SidTypeUser;
3679 MappedCount++;
3680 continue;
3681 }
3682
3683 /* Return unknown account */
3684 Use->Element[i] = SidTypeUnknown;
3685 }
3686
3687 done:
3688 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3689 Status = STATUS_SUCCESS;
3690
3691 if (NT_SUCCESS(Status))
3692 {
3693 if (MappedCount == 0)
3694 Status = STATUS_NONE_MAPPED;
3695 else if (MappedCount < Count)
3696 Status = STATUS_SOME_NOT_MAPPED;
3697 }
3698 else
3699 {
3700 if (Names->Element != NULL)
3701 {
3702 for (i = 0; i < Count; i++)
3703 {
3704 if (Names->Element[i].Buffer != NULL)
3705 midl_user_free(Names->Element[i].Buffer);
3706 }
3707
3708 midl_user_free(Names->Element);
3709 Names->Element = NULL;
3710 }
3711
3712 Names->Count = 0;
3713
3714 if (Use->Element != NULL)
3715 {
3716 midl_user_free(Use->Element);
3717 Use->Element = NULL;
3718 }
3719
3720 Use->Count = 0;
3721 }
3722
3723 RtlReleaseResource(&SampResource);
3724
3725 return Status;
3726 }
3727
3728
3729 /* Function 19 */
3730 NTSTATUS
3731 NTAPI
3732 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
3733 IN ACCESS_MASK DesiredAccess,
3734 IN unsigned long GroupId,
3735 OUT SAMPR_HANDLE *GroupHandle)
3736 {
3737 PSAM_DB_OBJECT DomainObject;
3738 PSAM_DB_OBJECT GroupObject;
3739 WCHAR szRid[9];
3740 NTSTATUS Status;
3741
3742 TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
3743 DomainHandle, DesiredAccess, GroupId, GroupHandle);
3744
3745 /* Map generic access rights */
3746 RtlMapGenericMask(&DesiredAccess,
3747 &GroupMapping);
3748
3749 RtlAcquireResourceShared(&SampResource,
3750 TRUE);
3751
3752 /* Validate the domain handle */
3753 Status = SampValidateDbObject(DomainHandle,
3754 SamDbDomainObject,
3755 DOMAIN_LOOKUP,
3756 &DomainObject);
3757 if (!NT_SUCCESS(Status))
3758 {
3759 TRACE("failed with status 0x%08lx\n", Status);
3760 goto done;
3761 }
3762
3763 /* Convert the RID into a string (hex) */
3764 swprintf(szRid, L"%08lX", GroupId);
3765
3766 /* Create the group object */
3767 Status = SampOpenDbObject(DomainObject,
3768 L"Groups",
3769 szRid,
3770 GroupId,
3771 SamDbGroupObject,
3772 DesiredAccess,
3773 &GroupObject);
3774 if (!NT_SUCCESS(Status))
3775 {
3776 TRACE("failed with status 0x%08lx\n", Status);
3777 goto done;
3778 }
3779
3780 *GroupHandle = (SAMPR_HANDLE)GroupObject;
3781
3782 done:
3783 RtlReleaseResource(&SampResource);
3784
3785 return Status;
3786 }
3787
3788
3789 static NTSTATUS
3790 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
3791 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3792 {
3793 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3794 SAM_GROUP_FIXED_DATA FixedData;
3795 ULONG MembersLength = 0;
3796 ULONG Length = 0;
3797 NTSTATUS Status;
3798
3799 *Buffer = NULL;
3800
3801 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3802 if (InfoBuffer == NULL)
3803 return STATUS_INSUFFICIENT_RESOURCES;
3804
3805 Status = SampGetObjectAttributeString(GroupObject,
3806 L"Name",
3807 &InfoBuffer->General.Name);
3808 if (!NT_SUCCESS(Status))
3809 {
3810 TRACE("Status 0x%08lx\n", Status);
3811 goto done;
3812 }
3813
3814 Status = SampGetObjectAttributeString(GroupObject,
3815 L"Description",
3816 &InfoBuffer->General.AdminComment);
3817 if (!NT_SUCCESS(Status))
3818 {
3819 TRACE("Status 0x%08lx\n", Status);
3820 goto done;
3821 }
3822
3823 Length = sizeof(SAM_GROUP_FIXED_DATA);
3824 Status = SampGetObjectAttribute(GroupObject,
3825 L"F",
3826 NULL,
3827 (PVOID)&FixedData,
3828 &Length);
3829 if (!NT_SUCCESS(Status))
3830 goto done;
3831
3832 InfoBuffer->General.Attributes = FixedData.Attributes;
3833
3834 Status = SampGetObjectAttribute(GroupObject,
3835 L"Members",
3836 NULL,
3837 NULL,
3838 &MembersLength);
3839 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3840 goto done;
3841
3842 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3843 InfoBuffer->General.MemberCount = 0;
3844 else
3845 InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
3846
3847 *Buffer = InfoBuffer;
3848
3849 done:
3850 if (!NT_SUCCESS(Status))
3851 {
3852 if (InfoBuffer != NULL)
3853 {
3854 if (InfoBuffer->General.Name.Buffer != NULL)
3855 midl_user_free(InfoBuffer->General.Name.Buffer);
3856
3857 if (InfoBuffer->General.AdminComment.Buffer != NULL)
3858 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
3859
3860 midl_user_free(InfoBuffer);
3861 }
3862 }
3863
3864 return Status;
3865 }
3866
3867
3868 static NTSTATUS
3869 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
3870 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3871 {
3872 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3873 NTSTATUS Status;
3874
3875 *Buffer = NULL;
3876
3877 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3878 if (InfoBuffer == NULL)
3879 return STATUS_INSUFFICIENT_RESOURCES;
3880
3881 Status = SampGetObjectAttributeString(GroupObject,
3882 L"Name",
3883 &InfoBuffer->Name.Name);
3884 if (!NT_SUCCESS(Status))
3885 {
3886 TRACE("Status 0x%08lx\n", Status);
3887 goto done;
3888 }
3889
3890 *Buffer = InfoBuffer;
3891
3892 done:
3893 if (!NT_SUCCESS(Status))
3894 {
3895 if (InfoBuffer != NULL)
3896 {
3897 if (InfoBuffer->Name.Name.Buffer != NULL)
3898 midl_user_free(InfoBuffer->Name.Name.Buffer);
3899
3900 midl_user_free(InfoBuffer);
3901 }
3902 }
3903
3904 return Status;
3905 }
3906
3907
3908 static NTSTATUS
3909 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
3910 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3911 {
3912 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3913 SAM_GROUP_FIXED_DATA FixedData;
3914 ULONG Length = 0;
3915 NTSTATUS Status;
3916
3917 *Buffer = NULL;
3918
3919 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3920 if (InfoBuffer == NULL)
3921 return STATUS_INSUFFICIENT_RESOURCES;
3922
3923 Length = sizeof(SAM_GROUP_FIXED_DATA);
3924 Status = SampGetObjectAttribute(GroupObject,
3925 L"F",
3926 NULL,
3927 (PVOID)&FixedData,
3928 &Length);
3929 if (!NT_SUCCESS(Status))
3930 goto done;
3931
3932 InfoBuffer->Attribute.Attributes = FixedData.Attributes;
3933
3934 *Buffer = InfoBuffer;
3935
3936 done:
3937 if (!NT_SUCCESS(Status))
3938 {
3939 if (InfoBuffer != NULL)
3940 {
3941 midl_user_free(InfoBuffer);
3942 }
3943 }
3944
3945 return Status;
3946 }
3947
3948
3949 static NTSTATUS
3950 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
3951 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3952 {
3953 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3954 NTSTATUS Status;
3955
3956 *Buffer = NULL;
3957
3958 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3959 if (InfoBuffer == NULL)
3960 return STATUS_INSUFFICIENT_RESOURCES;
3961
3962 Status = SampGetObjectAttributeString(GroupObject,
3963 L"Description",
3964 &InfoBuffer->AdminComment.AdminComment);
3965 if (!NT_SUCCESS(Status))
3966 {
3967 TRACE("Status 0x%08lx\n", Status);
3968 goto done;
3969 }
3970
3971 *Buffer = InfoBuffer;
3972
3973 done:
3974 if (!NT_SUCCESS(Status))
3975 {
3976 if (InfoBuffer != NULL)
3977 {
3978 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
3979 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
3980
3981 midl_user_free(InfoBuffer);
3982 }
3983 }
3984
3985 return Status;
3986 }
3987
3988
3989 /* Function 20 */
3990 NTSTATUS
3991 NTAPI
3992 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
3993 IN GROUP_INFORMATION_CLASS GroupInformationClass,
3994 OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
3995 {
3996 PSAM_DB_OBJECT GroupObject;
3997 NTSTATUS Status;
3998
3999 TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4000 GroupHandle, GroupInformationClass, Buffer);
4001
4002 RtlAcquireResourceShared(&SampResource,
4003 TRUE);
4004
4005 /* Validate the group handle */
4006 Status = SampValidateDbObject(GroupHandle,
4007 SamDbGroupObject,
4008 GROUP_READ_INFORMATION,
4009 &GroupObject);
4010 if (!NT_SUCCESS(Status))
4011 goto done;
4012
4013 switch (GroupInformationClass)
4014 {
4015 case GroupGeneralInformation:
4016 Status = SampQueryGroupGeneral(GroupObject,
4017 Buffer);
4018 break;
4019
4020 case GroupNameInformation:
4021 Status = SampQueryGroupName(GroupObject,
4022 Buffer);
4023 break;
4024
4025 case GroupAttributeInformation:
4026 Status = SampQueryGroupAttribute(GroupObject,
4027 Buffer);
4028 break;
4029
4030 case GroupAdminCommentInformation:
4031 Status = SampQueryGroupAdminComment(GroupObject,
4032 Buffer);
4033 break;
4034
4035 default:
4036 Status = STATUS_INVALID_INFO_CLASS;
4037 break;
4038 }
4039
4040 done:
4041 RtlReleaseResource(&SampResource);
4042
4043 return Status;
4044 }
4045
4046
4047 static NTSTATUS
4048 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
4049 PSAMPR_GROUP_INFO_BUFFER Buffer)
4050 {
4051 UNICODE_STRING OldGroupName = {0, 0, NULL};
4052 UNICODE_STRING NewGroupName;
4053 NTSTATUS Status;
4054
4055 Status = SampGetObjectAttributeString(GroupObject,
4056 L"Name",
4057 (PRPC_UNICODE_STRING)&OldGroupName);
4058 if (!NT_SUCCESS(Status))
4059 {
4060 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4061 goto done;
4062 }
4063
4064 /* Check the new account name */
4065 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4066 if (!NT_SUCCESS(Status))
4067 {
4068 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4069 return Status;
4070 }
4071
4072 NewGroupName.Length = Buffer->Name.Name.Length;
4073 NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4074 NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4075
4076 if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4077 {
4078 Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
4079 NewGroupName.Buffer);
4080 if (!NT_SUCCESS(Status))
4081 {
4082 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4083 NewGroupName.Buffer, Status);
4084 goto done;
4085 }
4086 }
4087
4088 Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
4089 L"Groups",
4090 NewGroupName.Buffer,
4091 GroupObject->RelativeId);
4092 if (!NT_SUCCESS(Status))
4093 {
4094 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4095 goto done;
4096 }
4097
4098 Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4099 L"Groups",
4100 OldGroupName.Buffer);
4101 if (!NT_SUCCESS(Status))
4102 {
4103 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4104 goto done;
4105 }
4106
4107 Status = SampSetObjectAttributeString(GroupObject,
4108 L"Name",
4109 (PRPC_UNICODE_STRING)&NewGroupName);
4110 if (!NT_SUCCESS(Status))
4111 {
4112 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4113 }
4114
4115 done:
4116 if (OldGroupName.Buffer != NULL)
4117 midl_user_free(OldGroupName.Buffer);
4118
4119 return Status;
4120 }
4121
4122
4123 static NTSTATUS
4124 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4125 PSAMPR_GROUP_INFO_BUFFER Buffer)
4126 {
4127 SAM_GROUP_FIXED_DATA FixedData;
4128 ULONG Length = 0;
4129 NTSTATUS Status;
4130
4131 Length = sizeof(SAM_GROUP_FIXED_DATA);
4132 Status = SampGetObjectAttribute(GroupObject,
4133 L"F",
4134 NULL,
4135 (PVOID)&FixedData,
4136 &Length);
4137 if (!NT_SUCCESS(Status))
4138 goto done;
4139
4140 FixedData.Attributes = Buffer->Attribute.Attributes;
4141
4142 Status = SampSetObjectAttribute(GroupObject,
4143 L"F",
4144 REG_BINARY,
4145 &FixedData,
4146 Length);
4147
4148 done:
4149 return Status;
4150 }
4151
4152
4153 /* Function 21 */
4154 NTSTATUS
4155 NTAPI
4156 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4157 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4158 IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4159 {
4160 PSAM_DB_OBJECT GroupObject;
4161 NTSTATUS Status;
4162
4163 TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4164 GroupHandle, GroupInformationClass, Buffer);
4165
4166 RtlAcquireResourceExclusive(&SampResource,
4167 TRUE);
4168
4169 /* Validate the group handle */
4170 Status = SampValidateDbObject(GroupHandle,
4171 SamDbGroupObject,
4172 GROUP_WRITE_ACCOUNT,
4173 &GroupObject);
4174 if (!NT_SUCCESS(Status))
4175 goto done;
4176
4177 switch (GroupInformationClass)
4178 {
4179 case GroupNameInformation:
4180 Status = SampSetGroupName(GroupObject,
4181 Buffer);
4182 break;
4183
4184 case GroupAttributeInformation:
4185 Status = SampSetGroupAttribute(GroupObject,
4186 Buffer);
4187 break;
4188
4189 case GroupAdminCommentInformation:
4190 Status = SampSetObjectAttributeString(GroupObject,
4191 L"Description",
4192 &Buffer->AdminComment.AdminComment);
4193 break;
4194
4195 default:
4196 Status = STATUS_INVALID_INFO_CLASS;
4197 break;
4198 }
4199
4200 done:
4201 RtlReleaseResource(&SampResource);
4202
4203 return Status;
4204 }
4205
4206
4207 /* Function 22 */
4208 NTSTATUS
4209 NTAPI
4210 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4211 IN unsigned long MemberId,
4212 IN unsigned long Attributes)
4213 {
4214 PSAM_DB_OBJECT GroupObject;
4215 PSAM_DB_OBJECT UserObject = NULL;
4216 NTSTATUS Status;
4217
4218 TRACE("(%p %lu %lx)\n",
4219 GroupHandle, MemberId, Attributes);
4220
4221 RtlAcquireResourceExclusive(&SampResource,
4222 TRUE);
4223
4224 /* Validate the group handle */
4225 Status = SampValidateDbObject(GroupHandle,
4226 SamDbGroupObject,
4227 GROUP_ADD_MEMBER,
4228 &GroupObject);
4229 if (!NT_SUCCESS(Status))
4230 goto done;
4231
4232 /* Open the user object in the same domain */
4233 Status = SampOpenUserObject(GroupObject->ParentObject,
4234 MemberId,
4235 0,
4236 &UserObject);
4237 if (!NT_SUCCESS(Status))
4238 {
4239 TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4240 goto done;
4241 }
4242
4243 /* Add group membership to the user object */
4244 Status = SampAddGroupMembershipToUser(UserObject,
4245 GroupObject->RelativeId,
4246 Attributes);
4247 if (!NT_SUCCESS(Status))
4248 {
4249 TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4250 goto done;
4251 }
4252
4253 /* Add the member to the group object */
4254 Status = SampAddMemberToGroup(GroupObject,
4255 MemberId);
4256 if (!NT_SUCCESS(Status))
4257 {
4258 TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4259 }
4260
4261 done:
4262 if (UserObject)
4263 SampCloseDbObject(UserObject);
4264
4265 RtlReleaseResource(&SampResource);
4266
4267 return Status;
4268 }
4269
4270
4271 /* Function 23 */
4272 NTSTATUS
4273 NTAPI
4274 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4275 {
4276 PSAM_DB_OBJECT GroupObject;
4277 ULONG Length = 0;
4278 NTSTATUS Status;
4279
4280 TRACE("(%p)\n", GroupHandle);
4281
4282 RtlAcquireResourceExclusive(&SampResource,
4283 TRUE);
4284
4285 /* Validate the group handle */
4286 Status = SampValidateDbObject(*GroupHandle,
4287 SamDbGroupObject,
4288 DELETE,
4289 &GroupObject);
4290 if (!NT_SUCCESS(Status))
4291 {
4292 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4293 goto done;
4294 }
4295
4296 /* Fail, if the group is built-in */
4297 if (GroupObject->RelativeId < 1000)
4298 {
4299 TRACE("You can not delete a special account!\n");
4300 Status = STATUS_SPECIAL_ACCOUNT;
4301 goto done;
4302 }
4303
4304 /* Get the length of the Members attribute */
4305 SampGetObjectAttribute(GroupObject,
4306 L"Members",
4307 NULL,
4308 NULL,
4309 &Length);
4310
4311 /* Fail, if the group has members */
4312 if (Length != 0)
4313 {
4314 TRACE("There are still members in the group!\n");
4315 Status = STATUS_MEMBER_IN_GROUP;
4316 goto done;
4317 }
4318
4319 /* FIXME: Remove the group from all aliases */
4320
4321 /* Delete the group from the database */
4322 Status = SampDeleteAccountDbObject(GroupObject);
4323 if (!NT_SUCCESS(Status))
4324 {
4325 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4326 goto done;
4327 }
4328
4329 /* Invalidate the handle */
4330 *GroupHandle = NULL;
4331
4332 done:
4333 RtlReleaseResource(&SampResource);
4334
4335 return Status;
4336 }
4337
4338
4339 /* Function 24 */
4340 NTSTATUS
4341 NTAPI
4342 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4343 IN unsigned long MemberId)
4344 {
4345 PSAM_DB_OBJECT GroupObject;
4346 PSAM_DB_OBJECT UserObject = NULL;
4347 NTSTATUS Status;
4348
4349 TRACE("(%p %lu)\n",
4350 GroupHandle, MemberId);
4351
4352 RtlAcquireResourceExclusive(&SampResource,
4353 TRUE);
4354
4355 /* Validate the group handle */
4356 Status = SampValidateDbObject(GroupHandle,
4357 SamDbGroupObject,
4358 GROUP_REMOVE_MEMBER,
4359 &GroupObject);
4360 if (!NT_SUCCESS(Status))
4361 goto done;
4362
4363 /* Open the user object in the same domain */
4364 Status = SampOpenUserObject(GroupObject->ParentObject,
4365 MemberId,
4366 0,
4367 &UserObject);
4368 if (!NT_SUCCESS(Status))
4369 {
4370 ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4371 goto done;
4372 }
4373
4374 /* Remove group membership from the user object */
4375 Status = SampRemoveGroupMembershipFromUser(UserObject,
4376 GroupObject->RelativeId);
4377 if (!NT_SUCCESS(Status))
4378 {
4379 ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4380 goto done;
4381 }
4382
4383 /* Remove the member from the group object */
4384 Status = SampRemoveMemberFromGroup(GroupObject,
4385 MemberId);
4386 if (!NT_SUCCESS(Status))
4387 {
4388 ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4389 }
4390
4391 done:
4392 if (UserObject)
4393 SampCloseDbObject(UserObject);
4394
4395 RtlReleaseResource(&SampResource);
4396
4397 return Status;
4398 }
4399
4400
4401 /* Function 25 */
4402 NTSTATUS
4403 NTAPI
4404 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4405 OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4406 {
4407 PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4408 PSAM_DB_OBJECT GroupObject;
4409 ULONG Length = 0;
4410 ULONG i;
4411 NTSTATUS Status;
4412
4413 RtlAcquireResourceShared(&SampResource,
4414 TRUE);
4415
4416 /* Validate the group handle */
4417 Status = SampValidateDbObject(GroupHandle,
4418 SamDbGroupObject,
4419 GROUP_LIST_MEMBERS,
4420 &GroupObject);
4421 if (!NT_SUCCESS(Status))
4422 goto done;
4423
4424 MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4425 if (MembersBuffer == NULL)
4426 {
4427 Status = STATUS_INSUFFICIENT_RESOURCES;
4428 goto done;
4429 }
4430
4431 SampGetObjectAttribute(GroupObject,
4432 L"Members",
4433 NULL,
4434 NULL,
4435 &Length);
4436
4437 if (Length == 0)
4438 {
4439 MembersBuffer->MemberCount = 0;
4440 MembersBuffer->Members = NULL;
4441 MembersBuffer->Attributes = NULL;
4442
4443 *Members = MembersBuffer;
4444
4445 Status = STATUS_SUCCESS;
4446 goto done;
4447 }
4448
4449 MembersBuffer->Members = midl_user_allocate(Length);
4450 if (MembersBuffer->Members == NULL)
4451 {
4452 Status = STATUS_INSUFFICIENT_RESOURCES;
4453 goto done;
4454 }
4455
4456 MembersBuffer->Attributes = midl_user_allocate(Length);
4457 if (MembersBuffer->Attributes == NULL)
4458 {
4459 Status = STATUS_INSUFFICIENT_RESOURCES;
4460 goto done;
4461 }
4462
4463 Status = SampGetObjectAttribute(GroupObject,
4464 L"Members",
4465 NULL,
4466 MembersBuffer->Members,
4467 &Length);
4468 if (!NT_SUCCESS(Status))
4469 {
4470 TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4471 goto done;
4472 }
4473
4474 MembersBuffer->MemberCount = Length / sizeof(ULONG);
4475
4476 for (i = 0; i < MembersBuffer->MemberCount; i++)
4477 {
4478 Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4479 MembersBuffer->Members[i],
4480 GroupObject->RelativeId,
4481 &(MembersBuffer->Attributes[i]));
4482 if (!NT_SUCCESS(Status))
4483 {
4484 TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4485 goto done;
4486 }
4487 }
4488
4489 *Members = MembersBuffer;
4490
4491 done:
4492 if (!NT_SUCCESS(Status))
4493 {
4494 if (MembersBuffer != NULL)
4495 {
4496 if (MembersBuffer->Members != NULL)
4497 midl_user_free(MembersBuffer->Members);
4498
4499 if (MembersBuffer->Attributes != NULL)
4500 midl_user_free(MembersBuffer->Attributes);
4501
4502 midl_user_free(MembersBuffer);
4503 }
4504 }
4505
4506 RtlReleaseResource(&SampResource);
4507
4508 return Status;
4509 }
4510
4511
4512 /* Function 26 */
4513 NTSTATUS
4514 NTAPI
4515 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4516 IN unsigned long MemberId,
4517 IN unsigned long Attributes)
4518 {
4519 PSAM_DB_OBJECT GroupObject;
4520 NTSTATUS Status;
4521
4522 RtlAcquireResourceExclusive(&SampResource,
4523 TRUE);
4524
4525 /* Validate the group handle */
4526 Status = SampValidateDbObject(GroupHandle,
4527 SamDbGroupObject,
4528 GROUP_ADD_MEMBER,
4529 &GroupObject);
4530 if (!NT_SUCCESS(Status))
4531 {
4532 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4533 goto done;
4534 }
4535
4536 Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4537 MemberId,
4538 GroupObject->RelativeId,
4539 Attributes);
4540 if (!NT_SUCCESS(Status))
4541 {
4542 TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4543 }
4544
4545 done:
4546 RtlReleaseResource(&SampResource);
4547
4548 return Status;
4549 }
4550
4551
4552 /* Function 27 */
4553 NTSTATUS
4554 NTAPI
4555 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4556 IN ACCESS_MASK DesiredAccess,
4557 IN ULONG AliasId,
4558 OUT SAMPR_HANDLE *AliasHandle)
4559 {
4560 PSAM_DB_OBJECT DomainObject;
4561 PSAM_DB_OBJECT AliasObject;
4562 WCHAR szRid[9];
4563 NTSTATUS Status;
4564
4565 TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4566 DomainHandle, DesiredAccess, AliasId, AliasHandle);
4567
4568 /* Map generic access rights */
4569 RtlMapGenericMask(&DesiredAccess,
4570 &AliasMapping);
4571
4572 RtlAcquireResourceShared(&SampResource,
4573 TRUE);
4574
4575 /* Validate the domain handle */
4576 Status = SampValidateDbObject(DomainHandle,
4577 SamDbDomainObject,
4578 DOMAIN_LOOKUP,
4579 &DomainObject);
4580 if (!NT_SUCCESS(Status))
4581 {
4582 TRACE("failed with status 0x%08lx\n", Status);
4583 goto done;
4584 }
4585
4586 /* Convert the RID into a string (hex) */
4587 swprintf(szRid, L"%08lX", AliasId);
4588
4589 /* Create the alias object */
4590 Status = SampOpenDbObject(DomainObject,
4591 L"Aliases",
4592 szRid,
4593 AliasId,
4594 SamDbAliasObject,
4595 DesiredAccess,
4596 &AliasObject);
4597 if (!NT_SUCCESS(Status))
4598 {
4599 TRACE("failed with status 0x%08lx\n", Status);
4600 goto done;
4601 }
4602
4603 *AliasHandle = (SAMPR_HANDLE)AliasObject;
4604
4605 done:
4606 RtlReleaseResource(&SampResource);
4607
4608 return Status;
4609 }
4610
4611
4612 static NTSTATUS
4613 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4614 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4615 {
4616 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4617 HANDLE MembersKeyHandle = NULL;
4618 NTSTATUS Status;
4619
4620 *Buffer = NULL;
4621
4622 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4623 if (InfoBuffer == NULL)
4624 return STATUS_INSUFFICIENT_RESOURCES;
4625
4626 Status = SampGetObjectAttributeString(AliasObject,
4627 L"Name",
4628 &InfoBuffer->General.Name);
4629 if (!NT_SUCCESS(Status))
4630 {
4631 TRACE("Status 0x%08lx\n", Status);
4632 goto done;
4633 }
4634
4635 Status = SampGetObjectAttributeString(AliasObject,
4636 L"Description",
4637 &InfoBuffer->General.AdminComment);
4638 if (!NT_SUCCESS(Status))
4639 {
4640 TRACE("Status 0x%08lx\n", Status);
4641 goto done;
4642 }
4643
4644 /* Open the Members subkey */
4645 Status = SampRegOpenKey(AliasObject->KeyHandle,
4646 L"Members",
4647 KEY_READ,
4648 &MembersKeyHandle);
4649 if (NT_SUCCESS(Status))
4650 {
4651 /* Retrieve the number of members of the alias */
4652 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4653 NULL,
4654 &InfoBuffer->General.MemberCount);
4655 if (!NT_SUCCESS(Status))
4656 {
4657 TRACE("Status 0x%08lx\n", Status);
4658 goto done;
4659 }
4660 }
4661 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4662 {
4663 InfoBuffer->General.MemberCount = 0;
4664 Status = STATUS_SUCCESS;
4665 }
4666 else
4667 {
4668 TRACE("Status 0x%08lx\n", Status);
4669 goto done;
4670 }
4671
4672 *Buffer = InfoBuffer;
4673
4674 done:
4675 SampRegCloseKey(&MembersKeyHandle);
4676
4677 if (!NT_SUCCESS(Status))
4678 {
4679 if (InfoBuffer != NULL)
4680 {
4681 if (InfoBuffer->General.Name.Buffer != NULL)
4682 midl_user_free(InfoBuffer->General.Name.Buffer);
4683
4684 if (InfoBuffer->General.AdminComment.Buffer != NULL)
4685 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4686
4687 midl_user_free(InfoBuffer);
4688 }
4689 }
4690
4691 return Status;
4692 }
4693
4694
4695 static NTSTATUS
4696 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
4697 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4698 {
4699 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4700 NTSTATUS Status;
4701
4702 *Buffer = NULL;
4703
4704 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4705 if (InfoBuffer == NULL)
4706 return STATUS_INSUFFICIENT_RESOURCES;
4707
4708 Status = SampGetObjectAttributeString(AliasObject,
4709 L"Name",
4710 &InfoBuffer->Name.Name);
4711 if (!NT_SUCCESS(Status))
4712 {
4713 TRACE("Status 0x%08lx\n", Status);
4714 goto done;
4715 }
4716
4717 *Buffer = InfoBuffer;
4718
4719 done:
4720 if (!NT_SUCCESS(Status))
4721 {
4722 if (InfoBuffer != NULL)
4723 {
4724 if (InfoBuffer->Name.Name.Buffer != NULL)
4725 midl_user_free(InfoBuffer->Name.Name.Buffer);
4726
4727 midl_user_free(InfoBuffer);
4728 }
4729 }
4730
4731 return Status;
4732 }
4733
4734
4735 static NTSTATUS
4736 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
4737 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4738 {
4739 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4740 NTSTATUS Status;
4741
4742 *Buffer = NULL;
4743
4744 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4745 if (InfoBuffer == NULL)
4746 return STATUS_INSUFFICIENT_RESOURCES;
4747
4748 Status = SampGetObjectAttributeString(AliasObject,
4749 L"Description",
4750 &InfoBuffer->AdminComment.AdminComment);
4751 if (!NT_SUCCESS(Status))
4752 {
4753 TRACE("Status 0x%08lx\n", Status);
4754 goto done;
4755 }
4756
4757 *Buffer = InfoBuffer;
4758
4759 done:
4760 if (!NT_SUCCESS(Status))
4761 {
4762 if (InfoBuffer != NULL)
4763 {
4764 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4765 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4766
4767 midl_user_free(InfoBuffer);
4768 }
4769 }
4770
4771 return Status;
4772 }
4773
4774
4775 /* Function 28 */
4776 NTSTATUS
4777 NTAPI
4778 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
4779 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4780 OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4781 {
4782 PSAM_DB_OBJECT AliasObject;
4783 NTSTATUS Status;
4784
4785 TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
4786 AliasHandle, AliasInformationClass, Buffer);
4787
4788 RtlAcquireResourceShared(&SampResource,
4789 TRUE);
4790
4791 /* Validate the alias handle */
4792 Status = SampValidateDbObject(AliasHandle,
4793 SamDbAliasObject,
4794 ALIAS_READ_INFORMATION,
4795 &AliasObject);
4796 if (!NT_SUCCESS(Status))
4797 goto done;
4798
4799 switch (AliasInformationClass)
4800 {
4801 case AliasGeneralInformation:
4802 Status = SampQueryAliasGeneral(AliasObject,
4803 Buffer);
4804 break;
4805
4806 case AliasNameInformation:
4807 Status = SampQueryAliasName(AliasObject,
4808 Buffer);
4809 break;
4810
4811 case AliasAdminCommentInformation:
4812 Status = SampQueryAliasAdminComment(AliasObject,
4813 Buffer);
4814 break;
4815
4816 default:
4817 Status = STATUS_INVALID_INFO_CLASS;
4818 break;
4819 }
4820
4821 done:
4822 RtlReleaseResource(&SampResource);
4823
4824 return Status;
4825 }
4826
4827
4828 static NTSTATUS
4829 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
4830 PSAMPR_ALIAS_INFO_BUFFER Buffer)
4831 {
4832 UNICODE_STRING OldAliasName = {0, 0, NULL};
4833 UNICODE_STRING NewAliasName;
4834 NTSTATUS Status;
4835
4836 Status = SampGetObjectAttributeString(AliasObject,
4837 L"Name",
4838 (PRPC_UNICODE_STRING)&OldAliasName);
4839 if (!NT_SUCCESS(Status))
4840 {
4841 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4842 goto done;
4843 }
4844
4845 /* Check the new account name */
4846 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4847 if (!NT_SUCCESS(Status))
4848 {
4849 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4850 return Status;
4851 }
4852
4853 NewAliasName.Length = Buffer->Name.Name.Length;
4854 NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
4855 NewAliasName.Buffer = Buffer->Name.Name.Buffer;
4856
4857 if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
4858 {
4859 Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
4860 NewAliasName.Buffer);
4861 if (!NT_SUCCESS(Status))
4862 {
4863 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
4864 NewAliasName.Buffer, Status);
4865 goto done;
4866 }
4867 }
4868
4869 Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
4870 L"Aliases",
4871 NewAliasName.Buffer,
4872 AliasObject->RelativeId);
4873 if (!NT_SUCCESS(Status))
4874 {
4875 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4876 goto done;
4877 }
4878
4879 Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
4880 L"Aliases",
4881 OldAliasName.Buffer);
4882 if (!NT_SUCCESS(Status))
4883 {
4884 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4885 goto done;
4886 }
4887
4888 Status = SampSetObjectAttributeString(AliasObject,
4889 L"Name",
4890 (PRPC_UNICODE_STRING)&NewAliasName);
4891 if (!NT_SUCCESS(Status))
4892 {
4893 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4894 }
4895
4896 done:
4897 if (OldAliasName.Buffer != NULL)
4898 midl_user_free(OldAliasName.Buffer);
4899
4900 return Status;
4901 }
4902
4903
4904 /* Function 29 */
4905 NTSTATUS
4906 NTAPI
4907 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
4908 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4909 IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
4910 {
4911 PSAM_DB_OBJECT AliasObject;
4912 NTSTATUS Status;
4913
4914 TRACE("SamrSetInformationAlias(%p %lu %p)\n",
4915 AliasHandle, AliasInformationClass, Buffer);
4916
4917 RtlAcquireResourceExclusive(&SampResource,
4918 TRUE);
4919
4920 /* Validate the alias handle */
4921 Status = SampValidateDbObject(AliasHandle,
4922 SamDbAliasObject,
4923 ALIAS_WRITE_ACCOUNT,
4924 &AliasObject);
4925 if (!NT_SUCCESS(Status))
4926 goto done;
4927
4928 switch (AliasInformationClass)
4929 {
4930 case AliasNameInformation:
4931 Status = SampSetAliasName(AliasObject,
4932 Buffer);
4933 break;
4934
4935 case AliasAdminCommentInformation:
4936 Status = SampSetObjectAttributeString(AliasObject,
4937 L"Description",
4938 &Buffer->AdminComment.AdminComment);
4939 break;
4940
4941 default:
4942 Status = STATUS_INVALID_INFO_CLASS;
4943 break;
4944 }
4945
4946 done:
4947 RtlReleaseResource(&SampResource);
4948
4949 return Status;
4950 }
4951
4952
4953 /* Function 30 */
4954 NTSTATUS
4955 NTAPI
4956 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
4957 {
4958 PSAM_DB_OBJECT AliasObject;
4959 NTSTATUS Status;
4960
4961 RtlAcquireResourceExclusive(&SampResource,
4962 TRUE);
4963
4964 /* Validate the alias handle */
4965 Status = SampValidateDbObject(*AliasHandle,
4966 SamDbAliasObject,
4967 DELETE,
4968 &AliasObject);
4969 if (!NT_SUCCESS(Status))
4970 {
4971 TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
4972 goto done;
4973 }
4974
4975 /* Fail, if the alias is built-in */
4976 if (AliasObject->RelativeId < 1000)
4977 {
4978 TRACE("You can not delete a special account!\n");
4979 Status = STATUS_SPECIAL_ACCOUNT;
4980 goto done;
4981 }
4982
4983 /* Remove all members from the alias */
4984 Status = SampRemoveAllMembersFromAlias(AliasObject);
4985 if (!NT_SUCCESS(Status))
4986 {
4987 TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
4988 goto done;
4989 }
4990
4991 /* Delete the alias from the database */
4992 Status = SampDeleteAccountDbObject(AliasObject);
4993 if (!NT_SUCCESS(Status))
4994 {
4995 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4996 goto done;
4997 }
4998
4999 /* Invalidate the handle */
5000 *AliasHandle = NULL;
5001
5002 done:
5003 RtlReleaseResource(&SampResource);
5004
5005 return Status;
5006 }
5007
5008
5009 /* Function 31 */
5010 NTSTATUS
5011 NTAPI
5012 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
5013 IN PRPC_SID MemberId)
5014 {
5015 PSAM_DB_OBJECT AliasObject;
5016 NTSTATUS Status;
5017
5018 TRACE("(%p %p)\n", AliasHandle, MemberId);
5019
5020 RtlAcquireResourceExclusive(&SampResource,
5021 TRUE);
5022
5023 /* Validate the alias handle */
5024 Status = SampValidateDbObject(AliasHandle,
5025 SamDbAliasObject,
5026 ALIAS_ADD_MEMBER,
5027 &AliasObject);
5028 if (!NT_SUCCESS(Status))
5029 {
5030 TRACE("failed with status 0x%08lx\n", Status);
5031 goto done;
5032 }
5033
5034 Status = SampAddMemberToAlias(AliasObject,
5035 MemberId);
5036 if (!NT_SUCCESS(Status))
5037 {
5038 TRACE("failed with status 0x%08lx\n", Status);
5039 }
5040
5041 done:
5042 RtlReleaseResource(&SampResource);
5043
5044 return Status;
5045 }
5046
5047
5048 /* Function 32 */
5049 NTSTATUS
5050 NTAPI
5051 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
5052 IN PRPC_SID MemberId)
5053 {
5054 PSAM_DB_OBJECT AliasObject;
5055 NTSTATUS Status;
5056
5057 TRACE("(%p %p)\n", AliasHandle, MemberId);
5058
5059 RtlAcquireResourceExclusive(&SampResource,
5060 TRUE);
5061
5062 /* Validate the alias handle */
5063 Status = SampValidateDbObject(AliasHandle,
5064 SamDbAliasObject,
5065 ALIAS_REMOVE_MEMBER,
5066 &AliasObject);
5067 if (!NT_SUCCESS(Status))
5068 {
5069 TRACE("failed with status 0x%08lx\n", Status);
5070 goto done;
5071 }
5072
5073 Status = SampRemoveMemberFromAlias(AliasObject,
5074 MemberId);
5075 if (!NT_SUCCESS(Status))
5076 {
5077 TRACE("failed with status 0x%08lx\n", Status);
5078 }
5079
5080 done:
5081 RtlReleaseResource(&SampResource);
5082
5083 return Status;
5084 }
5085
5086
5087 /* Function 33 */
5088 NTSTATUS
5089 NTAPI
5090 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
5091 OUT PSAMPR_PSID_ARRAY_OUT Members)
5092 {
5093 PSAM_DB_OBJECT AliasObject;
5094 PSAMPR_SID_INFORMATION MemberArray = NULL;
5095 ULONG MemberCount = 0;
5096 ULONG Index;
5097 NTSTATUS Status;
5098
5099 TRACE("SamrGetMembersInAlias(%p %p %p)\n",
5100 AliasHandle, Members);
5101
5102 RtlAcquireResourceShared(&SampResource,
5103 TRUE);
5104
5105 /* Validate the alias handle */
5106 Status = SampValidateDbObject(AliasHandle,
5107 SamDbAliasObject,
5108 ALIAS_LIST_MEMBERS,
5109 &AliasObject);
5110 if (!NT_SUCCESS(Status))
5111 {
5112 ERR("failed with status 0x%08lx\n", Status);
5113 goto done;
5114 }
5115
5116 Status = SampGetMembersInAlias(AliasObject,
5117 &MemberCount,
5118 &MemberArray);
5119
5120 /* Return the number of members and the member array */
5121 if (NT_SUCCESS(Status))
5122 {
5123 Members->Count = MemberCount;
5124 Members->Sids = MemberArray;
5125 }
5126
5127 done:
5128 /* Clean up the members array and the SID buffers if something failed */
5129 if (!NT_SUCCESS(Status))
5130 {
5131 if (MemberArray != NULL)
5132 {
5133 for (Index = 0; Index < MemberCount; Index++)
5134 {
5135 if (MemberArray[Index].SidPointer != NULL)
5136 midl_user_free(MemberArray[Index].SidPointer);
5137 }
5138
5139 midl_user_free(MemberArray);
5140 }
5141 }
5142
5143 RtlReleaseResource(&SampResource);
5144
5145 return Status;
5146 }
5147
5148
5149 /* Function 34 */
5150 NTSTATUS
5151 NTAPI
5152 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5153 IN ACCESS_MASK DesiredAccess,
5154 IN unsigned long UserId,
5155 OUT SAMPR_HANDLE *UserHandle)
5156 {
5157 PSAM_DB_OBJECT DomainObject;
5158 PSAM_DB_OBJECT UserObject;
5159 WCHAR szRid[9];
5160 NTSTATUS Status;
5161
5162 TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5163 DomainHandle, DesiredAccess, UserId, UserHandle);
5164
5165 /* Map generic access rights */
5166 RtlMapGenericMask(&DesiredAccess,
5167 &UserMapping);
5168
5169 RtlAcquireResourceShared(&SampResource,
5170 TRUE);
5171
5172 /* Validate the domain handle */
5173 Status = SampValidateDbObject(DomainHandle,
5174 SamDbDomainObject,
5175 DOMAIN_LOOKUP,
5176 &DomainObject);
5177 if (!NT_SUCCESS(Status))
5178 {
5179 TRACE("failed with status 0x%08lx\n", Status);
5180 goto done;
5181 }
5182
5183 /* Convert the RID into a string (hex) */
5184 swprintf(szRid, L"%08lX", UserId);
5185
5186 /* Create the user object */
5187 Status = SampOpenDbObject(DomainObject,
5188 L"Users",
5189 szRid,
5190 UserId,
5191 SamDbUserObject,
5192 DesiredAccess,
5193 &UserObject);
5194 if (!NT_SUCCESS(Status))
5195 {
5196 TRACE("failed with status 0x%08lx\n", Status);
5197 goto done;
5198 }
5199
5200 *UserHandle = (SAMPR_HANDLE)UserObject;
5201
5202 done:
5203 RtlReleaseResource(&SampResource);
5204
5205 return Status;
5206 }
5207
5208
5209 /* Function 35 */
5210 NTSTATUS
5211 NTAPI
5212 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5213 {
5214 PSAM_DB_OBJECT UserObject;
5215 NTSTATUS Status;
5216
5217 TRACE("(%p)\n", UserHandle);
5218
5219 RtlAcquireResourceExclusive(&SampResource,
5220 TRUE);
5221
5222 /* Validate the user handle */
5223 Status = SampValidateDbObject(*UserHandle,
5224 SamDbUserObject,
5225 DELETE,
5226 &UserObject);
5227 if (!NT_SUCCESS(Status))
5228 {
5229 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5230 goto done;
5231 }
5232
5233 /* Fail, if the user is built-in */
5234 if (UserObject->RelativeId < 1000)
5235 {
5236 TRACE("You can not delete a special account!\n");
5237 Status = STATUS_SPECIAL_ACCOUNT;
5238 goto done;
5239 }
5240
5241 /* FIXME: Remove the user from all groups */
5242
5243 /* FIXME: Remove the user from all aliases */
5244
5245 /* Delete the user from the database */
5246 Status = SampDeleteAccountDbObject(UserObject);
5247 if (!NT_SUCCESS(Status))
5248 {
5249 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5250 goto done;
5251 }
5252
5253 /* Invalidate the handle */
5254 *UserHandle = NULL;
5255
5256 done:
5257 RtlReleaseResource(&SampResource);
5258
5259 return Status;
5260 }
5261
5262
5263 static
5264 NTSTATUS
5265 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5266 PSAMPR_USER_INFO_BUFFER *Buffer)
5267 {
5268 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5269 SAM_USER_FIXED_DATA FixedData;
5270 ULONG Length = 0;
5271 NTSTATUS Status;
5272
5273 *Buffer = NULL;
5274
5275 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5276 if (InfoBuffer == NULL)
5277 return STATUS_INSUFFICIENT_RESOURCES;
5278
5279 Length = sizeof(SAM_USER_FIXED_DATA);
5280 Status = SampGetObjectAttribute(UserObject,
5281 L"F",
5282 NULL,
5283 (PVOID)&FixedData,
5284 &Length);
5285 if (!NT_SUCCESS(Status))
5286 goto done;
5287
5288 InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5289
5290 /* Get the Name string */
5291 Status = SampGetObjectAttributeString(UserObject,
5292 L"Name",
5293 &InfoBuffer->General.UserName);
5294 if (!NT_SUCCESS(Status))
5295 {
5296 TRACE("Status 0x%08lx\n", Status);
5297 goto done;
5298 }
5299
5300 /* Get the FullName string */
5301 Status = SampGetObjectAttributeString(UserObject,
5302 L"FullName",
5303 &InfoBuffer->General.FullName);
5304 if (!NT_SUCCESS(Status))
5305 {
5306 TRACE("Status 0x%08lx\n", Status);
5307 goto done;
5308 }
5309
5310 /* Get the AdminComment string */
5311 Status = SampGetObjectAttributeString(UserObject,
5312 L"AdminComment",
5313 &InfoBuffer->General.AdminComment);
5314 if (!NT_SUCCESS(Status))
5315 {
5316 TRACE("Status 0x%08lx\n", Status);
5317 goto done;
5318 }
5319
5320 /* Get the UserComment string */
5321 Status = SampGetObjectAttributeString(UserObject,
5322 L"UserComment",
5323 &InfoBuffer->General.UserComment);
5324 if (!NT_SUCCESS(Status))
5325 {
5326 TRACE("Status 0x%08lx\n", Status);
5327 goto done;
5328 }
5329
5330 *Buffer = InfoBuffer;
5331
5332 done:
5333 if (!NT_SUCCESS(Status))
5334 {
5335 if (InfoBuffer != NULL)
5336 {
5337 if (InfoBuffer->General.UserName.Buffer != NULL)
5338 midl_user_free(InfoBuffer->General.UserName.Buffer);
5339
5340 if (InfoBuffer->General.FullName.Buffer != NULL)
5341 midl_user_free(InfoBuffer->General.FullName.Buffer);
5342
5343 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5344 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5345
5346 if (InfoBuffer->General.UserComment.Buffer != NULL)
5347 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5348
5349 midl_user_free(InfoBuffer);
5350 }
5351 }
5352
5353 return Status;
5354 }
5355
5356
5357 static
5358 NTSTATUS
5359 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5360 PSAMPR_USER_INFO_BUFFER *Buffer)
5361 {
5362 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5363 SAM_USER_FIXED_DATA FixedData;
5364 ULONG Length = 0;
5365 NTSTATUS Status;
5366
5367 *Buffer = NULL;
5368
5369 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5370 if (InfoBuffer == NULL)
5371 return STATUS_INSUFFICIENT_RESOURCES;
5372
5373 Length = sizeof(SAM_USER_FIXED_DATA);
5374 Status = SampGetObjectAttribute(UserObject,
5375 L"F",
5376 NULL,
5377 (PVOID)&FixedData,
5378 &Length);
5379 if (!NT_SUCCESS(Status))
5380 goto done;
5381
5382 InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5383 InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5384
5385 /* Get the UserComment string */
5386 Status = SampGetObjectAttributeString(UserObject,
5387 L"UserComment",
5388 &InfoBuffer->Preferences.UserComment);
5389 if (!NT_SUCCESS(Status))
5390 {
5391 TRACE("Status 0x%08lx\n", Status);
5392 goto done;
5393 }
5394
5395 *Buffer = InfoBuffer;
5396
5397 done:
5398 if (!NT_SUCCESS(Status))
5399 {
5400 if (InfoBuffer != NULL)
5401 {
5402 if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5403 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5404
5405 midl_user_free(InfoBuffer);
5406 }
5407 }
5408
5409 return Status;
5410 }
5411
5412
5413 static
5414 NTSTATUS
5415 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5416 PSAMPR_USER_INFO_BUFFER *Buffer)
5417 {
5418 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5419 SAM_DOMAIN_FIXED_DATA DomainFixedData;
5420 SAM_USER_FIXED_DATA FixedData;
5421 LARGE_INTEGER PasswordCanChange;
5422 LARGE_INTEGER PasswordMustChange;
5423 ULONG Length = 0;
5424 NTSTATUS Status;
5425
5426 *Buffer = NULL;
5427
5428 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5429 if (InfoBuffer == NULL)
5430 return STATUS_INSUFFICIENT_RESOURCES;
5431
5432 /* Get the fixed size domain data */
5433 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5434 Status = SampGetObjectAttribute(UserObject->ParentObject,
5435 L"F",
5436 NULL,
5437 (PVOID)&DomainFixedData,
5438 &Length);
5439 if (!NT_SUCCESS(Status))
5440 goto done;
5441
5442 /* Get the fixed size user data */
5443 Length = sizeof(SAM_USER_FIXED_DATA);
5444 Status = SampGetObjectAttribute(UserObject,
5445 L"F",
5446 NULL,
5447 (PVOID)&FixedData,
5448 &Length);
5449 if (!NT_SUCCESS(Status))
5450 goto done;
5451
5452 InfoBuffer->Logon.UserId = FixedData.UserId;
5453 InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5454 InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5455 InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5456 InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5457 InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5458 InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5459 InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5460 InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5461 InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5462 InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5463
5464 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5465 DomainFixedData.MinPasswordAge);
5466 InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5467 InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5468
5469 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5470 DomainFixedData.MaxPasswordAge);
5471 InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5472 InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5473
5474 /* Get the Name string */
5475 Status = SampGetObjectAttributeString(UserObject,
5476 L"Name",
5477 &InfoBuffer->Logon.UserName);
5478 if (!NT_SUCCESS(Status))
5479 {
5480 TRACE("Status 0x%08lx\n", Status);
5481 goto done;
5482 }
5483
5484 /* Get the FullName string */
5485 Status = SampGetObjectAttributeString(UserObject,
5486 L"FullName",
5487 &InfoBuffer->Logon.FullName);
5488 if (!NT_SUCCESS(Status))
5489 {
5490 TRACE("Status 0x%08lx\n", Status);
5491 goto done;
5492 }
5493
5494 /* Get the HomeDirectory string */
5495 Status = SampGetObjectAttributeString(UserObject,
5496 L"HomeDirectory",
5497 &InfoBuffer->Logon.HomeDirectory);
5498 if (!NT_SUCCESS(Status))
5499 {
5500 TRACE("Status 0x%08lx\n", Status);
5501 goto done;
5502 }
5503
5504 /* Get the HomeDirectoryDrive string */
5505 Status = SampGetObjectAttributeString(UserObject,
5506 L"HomeDirectoryDrive",
5507 &InfoBuffer->Logon.HomeDirectoryDrive);
5508 if (!NT_SUCCESS(Status))
5509 {
5510 TRACE("Status 0x%08lx\n", Status);
5511 goto done;
5512 }
5513
5514 /* Get the ScriptPath string */
5515 Status = SampGetObjectAttributeString(UserObject,
5516 L"ScriptPath",
5517 &InfoBuffer->Logon.ScriptPath);
5518 if (!NT_SUCCESS(Status))
5519 {
5520 TRACE("Status 0x%08lx\n", Status);
5521 goto done;
5522 }
5523
5524 /* Get the ProfilePath string */
5525 Status = SampGetObjectAttributeString(UserObject,
5526 L"ProfilePath",
5527 &InfoBuffer->Logon.ProfilePath);
5528 if (!NT_SUCCESS(Status))
5529 {
5530 TRACE("Status 0x%08lx\n", Status);
5531 goto done;
5532 }
5533
5534 /* Get the WorkStations string */
5535 Status = SampGetObjectAttributeString(UserObject,
5536 L"WorkStations",
5537 &InfoBuffer->Logon.WorkStations);
5538 if (!NT_SUCCESS(Status))
5539 {
5540 TRACE("Status 0x%08lx\n", Status);
5541 goto done;
5542 }
5543
5544 /* Get the LogonHours attribute */
5545 Status = SampGetLogonHoursAttrbute(UserObject,
5546 &InfoBuffer->Logon.LogonHours);
5547 if (!NT_SUCCESS(Status))
5548 {
5549 TRACE("Status 0x%08lx\n", Status);
5550 goto done;
5551 }
5552
5553 *Buffer = InfoBuffer;
5554
5555 done:
5556 if (!NT_SUCCESS(Status))
5557 {
5558 if (InfoBuffer != NULL)
5559 {
5560 if (InfoBuffer->Logon.UserName.Buffer != NULL)
5561 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5562
5563 if (InfoBuffer->Logon.FullName.Buffer != NULL)
5564 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5565
5566 if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5567 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5568
5569 if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5570 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5571
5572 if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5573 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5574
5575 if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5576 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5577
5578 if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5579 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5580
5581 if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5582 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5583
5584 midl_user_free(InfoBuffer);
5585 }
5586 }
5587
5588 return Status;
5589 }
5590
5591
5592 static
5593 NTSTATUS
5594 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5595 PSAMPR_USER_INFO_BUFFER *Buffer)
5596 {
5597 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5598 SAM_USER_FIXED_DATA FixedData;
5599 ULONG Length = 0;
5600 NTSTATUS Status;
5601
5602 *Buffer = NULL;
5603
5604 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5605 if (InfoBuffer == NULL)
5606 return STATUS_INSUFFICIENT_RESOURCES;
5607
5608 Length = sizeof(SAM_USER_FIXED_DATA);
5609 Status = SampGetObjectAttribute(UserObject,
5610 L"F",
5611 NULL,
5612 (PVOID)&FixedData,
5613 &Length);
5614 if (!NT_SUCCESS(Status))
5615 goto done;
5616
5617 InfoBuffer->Account.UserId = FixedData.UserId;
5618 InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5619 InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5620 InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5621 InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5622 InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5623 InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5624 InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5625 InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5626 InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5627 InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
5628 InfoBuffer->Account.LogonCount = FixedData.LogonCount;
5629 InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
5630
5631 /* Get the Name string */
5632 Status = SampGetObjectAttributeString(UserObject,
5633 L"Name",
5634 &InfoBuffer->Account.UserName);
5635 if (!NT_SUCCESS(Status))
5636 {
5637 TRACE("Status 0x%08lx\n", Status);
5638 goto done;
5639 }
5640
5641 /* Get the FullName string */
5642 Status = SampGetObjectAttributeString(UserObject,
5643 L"FullName",
5644 &InfoBuffer->Account.FullName);
5645 if (!NT_SUCCESS(Status))
5646 {
5647 TRACE("Status 0x%08lx\n", Status);
5648 goto done;
5649 }
5650
5651 /* Get the HomeDirectory string */
5652 Status = SampGetObjectAttributeString(UserObject,
5653 L"HomeDirectory",
5654 &InfoBuffer->Account.HomeDirectory);
5655 if (!NT_SUCCESS(Status))
5656 {
5657 TRACE("Status 0x%08lx\n", Status);
5658 goto done;
5659 }
5660
5661 /* Get the HomeDirectoryDrive string */
5662 Status = SampGetObjectAttributeString(UserObject,
5663 L"HomeDirectoryDrive",
5664 &InfoBuffer->Account.HomeDirectoryDrive);
5665 if (!NT_SUCCESS(Status))
5666 {
5667 TRACE("Status 0x%08lx\n", Status);
5668 goto done;
5669 }
5670
5671 /* Get the ScriptPath string */
5672 Status = SampGetObjectAttributeString(UserObject,
5673 L"ScriptPath",
5674 &InfoBuffer->Account.ScriptPath);
5675 if (!NT_SUCCESS(Status))
5676 {
5677 TRACE("Status 0x%08lx\n", Status);
5678 goto done;
5679 }
5680
5681 /* Get the ProfilePath string */
5682 Status = SampGetObjectAttributeString(UserObject,
5683 L"ProfilePath",
5684 &InfoBuffer->Account.ProfilePath);
5685 if (!NT_SUCCESS(Status))
5686 {
5687 TRACE("Status 0x%08lx\n", Status);
5688 goto done;
5689 }
5690
5691 /* Get the AdminComment string */
5692 Status = SampGetObjectAttributeString(UserObject,
5693 L"AdminComment",
5694 &InfoBuffer->Account.AdminComment);
5695 if (!NT_SUCCESS(Status))
5696 {
5697 TRACE("Status 0x%08lx\n", Status);
5698 goto done;
5699 }
5700
5701 /* Get the WorkStations string */
5702 Status = SampGetObjectAttributeString(UserObject,
5703 L"WorkStations",
5704 &InfoBuffer->Account.WorkStations);
5705 if (!NT_SUCCESS(Status))
5706 {
5707 TRACE("Status 0x%08lx\n", Status);
5708 goto done;
5709 }
5710
5711 /* Get the LogonHours attribute */
5712 Status = SampGetLogonHoursAttrbute(UserObject,
5713 &InfoBuffer->Account.LogonHours);
5714 if (!NT_SUCCESS(Status))
5715 {
5716 TRACE("Status 0x%08lx\n", Status);
5717 goto done;
5718 }
5719
5720 *Buffer = InfoBuffer;
5721
5722 done:
5723 if (!NT_SUCCESS(Status))
5724 {
5725 if (InfoBuffer != NULL)
5726 {
5727 if (InfoBuffer->Account.UserName.Buffer != NULL)
5728 midl_user_free(InfoBuffer->Account.UserName.Buffer);
5729
5730 if (InfoBuffer->Account.FullName.Buffer != NULL)
5731 midl_user_free(InfoBuffer->Account.FullName.Buffer);
5732
5733 if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
5734 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
5735
5736 if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
5737 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
5738
5739 if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
5740 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
5741
5742 if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
5743 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
5744
5745 if (InfoBuffer->Account.AdminComment.Buffer != NULL)
5746 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
5747
5748 if (InfoBuffer->Account.WorkStations.Buffer != NULL)
5749 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
5750
5751 if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
5752 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
5753
5754 midl_user_free(InfoBuffer);
5755 }
5756 }
5757
5758 return Status;
5759 }
5760
5761
5762 static
5763 NTSTATUS
5764 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
5765 PSAMPR_USER_INFO_BUFFER *Buffer)
5766 {
5767 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5768 NTSTATUS Status;
5769
5770 TRACE("(%p %p)\n", UserObject, Buffer);
5771
5772 *Buffer = NULL;
5773
5774 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5775 if (InfoBuffer == NULL)
5776 {
5777 TRACE("Failed to allocate InfoBuffer!\n");
5778 return STATUS_INSUFFICIENT_RESOURCES;
5779 }
5780
5781 Status = SampGetLogonHoursAttrbute(UserObject,
5782 &InfoBuffer->LogonHours.LogonHours);
5783 if (!NT_SUCCESS(Status))
5784 {
5785 TRACE("SampGetLogonHoursAttrbute failed (Status 0x%08lx)\n", Status);
5786 goto done;
5787 }
5788
5789 *Buffer = InfoBuffer;
5790
5791 done:
5792 if (!NT_SUCCESS(Status))
5793 {
5794 if (InfoBuffer != NULL)
5795 {
5796 if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
5797 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
5798
5799 midl_user_free(InfoBuffer);
5800 }
5801 }
5802
5803 return Status;
5804 }
5805
5806
5807 static
5808 NTSTATUS
5809 SampQueryUserName(PSAM_DB_OBJECT UserObject,
5810 PSAMPR_USER_INFO_BUFFER *Buffer)
5811 {
5812 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5813 NTSTATUS Status;
5814
5815 *Buffer = NULL;
5816
5817 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5818 if (InfoBuffer == NULL)
5819 return STATUS_INSUFFICIENT_RESOURCES;
5820
5821 /* Get the Name string */
5822 Status = SampGetObjectAttributeString(UserObject,
5823 L"Name",
5824 &InfoBuffer->Name.UserName);
5825 if (!NT_SUCCESS(Status))
5826 {
5827 TRACE("Status 0x%08lx\n", Status);
5828 goto done;
5829 }
5830
5831 /* Get the FullName string */
5832 Status = SampGetObjectAttributeString(UserObject,
5833 L"FullName",
5834 &InfoBuffer->Name.FullName);
5835 if (!NT_SUCCESS(Status))
5836 {
5837 TRACE("Status 0x%08lx\n", Status);
5838 goto done;
5839 }
5840
5841 *Buffer = InfoBuffer;
5842
5843 done:
5844 if (!NT_SUCCESS(Status))
5845 {
5846 if (InfoBuffer != NULL)
5847 {
5848 if (InfoBuffer->Name.UserName.Buffer != NULL)
5849 midl_user_free(InfoBuffer->Name.UserName.Buffer);
5850
5851 if (InfoBuffer->Name.FullName.Buffer != NULL)
5852 midl_user_free(InfoBuffer->Name.FullName.Buffer);
5853
5854 midl_user_free(InfoBuffer);
5855 }
5856 }
5857
5858 return Status;
5859 }
5860
5861
5862 static NTSTATUS
5863 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
5864 PSAMPR_USER_INFO_BUFFER *Buffer)
5865 {
5866 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5867 NTSTATUS Status;
5868
5869 *Buffer = NULL;
5870
5871 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5872 if (InfoBuffer == NULL)
5873 return STATUS_INSUFFICIENT_RESOURCES;
5874
5875 /* Get the Name string */
5876 Status = SampGetObjectAttributeString(UserObject,
5877 L"Name",
5878 &InfoBuffer->AccountName.UserName);
5879 if (!NT_SUCCESS(Status))
5880 {
5881 TRACE("Status 0x%08lx\n", Status);
5882 goto done;
5883 }
5884
5885 *Buffer = InfoBuffer;
5886
5887 done:
5888 if (!NT_SUCCESS(Status))
5889 {
5890 if (InfoBuffer != NULL)
5891 {
5892 if (InfoBuffer->AccountName.UserName.Buffer != NULL)
5893 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
5894
5895 midl_user_free(InfoBuffer);
5896 }
5897 }
5898
5899 return Status;
5900 }
5901
5902
5903 static NTSTATUS
5904 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
5905 PSAMPR_USER_INFO_BUFFER *Buffer)
5906 {
5907 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5908 NTSTATUS Status;
5909
5910 *Buffer = NULL;
5911
5912 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5913 if (InfoBuffer == NULL)
5914 return STATUS_INSUFFICIENT_RESOURCES;
5915
5916 /* Get the FullName string */
5917 Status = SampGetObjectAttributeString(UserObject,
5918 L"FullName",
5919 &InfoBuffer->FullName.FullName);
5920 if (!NT_SUCCESS(Status))
5921 {
5922 TRACE("Status 0x%08lx\n", Status);
5923 goto done;
5924 }
5925
5926 *Buffer = InfoBuffer;
5927
5928 done:
5929 if (!NT_SUCCESS(Status))
5930 {
5931 if (InfoBuffer != NULL)
5932 {
5933 if (InfoBuffer->FullName.FullName.Buffer != NULL)
5934 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
5935
5936 midl_user_free(InfoBuffer);
5937 }
5938 }
5939
5940 return Status;
5941 }
5942
5943
5944 static
5945 NTSTATUS
5946 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
5947 PSAMPR_USER_INFO_BUFFER *Buffer)
5948 {
5949 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5950 SAM_USER_FIXED_DATA FixedData;
5951 ULONG Length = 0;
5952 NTSTATUS Status;
5953
5954 *Buffer = NULL;
5955
5956 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5957 if (InfoBuffer == NULL)
5958 return STATUS_INSUFFICIENT_RESOURCES;
5959
5960 Length = sizeof(SAM_USER_FIXED_DATA);
5961 Status = SampGetObjectAttribute(UserObject,
5962 L"F",
5963 NULL,
5964 (PVOID)&FixedData,
5965 &Length);
5966 if (!NT_SUCCESS(Status))
5967 goto done;
5968
5969 InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
5970
5971 *Buffer = InfoBuffer;
5972
5973 done:
5974 if (!NT_SUCCESS(Status))
5975 {
5976 if (InfoBuffer != NULL)
5977 {
5978 midl_user_free(InfoBuffer);
5979 }
5980 }
5981
5982 return Status;
5983 }
5984
5985
5986 static NTSTATUS
5987 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
5988 PSAMPR_USER_INFO_BUFFER *Buffer)
5989 {
5990 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5991 NTSTATUS Status;
5992
5993 *Buffer = NULL;
5994
5995 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5996 if (InfoBuffer == NULL)
5997 return STATUS_INSUFFICIENT_RESOURCES;
5998
5999 /* Get the HomeDirectory string */
6000 Status = SampGetObjectAttributeString(UserObject,
6001 L"HomeDirectory",
6002 &InfoBuffer->Home.HomeDirectory);
6003 if (!NT_SUCCESS(Status))
6004 {
6005 TRACE("Status 0x%08lx\n", Status);
6006 goto done;
6007 }
6008
6009 /* Get the HomeDirectoryDrive string */
6010 Status = SampGetObjectAttributeString(UserObject,
6011 L"HomeDirectoryDrive",
6012 &InfoBuffer->Home.HomeDirectoryDrive);
6013 if (!NT_SUCCESS(Status))
6014 {
6015 TRACE("Status 0x%08lx\n", Status);
6016 goto done;
6017 }
6018
6019 *Buffer = InfoBuffer;
6020
6021 done:
6022 if (!NT_SUCCESS(Status))
6023 {
6024 if (InfoBuffer != NULL)
6025 {
6026 if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
6027 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
6028
6029 if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
6030 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
6031
6032 midl_user_free(InfoBuffer);
6033 }
6034 }
6035
6036 return Status;
6037 }
6038
6039
6040 static NTSTATUS
6041 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
6042 PSAMPR_USER_INFO_BUFFER *Buffer)
6043 {
6044 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6045 NTSTATUS Status;
6046
6047 *Buffer = NULL;
6048
6049 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6050 if (InfoBuffer == NULL)
6051 return STATUS_INSUFFICIENT_RESOURCES;
6052
6053 /* Get the ScriptPath string */
6054 Status = SampGetObjectAttributeString(UserObject,
6055 L"ScriptPath",
6056 &InfoBuffer->Script.ScriptPath);
6057 if (!NT_SUCCESS(Status))
6058 {
6059 TRACE("Status 0x%08lx\n", Status);
6060 goto done;
6061 }
6062
6063 *Buffer = InfoBuffer;
6064
6065 done:
6066 if (!NT_SUCCESS(Status))
6067 {
6068 if (InfoBuffer != NULL)
6069 {
6070 if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
6071 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
6072
6073 midl_user_free(InfoBuffer);
6074 }
6075 }
6076
6077 return Status;
6078 }
6079
6080
6081 static NTSTATUS
6082 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
6083 PSAMPR_USER_INFO_BUFFER *Buffer)
6084 {
6085 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6086 NTSTATUS Status;
6087
6088 *Buffer = NULL;
6089
6090 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6091 if (InfoBuffer == NULL)
6092 return STATUS_INSUFFICIENT_RESOURCES;
6093
6094 /* Get the ProfilePath string */
6095 Status = SampGetObjectAttributeString(UserObject,
6096 L"ProfilePath",
6097 &InfoBuffer->Profile.ProfilePath);
6098 if (!NT_SUCCESS(Status))
6099 {
6100 TRACE("Status 0x%08lx\n", Status);
6101 goto done;
6102 }
6103
6104 *Buffer = InfoBuffer;
6105
6106 done:
6107 if (!NT_SUCCESS(Status))
6108 {
6109 if (InfoBuffer != NULL)
6110 {
6111 if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
6112 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
6113
6114 midl_user_free(InfoBuffer);
6115 }
6116 }
6117
6118 return Status;
6119 }
6120
6121
6122 static NTSTATUS
6123 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6124 PSAMPR_USER_INFO_BUFFER *Buffer)
6125 {
6126 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6127 NTSTATUS Status;
6128
6129 *Buffer = NULL;
6130
6131 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6132 if (InfoBuffer == NULL)
6133 return STATUS_INSUFFICIENT_RESOURCES;
6134
6135 /* Get the AdminComment string */
6136 Status = SampGetObjectAttributeString(UserObject,
6137 L"AdminComment",
6138 &InfoBuffer->AdminComment.AdminComment);
6139 if (!NT_SUCCESS(Status))
6140 {
6141 TRACE("Status 0x%08lx\n", Status);
6142 goto done;
6143 }
6144
6145 *Buffer = InfoBuffer;
6146
6147 done:
6148 if (!NT_SUCCESS(Status))
6149 {
6150 if (InfoBuffer != NULL)
6151 {
6152 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6153 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6154
6155 midl_user_free(InfoBuffer);
6156 }
6157 }
6158
6159 return Status;
6160 }
6161
6162
6163 static NTSTATUS
6164 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6165 PSAMPR_USER_INFO_BUFFER *Buffer)
6166 {
6167 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6168 NTSTATUS Status;
6169
6170 *Buffer = NULL;
6171
6172 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6173 if (InfoBuffer == NULL)
6174 return STATUS_INSUFFICIENT_RESOURCES;
6175
6176 /* Get the WorkStations string */
6177 Status = SampGetObjectAttributeString(UserObject,
6178 L"WorkStations",
6179 &InfoBuffer->WorkStations.WorkStations);
6180 if (!NT_SUCCESS(Status))
6181 {
6182 TRACE("Status 0x%08lx\n", Status);
6183 goto done;
6184 }
6185
6186 *Buffer = InfoBuffer;
6187
6188 done:
6189 if (!NT_SUCCESS(Status))
6190 {
6191 if (InfoBuffer != NULL)
6192 {
6193 if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6194 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6195
6196 midl_user_free(InfoBuffer);
6197 }
6198 }
6199
6200 return Status;
6201 }
6202
6203
6204 static
6205 NTSTATUS
6206 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6207 PSAMPR_USER_INFO_BUFFER *Buffer)
6208 {
6209 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6210 SAM_USER_FIXED_DATA FixedData;
6211 ULONG Length = 0;
6212 NTSTATUS Status;
6213
6214 *Buffer = NULL;
6215
6216 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6217 if (InfoBuffer == NULL)
6218 return STATUS_INSUFFICIENT_RESOURCES;
6219
6220 Length = sizeof(SAM_USER_FIXED_DATA);
6221 Status = SampGetObjectAttribute(UserObject,
6222 L"F",
6223 NULL,
6224 (PVOID)&FixedData,
6225 &Length);
6226 if (!NT_SUCCESS(Status))
6227 goto done;
6228
6229 InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6230
6231 *Buffer = InfoBuffer;
6232
6233 done:
6234 if (!NT_SUCCESS(Status))
6235 {
6236 if (InfoBuffer != NULL)
6237 {
6238 midl_user_free(InfoBuffer);
6239 }
6240 }
6241
6242 return Status;
6243 }
6244
6245
6246 static
6247 NTSTATUS
6248 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6249 PSAMPR_USER_INFO_BUFFER *Buffer)
6250 {
6251 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6252 SAM_USER_FIXED_DATA FixedData;
6253 ULONG Length = 0;
6254 NTSTATUS Status;
6255
6256 *Buffer = NULL;
6257
6258 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6259 if (InfoBuffer == NULL)
6260 return STATUS_INSUFFICIENT_RESOURCES;
6261
6262 Length = sizeof(SAM_USER_FIXED_DATA);
6263 Status = SampGetObjectAttribute(UserObject,
6264 L"F",
6265 NULL,
6266 (PVOID)&FixedData,
6267 &Length);
6268 if (!NT_SUCCESS(Status))
6269 goto done;
6270
6271 InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6272 InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6273
6274 *Buffer = InfoBuffer;
6275
6276 done:
6277 if (!NT_SUCCESS(Status))
6278 {
6279 if (InfoBuffer != NULL)
6280 {
6281 midl_user_free(InfoBuffer);
6282 }
6283 }
6284
6285 return Status;
6286 }
6287
6288
6289 static
6290 NTSTATUS
6291 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6292 PSAMPR_USER_INFO_BUFFER *Buffer)
6293 {
6294 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6295 ULONG Length = 0;
6296 NTSTATUS Status = STATUS_SUCCESS;
6297
6298 /* Fail, if the caller is not a trusted caller */
6299 if (UserObject->Trusted == FALSE)
6300 return STATUS_INVALID_INFO_CLASS;
6301
6302 *Buffer = NULL;
6303
6304 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6305 if (InfoBuffer == NULL)
6306 return STATUS_INSUFFICIENT_RESOURCES;
6307
6308 /* Get the NT password */
6309 Length = 0;
6310 SampGetObjectAttribute(UserObject,
6311 L"NTPwd",
6312 NULL,
6313 NULL,
6314 &Length);
6315
6316 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6317 {
6318 Status = SampGetObjectAttribute(UserObject,
6319 L"NTPwd",
6320 NULL,
6321 (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6322 &Length);
6323 if (!NT_SUCCESS(Status))
6324 goto done;
6325 }
6326
6327 InfoBuffer->Internal1.NtPasswordPresent = (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD));
6328
6329 /* Get the LM password */
6330 Length = 0;
6331 SampGetObjectAttribute(UserObject,
6332 L"LMPwd",
6333 NULL,
6334 NULL,
6335 &Length);
6336
6337 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6338 {
6339 Status = SampGetObjectAttribute(UserObject,
6340 L"LMPwd",
6341 NULL,
6342 (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6343 &Length);
6344 if (!NT_SUCCESS(Status))
6345 goto done;
6346 }
6347
6348 InfoBuffer->Internal1.LmPasswordPresent = (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD));
6349
6350 InfoBuffer->Internal1.PasswordExpired = FALSE;
6351
6352 *Buffer = InfoBuffer;
6353
6354 done:
6355 if (!NT_SUCCESS(Status))
6356 {
6357 if (InfoBuffer != NULL)
6358 {
6359 midl_user_free(InfoBuffer);
6360 }
6361 }
6362
6363 return Status;
6364 }
6365
6366
6367 static NTSTATUS
6368 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6369 PSAMPR_USER_INFO_BUFFER *Buffer)
6370 {
6371 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6372 NTSTATUS Status;
6373
6374 *Buffer = NULL;
6375
6376 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6377 if (InfoBuffer == NULL)
6378 return STATUS_INSUFFICIENT_RESOURCES;
6379
6380 /* Get the Parameters string */
6381 Status = SampGetObjectAttributeString(UserObject,
6382 L"Parameters",
6383 &InfoBuffer->Parameters.Parameters);
6384 if (!NT_SUCCESS(Status))
6385 {
6386 TRACE("Status 0x%08lx\n", Status);
6387 goto done;
6388 }
6389
6390 *Buffer = InfoBuffer;
6391
6392 done:
6393 if (!NT_SUCCESS(Status))
6394 {
6395 if (InfoBuffer != NULL)
6396 {
6397 if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6398 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6399
6400 midl_user_free(InfoBuffer);
6401 }
6402 }
6403
6404 return Status;
6405 }
6406
6407
6408 static NTSTATUS
6409 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6410 PSAMPR_USER_INFO_BUFFER *Buffer)
6411 {
6412 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6413 SAM_DOMAIN_FIXED_DATA DomainFixedData;
6414 SAM_USER_FIXED_DATA FixedData;
6415 LARGE_INTEGER PasswordCanChange;
6416 LARGE_INTEGER PasswordMustChange;
6417 ULONG Length = 0;
6418 NTSTATUS Status;
6419
6420 *Buffer = NULL;
6421
6422 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6423 if (InfoBuffer == NULL)
6424 return STATUS_INSUFFICIENT_RESOURCES;
6425
6426 /* Get the fixed size domain data */
6427 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6428 Status = SampGetObjectAttribute(UserObject->ParentObject,
6429 L"F",
6430 NULL,
6431 (PVOID)&DomainFixedData,
6432 &Length);
6433 if (!NT_SUCCESS(Status))
6434 goto done;
6435
6436 /* Get the fixed size user data */
6437 Length = sizeof(SAM_USER_FIXED_DATA);
6438 Status = SampGetObjectAttribute(UserObject,
6439 L"F",
6440 NULL,
6441 (PVOID)&FixedData,
6442 &Length);
6443 if (!NT_SUCCESS(Status))
6444 goto done;
6445
6446 /* Set the fields to be returned */
6447 if (UserObject->Trusted)
6448 {
6449 InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
6450 USER_ALL_READ_LOGON_MASK |
6451 USER_ALL_READ_ACCOUNT_MASK |
6452 USER_ALL_READ_PREFERENCES_MASK |
6453 USER_ALL_READ_TRUSTED_MASK;
6454 }
6455 else
6456 {
6457 InfoBuffer->All.WhichFields = 0;
6458
6459 if (UserObject->Access & USER_READ_GENERAL)
6460 InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6461
6462 if (UserObject->Access & USER_READ_LOGON)
6463 InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
6464
6465 if (UserObject->Access & USER_READ_ACCOUNT)
6466 InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6467
6468 if (UserObject->Access & USER_READ_PREFERENCES)
6469 InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6470 }
6471
6472 /* Fail, if no fields are to be returned */
6473 if (InfoBuffer->All.WhichFields == 0)
6474 {
6475 Status = STATUS_ACCESS_DENIED;
6476 goto done;
6477 }
6478
6479 /* Get the UserName attribute */
6480 if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
6481 {
6482 Status = SampGetObjectAttributeString(UserObject,
6483 L"Name",
6484 &InfoBuffer->All.UserName);
6485 if (!NT_SUCCESS(Status))
6486 {
6487 TRACE("Status 0x%08lx\n", Status);
6488 goto done;
6489 }
6490 }
6491
6492 /* Get the FullName attribute */
6493 if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
6494 {
6495 Status = SampGetObjectAttributeString(UserObject,
6496 L"FullName",
6497 &InfoBuffer->All.FullName);
6498 if (!NT_SUCCESS(Status))
6499 {
6500 TRACE("Status 0x%08lx\n", Status);
6501 goto done;
6502 }
6503 }
6504
6505 /* Get the UserId attribute */
6506 if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
6507 {
6508 InfoBuffer->All.UserId = FixedData.UserId;
6509 }
6510
6511 /* Get the PrimaryGroupId attribute */
6512 if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
6513 {
6514 InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6515 }
6516
6517 /* Get the AdminComment attribute */
6518 if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
6519 {
6520 Status = SampGetObjectAttributeString(UserObject,
6521 L"AdminComment",
6522 &InfoBuffer->All.AdminComment);
6523 if (!NT_SUCCESS(Status))
6524 {
6525 TRACE("Status 0x%08lx\n", Status);
6526 goto done;
6527 }
6528 }
6529
6530 /* Get the UserComment attribute */
6531 if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
6532 {
6533 Status = SampGetObjectAttributeString(UserObject,
6534 L"UserComment",
6535 &InfoBuffer->All.UserComment);
6536 if (!NT_SUCCESS(Status))
6537 {
6538 TRACE("Status 0x%08lx\n", Status);
6539 goto done;
6540 }
6541 }
6542
6543 /* Get the HomeDirectory attribute */
6544 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
6545 {
6546 Status = SampGetObjectAttributeString(UserObject,
6547 L"HomeDirectory",
6548 &InfoBuffer->All.HomeDirectory);
6549 if (!NT_SUCCESS(Status))
6550 {
6551 TRACE("Status 0x%08lx\n", Status);
6552 goto done;
6553 }
6554 }
6555
6556 /* Get the HomeDirectoryDrive attribute */
6557 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
6558 {
6559 Status = SampGetObjectAttributeString(UserObject,
6560 L"HomeDirectoryDrive",
6561 &InfoBuffer->Home.HomeDirectoryDrive);
6562 if (!NT_SUCCESS(Status))
6563 {
6564 TRACE("Status 0x%08lx\n", Status);
6565 goto done;
6566 }
6567 }
6568
6569 /* Get the ScriptPath attribute */
6570 if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
6571 {
6572 Status = SampGetObjectAttributeString(UserObject,
6573 L"ScriptPath",
6574 &InfoBuffer->All.ScriptPath);
6575 if (!NT_SUCCESS(Status))
6576 {
6577 TRACE("Status 0x%08lx\n", Status);
6578 goto done;
6579 }
6580 }
6581
6582 /* Get the ProfilePath attribute */
6583 if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
6584 {
6585 Status = SampGetObjectAttributeString(UserObject,
6586 L"ProfilePath",
6587 &InfoBuffer->All.ProfilePath);
6588 if (!NT_SUCCESS(Status))
6589 {
6590 TRACE("Status 0x%08lx\n", Status);
6591 goto done;
6592 }
6593 }
6594
6595 /* Get the WorkStations attribute */
6596 if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
6597 {
6598 Status = SampGetObjectAttributeString(UserObject,
6599 L"WorkStations",
6600 &InfoBuffer->All.WorkStations);
6601 if (!NT_SUCCESS(Status))
6602 {
6603 TRACE("Status 0x%08lx\n", Status);
6604 goto done;
6605 }
6606 }
6607
6608 /* Get the LastLogon attribute */
6609 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
6610 {
6611 InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6612 InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6613 }
6614
6615 /* Get the LastLogoff attribute */
6616 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
6617 {
6618 InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6619 InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6620 }
6621
6622 /* Get the LogonHours attribute */
6623 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
6624 {
6625 Status = SampGetLogonHoursAttrbute(UserObject,
6626 &InfoBuffer->All.LogonHours);
6627 if (!NT_SUCCESS(Status))
6628 {
6629 TRACE("Status 0x%08lx\n", Status);
6630 goto done;
6631 }
6632 }
6633
6634 /* Get the BadPasswordCount attribute */
6635 if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
6636 {
6637 InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
6638 }
6639
6640 /* Get the LogonCount attribute */
6641 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
6642 {
6643 InfoBuffer->All.LogonCount = FixedData.LogonCount;
6644 }
6645
6646 /* Get the PasswordCanChange attribute */
6647 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
6648 {
6649 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
6650 DomainFixedData.MinPasswordAge);
6651 InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
6652 InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
6653 }
6654
6655 /* Get the PasswordMustChange attribute */
6656 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
6657 {
6658 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
6659 DomainFixedData.MaxPasswordAge);
6660 InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
6661 InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
6662 }
6663
6664 /* Get the PasswordLastSet attribute */
6665 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
6666 {
6667 InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
6668 InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
6669 }
6670
6671 /* Get the AccountExpires attribute */
6672 if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
6673 {
6674 InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6675 InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6676 }
6677
6678 /* Get the UserAccountControl attribute */
6679 if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
6680 {
6681 InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
6682 }
6683
6684 /* Get the Parameters attribute */
6685 if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
6686 {
6687 Status = SampGetObjectAttributeString(UserObject,
6688 L"Parameters",
6689 &InfoBuffer->All.Parameters);
6690 if (!NT_SUCCESS(Status))
6691 {
6692 TRACE("Status 0x%08lx\n", Status);
6693 goto done;
6694 }
6695 }
6696
6697 /* Get the CountryCode attribute */
6698 if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
6699 {
6700 InfoBuffer->All.CountryCode = FixedData.CountryCode;
6701 }
6702
6703 /* Get the CodePage attribute */
6704 if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
6705 {
6706 InfoBuffer->All.CodePage = FixedData.CodePage;
6707 }
6708
6709 if (InfoBuffer->All.WhichFields & USER_ALL_NTPASSWORDPRESENT)
6710 {
6711 /* FIXME */
6712 }
6713
6714 if (InfoBuffer->All.WhichFields & USER_ALL_LMPASSWORDPRESENT)
6715 {
6716 /* FIXME */
6717 }
6718
6719 if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
6720 {
6721 /* FIXME */
6722 }
6723
6724 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
6725 {
6726 /* FIXME */
6727 }
6728
6729 if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
6730 {
6731 /* FIXME */
6732 }
6733
6734 *Buffer = InfoBuffer;
6735
6736 done:
6737 if (!NT_SUCCESS(Status))
6738 {
6739 if (InfoBuffer != NULL)
6740 {
6741 if (InfoBuffer->All.UserName.Buffer != NULL)
6742 midl_user_free(InfoBuffer->All.UserName.Buffer);
6743
6744 if (InfoBuffer->All.FullName.Buffer != NULL)
6745 midl_user_free(InfoBuffer->All.FullName.Buffer);
6746
6747 if (InfoBuffer->All.AdminComment.Buffer != NULL)
6748 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
6749
6750 if (InfoBuffer->All.UserComment.Buffer != NULL)
6751 midl_user_free(InfoBuffer->All.UserComment.Buffer);
6752
6753 if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
6754 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
6755
6756 if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
6757 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
6758
6759 if (InfoBuffer->All.ScriptPath.Buffer != NULL)
6760 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
6761
6762 if (InfoBuffer->All.ProfilePath.Buffer != NULL)
6763 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
6764
6765 if (InfoBuffer->All.WorkStations.Buffer != NULL)
6766 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
6767
6768 if (InfoBuffer->All.LogonHours.LogonHours != NULL)
6769 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
6770
6771 if (InfoBuffer->All.Parameters.Buffer != NULL)
6772 midl_user_free(InfoBuffer->All.Parameters.Buffer);
6773
6774 midl_user_free(InfoBuffer);
6775 }
6776 }
6777
6778 return Status;
6779 }
6780
6781
6782 /* Function 36 */
6783 NTSTATUS
6784 NTAPI
6785 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
6786 IN USER_INFORMATION_CLASS UserInformationClass,
6787 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
6788 {
6789 PSAM_DB_OBJECT UserObject;
6790 ACCESS_MASK DesiredAccess;
6791 NTSTATUS Status;
6792
6793 TRACE("SamrQueryInformationUser(%p %lu %p)\n",
6794 UserHandle, UserInformationClass, Buffer);
6795
6796 switch (UserInformationClass)
6797 {
6798 case UserGeneralInformation:
6799 case UserNameInformation:
6800 case UserAccountNameInformation:
6801 case UserFullNameInformation:
6802 case UserPrimaryGroupInformation:
6803 case UserAdminCommentInformation:
6804 DesiredAccess = USER_READ_GENERAL;
6805 break;
6806
6807 case UserLogonHoursInformation:
6808 case UserHomeInformation:
6809 case UserScriptInformation:
6810 case UserProfileInformation:
6811 case UserWorkStationsInformation:
6812 DesiredAccess = USER_READ_LOGON;
6813 break;
6814
6815 case UserControlInformation:
6816 case UserExpiresInformation:
6817 case UserParametersInformation:
6818 DesiredAccess = USER_READ_ACCOUNT;
6819 break;
6820
6821 case UserPreferencesInformation:
6822 DesiredAccess = USER_READ_GENERAL |
6823 USER_READ_PREFERENCES;
6824 break;
6825
6826 case UserLogonInformation:
6827 case UserAccountInformation:
6828 DesiredAccess = USER_READ_GENERAL |
6829 USER_READ_PREFERENCES |
6830 USER_READ_LOGON |
6831 USER_READ_ACCOUNT;
6832 break;
6833
6834 case UserInternal1Information:
6835 case UserAllInformation:
6836 DesiredAccess = 0;
6837 break;
6838
6839 default:
6840 return STATUS_INVALID_INFO_CLASS;
6841 }
6842
6843 RtlAcquireResourceShared(&SampResource,
6844 TRUE);
6845
6846 /* Validate the domain handle */
6847 Status = SampValidateDbObject(UserHandle,
6848 SamDbUserObject,
6849 DesiredAccess,
6850 &UserObject);
6851 if (!NT_SUCCESS(Status))
6852 {
6853 TRACE("failed with status 0x%08lx\n", Status);
6854 goto done;
6855 }
6856
6857 switch (UserInformationClass)
6858 {
6859 case UserGeneralInformation:
6860 Status = SampQueryUserGeneral(UserObject,
6861 Buffer);
6862 break;
6863
6864 case UserPreferencesInformation:
6865 Status = SampQueryUserPreferences(UserObject,
6866 Buffer);
6867 break;
6868
6869 case UserLogonInformation:
6870 Status = SampQueryUserLogon(UserObject,
6871 Buffer);
6872 break;
6873
6874 case UserLogonHoursInformation:
6875 Status = SampQueryUserLogonHours(UserObject,
6876 Buffer);
6877 break;
6878
6879 case UserAccountInformation:
6880 Status = SampQueryUserAccount(UserObject,
6881 Buffer);
6882 break;
6883
6884 case UserNameInformation:
6885 Status = SampQueryUserName(UserObject,
6886 Buffer);
6887 break;
6888
6889 case UserAccountNameInformation:
6890 Status = SampQueryUserAccountName(UserObject,
6891 Buffer);
6892 break;
6893
6894 case UserFullNameInformation:
6895 Status = SampQueryUserFullName(UserObject,
6896 Buffer);
6897 break;
6898
6899 case UserPrimaryGroupInformation:
6900 Status = SampQueryUserPrimaryGroup(UserObject,
6901 Buffer);
6902 break;
6903
6904 case UserHomeInformation:
6905 Status = SampQueryUserHome(UserObject,
6906 Buffer);
6907
6908 case UserScriptInformation:
6909 Status = SampQueryUserScript(UserObject,
6910 Buffer);
6911 break;
6912
6913 case UserProfileInformation:
6914 Status = SampQueryUserProfile(UserObject,
6915 Buffer);
6916 break;
6917
6918 case UserAdminCommentInformation:
6919 Status = SampQueryUserAdminComment(UserObject,
6920 Buffer);
6921 break;
6922
6923 case UserWorkStationsInformation:
6924 Status = SampQueryUserWorkStations(UserObject,
6925 Buffer);
6926 break;
6927
6928 case UserControlInformation:
6929 Status = SampQueryUserControl(UserObject,
6930 Buffer);
6931 break;
6932
6933 case UserExpiresInformation:
6934 Status = SampQueryUserExpires(UserObject,
6935 Buffer);
6936 break;
6937
6938 case UserInternal1Information:
6939 Status = SampQueryUserInternal1(UserObject,
6940 Buffer);
6941 break;
6942
6943 case UserParametersInformation:
6944 Status = SampQueryUserParameters(UserObject,
6945 Buffer);
6946 break;
6947
6948 case UserAllInformation:
6949 Status = SampQueryUserAll(UserObject,
6950 Buffer);
6951 break;
6952
6953 // case UserInternal4Information:
6954 // case UserInternal5Information:
6955 // case UserInternal4InformationNew:
6956 // case UserInternal5InformationNew:
6957
6958 default:
6959 Status = STATUS_INVALID_INFO_CLASS;
6960 }
6961
6962 done:
6963 RtlReleaseResource(&SampResource);
6964
6965 return Status;
6966 }
6967
6968
6969 static NTSTATUS
6970 SampSetUserName(PSAM_DB_OBJECT UserObject,
6971 PRPC_UNICODE_STRING NewUserName)
6972 {
6973 UNICODE_STRING OldUserName = {0, 0, NULL};
6974 NTSTATUS Status;
6975
6976 /* Check the account name */
6977 Status = SampCheckAccountName(NewUserName, 20);
6978 if (!NT_SUCCESS(Status))
6979 {
6980 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
6981 return Status;
6982 }
6983
6984 Status = SampGetObjectAttributeString(UserObject,
6985 L"Name",
6986 (PRPC_UNICODE_STRING)&OldUserName);
6987 if (!NT_SUCCESS(Status))
6988 {
6989 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
6990 goto done;
6991 }
6992
6993 if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
6994 {
6995 Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
6996 NewUserName->Buffer);
6997 if (!NT_SUCCESS(Status))
6998 {
6999 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7000 NewUserName->Buffer, Status);
7001 goto done;
7002 }
7003 }
7004
7005 Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7006 L"Users",
7007 NewUserName->Buffer,
7008 UserObject->RelativeId);
7009 if (!NT_SUCCESS(Status))
7010 {
7011 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7012 goto done;
7013 }
7014
7015 Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7016 L"Users",
7017 OldUserName.Buffer);
7018 if (!NT_SUCCESS(Status))
7019 {
7020 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7021 goto done;
7022 }
7023
7024 Status = SampSetObjectAttributeString(UserObject,
7025 L"Name",
7026 NewUserName);
7027 if (!NT_SUCCESS(Status))
7028 {
7029 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7030 }
7031
7032 done:
7033 if (OldUserName.Buffer != NULL)
7034 midl_user_free(OldUserName.Buffer);
7035
7036 return Status;
7037 }
7038
7039
7040 static NTSTATUS
7041 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7042 PSAMPR_USER_INFO_BUFFER Buffer)
7043 {
7044 SAM_USER_FIXED_DATA FixedData;
7045 ULONG Length = 0;
7046 NTSTATUS Status;
7047
7048 Length = sizeof(SAM_USER_FIXED_DATA);
7049 Status = SampGetObjectAttribute(UserObject,
7050 L"F",
7051 NULL,
7052 (PVOID)&FixedData,
7053 &Length);
7054 if (!NT_SUCCESS(Status))
7055 goto done;
7056
7057 FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7058
7059 Status = SampSetObjectAttribute(UserObject,
7060 L"F",
7061 REG_BINARY,
7062 &FixedData,
7063 Length);
7064 if (!NT_SUCCESS(Status))
7065 goto done;
7066
7067 Status = SampSetUserName(UserObject,
7068 &Buffer->General.UserName);
7069 if (!NT_SUCCESS(Status))
7070 goto done;
7071
7072 Status = SampSetObjectAttributeString(UserObject,
7073 L"FullName",
7074 &Buffer->General.FullName);
7075 if (!NT_SUCCESS(Status))
7076 goto done;
7077
7078 Status = SampSetObjectAttributeString(UserObject,
7079 L"AdminComment",
7080 &Buffer->General.AdminComment);
7081 if (!NT_SUCCESS(Status))
7082 goto done;
7083
7084 Status = SampSetObjectAttributeString(UserObject,
7085 L"UserComment",
7086 &Buffer->General.UserComment);
7087
7088 done:
7089 return Status;
7090 }
7091
7092
7093 static NTSTATUS
7094 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7095 PSAMPR_USER_INFO_BUFFER Buffer)
7096 {
7097 SAM_USER_FIXED_DATA FixedData;
7098 ULONG Length = 0;
7099 NTSTATUS Status;
7100
7101 Length = sizeof(SAM_USER_FIXED_DATA);
7102 Status = SampGetObjectAttribute(UserObject,
7103 L"F",
7104 NULL,
7105 (PVOID)&FixedData,
7106 &Length);
7107 if (!NT_SUCCESS(Status))
7108 goto done;
7109
7110 FixedData.CountryCode = Buffer->Preferences.CountryCode;
7111 FixedData.CodePage = Buffer->Preferences.CodePage;
7112
7113 Status = SampSetObjectAttribute(UserObject,
7114 L"F",
7115 REG_BINARY,
7116 &FixedData,
7117 Length);
7118 if (!NT_SUCCESS(Status))
7119 goto done;
7120
7121 Status = SampSetObjectAttributeString(UserObject,
7122 L"UserComment",
7123 &Buffer->Preferences.UserComment);
7124
7125 done:
7126 return Status;
7127 }
7128
7129
7130 static NTSTATUS
7131 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7132 PSAMPR_USER_INFO_BUFFER Buffer)
7133 {
7134 SAM_USER_FIXED_DATA FixedData;
7135 ULONG Length = 0;
7136 NTSTATUS Status;
7137
7138 Length = sizeof(SAM_USER_FIXED_DATA);
7139 Status = SampGetObjectAttribute(UserObject,
7140 L"F",
7141 NULL,
7142 (PVOID)&FixedData,
7143 &Length);
7144 if (!NT_SUCCESS(Status))
7145 goto done;
7146
7147 FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7148
7149 Status = SampSetObjectAttribute(UserObject,
7150 L"F",
7151 REG_BINARY,
7152 &FixedData,
7153 Length);
7154
7155 done:
7156 return Status;
7157 }
7158
7159
7160 static NTSTATUS
7161 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7162 PSAMPR_USER_INFO_BUFFER Buffer)
7163 {
7164 SAM_USER_FIXED_DATA FixedData;
7165 ULONG Length = 0;
7166 NTSTATUS Status;
7167
7168 Length = sizeof(SAM_USER_FIXED_DATA);
7169 Status = SampGetObjectAttribute(UserObject,
7170 L"F",
7171 NULL,
7172 (PVOID)&FixedData,
7173 &Length);
7174 if (!NT_SUCCESS(Status))
7175 goto done;
7176
7177 FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7178
7179 Status = SampSetObjectAttribute(UserObject,
7180 L"F",
7181 REG_BINARY,
7182 &FixedData,
7183 Length);
7184
7185 done:
7186 return Status;
7187 }
7188
7189
7190 static NTSTATUS
7191 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7192 PSAMPR_USER_INFO_BUFFER Buffer)
7193 {
7194 SAM_USER_FIXED_DATA FixedData;
7195 ULONG Length = 0;
7196 NTSTATUS Status;
7197
7198 Length = sizeof(SAM_USER_FIXED_DATA);
7199 Status = SampGetObjectAttribute(UserObject,
7200 L"F",
7201 NULL,
7202 (PVOID)&FixedData,
7203 &Length);
7204 if (!NT_SUCCESS(Status))
7205 goto done;
7206
7207 FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7208 FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7209
7210 Status = SampSetObjectAttribute(UserObject,
7211 L"F",
7212 REG_BINARY,
7213 &FixedData,
7214 Length);
7215
7216 done:
7217 return Status;
7218 }
7219
7220
7221 static NTSTATUS
7222 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7223 PSAMPR_USER_INFO_BUFFER Buffer)
7224 {
7225 SAM_USER_FIXED_DATA FixedData;
7226 ULONG Length = 0;
7227 NTSTATUS Status = STATUS_SUCCESS;
7228
7229 /* FIXME: Decrypt NT password */
7230 /* FIXME: Decrypt LM password */
7231
7232 Status = SampSetUserPassword(UserObject,
7233 &Buffer->Internal1.EncryptedNtOwfPassword,
7234 Buffer->Internal1.NtPasswordPresent,
7235 &Buffer->Internal1.EncryptedLmOwfPassword,
7236 Buffer->Internal1.LmPasswordPresent);
7237 if (!NT_SUCCESS(Status))
7238 goto done;
7239
7240 /* Get the fixed user attributes */
7241 Length = sizeof(SAM_USER_FIXED_DATA);
7242 Status = SampGetObjectAttribute(UserObject,
7243 L"F",
7244 NULL,
7245 (PVOID)&FixedData,
7246 &Length);
7247 if (!NT_SUCCESS(Status))
7248 goto done;
7249
7250 if (Buffer->Internal1.PasswordExpired)
7251 {
7252 /* The pasword was last set ages ago */
7253 FixedData.PasswordLastSet.LowPart = 0;
7254 FixedData.PasswordLastSet.HighPart = 0;
7255 }
7256 else
7257 {
7258 /* The pasword was last set right now */
7259 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7260 if (!NT_SUCCESS(Status))
7261 goto done;
7262 }
7263
7264 /* Set the fixed user attributes */
7265 Status = SampSetObjectAttribute(UserObject,
7266 L"F",
7267 REG_BINARY,
7268 &FixedData,
7269 Length);
7270
7271 done:
7272 return Status;
7273 }
7274
7275
7276 static NTSTATUS
7277 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7278 PSAMPR_USER_INFO_BUFFER Buffer)
7279 {
7280 SAM_USER_FIXED_DATA FixedData;
7281 ULONG Length = 0;
7282 ULONG WhichFields;
7283 PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7284 PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7285 BOOLEAN NtPasswordPresent = FALSE;
7286 BOOLEAN LmPasswordPresent = FALSE;
7287 BOOLEAN WriteFixedData = FALSE;
7288 NTSTATUS Status = STATUS_SUCCESS;
7289
7290 WhichFields = Buffer->All.WhichFields;
7291
7292 /* Get the fixed size attributes */
7293 Length = sizeof(SAM_USER_FIXED_DATA);
7294 Status = SampGetObjectAttribute(UserObject,
7295 L"F",
7296 NULL,
7297 (PVOID)&FixedData,
7298 &Length);
7299 if (!NT_SUCCESS(Status))
7300 goto done;
7301
7302 if (WhichFields & USER_ALL_USERNAME)
7303 {
7304 Status = SampSetUserName(UserObject,
7305 &Buffer->All.UserName);
7306 if (!NT_SUCCESS(Status))
7307 goto done;
7308 }
7309
7310 if (WhichFields & USER_ALL_FULLNAME)
7311 {
7312 Status = SampSetObjectAttributeString(UserObject,
7313 L"FullName",
7314 &Buffer->All.FullName);
7315 if (!NT_SUCCESS(Status))
7316 goto done;
7317 }
7318
7319 if (WhichFields & USER_ALL_ADMINCOMMENT)
7320 {
7321 Status = SampSetObjectAttributeString(UserObject,
7322 L"AdminComment",
7323 &Buffer->All.AdminComment);
7324 if (!NT_SUCCESS(Status))
7325 goto done;
7326 }
7327
7328 if (WhichFields & USER_ALL_USERCOMMENT)
7329 {
7330 Status = SampSetObjectAttributeString(UserObject,
7331 L"UserComment",
7332 &Buffer->All.UserComment);
7333 if (!NT_SUCCESS(Status))
7334 goto done;
7335 }
7336
7337 if (WhichFields & USER_ALL_HOMEDIRECTORY)
7338 {
7339 Status = SampSetObjectAttributeString(UserObject,
7340 L"HomeDirectory",
7341 &Buffer->All.HomeDirectory);
7342 if (!NT_SUCCESS(Status))
7343 goto done;
7344 }
7345
7346 if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7347 {
7348 Status = SampSetObjectAttributeString(UserObject,
7349 L"HomeDirectoryDrive",
7350 &Buffer->All.HomeDirectoryDrive);
7351 if (!NT_SUCCESS(Status))
7352 goto done;
7353 }
7354
7355 if (WhichFields & USER_ALL_SCRIPTPATH)
7356 {
7357 Status = SampSetObjectAttributeString(UserObject,
7358 L"ScriptPath",
7359 &Buffer->All.ScriptPath);
7360 if (!NT_SUCCESS(Status))
7361 goto done;
7362 }
7363
7364 if (WhichFields & USER_ALL_PROFILEPATH)
7365 {
7366 Status = SampSetObjectAttributeString(UserObject,
7367 L"ProfilePath",
7368 &Buffer->All.ProfilePath);
7369 if (!NT_SUCCESS(Status))
7370 goto done;
7371 }
7372
7373 if (WhichFields & USER_ALL_WORKSTATIONS)
7374 {
7375 Status = SampSetObjectAttributeString(UserObject,
7376 L"WorkStations",
7377 &Buffer->All.WorkStations);
7378 if (!NT_SUCCESS(Status))
7379 goto done;
7380 }
7381
7382 if (WhichFields & USER_ALL_PARAMETERS)
7383 {
7384 Status = SampSetObjectAttributeString(UserObject,
7385 L"Parameters",
7386 &Buffer->All.Parameters);
7387 if (!NT_SUCCESS(Status))
7388 goto done;
7389 }
7390
7391 if (WhichFields & USER_ALL_LOGONHOURS)
7392 {
7393 Status = SampSetLogonHoursAttrbute(UserObject,
7394 &Buffer->All.LogonHours);
7395 if (!NT_SUCCESS(Status))
7396 goto done;
7397 }
7398
7399 if (WhichFields & USER_ALL_PRIMARYGROUPID)
7400 {
7401 FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
7402 WriteFixedData = TRUE;
7403 }
7404
7405 if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
7406 {
7407 FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
7408 FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
7409 WriteFixedData = TRUE;
7410 }
7411
7412 if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
7413 {
7414 FixedData.UserAccountControl = Buffer->All.UserAccountControl;
7415 WriteFixedData = TRUE;
7416 }
7417
7418 if (WhichFields & USER_ALL_COUNTRYCODE)
7419 {
7420 FixedData.CountryCode = Buffer->All.CountryCode;
7421 WriteFixedData = TRUE;
7422 }
7423
7424 if (WhichFields & USER_ALL_CODEPAGE)
7425 {
7426 FixedData.CodePage = Buffer->All.CodePage;
7427 WriteFixedData = TRUE;
7428 }
7429
7430 if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
7431 USER_ALL_LMPASSWORDPRESENT))
7432 {
7433 if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
7434 {
7435 NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
7436 NtPasswordPresent = Buffer->All.NtPasswordPresent;
7437 }
7438
7439 if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
7440 {
7441 LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
7442 LmPasswordPresent = Buffer->All.LmPasswordPresent;
7443 }
7444
7445 Status = SampSetUserPassword(UserObject,
7446 NtPassword,
7447 NtPasswordPresent,
7448 LmPassword,
7449 LmPasswordPresent);
7450 if (!NT_SUCCESS(Status))
7451 goto done;
7452
7453 /* The password has just been set */
7454 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7455 if (!NT_SUCCESS(Status))
7456 goto done;
7457
7458 WriteFixedData = TRUE;
7459 }
7460
7461 if (WhichFields & USER_ALL_PASSWORDEXPIRED)
7462 {
7463 if (Buffer->All.PasswordExpired)
7464 {
7465 /* The pasword was last set ages ago */
7466 FixedData.PasswordLastSet.LowPart = 0;
7467 FixedData.PasswordLastSet.HighPart = 0;
7468 }
7469 else
7470 {
7471 /* The pasword was last set right now */
7472 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7473 if (!NT_SUCCESS(Status))
7474 goto done;
7475 }
7476
7477 WriteFixedData = TRUE;
7478 }
7479
7480 if (WriteFixedData == TRUE)
7481 {
7482 Status = SampSetObjectAttribute(UserObject,
7483 L"F",
7484 REG_BINARY,
7485 &FixedData,
7486 Length);
7487 if (!NT_SUCCESS(Status))
7488 goto done;
7489 }
7490
7491 done:
7492 return Status;
7493 }
7494
7495
7496 /* Function 37 */
7497 NTSTATUS
7498 NTAPI
7499 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
7500 IN USER_INFORMATION_CLASS UserInformationClass,
7501 IN PSAMPR_USER_INFO_BUFFER Buffer)
7502 {
7503 PSAM_DB_OBJECT UserObject;
7504 ACCESS_MASK DesiredAccess;
7505 NTSTATUS Status;
7506
7507 TRACE("SamrSetInformationUser(%p %lu %p)\n",
7508 UserHandle, UserInformationClass, Buffer);
7509
7510 switch (UserInformationClass)
7511 {
7512 case UserLogonHoursInformation:
7513 case UserNameInformation:
7514 case UserAccountNameInformation:
7515 case UserFullNameInformation:
7516 case UserPrimaryGroupInformation:
7517 case UserHomeInformation:
7518 case UserScriptInformation:
7519 case UserProfileInformation:
7520 case UserAdminCommentInformation:
7521 case UserWorkStationsInformation:
7522 case UserControlInformation:
7523 case UserExpiresInformation:
7524 case UserParametersInformation:
7525 DesiredAccess = USER_WRITE_ACCOUNT;
7526 break;
7527
7528 case UserGeneralInformation:
7529 DesiredAccess = USER_WRITE_ACCOUNT |
7530 USER_WRITE_PREFERENCES;
7531 break;
7532
7533 case UserPreferencesInformation:
7534 DesiredAccess = USER_WRITE_PREFERENCES;
7535 break;
7536
7537 case UserSetPasswordInformation:
7538 case UserInternal1Information:
7539 DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
7540 break;
7541
7542 case UserAllInformation:
7543 DesiredAccess = 0; /* FIXME */
7544 break;
7545
7546 default:
7547 return STATUS_INVALID_INFO_CLASS;
7548 }
7549
7550 RtlAcquireResourceExclusive(&SampResource,
7551 TRUE);
7552
7553 /* Validate the domain handle */
7554 Status = SampValidateDbObject(UserHandle,
7555 SamDbUserObject,
7556 DesiredAccess,
7557 &UserObject);
7558 if (!NT_SUCCESS(Status))
7559 {
7560 TRACE("failed with status 0x%08lx\n", Status);
7561 goto done;
7562 }
7563
7564 switch (UserInformationClass)
7565 {
7566 case UserGeneralInformation:
7567 Status = SampSetUserGeneral(UserObject,
7568 Buffer);
7569 break;
7570
7571 case UserPreferencesInformation:
7572 Status = SampSetUserPreferences(UserObject,
7573 Buffer);
7574 break;
7575
7576 case UserLogonHoursInformation:
7577 Status = SampSetLogonHoursAttrbute(UserObject,
7578 &Buffer->LogonHours.LogonHours);
7579 break;
7580
7581 case UserNameInformation:
7582 Status = SampSetUserName(UserObject,
7583 &Buffer->Name.UserName);
7584 if (!NT_SUCCESS(Status))
7585 break;
7586
7587 Status = SampSetObjectAttributeString(UserObject,
7588 L"FullName",
7589 &Buffer->Name.FullName);
7590 break;
7591
7592 case UserAccountNameInformation:
7593 Status = SampSetUserName(UserObject,
7594 &Buffer->AccountName.UserName);
7595 break;
7596
7597 case UserFullNameInformation:
7598 Status = SampSetObjectAttributeString(UserObject,
7599 L"FullName",
7600 &Buffer->FullName.FullName);
7601 break;
7602
7603 case UserPrimaryGroupInformation:
7604 Status = SampSetUserPrimaryGroup(UserObject,
7605 Buffer);
7606 break;
7607
7608 case UserHomeInformation:
7609 Status = SampSetObjectAttributeString(UserObject,
7610 L"HomeDirectory",
7611 &Buffer->Home.HomeDirectory);
7612 if (!NT_SUCCESS(Status))
7613 break;
7614
7615 Status = SampSetObjectAttributeString(UserObject,
7616 L"HomeDirectoryDrive",
7617 &Buffer->Home.HomeDirectoryDrive);
7618 break;
7619
7620 case UserScriptInformation:
7621 Status = SampSetObjectAttributeString(UserObject,
7622 L"ScriptPath",
7623 &Buffer->Script.ScriptPath);
7624 break;
7625
7626 case UserProfileInformation:
7627 Status = SampSetObjectAttributeString(UserObject,
7628 L"ProfilePath",
7629 &Buffer->Profile.ProfilePath);
7630 break;
7631
7632 case UserAdminCommentInformation:
7633 Status = SampSetObjectAttributeString(UserObject,
7634 L"AdminComment",
7635 &Buffer->AdminComment.AdminComment);
7636 break;
7637
7638 case UserWorkStationsInformation:
7639 Status = SampSetObjectAttributeString(UserObject,
7640 L"WorkStations",
7641 &Buffer->WorkStations.WorkStations);
7642 break;
7643
7644 case UserSetPasswordInformation:
7645 TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
7646 TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
7647
7648 Status = SampSetObjectAttributeString(UserObject,
7649 L"Password",
7650 &Buffer->SetPassword.Password);
7651 break;
7652
7653 case UserControlInformation:
7654 Status = SampSetUserControl(UserObject,
7655 Buffer);
7656 break;
7657
7658 case UserExpiresInformation:
7659 Status = SampSetUserExpires(UserObject,
7660 Buffer);
7661 break;
7662
7663 case UserInternal1Information:
7664 Status = SampSetUserInternal1(UserObject,
7665 Buffer);
7666 break;
7667
7668 case UserParametersInformation:
7669 Status = SampSetObjectAttributeString(UserObject,
7670 L"Parameters",
7671 &Buffer->Parameters.Parameters);
7672 break;
7673
7674 case UserAllInformation:
7675 Status = SampSetUserAll(UserObject,
7676 Buffer);
7677 break;
7678
7679 // case UserInternal4Information:
7680 // case UserInternal5Information:
7681 // case UserInternal4InformationNew:
7682 // case UserInternal5InformationNew:
7683
7684 default:
7685 Status = STATUS_INVALID_INFO_CLASS;
7686 }
7687
7688 done:
7689 RtlReleaseResource(&SampResource);
7690
7691 return Status;
7692 }
7693
7694
7695 /* Function 38 */
7696 NTSTATUS
7697 NTAPI
7698 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
7699 IN unsigned char LmPresent,
7700 IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
7701 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
7702 IN unsigned char NtPresent,
7703 IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
7704 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
7705 IN unsigned char NtCrossEncryptionPresent,
7706 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
7707 IN unsigned char LmCrossEncryptionPresent,
7708 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
7709 {
7710 ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
7711 ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
7712 PENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
7713 PENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
7714 PENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
7715 PENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
7716 BOOLEAN StoredLmPresent = FALSE;
7717 BOOLEAN StoredNtPresent = FALSE;
7718 BOOLEAN StoredLmEmpty = TRUE;
7719 BOOLEAN StoredNtEmpty = TRUE;
7720 PSAM_DB_OBJECT UserObject;
7721 ULONG Length;
7722 SAM_USER_FIXED_DATA UserFixedData;
7723 SAM_DOMAIN_FIXED_DATA DomainFixedData;
7724 LARGE_INTEGER SystemTime;
7725 NTSTATUS Status;
7726
7727 TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
7728 UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
7729 NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
7730 NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
7731
7732 RtlAcquireResourceExclusive(&SampResource,
7733 TRUE);
7734
7735 /* Validate the user handle */
7736 Status = SampValidateDbObject(UserHandle,
7737 SamDbUserObject,
7738 USER_CHANGE_PASSWORD,
7739 &UserObject);
7740 if (!NT_SUCCESS(Status))
7741 {
7742 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7743 goto done;
7744 }
7745
7746 /* Get the current time */
7747 Status = NtQuerySystemTime(&SystemTime);
7748 if (!NT_SUCCESS(Status))
7749 {
7750 TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
7751 goto done;
7752 }
7753
7754 /* Retrieve the LM password */
7755 Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7756 Status = SampGetObjectAttribute(UserObject,
7757 L"LMPwd",
7758 NULL,
7759 &StoredLmPassword,
7760 &Length);
7761 if (NT_SUCCESS(Status))
7762 {
7763 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
7764 {
7765 StoredLmPresent = TRUE;
7766 if (!RtlEqualMemory(&StoredLmPassword,
7767 &EmptyLmHash,
7768 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7769 StoredLmEmpty = FALSE;
7770 }
7771 }
7772
7773 /* Retrieve the NT password */
7774 Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7775 Status = SampGetObjectAttribute(UserObject,
7776 L"NTPwd",
7777 NULL,
7778 &StoredNtPassword,
7779 &Length);
7780 if (NT_SUCCESS(Status))
7781 {
7782 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
7783 {
7784 StoredNtPresent = TRUE;
7785 if (!RtlEqualMemory(&StoredNtPassword,
7786 &EmptyNtHash,
7787 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
7788 StoredNtEmpty = FALSE;
7789 }
7790 }
7791
7792 /* Retrieve the fixed size user data */
7793 Length = sizeof(SAM_USER_FIXED_DATA);
7794 Status = SampGetObjectAttribute(UserObject,
7795 L"F",
7796 NULL,
7797 &UserFixedData,
7798 &Length);
7799 if (!NT_SUCCESS(Status))
7800 {
7801 TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
7802 goto done;
7803 }
7804
7805 /* Check if we can change the password at this time */
7806 if ((StoredNtEmpty == FALSE) || (StoredNtEmpty == FALSE))
7807 {
7808 /* Get fixed domain data */
7809 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
7810 Status = SampGetObjectAttribute(UserObject->ParentObject,
7811 L"F",
7812 NULL,
7813 &DomainFixedData,
7814 &Length);
7815 if (!NT_SUCCESS(Status))
7816 {
7817 TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
7818 return Status;
7819 }
7820
7821 if (DomainFixedData.MinPasswordAge.QuadPart > 0)
7822 {
7823 if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
7824 return STATUS_ACCOUNT_RESTRICTION;
7825 }
7826 }
7827
7828 /* FIXME: Decrypt passwords */
7829 OldLmPassword = OldLmEncryptedWithNewLm;
7830 NewLmPassword = NewLmEncryptedWithOldLm;
7831 OldNtPassword = OldNtEncryptedWithNewNt;
7832 NewNtPassword = NewNtEncryptedWithOldNt;
7833
7834 /* Check if the old passwords match the stored ones */
7835 if (NtPresent)
7836 {
7837 if (LmPresent)
7838 {
7839 if (!RtlEqualMemory(&StoredLmPassword,
7840 OldLmPassword,
7841 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7842 {
7843 TRACE("Old LM Password does not match!\n");
7844 Status = STATUS_WRONG_PASSWORD;
7845 }
7846 else
7847 {
7848 if (!RtlEqualMemory(&StoredNtPassword,
7849 OldNtPassword,
7850 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7851 {
7852 TRACE("Old NT Password does not match!\n");
7853 Status = STATUS_WRONG_PASSWORD;
7854 }
7855 }
7856 }
7857 else
7858 {
7859 if (!RtlEqualMemory(&StoredNtPassword,
7860 OldNtPassword,
7861 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7862 {
7863 TRACE("Old NT Password does not match!\n");
7864 Status = STATUS_WRONG_PASSWORD;
7865 }
7866 }
7867 }
7868 else
7869 {
7870 if (LmPresent)
7871 {
7872 if (!RtlEqualMemory(&StoredLmPassword,
7873 OldLmPassword,
7874 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7875 {
7876 TRACE("Old LM Password does not match!\n");
7877 Status = STATUS_WRONG_PASSWORD;
7878 }
7879 }
7880 else
7881 {
7882 Status = STATUS_INVALID_PARAMETER;
7883 }
7884 }
7885
7886 /* Store the new password hashes */
7887 if (NT_SUCCESS(Status))
7888 {
7889 Status = SampSetUserPassword(UserObject,
7890 NewNtPassword,
7891 NtPresent,
7892 NewLmPassword,
7893 LmPresent);
7894 if (NT_SUCCESS(Status))
7895 {
7896 /* Update PasswordLastSet */
7897 UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
7898
7899 /* Set the fixed size user data */
7900 Length = sizeof(SAM_USER_FIXED_DATA);
7901 Status = SampSetObjectAttribute(UserObject,
7902 L"F",
7903 REG_BINARY,
7904 &UserFixedData,
7905 Length);
7906 }
7907 }
7908
7909 if (Status == STATUS_WRONG_PASSWORD)
7910 {
7911 /* Update BadPasswordCount and LastBadPasswordTime */
7912 UserFixedData.BadPasswordCount++;
7913 UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
7914
7915 /* Set the fixed size user data */
7916 Length = sizeof(SAM_USER_FIXED_DATA);
7917 Status = SampSetObjectAttribute(UserObject,
7918 L"F",
7919 REG_BINARY,
7920 &UserFixedData,
7921 Length);
7922 }
7923
7924 done:
7925 RtlReleaseResource(&SampResource);
7926
7927 return Status;
7928 }
7929
7930
7931 /* Function 39 */
7932 NTSTATUS
7933 NTAPI
7934 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
7935 OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
7936 {
7937 PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
7938 PSAM_DB_OBJECT UserObject;
7939 ULONG Length = 0;
7940 NTSTATUS Status;
7941
7942 TRACE("SamrGetGroupsForUser(%p %p)\n",
7943 UserHandle, Groups);
7944
7945 RtlAcquireResourceShared(&SampResource,
7946 TRUE);
7947
7948 /* Validate the user handle */
7949 Status = SampValidateDbObject(UserHandle,
7950 SamDbUserObject,
7951 USER_LIST_GROUPS,
7952 &UserObject);
7953 if (!NT_SUCCESS(Status))
7954 {
7955 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7956 goto done;
7957 }
7958
7959 /* Allocate the groups buffer */
7960 GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
7961 if (GroupsBuffer == NULL)
7962 {
7963 Status = STATUS_INSUFFICIENT_RESOURCES;
7964 goto done;
7965 }
7966
7967 /*
7968 * Get the size of the Groups attribute.
7969 * Do not check the status code because in case of an error
7970 * Length will be 0. And that is all we need.
7971 */
7972 SampGetObjectAttribute(UserObject,
7973 L"Groups",
7974 NULL,
7975 NULL,
7976 &Length);
7977
7978 /* If there is no Groups attribute, return a groups buffer without an array */
7979 if (Length == 0)
7980 {
7981 GroupsBuffer->MembershipCount = 0;
7982 GroupsBuffer->Groups = NULL;
7983
7984 *Groups = GroupsBuffer;
7985
7986 Status = STATUS_SUCCESS;
7987 goto done;
7988 }
7989
7990 /* Allocate a buffer for the Groups attribute */
7991 GroupsBuffer->Groups = midl_user_allocate(Length);
7992 if (GroupsBuffer->Groups == NULL)
7993 {
7994 Status = STATUS_INSUFFICIENT_RESOURCES;
7995 goto done;
7996 }
7997
7998 /* Retrieve the Grous attribute */
7999 Status = SampGetObjectAttribute(UserObject,
8000 L"Groups",
8001 NULL,
8002 GroupsBuffer->Groups,
8003 &Length);
8004 if (!NT_SUCCESS(Status))
8005 {
8006 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8007 goto done;
8008 }
8009
8010 /* Calculate the membership count */
8011 GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8012
8013 /* Return the groups buffer to the caller */
8014 *Groups = GroupsBuffer;
8015
8016 done:
8017 if (!NT_SUCCESS(Status))
8018 {
8019 if (GroupsBuffer != NULL)
8020 {
8021 if (GroupsBuffer->Groups != NULL)
8022 midl_user_free(GroupsBuffer->Groups);
8023
8024 midl_user_free(GroupsBuffer);
8025 }
8026 }
8027
8028 RtlReleaseResource(&SampResource);
8029
8030 return Status;
8031 }
8032
8033
8034 /* Function 40 */
8035 NTSTATUS
8036 NTAPI
8037 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8038 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8039 IN unsigned long Index,
8040 IN unsigned long EntryCount,
8041 IN unsigned long PreferredMaximumLength,
8042 OUT unsigned long *TotalAvailable,
8043 OUT unsigned long *TotalReturned,
8044 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8045 {
8046 UNIMPLEMENTED;
8047 return STATUS_NOT_IMPLEMENTED;
8048 }
8049
8050 /* Function 41 */
8051 NTSTATUS
8052 NTAPI
8053 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8054 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8055 IN PRPC_UNICODE_STRING Prefix,
8056 OUT unsigned long *Index)
8057 {
8058 UNIMPLEMENTED;
8059 return STATUS_NOT_IMPLEMENTED;
8060 }
8061
8062 /* Function 42 */
8063 NTSTATUS
8064 NTAPI
8065 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8066 {
8067 UNIMPLEMENTED;
8068 return STATUS_NOT_IMPLEMENTED;
8069 }
8070
8071 /* Function 43 */
8072 NTSTATUS
8073 NTAPI
8074 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8075 {
8076 UNIMPLEMENTED;
8077 return STATUS_NOT_IMPLEMENTED;
8078 }
8079
8080
8081 /* Function 44 */
8082 NTSTATUS
8083 NTAPI
8084 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8085 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8086 {
8087 SAM_DOMAIN_FIXED_DATA DomainFixedData;
8088 SAM_USER_FIXED_DATA UserFixedData;
8089 PSAM_DB_OBJECT DomainObject;
8090 PSAM_DB_OBJECT UserObject;
8091 ULONG Length = 0;
8092 NTSTATUS Status;
8093
8094 TRACE("(%p %p)\n",
8095 UserHandle, PasswordInformation);
8096
8097 RtlAcquireResourceShared(&SampResource,
8098 TRUE);
8099
8100 /* Validate the user handle */
8101 Status = SampValidateDbObject(UserHandle,
8102 SamDbUserObject,
8103 0,
8104 &UserObject);
8105 if (!NT_SUCCESS(Status))
8106 {
8107 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8108 goto done;
8109 }
8110
8111 /* Validate the domain object */
8112 Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8113 SamDbDomainObject,
8114 DOMAIN_READ_PASSWORD_PARAMETERS,
8115 &DomainObject);
8116 if (!NT_SUCCESS(Status))
8117 {
8118 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8119 goto done;
8120 }
8121
8122 /* Get fixed user data */
8123 Length = sizeof(SAM_USER_FIXED_DATA);
8124 Status = SampGetObjectAttribute(UserObject,
8125 L"F",
8126 NULL,
8127 (PVOID)&UserFixedData,
8128 &Length);
8129 if (!NT_SUCCESS(Status))
8130 {
8131 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8132 goto done;
8133 }
8134
8135 if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8136 (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8137 USER_WORKSTATION_TRUST_ACCOUNT |
8138 USER_SERVER_TRUST_ACCOUNT)))
8139 {
8140 PasswordInformation->MinPasswordLength = 0;
8141 PasswordInformation->PasswordProperties = 0;
8142 }
8143 else
8144 {
8145 /* Get fixed domain data */
8146 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8147 Status = SampGetObjectAttribute(DomainObject,
8148 L"F",
8149 NULL,
8150 (PVOID)&DomainFixedData,
8151 &Length);
8152 if (!NT_SUCCESS(Status))
8153 {
8154 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8155 goto done;
8156 }
8157
8158 PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8159 PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8160 }
8161
8162 done:
8163 RtlReleaseResource(&SampResource);
8164
8165 return STATUS_SUCCESS;
8166 }
8167
8168
8169 /* Function 45 */
8170 NTSTATUS
8171 NTAPI
8172 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8173 IN PRPC_SID MemberSid)
8174 {
8175 PSAM_DB_OBJECT DomainObject;
8176 ULONG Rid = 0;
8177 NTSTATUS Status;
8178
8179 TRACE("(%p %p)\n",
8180 DomainHandle, MemberSid);
8181
8182 RtlAcquireResourceExclusive(&SampResource,
8183 TRUE);
8184
8185 /* Validate the domain object */
8186 Status = SampValidateDbObject(DomainHandle,
8187 SamDbDomainObject,
8188 DOMAIN_LOOKUP,
8189 &DomainObject);
8190 if (!NT_SUCCESS(Status))
8191 {
8192 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8193 goto done;
8194 }
8195
8196 /* Retrieve the RID from the MemberSID */
8197 Status = SampGetRidFromSid((PSID)MemberSid,
8198 &Rid);
8199 if (!NT_SUCCESS(Status))
8200 {
8201 TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8202 goto done;
8203 }
8204
8205 /* Fail, if the RID represents a special account */
8206 if (Rid < 1000)
8207 {
8208 TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8209 Status = STATUS_SPECIAL_ACCOUNT;
8210 goto done;
8211 }
8212
8213 /* Remove the member from all aliases in the domain */
8214 Status = SampRemoveMemberFromAllAliases(DomainObject,
8215 MemberSid);
8216 if (!NT_SUCCESS(Status))
8217 {
8218 TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8219 }
8220
8221 done:
8222 RtlReleaseResource(&SampResource);
8223
8224 return Status;
8225 }
8226
8227
8228 /* Function 46 */
8229 NTSTATUS
8230 NTAPI
8231 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8232 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8233 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8234 {
8235 TRACE("(%p %lu %p)\n", DomainHandle, DomainInformationClass, Buffer);
8236
8237 return SamrQueryInformationDomain(DomainHandle,
8238 DomainInformationClass,
8239 Buffer);
8240 }
8241
8242
8243 /* Function 47 */
8244 NTSTATUS
8245 NTAPI
8246 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8247 IN USER_INFORMATION_CLASS UserInformationClass,
8248 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8249 {
8250 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
8251
8252 return SamrQueryInformationUser(UserHandle,
8253 UserInformationClass,
8254 Buffer);
8255 }
8256
8257
8258 /* Function 48 */
8259 NTSTATUS
8260 NTAPI
8261 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8262 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8263 IN unsigned long Index,
8264 IN unsigned long EntryCount,
8265 IN unsigned long PreferredMaximumLength,
8266 OUT unsigned long *TotalAvailable,
8267 OUT unsigned long *TotalReturned,
8268 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8269 {
8270 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
8271 DomainHandle, DisplayInformationClass, Index,
8272 EntryCount, PreferredMaximumLength, TotalAvailable,
8273 TotalReturned, Buffer);
8274
8275 return SamrQueryDisplayInformation(DomainHandle,
8276 DisplayInformationClass,
8277 Index,
8278 EntryCount,
8279 PreferredMaximumLength,
8280 TotalAvailable,
8281 TotalReturned,
8282 Buffer);
8283 }
8284
8285
8286 /* Function 49 */
8287 NTSTATUS
8288 NTAPI
8289 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8290 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8291 IN PRPC_UNICODE_STRING Prefix,
8292 OUT unsigned long *Index)
8293 {
8294 TRACE("(%p %lu %p %p)\n",
8295 DomainHandle, DisplayInformationClass, Prefix, Index);
8296
8297 return SamrGetDisplayEnumerationIndex(DomainHandle,
8298 DisplayInformationClass,
8299 Prefix,
8300 Index);
8301 }
8302
8303
8304 /* Function 50 */
8305 NTSTATUS
8306 NTAPI
8307 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8308 IN PRPC_UNICODE_STRING Name,
8309 IN unsigned long AccountType,
8310 IN ACCESS_MASK DesiredAccess,
8311 OUT SAMPR_HANDLE *UserHandle,
8312 OUT unsigned long *GrantedAccess,
8313 OUT unsigned long *RelativeId)
8314 {
8315 SAM_DOMAIN_FIXED_DATA FixedDomainData;
8316 SAM_USER_FIXED_DATA FixedUserData;
8317 PSAM_DB_OBJECT DomainObject;
8318 PSAM_DB_OBJECT UserObject;
8319 GROUP_MEMBERSHIP GroupMembership;
8320 UCHAR LogonHours[23];
8321 ULONG ulSize;
8322 ULONG ulRid;
8323 WCHAR szRid[9];
8324 NTSTATUS Status;
8325
8326 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
8327 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
8328
8329 if (Name == NULL ||
8330 Name->Length == 0 ||
8331 Name->Buffer == NULL ||
8332 UserHandle == NULL ||
8333 RelativeId == NULL)
8334 return STATUS_INVALID_PARAMETER;
8335
8336 /* Check for valid account type */
8337 if (AccountType != USER_NORMAL_ACCOUNT &&
8338 AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
8339 AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
8340 AccountType != USER_SERVER_TRUST_ACCOUNT &&
8341 AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
8342 return STATUS_INVALID_PARAMETER;
8343
8344 /* Map generic access rights */
8345 RtlMapGenericMask(&DesiredAccess,
8346 &UserMapping);
8347
8348 RtlAcquireResourceExclusive(&SampResource,
8349 TRUE);
8350
8351 /* Validate the domain handle */
8352 Status = SampValidateDbObject(DomainHandle,
8353 SamDbDomainObject,
8354 DOMAIN_CREATE_USER,
8355 &DomainObject);
8356 if (!NT_SUCCESS(Status))
8357 {
8358 TRACE("failed with status 0x%08lx\n", Status);
8359 goto done;
8360 }
8361
8362 /* Check the user account name */
8363 Status = SampCheckAccountName(Name, 20);
8364 if (!NT_SUCCESS(Status))
8365 {
8366 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
8367 goto done;
8368 }
8369
8370 /* Check if the user name already exists in the domain */
8371 Status = SampCheckAccountNameInDomain(DomainObject,
8372 Name->Buffer);
8373 if (!NT_SUCCESS(Status))
8374 {
8375 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
8376 Name->Buffer, Status);
8377 goto done;
8378 }
8379
8380 /* Get the fixed domain attributes */
8381 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
8382 Status = SampGetObjectAttribute(DomainObject,
8383 L"F",
8384 NULL,
8385 (PVOID)&FixedDomainData,
8386 &ulSize);
8387 if (!NT_SUCCESS(Status))
8388 {
8389 TRACE("failed with status 0x%08lx\n", Status);
8390 goto done;
8391 }
8392
8393 /* Increment the NextRid attribute */
8394 ulRid = FixedDomainData.NextRid;
8395 FixedDomainData.NextRid++;
8396
8397 /* Store the fixed domain attributes */
8398 Status = SampSetObjectAttribute(DomainObject,
8399 L"F",
8400 REG_BINARY,
8401 &FixedDomainData,
8402 ulSize);
8403 if (!NT_SUCCESS(Status))
8404 {
8405 TRACE("failed with status 0x%08lx\n", Status);
8406 goto done;
8407 }
8408
8409 TRACE("RID: %lx\n", ulRid);
8410
8411 /* Convert the RID into a string (hex) */
8412 swprintf(szRid, L"%08lX", ulRid);
8413
8414 /* Create the user object */
8415 Status = SampCreateDbObject(DomainObject,
8416 L"Users",
8417 szRid,
8418 ulRid,
8419 SamDbUserObject,
8420 DesiredAccess,
8421 &UserObject);
8422 if (!NT_SUCCESS(Status))
8423 {
8424 TRACE("failed with status 0x%08lx\n", Status);
8425 goto done;
8426 }
8427
8428 /* Add the account name for the user object */
8429 Status = SampSetAccountNameInDomain(DomainObject,
8430 L"Users",
8431 Name->Buffer,
8432 ulRid);
8433 if (!NT_SUCCESS(Status))
8434 {
8435 TRACE("failed with status 0x%08lx\n", Status);
8436 goto done;
8437 }
8438
8439 /* Initialize fixed user data */
8440 FixedUserData.Version = 1;
8441 FixedUserData.Reserved = 0;
8442 FixedUserData.LastLogon.QuadPart = 0;
8443 FixedUserData.LastLogoff.QuadPart = 0;
8444 FixedUserData.PasswordLastSet.QuadPart = 0;
8445 FixedUserData.AccountExpires.LowPart = MAXULONG;
8446 FixedUserData.AccountExpires.HighPart = MAXLONG;
8447 FixedUserData.LastBadPasswordTime.QuadPart = 0;
8448 FixedUserData.UserId = ulRid;
8449 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
8450 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
8451 USER_PASSWORD_NOT_REQUIRED |
8452 AccountType;
8453 FixedUserData.CountryCode = 0;
8454 FixedUserData.CodePage = 0;
8455 FixedUserData.BadPasswordCount = 0;
8456 FixedUserData.LogonCount = 0;
8457 FixedUserData.AdminCount = 0;
8458 FixedUserData.OperatorCount = 0;
8459
8460 /* Set fixed user data attribute */
8461 Status = SampSetObjectAttribute(UserObject,
8462 L"F",
8463 REG_BINARY,
8464 (LPVOID)&FixedUserData,
8465 sizeof(SAM_USER_FIXED_DATA));
8466 if (!NT_SUCCESS(Status))
8467 {
8468 TRACE("failed with status 0x%08lx\n", Status);
8469 goto done;
8470 }
8471
8472 /* Set the Name attribute */
8473 Status = SampSetObjectAttributeString(UserObject,
8474 L"Name",
8475 Name);
8476 if (!NT_SUCCESS(Status))
8477 {
8478 TRACE("failed with status 0x%08lx\n", Status);
8479 goto done;
8480 }
8481
8482 /* Set the FullName attribute */
8483 Status = SampSetObjectAttributeString(UserObject,
8484 L"FullName",
8485 NULL);
8486 if (!NT_SUCCESS(Status))
8487 {
8488 TRACE("failed with status 0x%08lx\n", Status);
8489 goto done;
8490 }
8491
8492 /* Set the HomeDirectory attribute */
8493 Status = SampSetObjectAttributeString(UserObject,
8494 L"HomeDirectory",
8495 NULL);
8496 if (!NT_SUCCESS(Status))
8497 {
8498 TRACE("failed with status 0x%08lx\n", Status);
8499 goto done;
8500 }
8501
8502 /* Set the HomeDirectoryDrive attribute */
8503 Status = SampSetObjectAttributeString(UserObject,
8504 L"HomeDirectoryDrive",
8505 NULL);
8506 if (!NT_SUCCESS(Status))
8507 {
8508 TRACE("failed with status 0x%08lx\n", Status);
8509 goto done;
8510 }
8511
8512 /* Set the ScriptPath attribute */
8513 Status = SampSetObjectAttributeString(UserObject,
8514 L"ScriptPath",
8515 NULL);
8516 if (!NT_SUCCESS(Status))
8517 {
8518 TRACE("failed with status 0x%08lx\n", Status);
8519 goto done;
8520 }
8521
8522 /* Set the ProfilePath attribute */
8523 Status = SampSetObjectAttributeString(UserObject,
8524 L"ProfilePath",
8525 NULL);
8526 if (!NT_SUCCESS(Status))
8527 {
8528 TRACE("failed with status 0x%08lx\n", Status);
8529 goto done;
8530 }
8531
8532 /* Set the AdminComment attribute */
8533 Status = SampSetObjectAttributeString(UserObject,
8534 L"AdminComment",
8535 NULL);
8536 if (!NT_SUCCESS(Status))
8537 {
8538 TRACE("failed with status 0x%08lx\n", Status);
8539 goto done;
8540 }
8541
8542 /* Set the UserComment attribute */
8543 Status = SampSetObjectAttributeString(UserObject,
8544 L"UserComment",
8545 NULL);
8546 if (!NT_SUCCESS(Status))
8547 {
8548 TRACE("failed with status 0x%08lx\n", Status);
8549 goto done;
8550 }
8551
8552 /* Set the WorkStations attribute */
8553 Status = SampSetObjectAttributeString(UserObject,
8554 L"WorkStations",
8555 NULL);
8556 if (!NT_SUCCESS(Status))
8557 {
8558 TRACE("failed with status 0x%08lx\n", Status);
8559 goto done;
8560 }
8561
8562 /* Set the Parameters attribute */
8563 Status = SampSetObjectAttributeString(UserObject,
8564 L"Parameters",
8565 NULL);
8566 if (!NT_SUCCESS(Status))
8567 {
8568 TRACE("failed with status 0x%08lx\n", Status);
8569 goto done;
8570 }
8571
8572 /* Set LogonHours attribute*/
8573 *((PUSHORT)LogonHours) = 168;
8574 memset(&(LogonHours[2]), 0xff, 21);
8575
8576 Status = SampSetObjectAttribute(UserObject,
8577 L"LogonHours",
8578 REG_BINARY,
8579 &LogonHours,
8580 sizeof(LogonHours));
8581 if (!NT_SUCCESS(Status))
8582 {
8583 TRACE("failed with status 0x%08lx\n", Status);
8584 goto done;
8585 }
8586
8587 /* Set Groups attribute*/
8588 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
8589 GroupMembership.Attributes = SE_GROUP_MANDATORY |
8590 SE_GROUP_ENABLED |
8591 SE_GROUP_ENABLED_BY_DEFAULT;
8592
8593 Status = SampSetObjectAttribute(UserObject,
8594 L"Groups",
8595 REG_BINARY,
8596 &GroupMembership,
8597 sizeof(GROUP_MEMBERSHIP));
8598 if (!NT_SUCCESS(Status))
8599 {
8600 TRACE("failed with status 0x%08lx\n", Status);
8601 goto done;
8602 }
8603
8604 /* Set LMPwd attribute*/
8605 Status = SampSetObjectAttribute(UserObject,
8606 L"LMPwd",
8607 REG_BINARY,
8608 NULL,
8609 0);
8610 if (!NT_SUCCESS(Status))
8611 {
8612 TRACE("failed with status 0x%08lx\n", Status);
8613 goto done;
8614 }
8615
8616 /* Set NTPwd attribute*/
8617 Status = SampSetObjectAttribute(UserObject,
8618 L"NTPwd",
8619 REG_BINARY,
8620 NULL,
8621 0);
8622 if (!NT_SUCCESS(Status))
8623 {
8624 TRACE("failed with status 0x%08lx\n", Status);
8625 goto done;
8626 }
8627
8628 /* Set LMPwdHistory attribute*/
8629 Status = SampSetObjectAttribute(UserObject,
8630 L"LMPwdHistory",
8631 REG_BINARY,
8632 NULL,
8633 0);
8634 if (!NT_SUCCESS(Status))
8635 {
8636 TRACE("failed with status 0x%08lx\n", Status);
8637 goto done;
8638 }
8639
8640 /* Set NTPwdHistory attribute*/
8641 Status = SampSetObjectAttribute(UserObject,
8642 L"NTPwdHistory",
8643 REG_BINARY,
8644 NULL,
8645 0);
8646 if (!NT_SUCCESS(Status))
8647 {
8648 TRACE("failed with status 0x%08lx\n", Status);
8649 goto done;
8650 }
8651
8652 /* FIXME: Set SecDesc attribute*/
8653
8654 if (NT_SUCCESS(Status))
8655 {
8656 *UserHandle = (SAMPR_HANDLE)UserObject;
8657 *RelativeId = ulRid;
8658 *GrantedAccess = UserObject->Access;
8659 }
8660
8661 done:
8662 RtlReleaseResource(&SampResource);
8663
8664 TRACE("returns with status 0x%08lx\n", Status);
8665
8666 return Status;
8667 }
8668
8669
8670 /* Function 51 */
8671 NTSTATUS
8672 NTAPI
8673 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
8674 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8675 IN unsigned long Index,
8676 IN unsigned long EntryCount,
8677 IN unsigned long PreferredMaximumLength,
8678 OUT unsigned long *TotalAvailable,
8679 OUT unsigned long *TotalReturned,
8680 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8681 {
8682 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
8683 DomainHandle, DisplayInformationClass, Index,
8684 EntryCount, PreferredMaximumLength, TotalAvailable,
8685 TotalReturned, Buffer);
8686
8687 return SamrQueryDisplayInformation(DomainHandle,
8688 DisplayInformationClass,
8689 Index,
8690 EntryCount,
8691 PreferredMaximumLength,
8692 TotalAvailable,
8693 TotalReturned,
8694 Buffer);
8695 }
8696
8697
8698 /* Function 52 */
8699 NTSTATUS
8700 NTAPI
8701 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
8702 IN PSAMPR_PSID_ARRAY MembersBuffer)
8703 {
8704 ULONG i;
8705 NTSTATUS Status = STATUS_SUCCESS;
8706
8707 TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
8708 AliasHandle, MembersBuffer);
8709
8710 for (i = 0; i < MembersBuffer->Count; i++)
8711 {
8712 Status = SamrAddMemberToAlias(AliasHandle,
8713 ((PSID *)MembersBuffer->Sids)[i]);
8714
8715 if (Status == STATUS_MEMBER_IN_ALIAS)
8716 Status = STATUS_SUCCESS;
8717
8718 if (!NT_SUCCESS(Status))
8719 break;
8720 }
8721
8722 return Status;
8723 }
8724
8725
8726 /* Function 53 */
8727 NTSTATUS
8728 NTAPI
8729 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
8730 IN PSAMPR_PSID_ARRAY MembersBuffer)
8731 {
8732 ULONG i;
8733 NTSTATUS Status = STATUS_SUCCESS;
8734
8735 TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
8736 AliasHandle, MembersBuffer);
8737
8738 for (i = 0; i < MembersBuffer->Count; i++)
8739 {
8740 Status = SamrRemoveMemberFromAlias(AliasHandle,
8741 ((PSID *)MembersBuffer->Sids)[i]);
8742
8743 if (Status == STATUS_MEMBER_IN_ALIAS)
8744 Status = STATUS_SUCCESS;
8745
8746 if (!NT_SUCCESS(Status))
8747 break;
8748 }
8749
8750 return Status;
8751 }
8752
8753
8754 /* Function 54 */
8755 NTSTATUS
8756 NTAPI
8757 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
8758 IN PRPC_STRING ServerName,
8759 IN PRPC_STRING UserName,
8760 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
8761 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
8762 {
8763 UNIMPLEMENTED;
8764 return STATUS_NOT_IMPLEMENTED;
8765 }
8766
8767 /* Function 55 */
8768 NTSTATUS
8769 NTAPI
8770 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
8771 IN PRPC_UNICODE_STRING ServerName,
8772 IN PRPC_UNICODE_STRING UserName,
8773 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
8774 IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
8775 IN unsigned char LmPresent,
8776 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
8777 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
8778 {
8779 UNIMPLEMENTED;
8780 return STATUS_NOT_IMPLEMENTED;
8781 }
8782
8783 /* Function 56 */
8784 NTSTATUS
8785 NTAPI
8786 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
8787 IN PRPC_UNICODE_STRING Unused,
8788 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8789 {
8790 UNIMPLEMENTED;
8791 return STATUS_NOT_IMPLEMENTED;
8792 }
8793
8794
8795 /* Function 57 */
8796 NTSTATUS
8797 NTAPI
8798 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
8799 OUT SAMPR_HANDLE *ServerHandle,
8800 IN ACCESS_MASK DesiredAccess)
8801 {
8802 TRACE("(%p %p %lx)\n", ServerName, ServerHandle, DesiredAccess);
8803
8804 return SamrConnect(ServerName,
8805 ServerHandle,
8806 DesiredAccess);
8807 }
8808
8809
8810 /* Function 58 */
8811 NTSTATUS
8812 NTAPI
8813 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
8814 IN USER_INFORMATION_CLASS UserInformationClass,
8815 IN PSAMPR_USER_INFO_BUFFER Buffer)
8816 {
8817 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
8818
8819 return SamrSetInformationUser(UserHandle,
8820 UserInformationClass,
8821 Buffer);
8822 }
8823
8824
8825 /* Function 59 */
8826 NTSTATUS
8827 NTAPI
8828 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
8829 {
8830 UNIMPLEMENTED;
8831 return STATUS_NOT_IMPLEMENTED;
8832 }
8833
8834 /* Function 60 */
8835 NTSTATUS
8836 NTAPI
8837 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
8838 {
8839 UNIMPLEMENTED;
8840 return STATUS_NOT_IMPLEMENTED;
8841 }
8842
8843 /* Function 61 */
8844 NTSTATUS
8845 NTAPI
8846 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
8847 {
8848 UNIMPLEMENTED;
8849 return STATUS_NOT_IMPLEMENTED;
8850 }
8851
8852 /* Function 62 */
8853 NTSTATUS
8854 NTAPI
8855 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
8856 OUT SAMPR_HANDLE *ServerHandle,
8857 IN unsigned long ClientRevision,
8858 IN ACCESS_MASK DesiredAccess)
8859 {
8860 UNIMPLEMENTED;
8861 return STATUS_NOT_IMPLEMENTED;
8862 }
8863
8864 /* Function 63 */
8865 NTSTATUS
8866 NTAPI
8867 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
8868 {
8869 UNIMPLEMENTED;
8870 return STATUS_NOT_IMPLEMENTED;
8871 }
8872
8873 /* Function 64 */
8874 NTSTATUS
8875 NTAPI
8876 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
8877 IN ACCESS_MASK DesiredAccess,
8878 IN unsigned long InVersion,
8879 IN SAMPR_REVISION_INFO *InRevisionInfo,
8880 OUT unsigned long *OutVersion,
8881 OUT SAMPR_REVISION_INFO *OutRevisionInfo,
8882 OUT SAMPR_HANDLE *ServerHandle)
8883 {
8884 UNIMPLEMENTED;
8885 return STATUS_NOT_IMPLEMENTED;
8886 }
8887
8888 /* Function 65 */
8889 NTSTATUS
8890 NTAPI
8891 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
8892 IN unsigned long Rid,
8893 OUT PRPC_SID *Sid)
8894 {
8895 UNIMPLEMENTED;
8896 return STATUS_NOT_IMPLEMENTED;
8897 }
8898
8899 /* Function 66 */
8900 NTSTATUS
8901 NTAPI
8902 SamrSetDSRMPassword(IN handle_t BindingHandle,
8903 IN PRPC_UNICODE_STRING Unused,
8904 IN unsigned long UserId,
8905 IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
8906 {
8907 UNIMPLEMENTED;
8908 return STATUS_NOT_IMPLEMENTED;
8909 }
8910
8911 /* Function 67 */
8912 NTSTATUS
8913 NTAPI
8914 SamrValidatePassword(IN handle_t Handle,
8915 IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
8916 IN PSAM_VALIDATE_INPUT_ARG InputArg,
8917 OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
8918 {
8919 UNIMPLEMENTED;
8920 return STATUS_NOT_IMPLEMENTED;
8921 }
8922
8923 /* EOF */