bb46f48e22fdf58e2a726eaeffcd5d253168e1bc
[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 = SampSetObjectAttribute(DomainObject,
1718 L"OemInformation",
1719 REG_SZ,
1720 DomainInformation->Oem.OemInformation.Buffer,
1721 DomainInformation->Oem.OemInformation.Length + sizeof(WCHAR));
1722 break;
1723
1724 case DomainNameInformation:
1725 Status = SampSetObjectAttribute(DomainObject,
1726 L"Name",
1727 REG_SZ,
1728 DomainInformation->Name.DomainName.Buffer,
1729 DomainInformation->Name.DomainName.Length + sizeof(WCHAR));
1730 break;
1731
1732 case DomainReplicationInformation:
1733 Status = SampSetObjectAttribute(DomainObject,
1734 L"ReplicaSourceNodeName",
1735 REG_SZ,
1736 DomainInformation->Replication.ReplicaSourceNodeName.Buffer,
1737 DomainInformation->Replication.ReplicaSourceNodeName.Length + sizeof(WCHAR));
1738 break;
1739
1740 case DomainServerRoleInformation:
1741 Status = SampSetDomainServerRole(DomainObject,
1742 DomainInformation);
1743 break;
1744
1745 case DomainStateInformation:
1746 Status = SampSetDomainState(DomainObject,
1747 DomainInformation);
1748 break;
1749
1750 case DomainLockoutInformation:
1751 Status = SampSetDomainLockout(DomainObject,
1752 DomainInformation);
1753 break;
1754
1755 default:
1756 Status = STATUS_NOT_IMPLEMENTED;
1757 }
1758
1759 done:
1760 RtlReleaseResource(&SampResource);
1761
1762 return Status;
1763 }
1764
1765
1766 /* Function 10 */
1767 NTSTATUS
1768 NTAPI
1769 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1770 IN PRPC_UNICODE_STRING Name,
1771 IN ACCESS_MASK DesiredAccess,
1772 OUT SAMPR_HANDLE *GroupHandle,
1773 OUT unsigned long *RelativeId)
1774 {
1775 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
1776 SAM_DOMAIN_FIXED_DATA FixedDomainData;
1777 SAM_GROUP_FIXED_DATA FixedGroupData;
1778 PSAM_DB_OBJECT DomainObject;
1779 PSAM_DB_OBJECT GroupObject;
1780 ULONG ulSize;
1781 ULONG ulRid;
1782 WCHAR szRid[9];
1783 NTSTATUS Status;
1784
1785 TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
1786 DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
1787
1788 /* Map generic access rights */
1789 RtlMapGenericMask(&DesiredAccess,
1790 &GroupMapping);
1791
1792 RtlAcquireResourceExclusive(&SampResource,
1793 TRUE);
1794
1795 /* Validate the domain handle */
1796 Status = SampValidateDbObject(DomainHandle,
1797 SamDbDomainObject,
1798 DOMAIN_CREATE_GROUP,
1799 &DomainObject);
1800 if (!NT_SUCCESS(Status))
1801 {
1802 TRACE("failed with status 0x%08lx\n", Status);
1803 goto done;
1804 }
1805
1806 /* Check the group account name */
1807 Status = SampCheckAccountName(Name, 256);
1808 if (!NT_SUCCESS(Status))
1809 {
1810 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
1811 goto done;
1812 }
1813
1814 /* Check if the group name already exists in the domain */
1815 Status = SampCheckAccountNameInDomain(DomainObject,
1816 Name->Buffer);
1817 if (!NT_SUCCESS(Status))
1818 {
1819 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
1820 Name->Buffer, Status);
1821 goto done;
1822 }
1823
1824 /* Get the fixed domain attributes */
1825 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
1826 Status = SampGetObjectAttribute(DomainObject,
1827 L"F",
1828 NULL,
1829 (PVOID)&FixedDomainData,
1830 &ulSize);
1831 if (!NT_SUCCESS(Status))
1832 {
1833 TRACE("failed with status 0x%08lx\n", Status);
1834 goto done;
1835 }
1836
1837 /* Increment the NextRid attribute */
1838 ulRid = FixedDomainData.NextRid;
1839 FixedDomainData.NextRid++;
1840
1841 /* Store the fixed domain attributes */
1842 Status = SampSetObjectAttribute(DomainObject,
1843 L"F",
1844 REG_BINARY,
1845 &FixedDomainData,
1846 ulSize);
1847 if (!NT_SUCCESS(Status))
1848 {
1849 TRACE("failed with status 0x%08lx\n", Status);
1850 goto done;
1851 }
1852
1853 TRACE("RID: %lx\n", ulRid);
1854
1855 /* Convert the RID into a string (hex) */
1856 swprintf(szRid, L"%08lX", ulRid);
1857
1858 /* Create the group object */
1859 Status = SampCreateDbObject(DomainObject,
1860 L"Groups",
1861 szRid,
1862 ulRid,
1863 SamDbGroupObject,
1864 DesiredAccess,
1865 &GroupObject);
1866 if (!NT_SUCCESS(Status))
1867 {
1868 TRACE("failed with status 0x%08lx\n", Status);
1869 goto done;
1870 }
1871
1872 /* Add the account name of the user object */
1873 Status = SampSetAccountNameInDomain(DomainObject,
1874 L"Groups",
1875 Name->Buffer,
1876 ulRid);
1877 if (!NT_SUCCESS(Status))
1878 {
1879 TRACE("failed with status 0x%08lx\n", Status);
1880 goto done;
1881 }
1882
1883 /* Initialize fixed user data */
1884 memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
1885 FixedGroupData.Version = 1;
1886 FixedGroupData.GroupId = ulRid;
1887
1888 /* Set fixed user data attribute */
1889 Status = SampSetObjectAttribute(GroupObject,
1890 L"F",
1891 REG_BINARY,
1892 (LPVOID)&FixedGroupData,
1893 sizeof(SAM_GROUP_FIXED_DATA));
1894 if (!NT_SUCCESS(Status))
1895 {
1896 TRACE("failed with status 0x%08lx\n", Status);
1897 goto done;
1898 }
1899
1900 /* Set the Name attribute */
1901 Status = SampSetObjectAttribute(GroupObject,
1902 L"Name",
1903 REG_SZ,
1904 (LPVOID)Name->Buffer,
1905 Name->MaximumLength);
1906 if (!NT_SUCCESS(Status))
1907 {
1908 TRACE("failed with status 0x%08lx\n", Status);
1909 goto done;
1910 }
1911
1912 /* Set the AdminComment attribute */
1913 Status = SampSetObjectAttribute(GroupObject,
1914 L"AdminComment",
1915 REG_SZ,
1916 EmptyString.Buffer,
1917 EmptyString.MaximumLength);
1918 if (!NT_SUCCESS(Status))
1919 {
1920 TRACE("failed with status 0x%08lx\n", Status);
1921 goto done;
1922 }
1923
1924 if (NT_SUCCESS(Status))
1925 {
1926 *GroupHandle = (SAMPR_HANDLE)GroupObject;
1927 *RelativeId = ulRid;
1928 }
1929
1930 done:
1931 RtlReleaseResource(&SampResource);
1932
1933 TRACE("returns with status 0x%08lx\n", Status);
1934
1935 return Status;
1936 }
1937
1938
1939 /* Function 11 */
1940 NTSTATUS
1941 NTAPI
1942 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
1943 IN OUT unsigned long *EnumerationContext,
1944 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
1945 IN unsigned long PreferedMaximumLength,
1946 OUT unsigned long *CountReturned)
1947 {
1948 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
1949 PSAM_DB_OBJECT DomainObject;
1950 HANDLE GroupsKeyHandle = NULL;
1951 HANDLE NamesKeyHandle = NULL;
1952 WCHAR GroupName[64];
1953 ULONG EnumIndex;
1954 ULONG EnumCount = 0;
1955 ULONG RequiredLength = 0;
1956 ULONG NameLength;
1957 ULONG DataLength;
1958 ULONG Rid;
1959 ULONG i;
1960 BOOLEAN MoreEntries = FALSE;
1961 NTSTATUS Status;
1962
1963 TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
1964 DomainHandle, EnumerationContext, Buffer,
1965 PreferedMaximumLength, CountReturned);
1966
1967 RtlAcquireResourceShared(&SampResource,
1968 TRUE);
1969
1970 /* Validate the domain handle */
1971 Status = SampValidateDbObject(DomainHandle,
1972 SamDbDomainObject,
1973 DOMAIN_LIST_ACCOUNTS,
1974 &DomainObject);
1975 if (!NT_SUCCESS(Status))
1976 goto done;
1977
1978 Status = SampRegOpenKey(DomainObject->KeyHandle,
1979 L"Groups",
1980 KEY_READ,
1981 &GroupsKeyHandle);
1982 if (!NT_SUCCESS(Status))
1983 goto done;
1984
1985 Status = SampRegOpenKey(GroupsKeyHandle,
1986 L"Names",
1987 KEY_READ,
1988 &NamesKeyHandle);
1989 if (!NT_SUCCESS(Status))
1990 goto done;
1991
1992 TRACE("Part 1\n");
1993
1994 EnumIndex = *EnumerationContext;
1995
1996 while (TRUE)
1997 {
1998 NameLength = 64 * sizeof(WCHAR);
1999 Status = SampRegEnumerateValue(NamesKeyHandle,
2000 EnumIndex,
2001 GroupName,
2002 &NameLength,
2003 NULL,
2004 NULL,
2005 NULL);
2006 if (!NT_SUCCESS(Status))
2007 {
2008 if (Status == STATUS_NO_MORE_ENTRIES)
2009 Status = STATUS_SUCCESS;
2010 break;
2011 }
2012
2013 TRACE("EnumIndex: %lu\n", EnumIndex);
2014 TRACE("Group name: %S\n", GroupName);
2015 TRACE("Name length: %lu\n", NameLength);
2016
2017 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2018 {
2019 MoreEntries = TRUE;
2020 break;
2021 }
2022
2023 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2024 EnumCount++;
2025
2026 EnumIndex++;
2027 }
2028
2029 TRACE("EnumCount: %lu\n", EnumCount);
2030 TRACE("RequiredLength: %lu\n", RequiredLength);
2031
2032 if (!NT_SUCCESS(Status))
2033 goto done;
2034
2035 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2036 if (EnumBuffer == NULL)
2037 {
2038 Status = STATUS_INSUFFICIENT_RESOURCES;
2039 goto done;
2040 }
2041
2042 EnumBuffer->EntriesRead = EnumCount;
2043 if (EnumCount == 0)
2044 goto done;
2045
2046 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2047 if (EnumBuffer->Buffer == NULL)
2048 {
2049 Status = STATUS_INSUFFICIENT_RESOURCES;
2050 goto done;
2051 }
2052
2053 TRACE("Part 2\n");
2054
2055 EnumIndex = *EnumerationContext;
2056 for (i = 0; i < EnumCount; i++, EnumIndex++)
2057 {
2058 NameLength = 64 * sizeof(WCHAR);
2059 DataLength = sizeof(ULONG);
2060 Status = SampRegEnumerateValue(NamesKeyHandle,
2061 EnumIndex,
2062 GroupName,
2063 &NameLength,
2064 NULL,
2065 &Rid,
2066 &DataLength);
2067 if (!NT_SUCCESS(Status))
2068 {
2069 if (Status == STATUS_NO_MORE_ENTRIES)
2070 Status = STATUS_SUCCESS;
2071 break;
2072 }
2073
2074 TRACE("EnumIndex: %lu\n", EnumIndex);
2075 TRACE("Group name: %S\n", GroupName);
2076 TRACE("Name length: %lu\n", NameLength);
2077 TRACE("RID: %lu\n", Rid);
2078
2079 EnumBuffer->Buffer[i].RelativeId = Rid;
2080
2081 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2082 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2083
2084 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2085 #if 0
2086 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2087 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2088 {
2089 Status = STATUS_INSUFFICIENT_RESOURCES;
2090 goto done;
2091 }
2092
2093 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2094 GroupName,
2095 EnumBuffer->Buffer[i].Name.Length);
2096 #endif
2097 }
2098
2099 done:
2100 if (NT_SUCCESS(Status))
2101 {
2102 *EnumerationContext += EnumCount;
2103 *Buffer = EnumBuffer;
2104 *CountReturned = EnumCount;
2105 }
2106 else
2107 {
2108 *EnumerationContext = 0;
2109 *Buffer = NULL;
2110 *CountReturned = 0;
2111
2112 if (EnumBuffer != NULL)
2113 {
2114 if (EnumBuffer->Buffer != NULL)
2115 {
2116 if (EnumBuffer->EntriesRead != 0)
2117 {
2118 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2119 {
2120 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2121 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2122 }
2123 }
2124
2125 midl_user_free(EnumBuffer->Buffer);
2126 }
2127
2128 midl_user_free(EnumBuffer);
2129 }
2130 }
2131
2132 SampRegCloseKey(&NamesKeyHandle);
2133 SampRegCloseKey(&GroupsKeyHandle);
2134
2135 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2136 Status = STATUS_MORE_ENTRIES;
2137
2138 RtlReleaseResource(&SampResource);
2139
2140 return Status;
2141 }
2142
2143
2144 /* Function 12 */
2145 NTSTATUS
2146 NTAPI
2147 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2148 IN PRPC_UNICODE_STRING Name,
2149 IN ACCESS_MASK DesiredAccess,
2150 OUT SAMPR_HANDLE *UserHandle,
2151 OUT unsigned long *RelativeId)
2152 {
2153 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2154 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2155 SAM_USER_FIXED_DATA FixedUserData;
2156 PSAM_DB_OBJECT DomainObject;
2157 PSAM_DB_OBJECT UserObject;
2158 GROUP_MEMBERSHIP GroupMembership;
2159 UCHAR LogonHours[23];
2160 ULONG ulSize;
2161 ULONG ulRid;
2162 WCHAR szRid[9];
2163 NTSTATUS Status;
2164
2165 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2166 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2167
2168 if (Name == NULL ||
2169 Name->Length == 0 ||
2170 Name->Buffer == NULL ||
2171 UserHandle == NULL ||
2172 RelativeId == NULL)
2173 return STATUS_INVALID_PARAMETER;
2174
2175 /* Map generic access rights */
2176 RtlMapGenericMask(&DesiredAccess,
2177 &UserMapping);
2178
2179 RtlAcquireResourceExclusive(&SampResource,
2180 TRUE);
2181
2182 /* Validate the domain handle */
2183 Status = SampValidateDbObject(DomainHandle,
2184 SamDbDomainObject,
2185 DOMAIN_CREATE_USER,
2186 &DomainObject);
2187 if (!NT_SUCCESS(Status))
2188 {
2189 TRACE("failed with status 0x%08lx\n", Status);
2190 goto done;
2191 }
2192
2193 /* Check the user account name */
2194 Status = SampCheckAccountName(Name, 20);
2195 if (!NT_SUCCESS(Status))
2196 {
2197 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2198 goto done;
2199 }
2200
2201 /* Check if the user name already exists in the domain */
2202 Status = SampCheckAccountNameInDomain(DomainObject,
2203 Name->Buffer);
2204 if (!NT_SUCCESS(Status))
2205 {
2206 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2207 Name->Buffer, Status);
2208 goto done;
2209 }
2210
2211 /* Get the fixed domain attributes */
2212 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2213 Status = SampGetObjectAttribute(DomainObject,
2214 L"F",
2215 NULL,
2216 (PVOID)&FixedDomainData,
2217 &ulSize);
2218 if (!NT_SUCCESS(Status))
2219 {
2220 TRACE("failed with status 0x%08lx\n", Status);
2221 goto done;
2222 }
2223
2224 /* Increment the NextRid attribute */
2225 ulRid = FixedDomainData.NextRid;
2226 FixedDomainData.NextRid++;
2227
2228 /* Store the fixed domain attributes */
2229 Status = SampSetObjectAttribute(DomainObject,
2230 L"F",
2231 REG_BINARY,
2232 &FixedDomainData,
2233 ulSize);
2234 if (!NT_SUCCESS(Status))
2235 {
2236 TRACE("failed with status 0x%08lx\n", Status);
2237 goto done;
2238 }
2239
2240 TRACE("RID: %lx\n", ulRid);
2241
2242 /* Convert the RID into a string (hex) */
2243 swprintf(szRid, L"%08lX", ulRid);
2244
2245 /* Create the user object */
2246 Status = SampCreateDbObject(DomainObject,
2247 L"Users",
2248 szRid,
2249 ulRid,
2250 SamDbUserObject,
2251 DesiredAccess,
2252 &UserObject);
2253 if (!NT_SUCCESS(Status))
2254 {
2255 TRACE("failed with status 0x%08lx\n", Status);
2256 goto done;
2257 }
2258
2259 /* Add the account name for the user object */
2260 Status = SampSetAccountNameInDomain(DomainObject,
2261 L"Users",
2262 Name->Buffer,
2263 ulRid);
2264 if (!NT_SUCCESS(Status))
2265 {
2266 TRACE("failed with status 0x%08lx\n", Status);
2267 goto done;
2268 }
2269
2270 /* Initialize fixed user data */
2271 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2272 FixedUserData.Version = 1;
2273 FixedUserData.Reserved = 0;
2274 FixedUserData.LastLogon.QuadPart = 0;
2275 FixedUserData.LastLogoff.QuadPart = 0;
2276 FixedUserData.PasswordLastSet.QuadPart = 0;
2277 FixedUserData.AccountExpires.LowPart = MAXULONG;
2278 FixedUserData.AccountExpires.HighPart = MAXLONG;
2279 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2280 FixedUserData.UserId = ulRid;
2281 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2282 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2283 USER_PASSWORD_NOT_REQUIRED |
2284 USER_NORMAL_ACCOUNT;
2285 FixedUserData.CountryCode = 0;
2286 FixedUserData.CodePage = 0;
2287 FixedUserData.BadPasswordCount = 0;
2288 FixedUserData.LogonCount = 0;
2289 FixedUserData.AdminCount = 0;
2290 FixedUserData.OperatorCount = 0;
2291
2292 /* Set fixed user data attribute */
2293 Status = SampSetObjectAttribute(UserObject,
2294 L"F",
2295 REG_BINARY,
2296 (LPVOID)&FixedUserData,
2297 sizeof(SAM_USER_FIXED_DATA));
2298 if (!NT_SUCCESS(Status))
2299 {
2300 TRACE("failed with status 0x%08lx\n", Status);
2301 goto done;
2302 }
2303
2304 /* Set the Name attribute */
2305 Status = SampSetObjectAttribute(UserObject,
2306 L"Name",
2307 REG_SZ,
2308 (LPVOID)Name->Buffer,
2309 Name->MaximumLength);
2310 if (!NT_SUCCESS(Status))
2311 {
2312 TRACE("failed with status 0x%08lx\n", Status);
2313 goto done;
2314 }
2315
2316 /* Set the FullName attribute */
2317 Status = SampSetObjectAttribute(UserObject,
2318 L"FullName",
2319 REG_SZ,
2320 EmptyString.Buffer,
2321 EmptyString.MaximumLength);
2322 if (!NT_SUCCESS(Status))
2323 {
2324 TRACE("failed with status 0x%08lx\n", Status);
2325 goto done;
2326 }
2327
2328 /* Set the HomeDirectory attribute */
2329 Status = SampSetObjectAttribute(UserObject,
2330 L"HomeDirectory",
2331 REG_SZ,
2332 EmptyString.Buffer,
2333 EmptyString.MaximumLength);
2334 if (!NT_SUCCESS(Status))
2335 {
2336 TRACE("failed with status 0x%08lx\n", Status);
2337 goto done;
2338 }
2339
2340 /* Set the HomeDirectoryDrive attribute */
2341 Status = SampSetObjectAttribute(UserObject,
2342 L"HomeDirectoryDrive",
2343 REG_SZ,
2344 EmptyString.Buffer,
2345 EmptyString.MaximumLength);
2346 if (!NT_SUCCESS(Status))
2347 {
2348 TRACE("failed with status 0x%08lx\n", Status);
2349 goto done;
2350 }
2351
2352 /* Set the ScriptPath attribute */
2353 Status = SampSetObjectAttribute(UserObject,
2354 L"ScriptPath",
2355 REG_SZ,
2356 EmptyString.Buffer,
2357 EmptyString.MaximumLength);
2358 if (!NT_SUCCESS(Status))
2359 {
2360 TRACE("failed with status 0x%08lx\n", Status);
2361 goto done;
2362 }
2363
2364 /* Set the ProfilePath attribute */
2365 Status = SampSetObjectAttribute(UserObject,
2366 L"ProfilePath",
2367 REG_SZ,
2368 EmptyString.Buffer,
2369 EmptyString.MaximumLength);
2370 if (!NT_SUCCESS(Status))
2371 {
2372 TRACE("failed with status 0x%08lx\n", Status);
2373 goto done;
2374 }
2375
2376 /* Set the AdminComment attribute */
2377 Status = SampSetObjectAttribute(UserObject,
2378 L"AdminComment",
2379 REG_SZ,
2380 EmptyString.Buffer,
2381 EmptyString.MaximumLength);
2382 if (!NT_SUCCESS(Status))
2383 {
2384 TRACE("failed with status 0x%08lx\n", Status);
2385 goto done;
2386 }
2387
2388 /* Set the UserComment attribute */
2389 Status = SampSetObjectAttribute(UserObject,
2390 L"UserComment",
2391 REG_SZ,
2392 EmptyString.Buffer,
2393 EmptyString.MaximumLength);
2394 if (!NT_SUCCESS(Status))
2395 {
2396 TRACE("failed with status 0x%08lx\n", Status);
2397 goto done;
2398 }
2399
2400 /* Set the WorkStations attribute */
2401 Status = SampSetObjectAttribute(UserObject,
2402 L"WorkStations",
2403 REG_SZ,
2404 EmptyString.Buffer,
2405 EmptyString.MaximumLength);
2406 if (!NT_SUCCESS(Status))
2407 {
2408 TRACE("failed with status 0x%08lx\n", Status);
2409 goto done;
2410 }
2411
2412 /* Set the Parameters attribute */
2413 Status = SampSetObjectAttribute(UserObject,
2414 L"Parameters",
2415 REG_SZ,
2416 EmptyString.Buffer,
2417 EmptyString.MaximumLength);
2418 if (!NT_SUCCESS(Status))
2419 {
2420 TRACE("failed with status 0x%08lx\n", Status);
2421 goto done;
2422 }
2423
2424 /* Set LogonHours attribute*/
2425 *((PUSHORT)LogonHours) = 168;
2426 memset(&(LogonHours[2]), 0xff, 21);
2427
2428 Status = SampSetObjectAttribute(UserObject,
2429 L"LogonHours",
2430 REG_BINARY,
2431 &LogonHours,
2432 sizeof(LogonHours));
2433 if (!NT_SUCCESS(Status))
2434 {
2435 TRACE("failed with status 0x%08lx\n", Status);
2436 goto done;
2437 }
2438
2439 /* Set Groups attribute*/
2440 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2441 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2442 SE_GROUP_ENABLED |
2443 SE_GROUP_ENABLED_BY_DEFAULT;
2444
2445 Status = SampSetObjectAttribute(UserObject,
2446 L"Groups",
2447 REG_BINARY,
2448 &GroupMembership,
2449 sizeof(GROUP_MEMBERSHIP));
2450 if (!NT_SUCCESS(Status))
2451 {
2452 TRACE("failed with status 0x%08lx\n", Status);
2453 goto done;
2454 }
2455
2456 /* Set LMPwd attribute*/
2457 Status = SampSetObjectAttribute(UserObject,
2458 L"LMPwd",
2459 REG_BINARY,
2460 &EmptyLmHash,
2461 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2462 if (!NT_SUCCESS(Status))
2463 {
2464 TRACE("failed with status 0x%08lx\n", Status);
2465 goto done;
2466 }
2467
2468 /* Set NTPwd attribute*/
2469 Status = SampSetObjectAttribute(UserObject,
2470 L"NTPwd",
2471 REG_BINARY,
2472 &EmptyNtHash,
2473 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2474 if (!NT_SUCCESS(Status))
2475 {
2476 TRACE("failed with status 0x%08lx\n", Status);
2477 goto done;
2478 }
2479
2480 /* Set LMPwdHistory attribute*/
2481 Status = SampSetObjectAttribute(UserObject,
2482 L"LMPwdHistory",
2483 REG_BINARY,
2484 NULL,
2485 0);
2486 if (!NT_SUCCESS(Status))
2487 {
2488 TRACE("failed with status 0x%08lx\n", Status);
2489 goto done;
2490 }
2491
2492 /* Set NTPwdHistory attribute*/
2493 Status = SampSetObjectAttribute(UserObject,
2494 L"NTPwdHistory",
2495 REG_BINARY,
2496 NULL,
2497 0);
2498 if (!NT_SUCCESS(Status))
2499 {
2500 TRACE("failed with status 0x%08lx\n", Status);
2501 goto done;
2502 }
2503
2504 /* FIXME: Set SecDesc attribute*/
2505
2506 if (NT_SUCCESS(Status))
2507 {
2508 *UserHandle = (SAMPR_HANDLE)UserObject;
2509 *RelativeId = ulRid;
2510 }
2511
2512 done:
2513 RtlReleaseResource(&SampResource);
2514
2515 TRACE("returns with status 0x%08lx\n", Status);
2516
2517 return Status;
2518 }
2519
2520
2521 /* Function 13 */
2522 NTSTATUS
2523 NTAPI
2524 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2525 IN OUT unsigned long *EnumerationContext,
2526 IN unsigned long UserAccountControl,
2527 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2528 IN unsigned long PreferedMaximumLength,
2529 OUT unsigned long *CountReturned)
2530 {
2531 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2532 PSAM_DB_OBJECT DomainObject;
2533 HANDLE UsersKeyHandle = NULL;
2534 HANDLE NamesKeyHandle = NULL;
2535 WCHAR UserName[64];
2536 ULONG EnumIndex;
2537 ULONG EnumCount = 0;
2538 ULONG RequiredLength = 0;
2539 ULONG NameLength;
2540 ULONG DataLength;
2541 ULONG Rid;
2542 ULONG i;
2543 BOOLEAN MoreEntries = FALSE;
2544 NTSTATUS Status;
2545
2546 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2547 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2548 PreferedMaximumLength, CountReturned);
2549
2550 RtlAcquireResourceShared(&SampResource,
2551 TRUE);
2552
2553 /* Validate the domain handle */
2554 Status = SampValidateDbObject(DomainHandle,
2555 SamDbDomainObject,
2556 DOMAIN_LIST_ACCOUNTS,
2557 &DomainObject);
2558 if (!NT_SUCCESS(Status))
2559 goto done;
2560
2561 Status = SampRegOpenKey(DomainObject->KeyHandle,
2562 L"Users",
2563 KEY_READ,
2564 &UsersKeyHandle);
2565 if (!NT_SUCCESS(Status))
2566 goto done;
2567
2568 Status = SampRegOpenKey(UsersKeyHandle,
2569 L"Names",
2570 KEY_READ,
2571 &NamesKeyHandle);
2572 if (!NT_SUCCESS(Status))
2573 goto done;
2574
2575 TRACE("Part 1\n");
2576
2577 EnumIndex = *EnumerationContext;
2578
2579 while (TRUE)
2580 {
2581 NameLength = 64 * sizeof(WCHAR);
2582 Status = SampRegEnumerateValue(NamesKeyHandle,
2583 EnumIndex,
2584 UserName,
2585 &NameLength,
2586 NULL,
2587 NULL,
2588 NULL);
2589 if (!NT_SUCCESS(Status))
2590 {
2591 if (Status == STATUS_NO_MORE_ENTRIES)
2592 Status = STATUS_SUCCESS;
2593 break;
2594 }
2595
2596 TRACE("EnumIndex: %lu\n", EnumIndex);
2597 TRACE("User name: %S\n", UserName);
2598 TRACE("Name length: %lu\n", NameLength);
2599
2600 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2601 {
2602 MoreEntries = TRUE;
2603 break;
2604 }
2605
2606 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2607 EnumCount++;
2608
2609 EnumIndex++;
2610 }
2611
2612 TRACE("EnumCount: %lu\n", EnumCount);
2613 TRACE("RequiredLength: %lu\n", RequiredLength);
2614
2615 if (!NT_SUCCESS(Status))
2616 goto done;
2617
2618 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2619 if (EnumBuffer == NULL)
2620 {
2621 Status = STATUS_INSUFFICIENT_RESOURCES;
2622 goto done;
2623 }
2624
2625 EnumBuffer->EntriesRead = EnumCount;
2626 if (EnumCount == 0)
2627 goto done;
2628
2629 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2630 if (EnumBuffer->Buffer == NULL)
2631 {
2632 Status = STATUS_INSUFFICIENT_RESOURCES;
2633 goto done;
2634 }
2635
2636 TRACE("Part 2\n");
2637
2638 EnumIndex = *EnumerationContext;
2639 for (i = 0; i < EnumCount; i++, EnumIndex++)
2640 {
2641 NameLength = 64 * sizeof(WCHAR);
2642 DataLength = sizeof(ULONG);
2643 Status = SampRegEnumerateValue(NamesKeyHandle,
2644 EnumIndex,
2645 UserName,
2646 &NameLength,
2647 NULL,
2648 &Rid,
2649 &DataLength);
2650 if (!NT_SUCCESS(Status))
2651 {
2652 if (Status == STATUS_NO_MORE_ENTRIES)
2653 Status = STATUS_SUCCESS;
2654 break;
2655 }
2656
2657 TRACE("EnumIndex: %lu\n", EnumIndex);
2658 TRACE("User name: %S\n", UserName);
2659 TRACE("Name length: %lu\n", NameLength);
2660 TRACE("RID: %lu\n", Rid);
2661
2662 EnumBuffer->Buffer[i].RelativeId = Rid;
2663
2664 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2665 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2666
2667 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2668 #if 0
2669 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2670 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2671 {
2672 Status = STATUS_INSUFFICIENT_RESOURCES;
2673 goto done;
2674 }
2675
2676 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2677 UserName,
2678 EnumBuffer->Buffer[i].Name.Length);
2679 #endif
2680 }
2681
2682 done:
2683 if (NT_SUCCESS(Status))
2684 {
2685 *EnumerationContext += EnumCount;
2686 *Buffer = EnumBuffer;
2687 *CountReturned = EnumCount;
2688 }
2689 else
2690 {
2691 *EnumerationContext = 0;
2692 *Buffer = NULL;
2693 *CountReturned = 0;
2694
2695 if (EnumBuffer != NULL)
2696 {
2697 if (EnumBuffer->Buffer != NULL)
2698 {
2699 if (EnumBuffer->EntriesRead != 0)
2700 {
2701 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2702 {
2703 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2704 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2705 }
2706 }
2707
2708 midl_user_free(EnumBuffer->Buffer);
2709 }
2710
2711 midl_user_free(EnumBuffer);
2712 }
2713 }
2714
2715 SampRegCloseKey(&NamesKeyHandle);
2716 SampRegCloseKey(&UsersKeyHandle);
2717
2718 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2719 Status = STATUS_MORE_ENTRIES;
2720
2721 RtlReleaseResource(&SampResource);
2722
2723 return Status;
2724 }
2725
2726
2727 /* Function 14 */
2728 NTSTATUS
2729 NTAPI
2730 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2731 IN PRPC_UNICODE_STRING AccountName,
2732 IN ACCESS_MASK DesiredAccess,
2733 OUT SAMPR_HANDLE *AliasHandle,
2734 OUT unsigned long *RelativeId)
2735 {
2736 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2737 PSAM_DB_OBJECT DomainObject;
2738 PSAM_DB_OBJECT AliasObject;
2739 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2740 ULONG ulSize;
2741 ULONG ulRid;
2742 WCHAR szRid[9];
2743 NTSTATUS Status;
2744
2745 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2746 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2747
2748 /* Map generic access rights */
2749 RtlMapGenericMask(&DesiredAccess,
2750 &AliasMapping);
2751
2752 RtlAcquireResourceExclusive(&SampResource,
2753 TRUE);
2754
2755 /* Validate the domain handle */
2756 Status = SampValidateDbObject(DomainHandle,
2757 SamDbDomainObject,
2758 DOMAIN_CREATE_ALIAS,
2759 &DomainObject);
2760 if (!NT_SUCCESS(Status))
2761 {
2762 TRACE("failed with status 0x%08lx\n", Status);
2763 goto done;
2764 }
2765
2766 /* Check the alias acoount name */
2767 Status = SampCheckAccountName(AccountName, 256);
2768 if (!NT_SUCCESS(Status))
2769 {
2770 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2771 goto done;
2772 }
2773
2774 /* Check if the alias name already exists in the domain */
2775 Status = SampCheckAccountNameInDomain(DomainObject,
2776 AccountName->Buffer);
2777 if (!NT_SUCCESS(Status))
2778 {
2779 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2780 AccountName->Buffer, Status);
2781 goto done;
2782 }
2783
2784 /* Get the fixed domain attributes */
2785 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2786 Status = SampGetObjectAttribute(DomainObject,
2787 L"F",
2788 NULL,
2789 (PVOID)&FixedDomainData,
2790 &ulSize);
2791 if (!NT_SUCCESS(Status))
2792 {
2793 TRACE("failed with status 0x%08lx\n", Status);
2794 goto done;
2795 }
2796
2797 /* Increment the NextRid attribute */
2798 ulRid = FixedDomainData.NextRid;
2799 FixedDomainData.NextRid++;
2800
2801 /* Store the fixed domain attributes */
2802 Status = SampSetObjectAttribute(DomainObject,
2803 L"F",
2804 REG_BINARY,
2805 &FixedDomainData,
2806 ulSize);
2807 if (!NT_SUCCESS(Status))
2808 {
2809 TRACE("failed with status 0x%08lx\n", Status);
2810 goto done;
2811 }
2812
2813 TRACE("RID: %lx\n", ulRid);
2814
2815 /* Convert the RID into a string (hex) */
2816 swprintf(szRid, L"%08lX", ulRid);
2817
2818 /* Create the alias object */
2819 Status = SampCreateDbObject(DomainObject,
2820 L"Aliases",
2821 szRid,
2822 ulRid,
2823 SamDbAliasObject,
2824 DesiredAccess,
2825 &AliasObject);
2826 if (!NT_SUCCESS(Status))
2827 {
2828 TRACE("failed with status 0x%08lx\n", Status);
2829 goto done;
2830 }
2831
2832 /* Add the account name for the alias object */
2833 Status = SampSetAccountNameInDomain(DomainObject,
2834 L"Aliases",
2835 AccountName->Buffer,
2836 ulRid);
2837 if (!NT_SUCCESS(Status))
2838 {
2839 TRACE("failed with status 0x%08lx\n", Status);
2840 goto done;
2841 }
2842
2843 /* Set the Name attribute */
2844 Status = SampSetObjectAttribute(AliasObject,
2845 L"Name",
2846 REG_SZ,
2847 (LPVOID)AccountName->Buffer,
2848 AccountName->MaximumLength);
2849 if (!NT_SUCCESS(Status))
2850 {
2851 TRACE("failed with status 0x%08lx\n", Status);
2852 goto done;
2853 }
2854
2855 /* Set the Description attribute */
2856 Status = SampSetObjectAttribute(AliasObject,
2857 L"Description",
2858 REG_SZ,
2859 EmptyString.Buffer,
2860 EmptyString.MaximumLength);
2861 if (!NT_SUCCESS(Status))
2862 {
2863 TRACE("failed with status 0x%08lx\n", Status);
2864 goto done;
2865 }
2866
2867 if (NT_SUCCESS(Status))
2868 {
2869 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2870 *RelativeId = ulRid;
2871 }
2872
2873 done:
2874 RtlReleaseResource(&SampResource);
2875
2876 TRACE("returns with status 0x%08lx\n", Status);
2877
2878 return Status;
2879 }
2880
2881
2882 /* Function 15 */
2883 NTSTATUS
2884 NTAPI
2885 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2886 IN OUT unsigned long *EnumerationContext,
2887 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2888 IN unsigned long PreferedMaximumLength,
2889 OUT unsigned long *CountReturned)
2890 {
2891 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2892 PSAM_DB_OBJECT DomainObject;
2893 HANDLE AliasesKeyHandle = NULL;
2894 HANDLE NamesKeyHandle = NULL;
2895 WCHAR AliasName[64];
2896 ULONG EnumIndex;
2897 ULONG EnumCount = 0;
2898 ULONG RequiredLength = 0;
2899 ULONG NameLength;
2900 ULONG DataLength;
2901 ULONG Rid;
2902 ULONG i;
2903 BOOLEAN MoreEntries = FALSE;
2904 NTSTATUS Status;
2905
2906 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2907 DomainHandle, EnumerationContext, Buffer,
2908 PreferedMaximumLength, CountReturned);
2909
2910 RtlAcquireResourceShared(&SampResource,
2911 TRUE);
2912
2913 /* Validate the domain handle */
2914 Status = SampValidateDbObject(DomainHandle,
2915 SamDbDomainObject,
2916 DOMAIN_LIST_ACCOUNTS,
2917 &DomainObject);
2918 if (!NT_SUCCESS(Status))
2919 goto done;
2920
2921 Status = SampRegOpenKey(DomainObject->KeyHandle,
2922 L"Aliases",
2923 KEY_READ,
2924 &AliasesKeyHandle);
2925 if (!NT_SUCCESS(Status))
2926 goto done;
2927
2928 Status = SampRegOpenKey(AliasesKeyHandle,
2929 L"Names",
2930 KEY_READ,
2931 &NamesKeyHandle);
2932 if (!NT_SUCCESS(Status))
2933 goto done;
2934
2935 TRACE("Part 1\n");
2936
2937 EnumIndex = *EnumerationContext;
2938
2939 while (TRUE)
2940 {
2941 NameLength = 64 * sizeof(WCHAR);
2942 Status = SampRegEnumerateValue(NamesKeyHandle,
2943 EnumIndex,
2944 AliasName,
2945 &NameLength,
2946 NULL,
2947 NULL,
2948 NULL);
2949 if (!NT_SUCCESS(Status))
2950 {
2951 if (Status == STATUS_NO_MORE_ENTRIES)
2952 Status = STATUS_SUCCESS;
2953 break;
2954 }
2955
2956 TRACE("EnumIndex: %lu\n", EnumIndex);
2957 TRACE("Alias name: %S\n", AliasName);
2958 TRACE("Name length: %lu\n", NameLength);
2959
2960 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2961 {
2962 MoreEntries = TRUE;
2963 break;
2964 }
2965
2966 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2967 EnumCount++;
2968
2969 EnumIndex++;
2970 }
2971
2972 TRACE("EnumCount: %lu\n", EnumCount);
2973 TRACE("RequiredLength: %lu\n", RequiredLength);
2974
2975 if (!NT_SUCCESS(Status))
2976 goto done;
2977
2978 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2979 if (EnumBuffer == NULL)
2980 {
2981 Status = STATUS_INSUFFICIENT_RESOURCES;
2982 goto done;
2983 }
2984
2985 EnumBuffer->EntriesRead = EnumCount;
2986 if (EnumCount == 0)
2987 goto done;
2988
2989 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2990 if (EnumBuffer->Buffer == NULL)
2991 {
2992 Status = STATUS_INSUFFICIENT_RESOURCES;
2993 goto done;
2994 }
2995
2996 TRACE("Part 2\n");
2997
2998 EnumIndex = *EnumerationContext;
2999 for (i = 0; i < EnumCount; i++, EnumIndex++)
3000 {
3001 NameLength = 64 * sizeof(WCHAR);
3002 DataLength = sizeof(ULONG);
3003 Status = SampRegEnumerateValue(NamesKeyHandle,
3004 EnumIndex,
3005 AliasName,
3006 &NameLength,
3007 NULL,
3008 &Rid,
3009 &DataLength);
3010 if (!NT_SUCCESS(Status))
3011 {
3012 if (Status == STATUS_NO_MORE_ENTRIES)
3013 Status = STATUS_SUCCESS;
3014 break;
3015 }
3016
3017 TRACE("EnumIndex: %lu\n", EnumIndex);
3018 TRACE("Alias name: %S\n", AliasName);
3019 TRACE("Name length: %lu\n", NameLength);
3020 TRACE("RID: %lu\n", Rid);
3021
3022 EnumBuffer->Buffer[i].RelativeId = Rid;
3023
3024 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3025 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
3026
3027 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3028 #if 0
3029 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3030 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3031 {
3032 Status = STATUS_INSUFFICIENT_RESOURCES;
3033 goto done;
3034 }
3035
3036 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3037 AliasName,
3038 EnumBuffer->Buffer[i].Name.Length);
3039 #endif
3040 }
3041
3042 done:
3043 if (NT_SUCCESS(Status))
3044 {
3045 *EnumerationContext += EnumCount;
3046 *Buffer = EnumBuffer;
3047 *CountReturned = EnumCount;
3048 }
3049 else
3050 {
3051 *EnumerationContext = 0;
3052 *Buffer = NULL;
3053 *CountReturned = 0;
3054
3055 if (EnumBuffer != NULL)
3056 {
3057 if (EnumBuffer->Buffer != NULL)
3058 {
3059 if (EnumBuffer->EntriesRead != 0)
3060 {
3061 for (i = 0; i < EnumBuffer->EntriesRead; i++)
3062 {
3063 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3064 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3065 }
3066 }
3067
3068 midl_user_free(EnumBuffer->Buffer);
3069 }
3070
3071 midl_user_free(EnumBuffer);
3072 }
3073 }
3074
3075 SampRegCloseKey(&NamesKeyHandle);
3076 SampRegCloseKey(&AliasesKeyHandle);
3077
3078 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
3079 Status = STATUS_MORE_ENTRIES;
3080
3081 RtlReleaseResource(&SampResource);
3082
3083 return Status;
3084 }
3085
3086
3087 /* Function 16 */
3088 NTSTATUS
3089 NTAPI
3090 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3091 IN PSAMPR_PSID_ARRAY SidArray,
3092 OUT PSAMPR_ULONG_ARRAY Membership)
3093 {
3094 PSAM_DB_OBJECT DomainObject;
3095 HANDLE AliasesKeyHandle = NULL;
3096 HANDLE MembersKeyHandle = NULL;
3097 HANDLE MemberKeyHandle = NULL;
3098 LPWSTR MemberSidString = NULL;
3099 PULONG RidArray = NULL;
3100 ULONG MaxSidCount = 0;
3101 ULONG ValueCount;
3102 ULONG DataLength;
3103 ULONG i, j;
3104 NTSTATUS Status;
3105 WCHAR NameBuffer[9];
3106
3107 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3108 DomainHandle, SidArray, Membership);
3109
3110 RtlAcquireResourceShared(&SampResource,
3111 TRUE);
3112
3113 /* Validate the domain handle */
3114 Status = SampValidateDbObject(DomainHandle,
3115 SamDbDomainObject,
3116 DOMAIN_GET_ALIAS_MEMBERSHIP,
3117 &DomainObject);
3118 if (!NT_SUCCESS(Status))
3119 goto done;
3120
3121 Status = SampRegOpenKey(DomainObject->KeyHandle,
3122 L"Aliases",
3123 KEY_READ,
3124 &AliasesKeyHandle);
3125 TRACE("SampRegOpenKey returned %08lX\n", Status);
3126 if (!NT_SUCCESS(Status))
3127 goto done;
3128
3129 Status = SampRegOpenKey(AliasesKeyHandle,
3130 L"Members",
3131 KEY_READ,
3132 &MembersKeyHandle);
3133 TRACE("SampRegOpenKey returned %08lX\n", Status);
3134
3135 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3136 {
3137 Status = STATUS_SUCCESS;
3138 goto done;
3139 }
3140
3141 if (!NT_SUCCESS(Status))
3142 goto done;
3143
3144 for (i = 0; i < SidArray->Count; i++)
3145 {
3146 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3147 TRACE("Open %S\n", MemberSidString);
3148
3149 Status = SampRegOpenKey(MembersKeyHandle,
3150 MemberSidString,
3151 KEY_READ,
3152 &MemberKeyHandle);
3153 TRACE("SampRegOpenKey returned %08lX\n", Status);
3154 if (NT_SUCCESS(Status))
3155 {
3156 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3157 NULL,
3158 &ValueCount);
3159 if (NT_SUCCESS(Status))
3160 {
3161 TRACE("Found %lu values\n", ValueCount);
3162 MaxSidCount += ValueCount;
3163 }
3164
3165 SampRegCloseKey(&MemberKeyHandle);
3166 }
3167
3168 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3169 Status = STATUS_SUCCESS;
3170
3171 LocalFree(MemberSidString);
3172 }
3173
3174 if (MaxSidCount == 0)
3175 {
3176 Status = STATUS_SUCCESS;
3177 goto done;
3178 }
3179
3180 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3181 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3182 if (RidArray == NULL)
3183 {
3184 Status = STATUS_INSUFFICIENT_RESOURCES;
3185 goto done;
3186 }
3187
3188 for (i = 0; i < SidArray->Count; i++)
3189 {
3190 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3191 TRACE("Open %S\n", MemberSidString);
3192
3193 Status = SampRegOpenKey(MembersKeyHandle,
3194 MemberSidString,
3195 KEY_READ,
3196 &MemberKeyHandle);
3197 TRACE("SampRegOpenKey returned %08lX\n", Status);
3198 if (NT_SUCCESS(Status))
3199 {
3200 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3201 NULL,
3202 &ValueCount);
3203 if (NT_SUCCESS(Status))
3204 {
3205 TRACE("Found %lu values\n", ValueCount);
3206
3207 for (j = 0; j < ValueCount; j++)
3208 {
3209 DataLength = 9 * sizeof(WCHAR);
3210 Status = SampRegEnumerateValue(MemberKeyHandle,
3211 j,
3212 NameBuffer,
3213 &DataLength,
3214 NULL,
3215 NULL,
3216 NULL);
3217 if (NT_SUCCESS(Status))
3218 {
3219 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3220 }
3221 }
3222 }
3223
3224 SampRegCloseKey(&MemberKeyHandle);
3225 }
3226
3227 LocalFree(MemberSidString);
3228 }
3229
3230 done:
3231 SampRegCloseKey(&MembersKeyHandle);
3232 SampRegCloseKey(&MembersKeyHandle);
3233 SampRegCloseKey(&AliasesKeyHandle);
3234
3235 if (NT_SUCCESS(Status))
3236 {
3237 Membership->Count = MaxSidCount;
3238 Membership->Element = RidArray;
3239 }
3240 else
3241 {
3242 if (RidArray != NULL)
3243 midl_user_free(RidArray);
3244 }
3245
3246 RtlReleaseResource(&SampResource);
3247
3248 return Status;
3249 }
3250
3251
3252 /* Function 17 */
3253 NTSTATUS
3254 NTAPI
3255 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3256 IN ULONG Count,
3257 IN RPC_UNICODE_STRING Names[],
3258 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3259 OUT PSAMPR_ULONG_ARRAY Use)
3260 {
3261 PSAM_DB_OBJECT DomainObject;
3262 HANDLE AccountsKeyHandle = NULL;
3263 HANDLE NamesKeyHandle = NULL;
3264 ULONG MappedCount = 0;
3265 ULONG DataLength;
3266 ULONG i;
3267 ULONG RelativeId;
3268 NTSTATUS Status;
3269
3270 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3271 DomainHandle, Count, Names, RelativeIds, Use);
3272
3273 RtlAcquireResourceShared(&SampResource,
3274 TRUE);
3275
3276 /* Validate the domain handle */
3277 Status = SampValidateDbObject(DomainHandle,
3278 SamDbDomainObject,
3279 DOMAIN_LOOKUP,
3280 &DomainObject);
3281 if (!NT_SUCCESS(Status))
3282 {
3283 TRACE("failed with status 0x%08lx\n", Status);
3284 goto done;
3285 }
3286
3287 RelativeIds->Count = 0;
3288 Use->Count = 0;
3289
3290 if (Count == 0)
3291 {
3292 Status = STATUS_SUCCESS;
3293 goto done;
3294 }
3295
3296 /* Allocate the relative IDs array */
3297 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3298 if (RelativeIds->Element == NULL)
3299 {
3300 Status = STATUS_INSUFFICIENT_RESOURCES;
3301 goto done;
3302 }
3303
3304 /* Allocate the use array */
3305 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3306 if (Use->Element == NULL)
3307 {
3308 Status = STATUS_INSUFFICIENT_RESOURCES;
3309 goto done;
3310 }
3311
3312 RelativeIds->Count = Count;
3313 Use->Count = Count;
3314
3315 for (i = 0; i < Count; i++)
3316 {
3317 TRACE("Name: %S\n", Names[i].Buffer);
3318
3319 RelativeId = 0;
3320
3321 /* Lookup aliases */
3322 Status = SampRegOpenKey(DomainObject->KeyHandle,
3323 L"Aliases",
3324 KEY_READ,
3325 &AccountsKeyHandle);
3326 if (NT_SUCCESS(Status))
3327 {
3328 Status = SampRegOpenKey(AccountsKeyHandle,
3329 L"Names",
3330 KEY_READ,
3331 &NamesKeyHandle);
3332 if (NT_SUCCESS(Status))
3333 {
3334 DataLength = sizeof(ULONG);
3335 Status = SampRegQueryValue(NamesKeyHandle,
3336 Names[i].Buffer,
3337 NULL,
3338 &RelativeId,
3339 &DataLength);
3340
3341 SampRegCloseKey(&NamesKeyHandle);
3342 }
3343
3344 SampRegCloseKey(&AccountsKeyHandle);
3345 }
3346
3347 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3348 break;
3349
3350 /* Return alias account */
3351 if (NT_SUCCESS(Status) && RelativeId != 0)
3352 {
3353 TRACE("Rid: %lu\n", RelativeId);
3354 RelativeIds->Element[i] = RelativeId;
3355 Use->Element[i] = SidTypeAlias;
3356 MappedCount++;
3357 continue;
3358 }
3359
3360 /* Lookup groups */
3361 Status = SampRegOpenKey(DomainObject->KeyHandle,
3362 L"Groups",
3363 KEY_READ,
3364 &AccountsKeyHandle);
3365 if (NT_SUCCESS(Status))
3366 {
3367 Status = SampRegOpenKey(AccountsKeyHandle,
3368 L"Names",
3369 KEY_READ,
3370 &NamesKeyHandle);
3371 if (NT_SUCCESS(Status))
3372 {
3373 DataLength = sizeof(ULONG);
3374 Status = SampRegQueryValue(NamesKeyHandle,
3375 Names[i].Buffer,
3376 NULL,
3377 &RelativeId,
3378 &DataLength);
3379
3380 SampRegCloseKey(&NamesKeyHandle);
3381 }
3382
3383 SampRegCloseKey(&AccountsKeyHandle);
3384 }
3385
3386 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3387 break;
3388
3389 /* Return group account */
3390 if (NT_SUCCESS(Status) && RelativeId != 0)
3391 {
3392 TRACE("Rid: %lu\n", RelativeId);
3393 RelativeIds->Element[i] = RelativeId;
3394 Use->Element[i] = SidTypeGroup;
3395 MappedCount++;
3396 continue;
3397 }
3398
3399 /* Lookup users */
3400 Status = SampRegOpenKey(DomainObject->KeyHandle,
3401 L"Users",
3402 KEY_READ,
3403 &AccountsKeyHandle);
3404 if (NT_SUCCESS(Status))
3405 {
3406 Status = SampRegOpenKey(AccountsKeyHandle,
3407 L"Names",
3408 KEY_READ,
3409 &NamesKeyHandle);
3410 if (NT_SUCCESS(Status))
3411 {
3412 DataLength = sizeof(ULONG);
3413 Status = SampRegQueryValue(NamesKeyHandle,
3414 Names[i].Buffer,
3415 NULL,
3416 &RelativeId,
3417 &DataLength);
3418
3419 SampRegCloseKey(&NamesKeyHandle);
3420 }
3421
3422 SampRegCloseKey(&AccountsKeyHandle);
3423 }
3424
3425 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3426 break;
3427
3428 /* Return user account */
3429 if (NT_SUCCESS(Status) && RelativeId != 0)
3430 {
3431 TRACE("Rid: %lu\n", RelativeId);
3432 RelativeIds->Element[i] = RelativeId;
3433 Use->Element[i] = SidTypeUser;
3434 MappedCount++;
3435 continue;
3436 }
3437
3438 /* Return unknown account */
3439 RelativeIds->Element[i] = 0;
3440 Use->Element[i] = SidTypeUnknown;
3441 }
3442
3443 done:
3444 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3445 Status = STATUS_SUCCESS;
3446
3447 if (NT_SUCCESS(Status))
3448 {
3449 if (MappedCount == 0)
3450 Status = STATUS_NONE_MAPPED;
3451 else if (MappedCount < Count)
3452 Status = STATUS_SOME_NOT_MAPPED;
3453 }
3454 else
3455 {
3456 if (RelativeIds->Element != NULL)
3457 {
3458 midl_user_free(RelativeIds->Element);
3459 RelativeIds->Element = NULL;
3460 }
3461
3462 RelativeIds->Count = 0;
3463
3464 if (Use->Element != NULL)
3465 {
3466 midl_user_free(Use->Element);
3467 Use->Element = NULL;
3468 }
3469
3470 Use->Count = 0;
3471 }
3472
3473 RtlReleaseResource(&SampResource);
3474
3475 TRACE("Returned Status %lx\n", Status);
3476
3477 return Status;
3478 }
3479
3480
3481 /* Function 18 */
3482 NTSTATUS
3483 NTAPI
3484 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3485 IN ULONG Count,
3486 IN ULONG *RelativeIds,
3487 OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3488 OUT PSAMPR_ULONG_ARRAY Use)
3489 {
3490 PSAM_DB_OBJECT DomainObject;
3491 WCHAR RidString[9];
3492 HANDLE AccountsKeyHandle = NULL;
3493 HANDLE AccountKeyHandle = NULL;
3494 ULONG MappedCount = 0;
3495 ULONG DataLength;
3496 ULONG i;
3497 NTSTATUS Status;
3498
3499 TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3500 DomainHandle, Count, RelativeIds, Names, Use);
3501
3502 RtlAcquireResourceShared(&SampResource,
3503 TRUE);
3504
3505 /* Validate the domain handle */
3506 Status = SampValidateDbObject(DomainHandle,
3507 SamDbDomainObject,
3508 DOMAIN_LOOKUP,
3509 &DomainObject);
3510 if (!NT_SUCCESS(Status))
3511 {
3512 TRACE("failed with status 0x%08lx\n", Status);
3513 goto done;
3514 }
3515
3516 Names->Count = 0;
3517 Use->Count = 0;
3518
3519 if (Count == 0)
3520 {
3521 Status = STATUS_SUCCESS;
3522 goto done;
3523 }
3524
3525 /* Allocate the names array */
3526 Names->Element = midl_user_allocate(Count * sizeof(ULONG));
3527 if (Names->Element == NULL)
3528 {
3529 Status = STATUS_INSUFFICIENT_RESOURCES;
3530 goto done;
3531 }
3532
3533 /* Allocate the use array */
3534 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3535 if (Use->Element == NULL)
3536 {
3537 Status = STATUS_INSUFFICIENT_RESOURCES;
3538 goto done;
3539 }
3540
3541 Names->Count = Count;
3542 Use->Count = Count;
3543
3544 for (i = 0; i < Count; i++)
3545 {
3546 TRACE("RID: %lu\n", RelativeIds[i]);
3547
3548 swprintf(RidString, L"%08lx", RelativeIds[i]);
3549
3550 /* Lookup aliases */
3551 Status = SampRegOpenKey(DomainObject->KeyHandle,
3552 L"Aliases",
3553 KEY_READ,
3554 &AccountsKeyHandle);
3555 if (NT_SUCCESS(Status))
3556 {
3557 Status = SampRegOpenKey(AccountsKeyHandle,
3558 RidString,
3559 KEY_READ,
3560 &AccountKeyHandle);
3561 if (NT_SUCCESS(Status))
3562 {
3563 DataLength = 0;
3564 Status = SampRegQueryValue(AccountKeyHandle,
3565 L"Name",
3566 NULL,
3567 NULL,
3568 &DataLength);
3569 if (NT_SUCCESS(Status))
3570 {
3571 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3572 if (Names->Element[i].Buffer == NULL)
3573 Status = STATUS_INSUFFICIENT_RESOURCES;
3574
3575 if (NT_SUCCESS(Status))
3576 {
3577 Names->Element[i].MaximumLength = (USHORT)DataLength;
3578 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3579
3580 Status = SampRegQueryValue(AccountKeyHandle,
3581 L"Name",
3582 NULL,
3583 Names->Element[i].Buffer,
3584 &DataLength);
3585 }
3586 }
3587
3588 SampRegCloseKey(&AccountKeyHandle);
3589 }
3590
3591 SampRegCloseKey(&AccountsKeyHandle);
3592 }
3593
3594 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3595 break;
3596
3597 /* Return alias account */
3598 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3599 {
3600 TRACE("Name: %S\n", Names->Element[i].Buffer);
3601 Use->Element[i] = SidTypeAlias;
3602 MappedCount++;
3603 continue;
3604 }
3605
3606 /* Lookup groups */
3607 Status = SampRegOpenKey(DomainObject->KeyHandle,
3608 L"Groups",
3609 KEY_READ,
3610 &AccountsKeyHandle);
3611 if (NT_SUCCESS(Status))
3612 {
3613 Status = SampRegOpenKey(AccountsKeyHandle,
3614 RidString,
3615 KEY_READ,
3616 &AccountKeyHandle);
3617 if (NT_SUCCESS(Status))
3618 {
3619 DataLength = 0;
3620 Status = SampRegQueryValue(AccountKeyHandle,
3621 L"Name",
3622 NULL,
3623 NULL,
3624 &DataLength);
3625 if (NT_SUCCESS(Status))
3626 {
3627 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3628 if (Names->Element[i].Buffer == NULL)
3629 Status = STATUS_INSUFFICIENT_RESOURCES;
3630
3631 if (NT_SUCCESS(Status))
3632 {
3633 Names->Element[i].MaximumLength = (USHORT)DataLength;
3634 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3635
3636 Status = SampRegQueryValue(AccountKeyHandle,
3637 L"Name",
3638 NULL,
3639 Names->Element[i].Buffer,
3640 &DataLength);
3641 }
3642 }
3643
3644 SampRegCloseKey(&AccountKeyHandle);
3645 }
3646
3647 SampRegCloseKey(&AccountsKeyHandle);
3648 }
3649
3650 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3651 break;
3652
3653 /* Return group account */
3654 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3655 {
3656 TRACE("Name: %S\n", Names->Element[i].Buffer);
3657 Use->Element[i] = SidTypeGroup;
3658 MappedCount++;
3659 continue;
3660 }
3661
3662 /* Lookup users */
3663 Status = SampRegOpenKey(DomainObject->KeyHandle,
3664 L"Users",
3665 KEY_READ,
3666 &AccountsKeyHandle);
3667 if (NT_SUCCESS(Status))
3668 {
3669 Status = SampRegOpenKey(AccountsKeyHandle,
3670 RidString,
3671 KEY_READ,
3672 &AccountKeyHandle);
3673 if (NT_SUCCESS(Status))
3674 {
3675 DataLength = 0;
3676 Status = SampRegQueryValue(AccountKeyHandle,
3677 L"Name",
3678 NULL,
3679 NULL,
3680 &DataLength);
3681 if (NT_SUCCESS(Status))
3682 {
3683 TRACE("DataLength: %lu\n", DataLength);
3684
3685 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3686 if (Names->Element[i].Buffer == NULL)
3687 Status = STATUS_INSUFFICIENT_RESOURCES;
3688
3689 if (NT_SUCCESS(Status))
3690 {
3691 Names->Element[i].MaximumLength = (USHORT)DataLength;
3692 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3693
3694 Status = SampRegQueryValue(AccountKeyHandle,
3695 L"Name",
3696 NULL,
3697 Names->Element[i].Buffer,
3698 &DataLength);
3699 }
3700 }
3701
3702 SampRegCloseKey(&AccountKeyHandle);
3703 }
3704
3705 SampRegCloseKey(&AccountsKeyHandle);
3706 }
3707
3708 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3709 break;
3710
3711 /* Return user account */
3712 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3713 {
3714 TRACE("Name: %S\n", Names->Element[i].Buffer);
3715 Use->Element[i] = SidTypeUser;
3716 MappedCount++;
3717 continue;
3718 }
3719
3720 /* Return unknown account */
3721 Use->Element[i] = SidTypeUnknown;
3722 }
3723
3724 done:
3725 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3726 Status = STATUS_SUCCESS;
3727
3728 if (NT_SUCCESS(Status))
3729 {
3730 if (MappedCount == 0)
3731 Status = STATUS_NONE_MAPPED;
3732 else if (MappedCount < Count)
3733 Status = STATUS_SOME_NOT_MAPPED;
3734 }
3735 else
3736 {
3737 if (Names->Element != NULL)
3738 {
3739 for (i = 0; i < Count; i++)
3740 {
3741 if (Names->Element[i].Buffer != NULL)
3742 midl_user_free(Names->Element[i].Buffer);
3743 }
3744
3745 midl_user_free(Names->Element);
3746 Names->Element = NULL;
3747 }
3748
3749 Names->Count = 0;
3750
3751 if (Use->Element != NULL)
3752 {
3753 midl_user_free(Use->Element);
3754 Use->Element = NULL;
3755 }
3756
3757 Use->Count = 0;
3758 }
3759
3760 RtlReleaseResource(&SampResource);
3761
3762 return Status;
3763 }
3764
3765
3766 /* Function 19 */
3767 NTSTATUS
3768 NTAPI
3769 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
3770 IN ACCESS_MASK DesiredAccess,
3771 IN unsigned long GroupId,
3772 OUT SAMPR_HANDLE *GroupHandle)
3773 {
3774 PSAM_DB_OBJECT DomainObject;
3775 PSAM_DB_OBJECT GroupObject;
3776 WCHAR szRid[9];
3777 NTSTATUS Status;
3778
3779 TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
3780 DomainHandle, DesiredAccess, GroupId, GroupHandle);
3781
3782 /* Map generic access rights */
3783 RtlMapGenericMask(&DesiredAccess,
3784 &GroupMapping);
3785
3786 RtlAcquireResourceShared(&SampResource,
3787 TRUE);
3788
3789 /* Validate the domain handle */
3790 Status = SampValidateDbObject(DomainHandle,
3791 SamDbDomainObject,
3792 DOMAIN_LOOKUP,
3793 &DomainObject);
3794 if (!NT_SUCCESS(Status))
3795 {
3796 TRACE("failed with status 0x%08lx\n", Status);
3797 goto done;
3798 }
3799
3800 /* Convert the RID into a string (hex) */
3801 swprintf(szRid, L"%08lX", GroupId);
3802
3803 /* Create the group object */
3804 Status = SampOpenDbObject(DomainObject,
3805 L"Groups",
3806 szRid,
3807 GroupId,
3808 SamDbGroupObject,
3809 DesiredAccess,
3810 &GroupObject);
3811 if (!NT_SUCCESS(Status))
3812 {
3813 TRACE("failed with status 0x%08lx\n", Status);
3814 goto done;
3815 }
3816
3817 *GroupHandle = (SAMPR_HANDLE)GroupObject;
3818
3819 done:
3820 RtlReleaseResource(&SampResource);
3821
3822 return Status;
3823 }
3824
3825
3826 static NTSTATUS
3827 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
3828 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3829 {
3830 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3831 SAM_GROUP_FIXED_DATA FixedData;
3832 ULONG MembersLength = 0;
3833 ULONG Length = 0;
3834 NTSTATUS Status;
3835
3836 *Buffer = NULL;
3837
3838 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3839 if (InfoBuffer == NULL)
3840 return STATUS_INSUFFICIENT_RESOURCES;
3841
3842 Status = SampGetObjectAttributeString(GroupObject,
3843 L"Name",
3844 &InfoBuffer->General.Name);
3845 if (!NT_SUCCESS(Status))
3846 {
3847 TRACE("Status 0x%08lx\n", Status);
3848 goto done;
3849 }
3850
3851 Status = SampGetObjectAttributeString(GroupObject,
3852 L"Description",
3853 &InfoBuffer->General.AdminComment);
3854 if (!NT_SUCCESS(Status))
3855 {
3856 TRACE("Status 0x%08lx\n", Status);
3857 goto done;
3858 }
3859
3860 Length = sizeof(SAM_GROUP_FIXED_DATA);
3861 Status = SampGetObjectAttribute(GroupObject,
3862 L"F",