3b42f573f4d619584675c0dd55aef2683b01faac
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Security Account Manager (SAM) Server
4 * FILE: reactos/dll/win32/samsrv/samrpc.c
5 * PURPOSE: RPC interface functions
6 *
7 * PROGRAMMERS: Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "samsrv.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
15
16 /* GLOBALS *******************************************************************/
17
18 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
19
20 static GENERIC_MAPPING ServerMapping =
21 {
22 SAM_SERVER_READ,
23 SAM_SERVER_WRITE,
24 SAM_SERVER_EXECUTE,
25 SAM_SERVER_ALL_ACCESS
26 };
27
28 static GENERIC_MAPPING DomainMapping =
29 {
30 DOMAIN_READ,
31 DOMAIN_WRITE,
32 DOMAIN_EXECUTE,
33 DOMAIN_ALL_ACCESS
34 };
35
36 static GENERIC_MAPPING AliasMapping =
37 {
38 ALIAS_READ,
39 ALIAS_WRITE,
40 ALIAS_EXECUTE,
41 ALIAS_ALL_ACCESS
42 };
43
44 static GENERIC_MAPPING GroupMapping =
45 {
46 GROUP_READ,
47 GROUP_WRITE,
48 GROUP_EXECUTE,
49 GROUP_ALL_ACCESS
50 };
51
52 static GENERIC_MAPPING UserMapping =
53 {
54 USER_READ,
55 USER_WRITE,
56 USER_EXECUTE,
57 USER_ALL_ACCESS
58 };
59
60 PGENERIC_MAPPING pServerMapping = &ServerMapping;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 static
66 LARGE_INTEGER
67 SampAddRelativeTimeToTime(IN LARGE_INTEGER AbsoluteTime,
68 IN LARGE_INTEGER RelativeTime)
69 {
70 LARGE_INTEGER NewTime;
71
72 NewTime.QuadPart = AbsoluteTime.QuadPart - RelativeTime.QuadPart;
73
74 if (NewTime.QuadPart < 0)
75 NewTime.QuadPart = 0;
76
77 return NewTime;
78 }
79
80
81 VOID
82 SampStartRpcServer(VOID)
83 {
84 RPC_STATUS Status;
85
86 TRACE("SampStartRpcServer() called\n");
87
88 Status = RpcServerUseProtseqEpW(L"ncacn_np",
89 10,
90 L"\\pipe\\samr",
91 NULL);
92 if (Status != RPC_S_OK)
93 {
94 WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
95 return;
96 }
97
98 Status = RpcServerRegisterIf(samr_v1_0_s_ifspec,
99 NULL,
100 NULL);
101 if (Status != RPC_S_OK)
102 {
103 WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
104 return;
105 }
106
107 Status = RpcServerListen(1, 20, TRUE);
108 if (Status != RPC_S_OK)
109 {
110 WARN("RpcServerListen() failed (Status %lx)\n", Status);
111 return;
112 }
113
114 TRACE("SampStartRpcServer() done\n");
115 }
116
117
118 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
119 {
120 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
121 }
122
123
124 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
125 {
126 HeapFree(GetProcessHeap(), 0, ptr);
127 }
128
129
130 void __RPC_USER SAMPR_HANDLE_rundown(SAMPR_HANDLE hHandle)
131 {
132 }
133
134
135 /* Function 0 */
136 NTSTATUS
137 NTAPI
138 SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
139 OUT SAMPR_HANDLE *ServerHandle,
140 IN ACCESS_MASK DesiredAccess)
141 {
142 PSAM_DB_OBJECT ServerObject;
143 NTSTATUS Status;
144
145 TRACE("SamrConnect(%p %p %lx)\n",
146 ServerName, ServerHandle, DesiredAccess);
147
148 RtlAcquireResourceShared(&SampResource,
149 TRUE);
150
151 /* Map generic access rights */
152 RtlMapGenericMask(&DesiredAccess,
153 &ServerMapping);
154
155 /* Open the Server Object */
156 Status = SampOpenDbObject(NULL,
157 NULL,
158 L"SAM",
159 0,
160 SamDbServerObject,
161 DesiredAccess,
162 &ServerObject);
163 if (NT_SUCCESS(Status))
164 *ServerHandle = (SAMPR_HANDLE)ServerObject;
165
166 RtlReleaseResource(&SampResource);
167
168 TRACE("SamrConnect done (Status 0x%08lx)\n", Status);
169
170 return Status;
171 }
172
173
174 /* Function 1 */
175 NTSTATUS
176 NTAPI
177 SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle)
178 {
179 PSAM_DB_OBJECT DbObject;
180 NTSTATUS Status = STATUS_SUCCESS;
181
182 TRACE("SamrCloseHandle(%p)\n", SamHandle);
183
184 RtlAcquireResourceShared(&SampResource,
185 TRUE);
186
187 Status = SampValidateDbObject(*SamHandle,
188 SamDbIgnoreObject,
189 0,
190 &DbObject);
191 if (Status == STATUS_SUCCESS)
192 {
193 Status = SampCloseDbObject(DbObject);
194 *SamHandle = NULL;
195 }
196
197 RtlReleaseResource(&SampResource);
198
199 TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
200
201 return Status;
202 }
203
204
205 /* Function 2 */
206 NTSTATUS
207 NTAPI
208 SamrSetSecurityObject(IN SAMPR_HANDLE ObjectHandle,
209 IN SECURITY_INFORMATION SecurityInformation,
210 IN PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
211 {
212 UNIMPLEMENTED;
213 return STATUS_NOT_IMPLEMENTED;
214 }
215
216
217 /* Function 3 */
218 NTSTATUS
219 NTAPI
220 SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
221 IN SECURITY_INFORMATION SecurityInformation,
222 OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
223 {
224 UNIMPLEMENTED;
225 return STATUS_NOT_IMPLEMENTED;
226 }
227
228
229 /* Function 4 */
230 NTSTATUS
231 NTAPI
232 SamrShutdownSamServer(IN SAMPR_HANDLE ServerHandle)
233 {
234 PSAM_DB_OBJECT ServerObject;
235 NTSTATUS Status;
236
237 TRACE("(%p)\n", ServerHandle);
238
239 RtlAcquireResourceShared(&SampResource,
240 TRUE);
241
242 /* Validate the server handle */
243 Status = SampValidateDbObject(ServerHandle,
244 SamDbServerObject,
245 SAM_SERVER_SHUTDOWN,
246 &ServerObject);
247
248 RtlReleaseResource(&SampResource);
249
250 if (!NT_SUCCESS(Status))
251 return Status;
252
253 /* Shut the server down */
254 RpcMgmtStopServerListening(0);
255
256 return STATUS_SUCCESS;
257 }
258
259
260 /* Function 5 */
261 NTSTATUS
262 NTAPI
263 SamrLookupDomainInSamServer(IN SAMPR_HANDLE ServerHandle,
264 IN PRPC_UNICODE_STRING Name,
265 OUT PRPC_SID *DomainId)
266 {
267 PSAM_DB_OBJECT ServerObject;
268 HANDLE DomainsKeyHandle = NULL;
269 HANDLE DomainKeyHandle = NULL;
270 WCHAR DomainKeyName[64];
271 ULONG Index;
272 WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
273 UNICODE_STRING DomainName;
274 ULONG Length;
275 BOOL Found = FALSE;
276 NTSTATUS Status;
277
278 TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
279 ServerHandle, Name, DomainId);
280
281 RtlAcquireResourceShared(&SampResource,
282 TRUE);
283
284 /* Validate the server handle */
285 Status = SampValidateDbObject(ServerHandle,
286 SamDbServerObject,
287 SAM_SERVER_LOOKUP_DOMAIN,
288 &ServerObject);
289 if (!NT_SUCCESS(Status))
290 goto done;
291
292 *DomainId = NULL;
293
294 Status = SampRegOpenKey(ServerObject->KeyHandle,
295 L"Domains",
296 KEY_READ,
297 &DomainsKeyHandle);
298 if (!NT_SUCCESS(Status))
299 goto done;
300
301 Index = 0;
302 while (Found == FALSE)
303 {
304 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
305 Index,
306 64,
307 DomainKeyName);
308 if (!NT_SUCCESS(Status))
309 {
310 if (Status == STATUS_NO_MORE_ENTRIES)
311 Status = STATUS_NO_SUCH_DOMAIN;
312 break;
313 }
314
315 TRACE("Domain key name: %S\n", DomainKeyName);
316
317 Status = SampRegOpenKey(DomainsKeyHandle,
318 DomainKeyName,
319 KEY_READ,
320 &DomainKeyHandle);
321 if (NT_SUCCESS(Status))
322 {
323 Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
324 Status = SampRegQueryValue(DomainKeyHandle,
325 L"Name",
326 NULL,
327 (PVOID)&DomainNameString,
328 &Length);
329 if (NT_SUCCESS(Status))
330 {
331 TRACE("Domain name: %S\n", DomainNameString);
332
333 RtlInitUnicodeString(&DomainName,
334 DomainNameString);
335 if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
336 {
337 TRACE("Found it!\n");
338 Found = TRUE;
339
340 Status = SampRegQueryValue(DomainKeyHandle,
341 L"SID",
342 NULL,
343 NULL,
344 &Length);
345 if (NT_SUCCESS(Status))
346 {
347 *DomainId = midl_user_allocate(Length);
348
349 SampRegQueryValue(DomainKeyHandle,
350 L"SID",
351 NULL,
352 (PVOID)*DomainId,
353 &Length);
354
355 Status = STATUS_SUCCESS;
356 break;
357 }
358 }
359 }
360
361 SampRegCloseKey(&DomainKeyHandle);
362 }
363
364 Index++;
365 }
366
367 done:
368 SampRegCloseKey(&DomainKeyHandle);
369 SampRegCloseKey(&DomainsKeyHandle);
370
371 RtlReleaseResource(&SampResource);
372
373 return Status;
374 }
375
376
377 /* Function 6 */
378 NTSTATUS
379 NTAPI
380 SamrEnumerateDomainsInSamServer(IN SAMPR_HANDLE ServerHandle,
381 IN OUT unsigned long *EnumerationContext,
382 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
383 IN ULONG PreferedMaximumLength,
384 OUT PULONG CountReturned)
385 {
386 PSAM_DB_OBJECT ServerObject;
387 WCHAR DomainKeyName[64];
388 HANDLE DomainsKeyHandle = NULL;
389 HANDLE DomainKeyHandle = NULL;
390 ULONG EnumIndex;
391 ULONG EnumCount;
392 ULONG RequiredLength;
393 ULONG DataLength;
394 ULONG i;
395 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
396 NTSTATUS Status;
397
398 TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
399 ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
400 CountReturned);
401
402 RtlAcquireResourceShared(&SampResource,
403 TRUE);
404
405 /* Validate the server handle */
406 Status = SampValidateDbObject(ServerHandle,
407 SamDbServerObject,
408 SAM_SERVER_ENUMERATE_DOMAINS,
409 &ServerObject);
410 if (!NT_SUCCESS(Status))
411 goto done;
412
413 Status = SampRegOpenKey(ServerObject->KeyHandle,
414 L"Domains",
415 KEY_READ,
416 &DomainsKeyHandle);
417 if (!NT_SUCCESS(Status))
418 goto done;
419
420 EnumIndex = *EnumerationContext;
421 EnumCount = 0;
422 RequiredLength = 0;
423
424 while (TRUE)
425 {
426 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
427 EnumIndex,
428 64 * sizeof(WCHAR),
429 DomainKeyName);
430 if (!NT_SUCCESS(Status))
431 break;
432
433 TRACE("EnumIndex: %lu\n", EnumIndex);
434 TRACE("Domain key name: %S\n", DomainKeyName);
435
436 Status = SampRegOpenKey(DomainsKeyHandle,
437 DomainKeyName,
438 KEY_READ,
439 &DomainKeyHandle);
440 TRACE("SampRegOpenKey returned %08lX\n", Status);
441 if (NT_SUCCESS(Status))
442 {
443 DataLength = 0;
444 Status = SampRegQueryValue(DomainKeyHandle,
445 L"Name",
446 NULL,
447 NULL,
448 &DataLength);
449 TRACE("SampRegQueryValue returned %08lX\n", Status);
450 if (NT_SUCCESS(Status))
451 {
452 TRACE("Data length: %lu\n", DataLength);
453
454 if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
455 break;
456
457 RequiredLength += (DataLength + sizeof(UNICODE_STRING));
458 EnumCount++;
459 }
460
461 SampRegCloseKey(&DomainKeyHandle);
462 }
463
464 EnumIndex++;
465 }
466
467 TRACE("EnumCount: %lu\n", EnumCount);
468 TRACE("RequiredLength: %lu\n", RequiredLength);
469
470 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
471 if (EnumBuffer == NULL)
472 {
473 Status = STATUS_INSUFFICIENT_RESOURCES;
474 goto done;
475 }
476
477 EnumBuffer->EntriesRead = EnumCount;
478 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
479 if (EnumBuffer->Buffer == NULL)
480 {
481 Status = STATUS_INSUFFICIENT_RESOURCES;
482 goto done;
483 }
484
485 EnumIndex = *EnumerationContext;
486 for (i = 0; i < EnumCount; i++, EnumIndex++)
487 {
488 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
489 EnumIndex,
490 64 * sizeof(WCHAR),
491 DomainKeyName);
492 if (!NT_SUCCESS(Status))
493 break;
494
495 TRACE("EnumIndex: %lu\n", EnumIndex);
496 TRACE("Domain key name: %S\n", DomainKeyName);
497
498 Status = SampRegOpenKey(DomainsKeyHandle,
499 DomainKeyName,
500 KEY_READ,
501 &DomainKeyHandle);
502 TRACE("SampRegOpenKey returned %08lX\n", Status);
503 if (NT_SUCCESS(Status))
504 {
505 DataLength = 0;
506 Status = SampRegQueryValue(DomainKeyHandle,
507 L"Name",
508 NULL,
509 NULL,
510 &DataLength);
511 TRACE("SampRegQueryValue returned %08lX\n", Status);
512 if (NT_SUCCESS(Status))
513 {
514 EnumBuffer->Buffer[i].RelativeId = 0;
515 EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
516 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
517 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
518 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
519 {
520 SampRegCloseKey(&DomainKeyHandle);
521 Status = STATUS_INSUFFICIENT_RESOURCES;
522 goto done;
523 }
524
525 Status = SampRegQueryValue(DomainKeyHandle,
526 L"Name",
527 NULL,
528 EnumBuffer->Buffer[i].Name.Buffer,
529 &DataLength);
530 TRACE("SampRegQueryValue returned %08lX\n", Status);
531 if (NT_SUCCESS(Status))
532 {
533 TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
534 }
535 }
536
537 SampRegCloseKey(&DomainKeyHandle);
538
539 if (!NT_SUCCESS(Status))
540 goto done;
541 }
542 }
543
544 if (NT_SUCCESS(Status))
545 {
546 *EnumerationContext += EnumCount;
547 *Buffer = EnumBuffer;
548 *CountReturned = EnumCount;
549 }
550
551 done:
552 SampRegCloseKey(&DomainKeyHandle);
553 SampRegCloseKey(&DomainsKeyHandle);
554
555 if (!NT_SUCCESS(Status))
556 {
557 *EnumerationContext = 0;
558 *Buffer = NULL;
559 *CountReturned = 0;
560
561 if (EnumBuffer != NULL)
562 {
563 if (EnumBuffer->Buffer != NULL)
564 {
565 if (EnumBuffer->EntriesRead != 0)
566 {
567 for (i = 0; i < EnumBuffer->EntriesRead; i++)
568 {
569 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
570 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
571 }
572 }
573
574 midl_user_free(EnumBuffer->Buffer);
575 }
576
577 midl_user_free(EnumBuffer);
578 }
579 }
580
581 RtlReleaseResource(&SampResource);
582
583 return Status;
584 }
585
586
587 /* Function 7 */
588 NTSTATUS
589 NTAPI
590 SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
591 IN ACCESS_MASK DesiredAccess,
592 IN PRPC_SID DomainId,
593 OUT SAMPR_HANDLE *DomainHandle)
594 {
595 PSAM_DB_OBJECT ServerObject;
596 PSAM_DB_OBJECT DomainObject;
597 NTSTATUS Status;
598
599 TRACE("SamrOpenDomain(%p %lx %p %p)\n",
600 ServerHandle, DesiredAccess, DomainId, DomainHandle);
601
602 /* Map generic access rights */
603 RtlMapGenericMask(&DesiredAccess,
604 &DomainMapping);
605
606 RtlAcquireResourceShared(&SampResource,
607 TRUE);
608
609 /* Validate the server handle */
610 Status = SampValidateDbObject(ServerHandle,
611 SamDbServerObject,
612 SAM_SERVER_LOOKUP_DOMAIN,
613 &ServerObject);
614 if (!NT_SUCCESS(Status))
615 return Status;
616
617 /* Validate the Domain SID */
618 if ((DomainId->Revision != SID_REVISION) ||
619 (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
620 (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
621 return STATUS_INVALID_PARAMETER;
622
623 /* Open the domain object */
624 if ((DomainId->SubAuthorityCount == 1) &&
625 (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
626 {
627 /* Builtin domain object */
628 TRACE("Opening the builtin domain object.\n");
629
630 Status = SampOpenDbObject(ServerObject,
631 L"Domains",
632 L"Builtin",
633 0,
634 SamDbDomainObject,
635 DesiredAccess,
636 &DomainObject);
637 }
638 else if ((DomainId->SubAuthorityCount == 4) &&
639 (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
640 {
641 /* Account domain object */
642 TRACE("Opening the account domain object.\n");
643
644 /* FIXME: Check the account domain sub authorities!!! */
645
646 Status = SampOpenDbObject(ServerObject,
647 L"Domains",
648 L"Account",
649 0,
650 SamDbDomainObject,
651 DesiredAccess,
652 &DomainObject);
653 }
654 else
655 {
656 /* No vaild domain SID */
657 Status = STATUS_INVALID_PARAMETER;
658 }
659
660 if (NT_SUCCESS(Status))
661 *DomainHandle = (SAMPR_HANDLE)DomainObject;
662
663 RtlReleaseResource(&SampResource);
664
665 TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
666
667 return Status;
668 }
669
670
671 static NTSTATUS
672 SampQueryDomainPassword(PSAM_DB_OBJECT DomainObject,
673 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
674 {
675 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
676 SAM_DOMAIN_FIXED_DATA FixedData;
677 ULONG Length = 0;
678 NTSTATUS Status;
679
680 *Buffer = NULL;
681
682 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
683 if (InfoBuffer == NULL)
684 return STATUS_INSUFFICIENT_RESOURCES;
685
686 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
687 Status = SampGetObjectAttribute(DomainObject,
688 L"F",
689 NULL,
690 (PVOID)&FixedData,
691 &Length);
692 if (!NT_SUCCESS(Status))
693 goto done;
694
695 InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
696 InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
697 InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
698 InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
699 InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
700 InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
701 InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
702
703 *Buffer = InfoBuffer;
704
705 done:
706 if (!NT_SUCCESS(Status))
707 {
708 if (InfoBuffer != NULL)
709 {
710 midl_user_free(InfoBuffer);
711 }
712 }
713
714 return Status;
715 }
716
717
718 static NTSTATUS
719 SampGetNumberOfAccounts(PSAM_DB_OBJECT DomainObject,
720 LPCWSTR AccountType,
721 PULONG Count)
722 {
723 HANDLE AccountKeyHandle = NULL;
724 HANDLE NamesKeyHandle = NULL;
725 NTSTATUS Status;
726
727 *Count = 0;
728
729 Status = SampRegOpenKey(DomainObject->KeyHandle,
730 AccountType,
731 KEY_READ,
732 &AccountKeyHandle);
733 if (!NT_SUCCESS(Status))
734 return Status;
735
736 Status = SampRegOpenKey(AccountKeyHandle,
737 L"Names",
738 KEY_READ,
739 &NamesKeyHandle);
740 if (!NT_SUCCESS(Status))
741 goto done;
742
743 Status = SampRegQueryKeyInfo(NamesKeyHandle,
744 NULL,
745 Count);
746
747 done:
748 SampRegCloseKey(&NamesKeyHandle);
749 SampRegCloseKey(&AccountKeyHandle);
750
751 return Status;
752 }
753
754
755 static NTSTATUS
756 SampQueryDomainGeneral(PSAM_DB_OBJECT DomainObject,
757 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
758 {
759 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
760 SAM_DOMAIN_FIXED_DATA FixedData;
761 ULONG Length = 0;
762 NTSTATUS Status;
763
764 *Buffer = NULL;
765
766 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
767 if (InfoBuffer == NULL)
768 return STATUS_INSUFFICIENT_RESOURCES;
769
770 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
771 Status = SampGetObjectAttribute(DomainObject,
772 L"F",
773 NULL,
774 (PVOID)&FixedData,
775 &Length);
776 if (!NT_SUCCESS(Status))
777 goto done;
778
779 InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
780 InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
781 InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
782 InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
783 InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
784 InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
785 InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
786
787 /* Get the OemInformation string */
788 Status = SampGetObjectAttributeString(DomainObject,
789 L"OemInformation",
790 &InfoBuffer->General.OemInformation);
791 if (!NT_SUCCESS(Status))
792 {
793 TRACE("Status 0x%08lx\n", Status);
794 goto done;
795 }
796
797 /* Get the Name string */
798 Status = SampGetObjectAttributeString(DomainObject,
799 L"Name",
800 &InfoBuffer->General.DomainName);
801 if (!NT_SUCCESS(Status))
802 {
803 TRACE("Status 0x%08lx\n", Status);
804 goto done;
805 }
806
807 /* Get the ReplicaSourceNodeName string */
808 Status = SampGetObjectAttributeString(DomainObject,
809 L"ReplicaSourceNodeName",
810 &InfoBuffer->General.ReplicaSourceNodeName);
811 if (!NT_SUCCESS(Status))
812 {
813 TRACE("Status 0x%08lx\n", Status);
814 goto done;
815 }
816
817 /* Get the number of Users in the Domain */
818 Status = SampGetNumberOfAccounts(DomainObject,
819 L"Users",
820 &InfoBuffer->General.UserCount);
821 if (!NT_SUCCESS(Status))
822 {
823 TRACE("Status 0x%08lx\n", Status);
824 goto done;
825 }
826
827 /* Get the number of Groups in the Domain */
828 Status = SampGetNumberOfAccounts(DomainObject,
829 L"Groups",
830 &InfoBuffer->General.GroupCount);
831 if (!NT_SUCCESS(Status))
832 {
833 TRACE("Status 0x%08lx\n", Status);
834 goto done;
835 }
836
837 /* Get the number of Aliases in the Domain */
838 Status = SampGetNumberOfAccounts(DomainObject,
839 L"Aliases",
840 &InfoBuffer->General.AliasCount);
841 if (!NT_SUCCESS(Status))
842 {
843 TRACE("Status 0x%08lx\n", Status);
844 goto done;
845 }
846
847 *Buffer = InfoBuffer;
848
849 done:
850 if (!NT_SUCCESS(Status))
851 {
852 if (InfoBuffer != NULL)
853 {
854 if (InfoBuffer->General.OemInformation.Buffer != NULL)
855 midl_user_free(InfoBuffer->General.OemInformation.Buffer);
856
857 if (InfoBuffer->General.DomainName.Buffer != NULL)
858 midl_user_free(InfoBuffer->General.DomainName.Buffer);
859
860 if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
861 midl_user_free(InfoBuffer->General.ReplicaSourceNodeName.Buffer);
862
863 midl_user_free(InfoBuffer);
864 }
865 }
866
867 return Status;
868 }
869
870
871 static NTSTATUS
872 SampQueryDomainLogoff(PSAM_DB_OBJECT DomainObject,
873 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
874 {
875 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
876 SAM_DOMAIN_FIXED_DATA FixedData;
877 ULONG Length = 0;
878 NTSTATUS Status;
879
880 *Buffer = NULL;
881
882 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
883 if (InfoBuffer == NULL)
884 return STATUS_INSUFFICIENT_RESOURCES;
885
886 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
887 Status = SampGetObjectAttribute(DomainObject,
888 L"F",
889 NULL,
890 (PVOID)&FixedData,
891 &Length);
892 if (!NT_SUCCESS(Status))
893 goto done;
894
895 InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
896 InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
897
898 *Buffer = InfoBuffer;
899
900 done:
901 if (!NT_SUCCESS(Status))
902 {
903 if (InfoBuffer != NULL)
904 {
905 midl_user_free(InfoBuffer);
906 }
907 }
908
909 return Status;
910 }
911
912
913 static NTSTATUS
914 SampQueryDomainOem(PSAM_DB_OBJECT DomainObject,
915 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
916 {
917 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
918 NTSTATUS Status;
919
920 *Buffer = NULL;
921
922 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
923 if (InfoBuffer == NULL)
924 return STATUS_INSUFFICIENT_RESOURCES;
925
926 /* Get the OemInformation string */
927 Status = SampGetObjectAttributeString(DomainObject,
928 L"OemInformation",
929 &InfoBuffer->Oem.OemInformation);
930 if (!NT_SUCCESS(Status))
931 {
932 TRACE("Status 0x%08lx\n", Status);
933 goto done;
934 }
935
936 *Buffer = InfoBuffer;
937
938 done:
939 if (!NT_SUCCESS(Status))
940 {
941 if (InfoBuffer != NULL)
942 {
943 if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
944 midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
945
946 midl_user_free(InfoBuffer);
947 }
948 }
949
950 return Status;
951 }
952
953
954 static NTSTATUS
955 SampQueryDomainName(PSAM_DB_OBJECT DomainObject,
956 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
957 {
958 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
959 NTSTATUS Status;
960
961 *Buffer = NULL;
962
963 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
964 if (InfoBuffer == NULL)
965 return STATUS_INSUFFICIENT_RESOURCES;
966
967 /* Get the Name string */
968 Status = SampGetObjectAttributeString(DomainObject,
969 L"Name",
970 &InfoBuffer->Name.DomainName);
971 if (!NT_SUCCESS(Status))
972 {
973 TRACE("Status 0x%08lx\n", Status);
974 goto done;
975 }
976
977 *Buffer = InfoBuffer;
978
979 done:
980 if (!NT_SUCCESS(Status))
981 {
982 if (InfoBuffer != NULL)
983 {
984 if (InfoBuffer->Name.DomainName.Buffer != NULL)
985 midl_user_free(InfoBuffer->Name.DomainName.Buffer);
986
987 midl_user_free(InfoBuffer);
988 }
989 }
990
991 return Status;
992 }
993
994
995 static NTSTATUS
996 SampQueryDomainReplication(PSAM_DB_OBJECT DomainObject,
997 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
998 {
999 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1000 NTSTATUS Status;
1001
1002 *Buffer = NULL;
1003
1004 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1005 if (InfoBuffer == NULL)
1006 return STATUS_INSUFFICIENT_RESOURCES;
1007
1008 /* Get the ReplicaSourceNodeName string */
1009 Status = SampGetObjectAttributeString(DomainObject,
1010 L"ReplicaSourceNodeName",
1011 &InfoBuffer->Replication.ReplicaSourceNodeName);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 TRACE("Status 0x%08lx\n", Status);
1015 goto done;
1016 }
1017
1018 *Buffer = InfoBuffer;
1019
1020 done:
1021 if (!NT_SUCCESS(Status))
1022 {
1023 if (InfoBuffer != NULL)
1024 {
1025 if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
1026 midl_user_free(InfoBuffer->Replication.ReplicaSourceNodeName.Buffer);
1027
1028 midl_user_free(InfoBuffer);
1029 }
1030 }
1031
1032 return Status;
1033 }
1034
1035
1036 static NTSTATUS
1037 SampQueryDomainServerRole(PSAM_DB_OBJECT DomainObject,
1038 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1039 {
1040 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1041 SAM_DOMAIN_FIXED_DATA FixedData;
1042 ULONG Length = 0;
1043 NTSTATUS Status;
1044
1045 *Buffer = NULL;
1046
1047 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1048 if (InfoBuffer == NULL)
1049 return STATUS_INSUFFICIENT_RESOURCES;
1050
1051 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1052 Status = SampGetObjectAttribute(DomainObject,
1053 L"F",
1054 NULL,
1055 (PVOID)&FixedData,
1056 &Length);
1057 if (!NT_SUCCESS(Status))
1058 goto done;
1059
1060 InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
1061
1062 *Buffer = InfoBuffer;
1063
1064 done:
1065 if (!NT_SUCCESS(Status))
1066 {
1067 if (InfoBuffer != NULL)
1068 {
1069 midl_user_free(InfoBuffer);
1070 }
1071 }
1072
1073 return Status;
1074 }
1075
1076
1077 static NTSTATUS
1078 SampQueryDomainModified(PSAM_DB_OBJECT DomainObject,
1079 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1080 {
1081 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1082 SAM_DOMAIN_FIXED_DATA FixedData;
1083 ULONG Length = 0;
1084 NTSTATUS Status;
1085
1086 *Buffer = NULL;
1087
1088 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1089 if (InfoBuffer == NULL)
1090 return STATUS_INSUFFICIENT_RESOURCES;
1091
1092 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1093 Status = SampGetObjectAttribute(DomainObject,
1094 L"F",
1095 NULL,
1096 (PVOID)&FixedData,
1097 &Length);
1098 if (!NT_SUCCESS(Status))
1099 goto done;
1100
1101 InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1102 InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1103 InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1104 InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1105
1106 *Buffer = InfoBuffer;
1107
1108 done:
1109 if (!NT_SUCCESS(Status))
1110 {
1111 if (InfoBuffer != NULL)
1112 {
1113 midl_user_free(InfoBuffer);
1114 }
1115 }
1116
1117 return Status;
1118 }
1119
1120
1121 static NTSTATUS
1122 SampQueryDomainState(PSAM_DB_OBJECT DomainObject,
1123 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1124 {
1125 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1126 SAM_DOMAIN_FIXED_DATA FixedData;
1127 ULONG Length = 0;
1128 NTSTATUS Status;
1129
1130 *Buffer = NULL;
1131
1132 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1133 if (InfoBuffer == NULL)
1134 return STATUS_INSUFFICIENT_RESOURCES;
1135
1136 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1137 Status = SampGetObjectAttribute(DomainObject,
1138 L"F",
1139 NULL,
1140 (PVOID)&FixedData,
1141 &Length);
1142 if (!NT_SUCCESS(Status))
1143 goto done;
1144
1145 InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1146
1147 *Buffer = InfoBuffer;
1148
1149 done:
1150 if (!NT_SUCCESS(Status))
1151 {
1152 if (InfoBuffer != NULL)
1153 {
1154 midl_user_free(InfoBuffer);
1155 }
1156 }
1157
1158 return Status;
1159 }
1160
1161
1162 static NTSTATUS
1163 SampQueryDomainGeneral2(PSAM_DB_OBJECT DomainObject,
1164 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1165 {
1166 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1167 SAM_DOMAIN_FIXED_DATA FixedData;
1168 ULONG Length = 0;
1169 NTSTATUS Status;
1170
1171 *Buffer = NULL;
1172
1173 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1174 if (InfoBuffer == NULL)
1175 return STATUS_INSUFFICIENT_RESOURCES;
1176
1177 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1178 Status = SampGetObjectAttribute(DomainObject,
1179 L"F",
1180 NULL,
1181 (PVOID)&FixedData,
1182 &Length);
1183 if (!NT_SUCCESS(Status))
1184 goto done;
1185
1186 InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1187 InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1188 InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1189 InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1190 InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1191 InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1192 InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1193
1194 InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1195 InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1196 InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1197
1198 /* Get the OemInformation string */
1199 Status = SampGetObjectAttributeString(DomainObject,
1200 L"OemInformation",
1201 &InfoBuffer->General2.I1.OemInformation);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 TRACE("Status 0x%08lx\n", Status);
1205 goto done;
1206 }
1207
1208 /* Get the Name string */
1209 Status = SampGetObjectAttributeString(DomainObject,
1210 L"Name",
1211 &InfoBuffer->General2.I1.DomainName);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 TRACE("Status 0x%08lx\n", Status);
1215 goto done;
1216 }
1217
1218 /* Get the ReplicaSourceNodeName string */
1219 Status = SampGetObjectAttributeString(DomainObject,
1220 L"ReplicaSourceNodeName",
1221 &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1222 if (!NT_SUCCESS(Status))
1223 {
1224 TRACE("Status 0x%08lx\n", Status);
1225 goto done;
1226 }
1227
1228 /* Get the number of Users in the Domain */
1229 Status = SampGetNumberOfAccounts(DomainObject,
1230 L"Users",
1231 &InfoBuffer->General2.I1.UserCount);
1232 if (!NT_SUCCESS(Status))
1233 {
1234 TRACE("Status 0x%08lx\n", Status);
1235 goto done;
1236 }
1237
1238 /* Get the number of Groups in the Domain */
1239 Status = SampGetNumberOfAccounts(DomainObject,
1240 L"Groups",
1241 &InfoBuffer->General2.I1.GroupCount);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 TRACE("Status 0x%08lx\n", Status);
1245 goto done;
1246 }
1247
1248 /* Get the number of Aliases in the Domain */
1249 Status = SampGetNumberOfAccounts(DomainObject,
1250 L"Aliases",
1251 &InfoBuffer->General2.I1.AliasCount);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 TRACE("Status 0x%08lx\n", Status);
1255 goto done;
1256 }
1257
1258 *Buffer = InfoBuffer;
1259
1260 done:
1261 if (!NT_SUCCESS(Status))
1262 {
1263 if (InfoBuffer != NULL)
1264 {
1265 if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1266 midl_user_free(InfoBuffer->General2.I1.OemInformation.Buffer);
1267
1268 if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1269 midl_user_free(InfoBuffer->General2.I1.DomainName.Buffer);
1270
1271 if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1272 midl_user_free(InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer);
1273
1274 midl_user_free(InfoBuffer);
1275 }
1276 }
1277
1278 return Status;
1279 }
1280
1281
1282 static NTSTATUS
1283 SampQueryDomainLockout(PSAM_DB_OBJECT DomainObject,
1284 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1285 {
1286 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1287 SAM_DOMAIN_FIXED_DATA FixedData;
1288 ULONG Length = 0;
1289 NTSTATUS Status;
1290
1291 *Buffer = NULL;
1292
1293 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1294 if (InfoBuffer == NULL)
1295 return STATUS_INSUFFICIENT_RESOURCES;
1296
1297 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1298 Status = SampGetObjectAttribute(DomainObject,
1299 L"F",
1300 NULL,
1301 (PVOID)&FixedData,
1302 &Length);
1303 if (!NT_SUCCESS(Status))
1304 goto done;
1305
1306 InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1307 InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1308 InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1309
1310 *Buffer = InfoBuffer;
1311
1312 done:
1313 if (!NT_SUCCESS(Status))
1314 {
1315 if (InfoBuffer != NULL)
1316 {
1317 midl_user_free(InfoBuffer);
1318 }
1319 }
1320
1321 return Status;
1322 }
1323
1324
1325 static NTSTATUS
1326 SampQueryDomainModified2(PSAM_DB_OBJECT DomainObject,
1327 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1328 {
1329 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1330 SAM_DOMAIN_FIXED_DATA FixedData;
1331 ULONG Length = 0;
1332 NTSTATUS Status;
1333
1334 *Buffer = NULL;
1335
1336 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1337 if (InfoBuffer == NULL)
1338 return STATUS_INSUFFICIENT_RESOURCES;
1339
1340 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1341 Status = SampGetObjectAttribute(DomainObject,
1342 L"F",
1343 NULL,
1344 (PVOID)&FixedData,
1345 &Length);
1346 if (!NT_SUCCESS(Status))
1347 goto done;
1348
1349 InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1350 InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1351 InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1352 InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1353 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1354 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1355
1356 *Buffer = InfoBuffer;
1357
1358 done:
1359 if (!NT_SUCCESS(Status))
1360 {
1361 if (InfoBuffer != NULL)
1362 {
1363 midl_user_free(InfoBuffer);
1364 }
1365 }
1366
1367 return Status;
1368 }
1369
1370
1371 /* Function 8 */
1372 NTSTATUS
1373 NTAPI
1374 SamrQueryInformationDomain(IN SAMPR_HANDLE DomainHandle,
1375 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1376 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1377 {
1378 PSAM_DB_OBJECT DomainObject;
1379 ACCESS_MASK DesiredAccess;
1380 NTSTATUS Status;
1381
1382 TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1383 DomainHandle, DomainInformationClass, Buffer);
1384
1385 switch (DomainInformationClass)
1386 {
1387 case DomainPasswordInformation:
1388 case DomainLockoutInformation:
1389 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
1390 break;
1391
1392 case DomainGeneralInformation:
1393 case DomainLogoffInformation:
1394 case DomainOemInformation:
1395 case DomainNameInformation:
1396 case DomainReplicationInformation:
1397 case DomainServerRoleInformation:
1398 case DomainModifiedInformation:
1399 case DomainStateInformation:
1400 case DomainModifiedInformation2:
1401 DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
1402 break;
1403
1404 case DomainGeneralInformation2:
1405 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS |
1406 DOMAIN_READ_OTHER_PARAMETERS;
1407 break;
1408
1409 default:
1410 return STATUS_INVALID_INFO_CLASS;
1411 }
1412
1413 RtlAcquireResourceShared(&SampResource,
1414 TRUE);
1415
1416 /* Validate the server handle */
1417 Status = SampValidateDbObject(DomainHandle,
1418 SamDbDomainObject,
1419 DesiredAccess,
1420 &DomainObject);
1421 if (!NT_SUCCESS(Status))
1422 goto done;
1423
1424 switch (DomainInformationClass)
1425 {
1426 case DomainPasswordInformation:
1427 Status = SampQueryDomainPassword(DomainObject,
1428 Buffer);
1429 break;
1430
1431 case DomainGeneralInformation:
1432 Status = SampQueryDomainGeneral(DomainObject,
1433 Buffer);
1434 break;
1435
1436 case DomainLogoffInformation:
1437 Status = SampQueryDomainLogoff(DomainObject,
1438 Buffer);
1439 break;
1440
1441 case DomainOemInformation:
1442 Status = SampQueryDomainOem(DomainObject,
1443 Buffer);
1444 break;
1445
1446 case DomainNameInformation:
1447 Status = SampQueryDomainName(DomainObject,
1448 Buffer);
1449 break;
1450
1451 case DomainReplicationInformation:
1452 Status = SampQueryDomainReplication(DomainObject,
1453 Buffer);
1454 break;
1455
1456 case DomainServerRoleInformation:
1457 Status = SampQueryDomainServerRole(DomainObject,
1458 Buffer);
1459 break;
1460
1461 case DomainModifiedInformation:
1462 Status = SampQueryDomainModified(DomainObject,
1463 Buffer);
1464 break;
1465
1466 case DomainStateInformation:
1467 Status = SampQueryDomainState(DomainObject,
1468 Buffer);
1469 break;
1470
1471 case DomainGeneralInformation2:
1472 Status = SampQueryDomainGeneral2(DomainObject,
1473 Buffer);
1474 break;
1475
1476 case DomainLockoutInformation:
1477 Status = SampQueryDomainLockout(DomainObject,
1478 Buffer);
1479 break;
1480
1481 case DomainModifiedInformation2:
1482 Status = SampQueryDomainModified2(DomainObject,
1483 Buffer);
1484 break;
1485
1486 default:
1487 Status = STATUS_NOT_IMPLEMENTED;
1488 }
1489
1490 done:
1491 RtlReleaseResource(&SampResource);
1492
1493 return Status;
1494 }
1495
1496
1497 static NTSTATUS
1498 SampSetDomainPassword(PSAM_DB_OBJECT DomainObject,
1499 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1500 {
1501 SAM_DOMAIN_FIXED_DATA FixedData;
1502 ULONG Length = 0;
1503 NTSTATUS Status;
1504
1505 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1506 Status = SampGetObjectAttribute(DomainObject,
1507 L"F",
1508 NULL,
1509 (PVOID)&FixedData,
1510 &Length);
1511 if (!NT_SUCCESS(Status))
1512 goto done;
1513
1514 FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1515 FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1516 FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1517 FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1518 FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1519 FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1520 FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1521
1522 Status = SampSetObjectAttribute(DomainObject,
1523 L"F",
1524 REG_BINARY,
1525 &FixedData,
1526 Length);
1527
1528 done:
1529 return Status;
1530 }
1531
1532
1533 static NTSTATUS
1534 SampSetDomainLogoff(PSAM_DB_OBJECT DomainObject,
1535 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1536 {
1537 SAM_DOMAIN_FIXED_DATA FixedData;
1538 ULONG Length = 0;
1539 NTSTATUS Status;
1540
1541 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1542 Status = SampGetObjectAttribute(DomainObject,
1543 L"F",
1544 NULL,
1545 (PVOID)&FixedData,
1546 &Length);
1547 if (!NT_SUCCESS(Status))
1548 goto done;
1549
1550 FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1551 FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1552
1553 Status = SampSetObjectAttribute(DomainObject,
1554 L"F",
1555 REG_BINARY,
1556 &FixedData,
1557 Length);
1558
1559 done:
1560 return Status;
1561 }
1562
1563
1564 static NTSTATUS
1565 SampSetDomainServerRole(PSAM_DB_OBJECT DomainObject,
1566 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1567 {
1568 SAM_DOMAIN_FIXED_DATA FixedData;
1569 ULONG Length = 0;
1570 NTSTATUS Status;
1571
1572 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1573 Status = SampGetObjectAttribute(DomainObject,
1574 L"F",
1575 NULL,
1576 (PVOID)&FixedData,
1577 &Length);
1578 if (!NT_SUCCESS(Status))
1579 goto done;
1580
1581 FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1582
1583 Status = SampSetObjectAttribute(DomainObject,
1584 L"F",
1585 REG_BINARY,
1586 &FixedData,
1587 Length);
1588
1589 done:
1590 return Status;
1591 }
1592
1593
1594 static NTSTATUS
1595 SampSetDomainState(PSAM_DB_OBJECT DomainObject,
1596 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1597 {
1598 SAM_DOMAIN_FIXED_DATA FixedData;
1599 ULONG Length = 0;
1600 NTSTATUS Status;
1601
1602 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1603 Status = SampGetObjectAttribute(DomainObject,
1604 L"F",
1605 NULL,
1606 (PVOID)&FixedData,
1607 &Length);
1608 if (!NT_SUCCESS(Status))
1609 goto done;
1610
1611 FixedData.DomainServerState = Buffer->State.DomainServerState;
1612
1613 Status = SampSetObjectAttribute(DomainObject,
1614 L"F",
1615 REG_BINARY,
1616 &FixedData,
1617 Length);
1618
1619 done:
1620 return Status;
1621 }
1622
1623
1624 static NTSTATUS
1625 SampSetDomainLockout(PSAM_DB_OBJECT DomainObject,
1626 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1627 {
1628 SAM_DOMAIN_FIXED_DATA FixedData;
1629 ULONG Length = 0;
1630 NTSTATUS Status;
1631
1632 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1633 Status = SampGetObjectAttribute(DomainObject,
1634 L"F",
1635 NULL,
1636 (PVOID)&FixedData,
1637 &Length);
1638 if (!NT_SUCCESS(Status))
1639 goto done;
1640
1641 FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1642 FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1643 FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1644
1645 Status = SampSetObjectAttribute(DomainObject,
1646 L"F",
1647 REG_BINARY,
1648 &FixedData,
1649 Length);
1650
1651 done:
1652 return Status;
1653 }
1654
1655
1656 /* Function 9 */
1657 NTSTATUS
1658 NTAPI
1659 SamrSetInformationDomain(IN SAMPR_HANDLE DomainHandle,
1660 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1661 IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1662 {
1663 PSAM_DB_OBJECT DomainObject;
1664 ACCESS_MASK DesiredAccess;
1665 NTSTATUS Status;
1666
1667 TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1668 DomainHandle, DomainInformationClass, DomainInformation);
1669
1670 switch (DomainInformationClass)
1671 {
1672 case DomainPasswordInformation:
1673 case DomainLockoutInformation:
1674 DesiredAccess = DOMAIN_WRITE_PASSWORD_PARAMS;
1675 break;
1676
1677 case DomainLogoffInformation:
1678 case DomainOemInformation:
1679 case DomainNameInformation:
1680 DesiredAccess = DOMAIN_WRITE_OTHER_PARAMETERS;
1681 break;
1682
1683 case DomainReplicationInformation:
1684 case DomainServerRoleInformation:
1685 case DomainStateInformation:
1686 DesiredAccess = DOMAIN_ADMINISTER_SERVER;
1687 break;
1688
1689 default:
1690 return STATUS_INVALID_INFO_CLASS;
1691 }
1692
1693 RtlAcquireResourceExclusive(&SampResource,
1694 TRUE);
1695
1696 /* Validate the server handle */
1697 Status = SampValidateDbObject(DomainHandle,
1698 SamDbDomainObject,
1699 DesiredAccess,
1700 &DomainObject);
1701 if (!NT_SUCCESS(Status))
1702 goto done;
1703
1704 switch (DomainInformationClass)
1705 {
1706 case DomainPasswordInformation:
1707 Status = SampSetDomainPassword(DomainObject,
1708 DomainInformation);
1709 break;
1710
1711 case DomainLogoffInformation:
1712 Status = SampSetDomainLogoff(DomainObject,
1713 DomainInformation);
1714 break;
1715
1716 case DomainOemInformation:
1717 Status = SampSetObjectAttributeString(DomainObject,
1718 L"OemInformation",
1719 &DomainInformation->Oem.OemInformation);
1720 break;
1721
1722 case DomainNameInformation:
1723 Status = SampSetObjectAttributeString(DomainObject,
1724 L"Name",
1725 &DomainInformation->Name.DomainName);
1726 break;
1727
1728 case DomainReplicationInformation:
1729 Status = SampSetObjectAttributeString(DomainObject,
1730 L"ReplicaSourceNodeName",
1731 &DomainInformation->Replication.ReplicaSourceNodeName);
1732 break;
1733
1734 case DomainServerRoleInformation:
1735 Status = SampSetDomainServerRole(DomainObject,
1736 DomainInformation);
1737 break;
1738
1739 case DomainStateInformation:
1740 Status = SampSetDomainState(DomainObject,
1741 DomainInformation);
1742 break;
1743
1744 case DomainLockoutInformation:
1745 Status = SampSetDomainLockout(DomainObject,
1746 DomainInformation);
1747 break;
1748
1749 default:
1750 Status = STATUS_NOT_IMPLEMENTED;
1751 }
1752
1753 done:
1754 RtlReleaseResource(&SampResource);
1755
1756 return Status;
1757 }
1758
1759
1760 /* Function 10 */
1761 NTSTATUS
1762 NTAPI
1763 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1764 IN PRPC_UNICODE_STRING Name,
1765 IN ACCESS_MASK DesiredAccess,
1766 OUT SAMPR_HANDLE *GroupHandle,
1767 OUT unsigned long *RelativeId)
1768 {
1769 SAM_DOMAIN_FIXED_DATA FixedDomainData;
1770 SAM_GROUP_FIXED_DATA FixedGroupData;
1771 PSAM_DB_OBJECT DomainObject;
1772 PSAM_DB_OBJECT GroupObject;
1773 PSECURITY_DESCRIPTOR Sd = NULL;
1774 ULONG SdSize = 0;
1775 ULONG ulSize;
1776 ULONG ulRid;
1777 WCHAR szRid[9];
1778 NTSTATUS Status;
1779
1780 TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
1781 DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
1782
1783 /* Map generic access rights */
1784 RtlMapGenericMask(&DesiredAccess,
1785 &GroupMapping);
1786
1787 RtlAcquireResourceExclusive(&SampResource,
1788 TRUE);
1789
1790 /* Validate the domain handle */
1791 Status = SampValidateDbObject(DomainHandle,
1792 SamDbDomainObject,
1793 DOMAIN_CREATE_GROUP,
1794 &DomainObject);
1795 if (!NT_SUCCESS(Status))
1796 {
1797 TRACE("failed with status 0x%08lx\n", Status);
1798 goto done;
1799 }
1800
1801 /* Check the group account name */
1802 Status = SampCheckAccountName(Name, 256);
1803 if (!NT_SUCCESS(Status))
1804 {
1805 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
1806 goto done;
1807 }
1808
1809 /* Check if the group name already exists in the domain */
1810 Status = SampCheckAccountNameInDomain(DomainObject,
1811 Name->Buffer);
1812 if (!NT_SUCCESS(Status))
1813 {
1814 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
1815 Name->Buffer, Status);
1816 goto done;
1817 }
1818
1819 /* Create the security descriptor */
1820 Status = SampCreateGroupSD(&Sd,
1821 &SdSize);
1822 if (!NT_SUCCESS(Status))
1823 {
1824 TRACE("SampCreateGroupSD failed (Status 0x%08lx)\n", Status);
1825 goto done;
1826 }
1827
1828 /* Get the fixed domain attributes */
1829 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
1830 Status = SampGetObjectAttribute(DomainObject,
1831 L"F",
1832 NULL,
1833 (PVOID)&FixedDomainData,
1834 &ulSize);
1835 if (!NT_SUCCESS(Status))
1836 {
1837 TRACE("failed with status 0x%08lx\n", Status);
1838 goto done;
1839 }
1840
1841 /* Increment the NextRid attribute */
1842 ulRid = FixedDomainData.NextRid;
1843 FixedDomainData.NextRid++;
1844
1845 /* Store the fixed domain attributes */
1846 Status = SampSetObjectAttribute(DomainObject,
1847 L"F",
1848 REG_BINARY,
1849 &FixedDomainData,
1850 ulSize);
1851 if (!NT_SUCCESS(Status))
1852 {
1853 TRACE("failed with status 0x%08lx\n", Status);
1854 goto done;
1855 }
1856
1857 TRACE("RID: %lx\n", ulRid);
1858
1859 /* Convert the RID into a string (hex) */
1860 swprintf(szRid, L"%08lX", ulRid);
1861
1862 /* Create the group object */
1863 Status = SampCreateDbObject(DomainObject,
1864 L"Groups",
1865 szRid,
1866 ulRid,
1867 SamDbGroupObject,
1868 DesiredAccess,
1869 &GroupObject);
1870 if (!NT_SUCCESS(Status))
1871 {
1872 TRACE("failed with status 0x%08lx\n", Status);
1873 goto done;
1874 }
1875
1876 /* Add the account name of the user object */
1877 Status = SampSetAccountNameInDomain(DomainObject,
1878 L"Groups",
1879 Name->Buffer,
1880 ulRid);
1881 if (!NT_SUCCESS(Status))
1882 {
1883 TRACE("failed with status 0x%08lx\n", Status);
1884 goto done;
1885 }
1886
1887 /* Initialize fixed user data */
1888 memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
1889 FixedGroupData.Version = 1;
1890 FixedGroupData.GroupId = ulRid;
1891
1892 /* Set fixed user data attribute */
1893 Status = SampSetObjectAttribute(GroupObject,
1894 L"F",
1895 REG_BINARY,
1896 (LPVOID)&FixedGroupData,
1897 sizeof(SAM_GROUP_FIXED_DATA));
1898 if (!NT_SUCCESS(Status))
1899 {
1900 TRACE("failed with status 0x%08lx\n", Status);
1901 goto done;
1902 }
1903
1904 /* Set the Name attribute */
1905 Status = SampSetObjectAttributeString(GroupObject,
1906 L"Name",
1907 Name);
1908 if (!NT_SUCCESS(Status))
1909 {
1910 TRACE("failed with status 0x%08lx\n", Status);
1911 goto done;
1912 }
1913
1914 /* Set the AdminComment attribute */
1915 Status = SampSetObjectAttributeString(GroupObject,
1916 L"AdminComment",
1917 NULL);
1918 if (!NT_SUCCESS(Status))
1919 {
1920 TRACE("failed with status 0x%08lx\n", Status);
1921 goto done;
1922 }
1923
1924 /* Set the SecDesc attribute*/
1925 Status = SampSetObjectAttribute(GroupObject,
1926 L"SecDesc",
1927 REG_BINARY,
1928 Sd,
1929 SdSize);
1930 if (!NT_SUCCESS(Status))
1931 {
1932 TRACE("failed with status 0x%08lx\n", Status);
1933 goto done;
1934 }
1935
1936 if (NT_SUCCESS(Status))
1937 {
1938 *GroupHandle = (SAMPR_HANDLE)GroupObject;
1939 *RelativeId = ulRid;
1940 }
1941
1942 done:
1943 if (Sd != NULL)
1944 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
1945
1946 RtlReleaseResource(&SampResource);
1947
1948 TRACE("returns with status 0x%08lx\n", Status);
1949
1950 return Status;
1951 }
1952
1953
1954 /* Function 11 */
1955 NTSTATUS
1956 NTAPI
1957 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
1958 IN OUT unsigned long *EnumerationContext,
1959 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
1960 IN unsigned long PreferedMaximumLength,
1961 OUT unsigned long *CountReturned)
1962 {
1963 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
1964 PSAM_DB_OBJECT DomainObject;
1965 HANDLE GroupsKeyHandle = NULL;
1966 HANDLE NamesKeyHandle = NULL;
1967 WCHAR GroupName[64];
1968 ULONG EnumIndex;
1969 ULONG EnumCount = 0;
1970 ULONG RequiredLength = 0;
1971 ULONG NameLength;
1972 ULONG DataLength;
1973 ULONG Rid;
1974 ULONG i;
1975 BOOLEAN MoreEntries = FALSE;
1976 NTSTATUS Status;
1977
1978 TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
1979 DomainHandle, EnumerationContext, Buffer,
1980 PreferedMaximumLength, CountReturned);
1981
1982 RtlAcquireResourceShared(&SampResource,
1983 TRUE);
1984
1985 /* Validate the domain handle */
1986 Status = SampValidateDbObject(DomainHandle,
1987 SamDbDomainObject,
1988 DOMAIN_LIST_ACCOUNTS,
1989 &DomainObject);
1990 if (!NT_SUCCESS(Status))
1991 goto done;
1992
1993 Status = SampRegOpenKey(DomainObject->KeyHandle,
1994 L"Groups",
1995 KEY_READ,
1996 &GroupsKeyHandle);
1997 if (!NT_SUCCESS(Status))
1998 goto done;
1999
2000 Status = SampRegOpenKey(GroupsKeyHandle,
2001 L"Names",
2002 KEY_READ,
2003 &NamesKeyHandle);
2004 if (!NT_SUCCESS(Status))
2005 goto done;
2006
2007 TRACE("Part 1\n");
2008
2009 EnumIndex = *EnumerationContext;
2010
2011 while (TRUE)
2012 {
2013 NameLength = 64 * sizeof(WCHAR);
2014 Status = SampRegEnumerateValue(NamesKeyHandle,
2015 EnumIndex,
2016 GroupName,
2017 &NameLength,
2018 NULL,
2019 NULL,
2020 NULL);
2021 if (!NT_SUCCESS(Status))
2022 {
2023 if (Status == STATUS_NO_MORE_ENTRIES)
2024 Status = STATUS_SUCCESS;
2025 break;
2026 }
2027
2028 TRACE("EnumIndex: %lu\n", EnumIndex);
2029 TRACE("Group name: %S\n", GroupName);
2030 TRACE("Name length: %lu\n", NameLength);
2031
2032 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2033 {
2034 MoreEntries = TRUE;
2035 break;
2036 }
2037
2038 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2039 EnumCount++;
2040
2041 EnumIndex++;
2042 }
2043
2044 TRACE("EnumCount: %lu\n", EnumCount);
2045 TRACE("RequiredLength: %lu\n", RequiredLength);
2046
2047 if (!NT_SUCCESS(Status))
2048 goto done;
2049
2050 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2051 if (EnumBuffer == NULL)
2052 {
2053 Status = STATUS_INSUFFICIENT_RESOURCES;
2054 goto done;
2055 }
2056
2057 EnumBuffer->EntriesRead = EnumCount;
2058 if (EnumCount == 0)
2059 goto done;
2060
2061 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2062 if (EnumBuffer->Buffer == NULL)
2063 {
2064 Status = STATUS_INSUFFICIENT_RESOURCES;
2065 goto done;
2066 }
2067
2068 TRACE("Part 2\n");
2069
2070 EnumIndex = *EnumerationContext;
2071 for (i = 0; i < EnumCount; i++, EnumIndex++)
2072 {
2073 NameLength = 64 * sizeof(WCHAR);
2074 DataLength = sizeof(ULONG);
2075 Status = SampRegEnumerateValue(NamesKeyHandle,
2076 EnumIndex,
2077 GroupName,
2078 &NameLength,
2079 NULL,
2080 &Rid,
2081 &DataLength);
2082 if (!NT_SUCCESS(Status))
2083 {
2084 if (Status == STATUS_NO_MORE_ENTRIES)
2085 Status = STATUS_SUCCESS;
2086 break;
2087 }
2088
2089 TRACE("EnumIndex: %lu\n", EnumIndex);
2090 TRACE("Group name: %S\n", GroupName);
2091 TRACE("Name length: %lu\n", NameLength);
2092 TRACE("RID: %lu\n", Rid);
2093
2094 EnumBuffer->Buffer[i].RelativeId = Rid;
2095
2096 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2097 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2098
2099 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2100 #if 0
2101 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2102 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2103 {
2104 Status = STATUS_INSUFFICIENT_RESOURCES;
2105 goto done;
2106 }
2107
2108 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2109 GroupName,
2110 EnumBuffer->Buffer[i].Name.Length);
2111 #endif
2112 }
2113
2114 done:
2115 if (NT_SUCCESS(Status))
2116 {
2117 *EnumerationContext += EnumCount;
2118 *Buffer = EnumBuffer;
2119 *CountReturned = EnumCount;
2120 }
2121 else
2122 {
2123 *EnumerationContext = 0;
2124 *Buffer = NULL;
2125 *CountReturned = 0;
2126
2127 if (EnumBuffer != NULL)
2128 {
2129 if (EnumBuffer->Buffer != NULL)
2130 {
2131 if (EnumBuffer->EntriesRead != 0)
2132 {
2133 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2134 {
2135 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2136 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2137 }
2138 }
2139
2140 midl_user_free(EnumBuffer->Buffer);
2141 }
2142
2143 midl_user_free(EnumBuffer);
2144 }
2145 }
2146
2147 SampRegCloseKey(&NamesKeyHandle);
2148 SampRegCloseKey(&GroupsKeyHandle);
2149
2150 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2151 Status = STATUS_MORE_ENTRIES;
2152
2153 RtlReleaseResource(&SampResource);
2154
2155 return Status;
2156 }
2157
2158
2159 /* Function 12 */
2160 NTSTATUS
2161 NTAPI
2162 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2163 IN PRPC_UNICODE_STRING Name,
2164 IN ACCESS_MASK DesiredAccess,
2165 OUT SAMPR_HANDLE *UserHandle,
2166 OUT unsigned long *RelativeId)
2167 {
2168 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2169 SAM_USER_FIXED_DATA FixedUserData;
2170 PSAM_DB_OBJECT DomainObject;
2171 PSAM_DB_OBJECT UserObject;
2172 GROUP_MEMBERSHIP GroupMembership;
2173 UCHAR LogonHours[23];
2174 ULONG ulSize;
2175 ULONG ulRid;
2176 WCHAR szRid[9];
2177 NTSTATUS Status;
2178
2179 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2180 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2181
2182 if (Name == NULL ||
2183 Name->Length == 0 ||
2184 Name->Buffer == NULL ||
2185 UserHandle == NULL ||
2186 RelativeId == NULL)
2187 return STATUS_INVALID_PARAMETER;
2188
2189 /* Map generic access rights */
2190 RtlMapGenericMask(&DesiredAccess,
2191 &UserMapping);
2192
2193 RtlAcquireResourceExclusive(&SampResource,
2194 TRUE);
2195
2196 /* Validate the domain handle */
2197 Status = SampValidateDbObject(DomainHandle,
2198 SamDbDomainObject,
2199 DOMAIN_CREATE_USER,
2200 &DomainObject);
2201 if (!NT_SUCCESS(Status))
2202 {
2203 TRACE("failed with status 0x%08lx\n", Status);
2204 goto done;
2205 }
2206
2207 /* Check the user account name */
2208 Status = SampCheckAccountName(Name, 20);
2209 if (!NT_SUCCESS(Status))
2210 {
2211 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2212 goto done;
2213 }
2214
2215 /* Check if the user name already exists in the domain */
2216 Status = SampCheckAccountNameInDomain(DomainObject,
2217 Name->Buffer);
2218 if (!NT_SUCCESS(Status))
2219 {
2220 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2221 Name->Buffer, Status);
2222 goto done;
2223 }
2224
2225 /* Get the fixed domain attributes */
2226 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2227 Status = SampGetObjectAttribute(DomainObject,
2228 L"F",
2229 NULL,
2230 (PVOID)&FixedDomainData,
2231 &ulSize);
2232 if (!NT_SUCCESS(Status))
2233 {
2234 TRACE("failed with status 0x%08lx\n", Status);
2235 goto done;
2236 }
2237
2238 /* Increment the NextRid attribute */
2239 ulRid = FixedDomainData.NextRid;
2240 FixedDomainData.NextRid++;
2241
2242 /* Store the fixed domain attributes */
2243 Status = SampSetObjectAttribute(DomainObject,
2244 L"F",
2245 REG_BINARY,
2246 &FixedDomainData,
2247 ulSize);
2248 if (!NT_SUCCESS(Status))
2249 {
2250 TRACE("failed with status 0x%08lx\n", Status);
2251 goto done;
2252 }
2253
2254 TRACE("RID: %lx\n", ulRid);
2255
2256 /* Convert the RID into a string (hex) */
2257 swprintf(szRid, L"%08lX", ulRid);
2258
2259 /* Create the user object */
2260 Status = SampCreateDbObject(DomainObject,
2261 L"Users",
2262 szRid,
2263 ulRid,
2264 SamDbUserObject,
2265 DesiredAccess,
2266 &UserObject);
2267 if (!NT_SUCCESS(Status))
2268 {
2269 TRACE("failed with status 0x%08lx\n", Status);
2270 goto done;
2271 }
2272
2273 /* Add the account name for the user object */
2274 Status = SampSetAccountNameInDomain(DomainObject,
2275 L"Users",
2276 Name->Buffer,
2277 ulRid);
2278 if (!NT_SUCCESS(Status))
2279 {
2280 TRACE("failed with status 0x%08lx\n", Status);
2281 goto done;
2282 }
2283
2284 /* Initialize fixed user data */
2285 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2286 FixedUserData.Version = 1;
2287 FixedUserData.Reserved = 0;
2288 FixedUserData.LastLogon.QuadPart = 0;
2289 FixedUserData.LastLogoff.QuadPart = 0;
2290 FixedUserData.PasswordLastSet.QuadPart = 0;
2291 FixedUserData.AccountExpires.LowPart = MAXULONG;
2292 FixedUserData.AccountExpires.HighPart = MAXLONG;
2293 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2294 FixedUserData.UserId = ulRid;
2295 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2296 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2297 USER_PASSWORD_NOT_REQUIRED |
2298 USER_NORMAL_ACCOUNT;
2299 FixedUserData.CountryCode = 0;
2300 FixedUserData.CodePage = 0;
2301 FixedUserData.BadPasswordCount = 0;
2302 FixedUserData.LogonCount = 0;
2303 FixedUserData.AdminCount = 0;
2304 FixedUserData.OperatorCount = 0;
2305
2306 /* Set fixed user data attribute */
2307 Status = SampSetObjectAttribute(UserObject,
2308 L"F",
2309 REG_BINARY,
2310 (LPVOID)&FixedUserData,
2311 sizeof(SAM_USER_FIXED_DATA));
2312 if (!NT_SUCCESS(Status))
2313 {
2314 TRACE("failed with status 0x%08lx\n", Status);
2315 goto done;
2316 }
2317
2318 /* Set the Name attribute */
2319 Status = SampSetObjectAttributeString(UserObject,
2320 L"Name",
2321 Name);
2322 if (!NT_SUCCESS(Status))
2323 {
2324 TRACE("failed with status 0x%08lx\n", Status);
2325 goto done;
2326 }
2327
2328 /* Set the FullName attribute */
2329 Status = SampSetObjectAttributeString(UserObject,
2330 L"FullName",
2331 NULL);
2332 if (!NT_SUCCESS(Status))
2333 {
2334 TRACE("failed with status 0x%08lx\n", Status);
2335 goto done;
2336 }
2337
2338 /* Set the HomeDirectory attribute */
2339 Status = SampSetObjectAttributeString(UserObject,
2340 L"HomeDirectory",
2341 NULL);
2342 if (!NT_SUCCESS(Status))
2343 {
2344 TRACE("failed with status 0x%08lx\n", Status);
2345 goto done;
2346 }
2347
2348 /* Set the HomeDirectoryDrive attribute */
2349 Status = SampSetObjectAttributeString(UserObject,
2350 L"HomeDirectoryDrive",
2351 NULL);
2352 if (!NT_SUCCESS(Status))
2353 {
2354 TRACE("failed with status 0x%08lx\n", Status);
2355 goto done;
2356 }
2357
2358 /* Set the ScriptPath attribute */
2359 Status = SampSetObjectAttributeString(UserObject,
2360 L"ScriptPath",
2361 NULL);
2362 if (!NT_SUCCESS(Status))
2363 {
2364 TRACE("failed with status 0x%08lx\n", Status);
2365 goto done;
2366 }
2367
2368 /* Set the ProfilePath attribute */
2369 Status = SampSetObjectAttributeString(UserObject,
2370 L"ProfilePath",
2371 NULL);
2372 if (!NT_SUCCESS(Status))
2373 {
2374 TRACE("failed with status 0x%08lx\n", Status);
2375 goto done;
2376 }
2377
2378 /* Set the AdminComment attribute */
2379 Status = SampSetObjectAttributeString(UserObject,
2380 L"AdminComment",
2381 NULL);
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 = SampSetObjectAttributeString(UserObject,
2390 L"UserComment",
2391 NULL);
2392 if (!NT_SUCCESS(Status))
2393 {
2394 TRACE("failed with status 0x%08lx\n", Status);
2395 goto done;
2396 }
2397
2398 /* Set the WorkStations attribute */
2399 Status = SampSetObjectAttributeString(UserObject,
2400 L"WorkStations",
2401 NULL);
2402 if (!NT_SUCCESS(Status))
2403 {
2404 TRACE("failed with status 0x%08lx\n", Status);
2405 goto done;
2406 }
2407
2408 /* Set the Parameters attribute */
2409 Status = SampSetObjectAttributeString(UserObject,
2410 L"Parameters",
2411 NULL);
2412 if (!NT_SUCCESS(Status))
2413 {
2414 TRACE("failed with status 0x%08lx\n", Status);
2415 goto done;
2416 }
2417
2418 /* Set LogonHours attribute*/
2419 *((PUSHORT)LogonHours) = 168;
2420 memset(&(LogonHours[2]), 0xff, 21);
2421
2422 Status = SampSetObjectAttribute(UserObject,
2423 L"LogonHours",
2424 REG_BINARY,
2425 &LogonHours,
2426 sizeof(LogonHours));
2427 if (!NT_SUCCESS(Status))
2428 {
2429 TRACE("failed with status 0x%08lx\n", Status);
2430 goto done;
2431 }
2432
2433 /* Set Groups attribute*/
2434 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2435 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2436 SE_GROUP_ENABLED |
2437 SE_GROUP_ENABLED_BY_DEFAULT;
2438
2439 Status = SampSetObjectAttribute(UserObject,
2440 L"Groups",
2441 REG_BINARY,
2442 &GroupMembership,
2443 sizeof(GROUP_MEMBERSHIP));
2444 if (!NT_SUCCESS(Status))
2445 {
2446 TRACE("failed with status 0x%08lx\n", Status);
2447 goto done;
2448 }
2449
2450 /* Set LMPwd attribute*/
2451 Status = SampSetObjectAttribute(UserObject,
2452 L"LMPwd",
2453 REG_BINARY,
2454 &EmptyLmHash,
2455 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2456 if (!NT_SUCCESS(Status))
2457 {
2458 TRACE("failed with status 0x%08lx\n", Status);
2459 goto done;
2460 }
2461
2462 /* Set NTPwd attribute*/
2463 Status = SampSetObjectAttribute(UserObject,
2464 L"NTPwd",
2465 REG_BINARY,
2466 &EmptyNtHash,
2467 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2468 if (!NT_SUCCESS(Status))
2469 {
2470 TRACE("failed with status 0x%08lx\n", Status);
2471 goto done;
2472 }
2473
2474 /* Set LMPwdHistory attribute*/
2475 Status = SampSetObjectAttribute(UserObject,
2476 L"LMPwdHistory",
2477 REG_BINARY,
2478 NULL,
2479 0);
2480 if (!NT_SUCCESS(Status))
2481 {
2482 TRACE("failed with status 0x%08lx\n", Status);
2483 goto done;
2484 }
2485
2486 /* Set NTPwdHistory attribute*/
2487 Status = SampSetObjectAttribute(UserObject,
2488 L"NTPwdHistory",
2489 REG_BINARY,
2490 NULL,
2491 0);
2492 if (!NT_SUCCESS(Status))
2493 {
2494 TRACE("failed with status 0x%08lx\n", Status);
2495 goto done;
2496 }
2497
2498 /* Set the PrivateData attribute */
2499 Status = SampSetObjectAttributeString(UserObject,
2500 L"PrivateData",
2501 NULL);
2502 if (!NT_SUCCESS(Status))
2503 {
2504 TRACE("failed with status 0x%08lx\n", Status);
2505 goto done;
2506 }
2507
2508 /* FIXME: Set SecDesc attribute*/
2509
2510 if (NT_SUCCESS(Status))
2511 {
2512 *UserHandle = (SAMPR_HANDLE)UserObject;
2513 *RelativeId = ulRid;
2514 }
2515
2516 done:
2517 RtlReleaseResource(&SampResource);
2518
2519 TRACE("returns with status 0x%08lx\n", Status);
2520
2521 return Status;
2522 }
2523
2524
2525 /* Function 13 */
2526 NTSTATUS
2527 NTAPI
2528 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2529 IN OUT unsigned long *EnumerationContext,
2530 IN unsigned long UserAccountControl,
2531 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2532 IN unsigned long PreferedMaximumLength,
2533 OUT unsigned long *CountReturned)
2534 {
2535 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2536 PSAM_DB_OBJECT DomainObject;
2537 HANDLE UsersKeyHandle = NULL;
2538 HANDLE NamesKeyHandle = NULL;
2539 WCHAR UserName[64];
2540 ULONG EnumIndex;
2541 ULONG EnumCount = 0;
2542 ULONG RequiredLength = 0;
2543 ULONG NameLength;
2544 ULONG DataLength;
2545 ULONG Rid;
2546 ULONG i;
2547 BOOLEAN MoreEntries = FALSE;
2548 NTSTATUS Status;
2549
2550 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2551 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2552 PreferedMaximumLength, CountReturned);
2553
2554 RtlAcquireResourceShared(&SampResource,
2555 TRUE);
2556
2557 /* Validate the domain handle */
2558 Status = SampValidateDbObject(DomainHandle,
2559 SamDbDomainObject,
2560 DOMAIN_LIST_ACCOUNTS,
2561 &DomainObject);
2562 if (!NT_SUCCESS(Status))
2563 goto done;
2564
2565 Status = SampRegOpenKey(DomainObject->KeyHandle,
2566 L"Users",
2567 KEY_READ,
2568 &UsersKeyHandle);
2569 if (!NT_SUCCESS(Status))
2570 goto done;
2571
2572 Status = SampRegOpenKey(UsersKeyHandle,
2573 L"Names",
2574 KEY_READ,
2575 &NamesKeyHandle);
2576 if (!NT_SUCCESS(Status))
2577 goto done;
2578
2579 TRACE("Part 1\n");
2580
2581 EnumIndex = *EnumerationContext;
2582
2583 while (TRUE)
2584 {
2585 NameLength = 64 * sizeof(WCHAR);
2586 Status = SampRegEnumerateValue(NamesKeyHandle,
2587 EnumIndex,
2588 UserName,
2589 &NameLength,
2590 NULL,
2591 NULL,
2592 NULL);
2593 if (!NT_SUCCESS(Status))
2594 {
2595 if (Status == STATUS_NO_MORE_ENTRIES)
2596 Status = STATUS_SUCCESS;
2597 break;
2598 }
2599
2600 TRACE("EnumIndex: %lu\n", EnumIndex);
2601 TRACE("User name: %S\n", UserName);
2602 TRACE("Name length: %lu\n", NameLength);
2603
2604 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2605 {
2606 MoreEntries = TRUE;
2607 break;
2608 }
2609
2610 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2611 EnumCount++;
2612
2613 EnumIndex++;
2614 }
2615
2616 TRACE("EnumCount: %lu\n", EnumCount);
2617 TRACE("RequiredLength: %lu\n", RequiredLength);
2618
2619 if (!NT_SUCCESS(Status))
2620 goto done;
2621
2622 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2623 if (EnumBuffer == NULL)
2624 {
2625 Status = STATUS_INSUFFICIENT_RESOURCES;
2626 goto done;
2627 }
2628
2629 EnumBuffer->EntriesRead = EnumCount;
2630 if (EnumCount == 0)
2631 goto done;
2632
2633 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2634 if (EnumBuffer->Buffer == NULL)
2635 {
2636 Status = STATUS_INSUFFICIENT_RESOURCES;
2637 goto done;
2638 }
2639
2640 TRACE("Part 2\n");
2641
2642 EnumIndex = *EnumerationContext;
2643 for (i = 0; i < EnumCount; i++, EnumIndex++)
2644 {
2645 NameLength = 64 * sizeof(WCHAR);
2646 DataLength = sizeof(ULONG);
2647 Status = SampRegEnumerateValue(NamesKeyHandle,
2648 EnumIndex,
2649 UserName,
2650 &NameLength,
2651 NULL,
2652 &Rid,
2653 &DataLength);
2654 if (!NT_SUCCESS(Status))
2655 {
2656 if (Status == STATUS_NO_MORE_ENTRIES)
2657 Status = STATUS_SUCCESS;
2658 break;
2659 }
2660
2661 TRACE("EnumIndex: %lu\n", EnumIndex);
2662 TRACE("User name: %S\n", UserName);
2663 TRACE("Name length: %lu\n", NameLength);
2664 TRACE("RID: %lu\n", Rid);
2665
2666 EnumBuffer->Buffer[i].RelativeId = Rid;
2667
2668 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2669 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2670
2671 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2672 #if 0
2673 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2674 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2675 {
2676 Status = STATUS_INSUFFICIENT_RESOURCES;
2677 goto done;
2678 }
2679
2680 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2681 UserName,
2682 EnumBuffer->Buffer[i].Name.Length);
2683 #endif
2684 }
2685
2686 done:
2687 if (NT_SUCCESS(Status))
2688 {
2689 *EnumerationContext += EnumCount;
2690 *Buffer = EnumBuffer;
2691 *CountReturned = EnumCount;
2692 }
2693 else
2694 {
2695 *EnumerationContext = 0;
2696 *Buffer = NULL;
2697 *CountReturned = 0;
2698
2699 if (EnumBuffer != NULL)
2700 {
2701 if (EnumBuffer->Buffer != NULL)
2702 {
2703 if (EnumBuffer->EntriesRead != 0)
2704 {
2705 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2706 {
2707 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2708 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2709 }
2710 }
2711
2712 midl_user_free(EnumBuffer->Buffer);
2713 }
2714
2715 midl_user_free(EnumBuffer);
2716 }
2717 }
2718
2719 SampRegCloseKey(&NamesKeyHandle);
2720 SampRegCloseKey(&UsersKeyHandle);
2721
2722 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2723 Status = STATUS_MORE_ENTRIES;
2724
2725 RtlReleaseResource(&SampResource);
2726
2727 return Status;
2728 }
2729
2730
2731 /* Function 14 */
2732 NTSTATUS
2733 NTAPI
2734 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2735 IN PRPC_UNICODE_STRING AccountName,
2736 IN ACCESS_MASK DesiredAccess,
2737 OUT SAMPR_HANDLE *AliasHandle,
2738 OUT unsigned long *RelativeId)
2739 {
2740 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2741 PSAM_DB_OBJECT DomainObject;
2742 PSAM_DB_OBJECT AliasObject;
2743 PSECURITY_DESCRIPTOR Sd = NULL;
2744 ULONG SdSize = 0;
2745 ULONG ulSize;
2746 ULONG ulRid;
2747 WCHAR szRid[9];
2748 NTSTATUS Status;
2749
2750 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2751 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2752
2753 /* Map generic access rights */
2754 RtlMapGenericMask(&DesiredAccess,
2755 &AliasMapping);
2756
2757 RtlAcquireResourceExclusive(&SampResource,
2758 TRUE);
2759
2760 /* Validate the domain handle */
2761 Status = SampValidateDbObject(DomainHandle,
2762 SamDbDomainObject,
2763 DOMAIN_CREATE_ALIAS,
2764 &DomainObject);
2765 if (!NT_SUCCESS(Status))
2766 {
2767 TRACE("failed with status 0x%08lx\n", Status);
2768 goto done;
2769 }
2770
2771 /* Check the alias acoount name */
2772 Status = SampCheckAccountName(AccountName, 256);
2773 if (!NT_SUCCESS(Status))
2774 {
2775 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2776 goto done;
2777 }
2778
2779 /* Check if the alias name already exists in the domain */
2780 Status = SampCheckAccountNameInDomain(DomainObject,
2781 AccountName->Buffer);
2782 if (!NT_SUCCESS(Status))
2783 {
2784 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2785 AccountName->Buffer, Status);
2786 goto done;
2787 }
2788
2789 /* Create the security descriptor */
2790 Status = SampCreateAliasSD(&Sd,
2791 &SdSize);
2792 if (!NT_SUCCESS(Status))
2793 {
2794 TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
2795 goto done;
2796 }
2797
2798 /* Get the fixed domain attributes */
2799 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2800 Status = SampGetObjectAttribute(DomainObject,
2801 L"F",
2802 NULL,
2803 (PVOID)&FixedDomainData,
2804 &ulSize);
2805 if (!NT_SUCCESS(Status))
2806 {
2807 TRACE("failed with status 0x%08lx\n", Status);
2808 goto done;
2809 }
2810
2811 /* Increment the NextRid attribute */
2812 ulRid = FixedDomainData.NextRid;
2813 FixedDomainData.NextRid++;
2814
2815 /* Store the fixed domain attributes */
2816 Status = SampSetObjectAttribute(DomainObject,
2817 L"F",
2818 REG_BINARY,
2819 &FixedDomainData,
2820 ulSize);
2821 if (!NT_SUCCESS(Status))
2822 {
2823 TRACE("failed with status 0x%08lx\n", Status);
2824 goto done;
2825 }
2826
2827 TRACE("RID: %lx\n", ulRid);
2828
2829 /* Convert the RID into a string (hex) */
2830 swprintf(szRid, L"%08lX", ulRid);
2831
2832 /* Create the alias object */
2833 Status = SampCreateDbObject(DomainObject,
2834 L"Aliases",
2835 szRid,
2836 ulRid,
2837 SamDbAliasObject,
2838 DesiredAccess,
2839 &AliasObject);
2840 if (!NT_SUCCESS(Status))
2841 {
2842 TRACE("failed with status 0x%08lx\n", Status);
2843 goto done;
2844 }
2845
2846 /* Add the account name for the alias object */
2847 Status = SampSetAccountNameInDomain(DomainObject,
2848 L"Aliases",
2849 AccountName->Buffer,
2850 ulRid);
2851 if (!NT_SUCCESS(Status))
2852 {
2853 TRACE("failed with status 0x%08lx\n", Status);
2854 goto done;
2855 }
2856
2857 /* Set the Name attribute */
2858 Status = SampSetObjectAttributeString(AliasObject,
2859 L"Name",
2860 AccountName);
2861 if (!NT_SUCCESS(Status))
2862 {
2863 TRACE("failed with status 0x%08lx\n", Status);
2864 goto done;
2865 }
2866
2867 /* Set the Description attribute */
2868 Status = SampSetObjectAttributeString(AliasObject,
2869 L"Description",
2870 NULL);
2871 if (!NT_SUCCESS(Status))
2872 {
2873 TRACE("failed with status 0x%08lx\n", Status);
2874 goto done;
2875 }
2876
2877 /* Set the SecDesc attribute*/
2878 Status = SampSetObjectAttribute(AliasObject,
2879 L"SecDesc",
2880 REG_BINARY,
2881 Sd,
2882 SdSize);
2883 if (!NT_SUCCESS(Status))
2884 {
2885 TRACE("failed with status 0x%08lx\n", Status);
2886 goto done;
2887 }
2888
2889 if (NT_SUCCESS(Status))
2890 {
2891 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2892 *RelativeId = ulRid;
2893 }
2894
2895 done:
2896 if (Sd != NULL)
2897 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2898
2899 RtlReleaseResource(&SampResource);
2900
2901 TRACE("returns with status 0x%08lx\n", Status);
2902
2903 return Status;
2904 }
2905
2906
2907 /* Function 15 */
2908 NTSTATUS
2909 NTAPI
2910 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2911 IN OUT unsigned long *EnumerationContext,
2912 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2913 IN unsigned long PreferedMaximumLength,
2914 OUT unsigned long *CountReturned)
2915 {
2916 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2917 PSAM_DB_OBJECT DomainObject;
2918 HANDLE AliasesKeyHandle = NULL;
2919 HANDLE NamesKeyHandle = NULL;
2920 WCHAR AliasName[64];
2921 ULONG EnumIndex;
2922 ULONG EnumCount = 0;
2923 ULONG RequiredLength = 0;
2924 ULONG NameLength;
2925 ULONG DataLength;
2926 ULONG Rid;
2927 ULONG i;
2928 BOOLEAN MoreEntries = FALSE;
2929 NTSTATUS Status;
2930
2931 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2932 DomainHandle, EnumerationContext, Buffer,
2933 PreferedMaximumLength, CountReturned);
2934
2935 RtlAcquireResourceShared(&SampResource,
2936 TRUE);
2937
2938 /* Validate the domain handle */
2939 Status = SampValidateDbObject(DomainHandle,
2940 SamDbDomainObject,
2941 DOMAIN_LIST_ACCOUNTS,
2942 &DomainObject);
2943 if (!NT_SUCCESS(Status))
2944 goto done;
2945
2946 Status = SampRegOpenKey(DomainObject->KeyHandle,
2947 L"Aliases",
2948 KEY_READ,
2949 &AliasesKeyHandle);
2950 if (!NT_SUCCESS(Status))
2951 goto done;
2952
2953 Status = SampRegOpenKey(AliasesKeyHandle,
2954 L"Names",
2955 KEY_READ,
2956 &NamesKeyHandle);
2957 if (!NT_SUCCESS(Status))
2958 goto done;
2959
2960 TRACE("Part 1\n");
2961
2962 EnumIndex = *EnumerationContext;
2963
2964 while (TRUE)
2965 {
2966 NameLength = 64 * sizeof(WCHAR);
2967 Status = SampRegEnumerateValue(NamesKeyHandle,
2968 EnumIndex,
2969 AliasName,
2970 &NameLength,
2971 NULL,
2972 NULL,
2973 NULL);
2974 if (!NT_SUCCESS(Status))
2975 {
2976 if (Status == STATUS_NO_MORE_ENTRIES)
2977 Status = STATUS_SUCCESS;
2978 break;
2979 }
2980
2981 TRACE("EnumIndex: %lu\n", EnumIndex);
2982 TRACE("Alias name: %S\n", AliasName);
2983 TRACE("Name length: %lu\n", NameLength);
2984
2985 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2986 {
2987 MoreEntries = TRUE;
2988 break;
2989 }
2990
2991 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2992 EnumCount++;
2993
2994 EnumIndex++;
2995 }
2996
2997 TRACE("EnumCount: %lu\n", EnumCount);
2998 TRACE("RequiredLength: %lu\n", RequiredLength);
2999
3000 if (!NT_SUCCESS(Status))
3001 goto done;
3002
3003 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3004 if (EnumBuffer == NULL)
3005 {
3006 Status = STATUS_INSUFFICIENT_RESOURCES;
3007 goto done;
3008 }
3009
3010 EnumBuffer->EntriesRead = EnumCount;
3011 if (EnumCount == 0)
3012 goto done;
3013
3014 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3015 if (EnumBuffer->Buffer == NULL)
3016 {
3017 Status = STATUS_INSUFFICIENT_RESOURCES;
3018 goto done;
3019 }
3020
3021 TRACE("Part 2\n");
3022
3023 EnumIndex = *EnumerationContext;
3024 for (i = 0; i < EnumCount; i++, EnumIndex++)
3025 {
3026 NameLength = 64 * sizeof(WCHAR);
3027 DataLength = sizeof(ULONG);
3028 Status = SampRegEnumerateValue(NamesKeyHandle,
3029 EnumIndex,
3030 AliasName,
3031 &NameLength,
3032 NULL,
3033 &Rid,
3034 &DataLength);
3035 if (!NT_SUCCESS(Status))
3036 {
3037 if (Status == STATUS_NO_MORE_ENTRIES)
3038 Status = STATUS_SUCCESS;
3039 break;
3040 }
3041
3042 TRACE("EnumIndex: %lu\n", EnumIndex);
3043 TRACE("Alias name: %S\n", AliasName);
3044 TRACE("Name length: %lu\n", NameLength);
3045 TRACE("RID: %lu\n", Rid);
3046
3047 EnumBuffer->Buffer[i].RelativeId = Rid;
3048
3049 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3050 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
3051
3052 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3053 #if 0
3054 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3055 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3056 {
3057 Status = STATUS_INSUFFICIENT_RESOURCES;
3058 goto done;
3059 }
3060
3061 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3062 AliasName,
3063 EnumBuffer->Buffer[i].Name.Length);
3064 #endif
3065 }
3066
3067 done:
3068 if (NT_SUCCESS(Status))
3069 {
3070 *EnumerationContext += EnumCount;
3071 *Buffer = EnumBuffer;
3072 *CountReturned = EnumCount;
3073 }
3074 else
3075 {
3076 *EnumerationContext = 0;
3077 *Buffer = NULL;
3078 *CountReturned = 0;
3079
3080 if (EnumBuffer != NULL)
3081 {
3082 if (EnumBuffer->Buffer != NULL)
3083 {
3084 if (EnumBuffer->EntriesRead != 0)
3085 {
3086 for (i = 0; i < EnumBuffer->EntriesRead; i++)
3087 {
3088 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3089 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3090 }
3091 }
3092
3093 midl_user_free(EnumBuffer->Buffer);
3094 }
3095
3096 midl_user_free(EnumBuffer);
3097 }
3098 }
3099
3100 SampRegCloseKey(&NamesKeyHandle);
3101 SampRegCloseKey(&AliasesKeyHandle);
3102
3103 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
3104 Status = STATUS_MORE_ENTRIES;
3105
3106 RtlReleaseResource(&SampResource);
3107
3108 return Status;
3109 }
3110
3111
3112 /* Function 16 */
3113 NTSTATUS
3114 NTAPI
3115 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3116 IN PSAMPR_PSID_ARRAY SidArray,
3117 OUT PSAMPR_ULONG_ARRAY Membership)
3118 {
3119 PSAM_DB_OBJECT DomainObject;
3120 HANDLE AliasesKeyHandle = NULL;
3121 HANDLE MembersKeyHandle = NULL;
3122 HANDLE MemberKeyHandle = NULL;
3123 LPWSTR MemberSidString = NULL;
3124 PULONG RidArray = NULL;
3125 ULONG MaxSidCount = 0;
3126 ULONG ValueCount;
3127 ULONG DataLength;
3128 ULONG i, j;
3129 NTSTATUS Status;
3130 WCHAR NameBuffer[9];
3131
3132 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3133 DomainHandle, SidArray, Membership);
3134
3135 RtlAcquireResourceShared(&SampResource,
3136 TRUE);
3137
3138 /* Validate the domain handle */
3139 Status = SampValidateDbObject(DomainHandle,
3140 SamDbDomainObject,
3141 DOMAIN_GET_ALIAS_MEMBERSHIP,
3142 &DomainObject);
3143 if (!NT_SUCCESS(Status))
3144 goto done;
3145
3146 Status = SampRegOpenKey(DomainObject->KeyHandle,
3147 L"Aliases",
3148 KEY_READ,
3149 &AliasesKeyHandle);
3150 TRACE("SampRegOpenKey returned %08lX\n", Status);
3151 if (!NT_SUCCESS(Status))
3152 goto done;
3153
3154 Status = SampRegOpenKey(AliasesKeyHandle,
3155 L"Members",
3156 KEY_READ,
3157 &MembersKeyHandle);
3158 TRACE("SampRegOpenKey returned %08lX\n", Status);
3159
3160 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3161 {
3162 Status = STATUS_SUCCESS;
3163 goto done;
3164 }
3165
3166 if (!NT_SUCCESS(Status))
3167 goto done;
3168
3169 for (i = 0; i < SidArray->Count; i++)
3170 {
3171 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3172 TRACE("Open %S\n", MemberSidString);
3173
3174 Status = SampRegOpenKey(MembersKeyHandle,
3175 MemberSidString,
3176 KEY_READ,
3177 &MemberKeyHandle);
3178 TRACE("SampRegOpenKey returned %08lX\n", Status);
3179 if (NT_SUCCESS(Status))
3180 {
3181 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3182 NULL,
3183 &ValueCount);
3184 if (NT_SUCCESS(Status))
3185 {
3186 TRACE("Found %lu values\n", ValueCount);
3187 MaxSidCount += ValueCount;
3188 }
3189
3190 SampRegCloseKey(&MemberKeyHandle);
3191 }
3192
3193 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3194 Status = STATUS_SUCCESS;
3195
3196 LocalFree(MemberSidString);
3197 }
3198
3199 if (MaxSidCount == 0)
3200 {
3201 Status = STATUS_SUCCESS;
3202 goto done;
3203 }
3204
3205 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3206 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3207 if (RidArray == NULL)
3208 {
3209 Status = STATUS_INSUFFICIENT_RESOURCES;
3210 goto done;
3211 }
3212
3213 for (i = 0; i < SidArray->Count; i++)
3214 {
3215 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3216 TRACE("Open %S\n", MemberSidString);
3217
3218 Status = SampRegOpenKey(MembersKeyHandle,
3219 MemberSidString,
3220 KEY_READ,
3221 &MemberKeyHandle);
3222 TRACE("SampRegOpenKey returned %08lX\n", Status);
3223 if (NT_SUCCESS(Status))
3224 {
3225 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3226 NULL,
3227 &ValueCount);
3228 if (NT_SUCCESS(Status))
3229 {
3230 TRACE("Found %lu values\n", ValueCount);
3231
3232 for (j = 0; j < ValueCount; j++)
3233 {
3234 DataLength = 9 * sizeof(WCHAR);
3235 Status = SampRegEnumerateValue(MemberKeyHandle,
3236 j,
3237 NameBuffer,
3238 &DataLength,
3239 NULL,
3240 NULL,
3241 NULL);
3242 if (NT_SUCCESS(Status))
3243 {
3244 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3245 }
3246 }
3247 }
3248
3249 SampRegCloseKey(&MemberKeyHandle);
3250 }
3251
3252 LocalFree(MemberSidString);
3253 }
3254
3255 done:
3256 SampRegCloseKey(&MembersKeyHandle);
3257 SampRegCloseKey(&AliasesKeyHandle);
3258
3259 if (NT_SUCCESS(Status))
3260 {
3261 Membership->Count = MaxSidCount;
3262 Membership->Element = RidArray;
3263 }
3264 else
3265 {
3266 if (RidArray != NULL)
3267 midl_user_free(RidArray);
3268 }
3269
3270 RtlReleaseResource(&SampResource);
3271
3272 return Status;
3273 }
3274
3275
3276 /* Function 17 */
3277 NTSTATUS
3278 NTAPI
3279 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3280 IN ULONG Count,
3281 IN RPC_UNICODE_STRING Names[],
3282 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3283 OUT PSAMPR_ULONG_ARRAY Use)
3284 {
3285 PSAM_DB_OBJECT DomainObject;
3286 HANDLE AccountsKeyHandle = NULL;
3287 HANDLE NamesKeyHandle = NULL;
3288 ULONG MappedCount = 0;
3289 ULONG DataLength;
3290 ULONG i;
3291 ULONG RelativeId;
3292 NTSTATUS Status;
3293
3294 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3295 DomainHandle, Count, Names, RelativeIds, Use);
3296
3297 RtlAcquireResourceShared(&SampResource,
3298 TRUE);
3299
3300 /* Validate the domain handle */
3301 Status = SampValidateDbObject(DomainHandle,
3302 SamDbDomainObject,
3303 DOMAIN_LOOKUP,
3304 &DomainObject);
3305 if (!NT_SUCCESS(Status))
3306 {
3307 TRACE("failed with status 0x%08lx\n", Status);
3308 goto done;
3309 }
3310
3311 RelativeIds->Count = 0;
3312 Use->Count = 0;
3313
3314 if (Count == 0)
3315 {
3316 Status = STATUS_SUCCESS;
3317 goto done;
3318 }
3319
3320 /* Allocate the relative IDs array */
3321 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3322 if (RelativeIds->Element == NULL)
3323 {
3324 Status = STATUS_INSUFFICIENT_RESOURCES;
3325 goto done;
3326 }
3327
3328 /* Allocate the use array */
3329 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3330 if (Use->Element == NULL)
3331 {
3332 Status = STATUS_INSUFFICIENT_RESOURCES;
3333 goto done;
3334 }
3335
3336 RelativeIds->Count = Count;
3337 Use->Count = Count;
3338
3339 for (i = 0; i < Count; i++)
3340 {
3341 TRACE("Name: %S\n", Names[i].Buffer);
3342
3343 RelativeId = 0;
3344
3345 /* Lookup aliases */
3346 Status = SampRegOpenKey(DomainObject->KeyHandle,
3347 L"Aliases",
3348 KEY_READ,
3349 &AccountsKeyHandle);
3350 if (NT_SUCCESS(Status))
3351 {
3352 Status = SampRegOpenKey(AccountsKeyHandle,
3353 L"Names",
3354 KEY_READ,
3355 &NamesKeyHandle);
3356 if (NT_SUCCESS(Status))
3357 {
3358 DataLength = sizeof(ULONG);
3359 Status = SampRegQueryValue(NamesKeyHandle,
3360 Names[i].Buffer,
3361 NULL,
3362 &RelativeId,
3363 &DataLength);
3364
3365 SampRegCloseKey(&NamesKeyHandle);
3366 }
3367
3368 SampRegCloseKey(&AccountsKeyHandle);
3369 }
3370
3371 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3372 break;
3373
3374 /* Return alias account */
3375 if (NT_SUCCESS(Status) && RelativeId != 0)
3376 {
3377 TRACE("Rid: %lu\n", RelativeId);
3378 RelativeIds->Element[i] = RelativeId;
3379 Use->Element[i] = SidTypeAlias;
3380 MappedCount++;
3381 continue;
3382 }
3383
3384 /* Lookup groups */
3385 Status = SampRegOpenKey(DomainObject->KeyHandle,
3386 L"Groups",
3387 KEY_READ,
3388 &AccountsKeyHandle);
3389 if (NT_SUCCESS(Status))
3390 {
3391 Status = SampRegOpenKey(AccountsKeyHandle,
3392 L"Names",
3393 KEY_READ,
3394 &NamesKeyHandle);
3395 if (NT_SUCCESS(Status))
3396 {
3397 DataLength = sizeof(ULONG);
3398 Status = SampRegQueryValue(NamesKeyHandle,
3399 Names[i].Buffer,
3400 NULL,
3401 &RelativeId,
3402 &DataLength);
3403
3404 SampRegCloseKey(&NamesKeyHandle);
3405 }
3406
3407 SampRegCloseKey(&AccountsKeyHandle);
3408 }
3409
3410 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3411 break;
3412
3413 /* Return group account */
3414 if (NT_SUCCESS(Status) && RelativeId != 0)
3415 {
3416 TRACE("Rid: %lu\n", RelativeId);
3417 RelativeIds->Element[i] = RelativeId;
3418 Use->Element[i] = SidTypeGroup;
3419 MappedCount++;
3420 continue;
3421 }
3422
3423 /* Lookup users */
3424 Status = SampRegOpenKey(DomainObject->KeyHandle,
3425 L"Users",
3426 KEY_READ,
3427 &AccountsKeyHandle);
3428 if (NT_SUCCESS(Status))
3429 {
3430 Status = SampRegOpenKey(AccountsKeyHandle,
3431 L"Names",
3432 KEY_READ,
3433 &NamesKeyHandle);
3434 if (NT_SUCCESS(Status))
3435 {
3436 DataLength = sizeof(ULONG);
3437 Status = SampRegQueryValue(NamesKeyHandle,
3438 Names[i].Buffer,
3439 NULL,
3440 &RelativeId,
3441 &DataLength);
3442
3443 SampRegCloseKey(&NamesKeyHandle);
3444 }
3445
3446 SampRegCloseKey(&AccountsKeyHandle);
3447 }
3448
3449 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3450 break;
3451
3452 /* Return user account */
3453 if (NT_SUCCESS(Status) && RelativeId != 0)
3454 {
3455 TRACE("Rid: %lu\n", RelativeId);
3456 RelativeIds->Element[i] = RelativeId;
3457 Use->Element[i] = SidTypeUser;
3458 MappedCount++;
3459 continue;
3460 }
3461
3462 /* Return unknown account */
3463 RelativeIds->Element[i] = 0;
3464 Use->Element[i] = SidTypeUnknown;
3465 }
3466
3467 done:
3468 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3469 Status = STATUS_SUCCESS;
3470
3471 if (NT_SUCCESS(Status))
3472 {
3473 if (MappedCount == 0)
3474 Status = STATUS_NONE_MAPPED;
3475 else if (MappedCount < Count)
3476 Status = STATUS_SOME_NOT_MAPPED;
3477 }
3478 else
3479 {
3480 if (RelativeIds->Element != NULL)
3481 {
3482 midl_user_free(RelativeIds->Element);
3483 RelativeIds->Element = NULL;
3484 }
3485
3486 RelativeIds->Count = 0;
3487
3488 if (Use->Element != NULL)
3489 {
3490 midl_user_free(Use->Element);
3491 Use->Element = NULL;
3492 }
3493
3494 Use->Count = 0;
3495 }
3496
3497 RtlReleaseResource(&SampResource);
3498
3499 TRACE("Returned Status %lx\n", Status);
3500
3501 return Status;
3502 }
3503
3504
3505 /* Function 18 */
3506 NTSTATUS
3507 NTAPI
3508 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3509 IN ULONG Count,
3510 IN ULONG *RelativeIds,
3511 OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3512 OUT PSAMPR_ULONG_ARRAY Use)
3513 {
3514 PSAM_DB_OBJECT DomainObject;
3515 WCHAR RidString[9];
3516 HANDLE AccountsKeyHandle = NULL;
3517 HANDLE AccountKeyHandle = NULL;
3518 ULONG MappedCount = 0;
3519 ULONG DataLength;
3520 ULONG i;
3521 NTSTATUS Status;
3522
3523 TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3524 DomainHandle, Count, RelativeIds, Names, Use);
3525
3526 RtlAcquireResourceShared(&SampResource,
3527 TRUE);
3528
3529 /* Validate the domain handle */
3530 Status = SampValidateDbObject(DomainHandle,
3531 SamDbDomainObject,
3532 DOMAIN_LOOKUP,
3533 &DomainObject);
3534 if (!NT_SUCCESS(Status))
3535 {
3536 TRACE("failed with status 0x%08lx\n", Status);
3537 goto done;
3538 }
3539
3540 Names->Count = 0;
3541 Use->Count = 0;
3542
3543 if (Count == 0)
3544 {
3545 Status = STATUS_SUCCESS;
3546 goto done;
3547 }
3548
3549 /* Allocate the names array */
3550 Names->Element = midl_user_allocate(Count * sizeof(ULONG));
3551 if (Names->Element == NULL)
3552 {
3553 Status = STATUS_INSUFFICIENT_RESOURCES;
3554 goto done;
3555 }
3556
3557 /* Allocate the use array */
3558 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3559 if (Use->Element == NULL)
3560 {
3561 Status = STATUS_INSUFFICIENT_RESOURCES;
3562 goto done;
3563 }
3564
3565 Names->Count = Count;
3566 Use->Count = Count;
3567
3568 for (i = 0; i < Count; i++)
3569 {
3570 TRACE("RID: %lu\n", RelativeIds[i]);
3571
3572 swprintf(RidString, L"%08lx", RelativeIds[i]);
3573
3574 /* Lookup aliases */
3575 Status = SampRegOpenKey(DomainObject->KeyHandle,
3576 L"Aliases",
3577 KEY_READ,
3578 &AccountsKeyHandle);
3579 if (NT_SUCCESS(Status))
3580 {
3581 Status = SampRegOpenKey(AccountsKeyHandle,
3582 RidString,
3583 KEY_READ,
3584 &AccountKeyHandle);
3585 if (NT_SUCCESS(Status))
3586 {
3587 DataLength = 0;
3588 Status = SampRegQueryValue(AccountKeyHandle,
3589 L"Name",
3590 NULL,
3591 NULL,
3592 &DataLength);
3593 if (NT_SUCCESS(Status))
3594 {
3595 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3596 if (Names->Element[i].Buffer == NULL)
3597 Status = STATUS_INSUFFICIENT_RESOURCES;
3598
3599 if (NT_SUCCESS(Status))
3600 {
3601 Names->Element[i].MaximumLength = (USHORT)DataLength;
3602 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3603
3604 Status = SampRegQueryValue(AccountKeyHandle,
3605 L"Name",
3606 NULL,
3607 Names->Element[i].Buffer,
3608 &DataLength);
3609 }
3610 }
3611
3612 SampRegCloseKey(&AccountKeyHandle);
3613 }
3614
3615 SampRegCloseKey(&AccountsKeyHandle);
3616 }
3617
3618 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3619 break;
3620
3621 /* Return alias account */
3622 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3623 {
3624 TRACE("Name: %S\n", Names->Element[i].Buffer);
3625 Use->Element[i] = SidTypeAlias;
3626 MappedCount++;
3627 continue;
3628 }
3629
3630 /* Lookup groups */
3631 Status = SampRegOpenKey(DomainObject->KeyHandle,
3632 L"Groups",
3633 KEY_READ,
3634 &AccountsKeyHandle);
3635 if (NT_SUCCESS(Status))
3636 {
3637 Status = SampRegOpenKey(AccountsKeyHandle,
3638 RidString,
3639 KEY_READ,
3640 &AccountKeyHandle);
3641 if (NT_SUCCESS(Status))
3642 {
3643 DataLength = 0;
3644 Status = SampRegQueryValue(AccountKeyHandle,
3645 L"Name",
3646 NULL,
3647 NULL,
3648 &DataLength);
3649 if (NT_SUCCESS(Status))
3650 {
3651 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3652 if (Names->Element[i].Buffer == NULL)
3653 Status = STATUS_INSUFFICIENT_RESOURCES;
3654
3655 if (NT_SUCCESS(Status))
3656 {
3657 Names->Element[i].MaximumLength = (USHORT)DataLength;
3658 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3659
3660 Status = SampRegQueryValue(AccountKeyHandle,
3661 L"Name",
3662 NULL,
3663 Names->Element[i].Buffer,
3664 &DataLength);
3665 }
3666 }
3667
3668 SampRegCloseKey(&AccountKeyHandle);
3669 }
3670
3671 SampRegCloseKey(&AccountsKeyHandle);
3672 }
3673
3674 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3675 break;
3676
3677 /* Return group account */
3678 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3679 {
3680 TRACE("Name: %S\n", Names->Element[i].Buffer);
3681 Use->Element[i] = SidTypeGroup;
3682 MappedCount++;
3683 continue;
3684 }
3685
3686 /* Lookup users */
3687 Status = SampRegOpenKey(DomainObject->KeyHandle,
3688 L"Users",
3689 KEY_READ,
3690 &AccountsKeyHandle);
3691 if (NT_SUCCESS(Status))
3692 {
3693 Status = SampRegOpenKey(AccountsKeyHandle,
3694 RidString,
3695 KEY_READ,
3696 &AccountKeyHandle);
3697 if (NT_SUCCESS(Status))
3698 {
3699 DataLength = 0;
3700 Status = SampRegQueryValue(AccountKeyHandle,
3701 L"Name",
3702 NULL,
3703 NULL,
3704 &DataLength);
3705 if (NT_SUCCESS(Status))
3706 {
3707 TRACE("DataLength: %lu\n", DataLength);
3708
3709 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3710 if (Names->Element[i].Buffer == NULL)
3711 Status = STATUS_INSUFFICIENT_RESOURCES;
3712
3713 if (NT_SUCCESS(Status))
3714 {
3715 Names->Element[i].MaximumLength = (USHORT)DataLength;
3716 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3717
3718 Status = SampRegQueryValue(AccountKeyHandle,
3719 L"Name",
3720 NULL,
3721 Names->Element[i].Buffer,
3722 &DataLength);
3723 }
3724 }
3725
3726 SampRegCloseKey(&AccountKeyHandle);
3727 }
3728
3729 SampRegCloseKey(&AccountsKeyHandle);
3730 }
3731
3732 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3733 break;
3734
3735 /* Return user account */
3736 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3737 {
3738 TRACE("Name: %S\n", Names->Element[i].Buffer);
3739 Use->Element[i] = SidTypeUser;
3740 MappedCount++;
3741 continue;
3742 }
3743
3744 /* Return unknown account */
3745 Use->Element[i] = SidTypeUnknown;
3746 }
3747
3748 done:
3749 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3750 Status = STATUS_SUCCESS;
3751
3752 if (NT_SUCCESS(Status))
3753 {
3754 if (MappedCount == 0)
3755 Status = STATUS_NONE_MAPPED;
3756 else if (MappedCount < Count)
3757 Status = STATUS_SOME_NOT_MAPPED;
3758 }
3759 else
3760 {
3761 if (Names->Element != NULL)
3762 {
3763 for (i = 0; i < Count; i++)
3764 {
3765 if (Names->Element[i].Buffer != NULL)
3766 midl_user_free(Names->Element[i].Buffer);
3767 }
3768
3769 midl_user_free(Names->Element);
3770 Names->Element = NULL;
3771 }
3772
3773 Names->Count = 0;
3774
3775 if (Use->Element != NULL)
3776 {
3777 midl_user_free(Use->Element);
3778 Use->Element = NULL;
3779 }
3780
3781 Use->Count = 0;
3782 }
3783
3784 RtlReleaseResource(&SampResource);
3785
3786 return Status;
3787 }
3788
3789
3790 /* Function 19 */
3791 NTSTATUS
3792 NTAPI
3793 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
3794 IN ACCESS_MASK DesiredAccess,
3795 IN unsigned long GroupId,
3796 OUT SAMPR_HANDLE *GroupHandle)
3797 {
3798 PSAM_DB_OBJECT DomainObject;
3799 PSAM_DB_OBJECT GroupObject;
3800 WCHAR szRid[9];
3801 NTSTATUS Status;
3802
3803 TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
3804 DomainHandle, DesiredAccess, GroupId, GroupHandle);
3805
3806 /* Map generic access rights */
3807 RtlMapGenericMask(&DesiredAccess,
3808 &GroupMapping);
3809
3810 RtlAcquireResourceShared(&SampResource,
3811 TRUE);
3812
3813 /* Validate the domain handle */
3814 Status = SampValidateDbObject(DomainHandle,
3815 SamDbDomainObject,
3816 DOMAIN_LOOKUP,
3817 &DomainObject);
3818 if (!NT_SUCCESS(Status))
3819 {
3820 TRACE("failed with status 0x%08lx\n", Status);
3821 goto done;
3822 }
3823
3824 /* Convert the RID into a string (hex) */
3825 swprintf(szRid, L"%08lX", GroupId);
3826
3827 /* Create the group object */
3828 Status = SampOpenDbObject(DomainObject,
3829 L"Groups",
3830 szRid,
3831 GroupId,
3832 SamDbGroupObject,
3833 DesiredAccess,
3834 &GroupObject);
3835 if (!NT_SUCCESS(Status))
3836 {
3837 TRACE("failed with status 0x%08lx\n", Status);
3838 goto done;
3839 }
3840
3841 *GroupHandle = (SAMPR_HANDLE)GroupObject;
3842
3843 done:
3844 RtlReleaseResource(&SampResource);
3845
3846 return Status;
3847 }
3848
3849
3850 static NTSTATUS
3851 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
3852 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3853 {
3854 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3855 SAM_GROUP_FIXED_DATA FixedData;
3856 ULONG MembersLength = 0;
3857 ULONG Length = 0;
3858 NTSTATUS Status;
3859
3860 *Buffer = NULL;
3861
3862 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3863 if (InfoBuffer == NULL)
3864 return STATUS_INSUFFICIENT_RESOURCES;
3865
3866 Status = SampGetObjectAttributeString(GroupObject,
3867 L"Name",
3868 &InfoBuffer->Gen