[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 {