[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Security Account Manager (SAM) Server
4 * FILE: reactos/dll/win32/samsrv/samrpc.c
5 * PURPOSE: RPC interface functions
6 *
7 * PROGRAMMERS: Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "samsrv.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
15
16 /* GLOBALS *******************************************************************/
17
18 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
19
20 static GENERIC_MAPPING ServerMapping =
21 {
22 SAM_SERVER_READ,
23 SAM_SERVER_WRITE,
24 SAM_SERVER_EXECUTE,
25 SAM_SERVER_ALL_ACCESS
26 };
27
28 static GENERIC_MAPPING DomainMapping =
29 {
30 DOMAIN_READ,
31 DOMAIN_WRITE,
32 DOMAIN_EXECUTE,
33 DOMAIN_ALL_ACCESS
34 };
35
36 static GENERIC_MAPPING AliasMapping =
37 {
38 ALIAS_READ,
39 ALIAS_WRITE,
40 ALIAS_EXECUTE,
41 ALIAS_ALL_ACCESS
42 };
43
44 static GENERIC_MAPPING GroupMapping =
45 {
46 GROUP_READ,
47 GROUP_WRITE,
48 GROUP_EXECUTE,
49 GROUP_ALL_ACCESS
50 };
51
52 static GENERIC_MAPPING UserMapping =
53 {
54 USER_READ,
55 USER_WRITE,
56 USER_EXECUTE,
57 USER_ALL_ACCESS
58 };
59
60 PGENERIC_MAPPING pServerMapping = &ServerMapping;
61
62
63 /* FUNCTIONS *****************************************************************/
64
65 static
66 LARGE_INTEGER
67 SampAddRelativeTimeToTime(IN LARGE_INTEGER AbsoluteTime,
68 IN LARGE_INTEGER RelativeTime)
69 {
70 LARGE_INTEGER NewTime;
71
72 NewTime.QuadPart = AbsoluteTime.QuadPart - RelativeTime.QuadPart;
73
74 if (NewTime.QuadPart < 0)
75 NewTime.QuadPart = 0;
76
77 return NewTime;
78 }
79
80
81 VOID
82 SampStartRpcServer(VOID)
83 {
84 RPC_STATUS Status;
85
86 TRACE("SampStartRpcServer() called\n");
87
88 Status = RpcServerUseProtseqEpW(L"ncacn_np",
89 10,
90 L"\\pipe\\samr",
91 NULL);
92 if (Status != RPC_S_OK)
93 {
94 WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
95 return;
96 }
97
98 Status = RpcServerRegisterIf(samr_v1_0_s_ifspec,
99 NULL,
100 NULL);
101 if (Status != RPC_S_OK)
102 {
103 WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
104 return;
105 }
106
107 Status = RpcServerListen(1, 20, TRUE);
108 if (Status != RPC_S_OK)
109 {
110 WARN("RpcServerListen() failed (Status %lx)\n", Status);
111 return;
112 }
113
114 TRACE("SampStartRpcServer() done\n");
115 }
116
117
118 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
119 {
120 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
121 }
122
123
124 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
125 {
126 HeapFree(GetProcessHeap(), 0, ptr);
127 }
128
129
130 void __RPC_USER SAMPR_HANDLE_rundown(SAMPR_HANDLE hHandle)
131 {
132 }
133
134
135 /* Function 0 */
136 NTSTATUS
137 NTAPI
138 SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
139 OUT SAMPR_HANDLE *ServerHandle,
140 IN ACCESS_MASK DesiredAccess)
141 {
142 PSAM_DB_OBJECT ServerObject;
143 NTSTATUS Status;
144
145 TRACE("SamrConnect(%p %p %lx)\n",
146 ServerName, ServerHandle, DesiredAccess);
147
148 RtlAcquireResourceShared(&SampResource,
149 TRUE);
150
151 /* Map generic access rights */
152 RtlMapGenericMask(&DesiredAccess,
153 &ServerMapping);
154
155 /* Open the Server Object */
156 Status = SampOpenDbObject(NULL,
157 NULL,
158 L"SAM",
159 0,
160 SamDbServerObject,
161 DesiredAccess,
162 &ServerObject);
163 if (NT_SUCCESS(Status))
164 *ServerHandle = (SAMPR_HANDLE)ServerObject;
165
166 RtlReleaseResource(&SampResource);
167
168 TRACE("SamrConnect done (Status 0x%08lx)\n", Status);
169
170 return Status;
171 }
172
173
174 /* Function 1 */
175 NTSTATUS
176 NTAPI
177 SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle)
178 {
179 PSAM_DB_OBJECT DbObject;
180 NTSTATUS Status = STATUS_SUCCESS;
181
182 TRACE("SamrCloseHandle(%p)\n", SamHandle);
183
184 RtlAcquireResourceShared(&SampResource,
185 TRUE);
186
187 Status = SampValidateDbObject(*SamHandle,
188 SamDbIgnoreObject,
189 0,
190 &DbObject);
191 if (Status == STATUS_SUCCESS)
192 {
193 Status = SampCloseDbObject(DbObject);
194 *SamHandle = NULL;
195 }
196
197 RtlReleaseResource(&SampResource);
198
199 TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
200
201 return Status;
202 }
203
204
205 /* Function 2 */
206 NTSTATUS
207 NTAPI
208 SamrSetSecurityObject(IN SAMPR_HANDLE ObjectHandle,
209 IN SECURITY_INFORMATION SecurityInformation,
210 IN PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
211 {
212 UNIMPLEMENTED;
213 return STATUS_NOT_IMPLEMENTED;
214 }
215
216
217 /* Function 3 */
218 NTSTATUS
219 NTAPI
220 SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
221 IN SECURITY_INFORMATION SecurityInformation,
222 OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
223 {
224 UNIMPLEMENTED;
225 return STATUS_NOT_IMPLEMENTED;
226 }
227
228
229 /* Function 4 */
230 NTSTATUS
231 NTAPI
232 SamrShutdownSamServer(IN SAMPR_HANDLE ServerHandle)
233 {
234 PSAM_DB_OBJECT ServerObject;
235 NTSTATUS Status;
236
237 TRACE("(%p)\n", ServerHandle);
238
239 RtlAcquireResourceShared(&SampResource,
240 TRUE);
241
242 /* Validate the server handle */
243 Status = SampValidateDbObject(ServerHandle,
244 SamDbServerObject,
245 SAM_SERVER_SHUTDOWN,
246 &ServerObject);
247
248 RtlReleaseResource(&SampResource);
249
250 if (!NT_SUCCESS(Status))
251 return Status;
252
253 /* Shut the server down */
254 RpcMgmtStopServerListening(0);
255
256 return STATUS_SUCCESS;
257 }
258
259
260 /* Function 5 */
261 NTSTATUS
262 NTAPI
263 SamrLookupDomainInSamServer(IN SAMPR_HANDLE ServerHandle,
264 IN PRPC_UNICODE_STRING Name,
265 OUT PRPC_SID *DomainId)
266 {
267 PSAM_DB_OBJECT ServerObject;
268 HANDLE DomainsKeyHandle = NULL;
269 HANDLE DomainKeyHandle = NULL;
270 WCHAR DomainKeyName[64];
271 ULONG Index;
272 WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
273 UNICODE_STRING DomainName;
274 ULONG Length;
275 BOOL Found = FALSE;
276 NTSTATUS Status;
277
278 TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
279 ServerHandle, Name, DomainId);
280
281 RtlAcquireResourceShared(&SampResource,
282 TRUE);
283
284 /* Validate the server handle */
285 Status = SampValidateDbObject(ServerHandle,
286 SamDbServerObject,
287 SAM_SERVER_LOOKUP_DOMAIN,
288 &ServerObject);
289 if (!NT_SUCCESS(Status))
290 goto done;
291
292 *DomainId = NULL;
293
294 Status = SampRegOpenKey(ServerObject->KeyHandle,
295 L"Domains",
296 KEY_READ,
297 &DomainsKeyHandle);
298 if (!NT_SUCCESS(Status))
299 goto done;
300
301 Index = 0;
302 while (Found == FALSE)
303 {
304 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
305 Index,
306 64,
307 DomainKeyName);
308 if (!NT_SUCCESS(Status))
309 {
310 if (Status == STATUS_NO_MORE_ENTRIES)
311 Status = STATUS_NO_SUCH_DOMAIN;
312 break;
313 }
314
315 TRACE("Domain key name: %S\n", DomainKeyName);
316
317 Status = SampRegOpenKey(DomainsKeyHandle,
318 DomainKeyName,
319 KEY_READ,
320 &DomainKeyHandle);
321 if (NT_SUCCESS(Status))
322 {
323 Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
324 Status = SampRegQueryValue(DomainKeyHandle,
325 L"Name",
326 NULL,
327 (PVOID)&DomainNameString,
328 &Length);
329 if (NT_SUCCESS(Status))
330 {
331 TRACE("Domain name: %S\n", DomainNameString);
332
333 RtlInitUnicodeString(&DomainName,
334 DomainNameString);
335 if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
336 {
337 TRACE("Found it!\n");
338 Found = TRUE;
339
340 Status = SampRegQueryValue(DomainKeyHandle,
341 L"SID",
342 NULL,
343 NULL,
344 &Length);
345 if (NT_SUCCESS(Status))
346 {
347 *DomainId = midl_user_allocate(Length);
348
349 SampRegQueryValue(DomainKeyHandle,
350 L"SID",
351 NULL,
352 (PVOID)*DomainId,
353 &Length);
354
355 Status = STATUS_SUCCESS;
356 break;
357 }
358 }
359 }
360
361 SampRegCloseKey(&DomainKeyHandle);
362 }
363
364 Index++;
365 }
366
367 done:
368 SampRegCloseKey(&DomainKeyHandle);
369 SampRegCloseKey(&DomainsKeyHandle);
370
371 RtlReleaseResource(&SampResource);
372
373 return Status;
374 }
375
376
377 /* Function 6 */
378 NTSTATUS
379 NTAPI
380 SamrEnumerateDomainsInSamServer(IN SAMPR_HANDLE ServerHandle,
381 IN OUT unsigned long *EnumerationContext,
382 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
383 IN ULONG PreferedMaximumLength,
384 OUT PULONG CountReturned)
385 {
386 PSAM_DB_OBJECT ServerObject;
387 WCHAR DomainKeyName[64];
388 HANDLE DomainsKeyHandle = NULL;
389 HANDLE DomainKeyHandle = NULL;
390 ULONG EnumIndex;
391 ULONG EnumCount;
392 ULONG RequiredLength;
393 ULONG DataLength;
394 ULONG i;
395 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
396 NTSTATUS Status;
397
398 TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
399 ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
400 CountReturned);
401
402 RtlAcquireResourceShared(&SampResource,
403 TRUE);
404
405 /* Validate the server handle */
406 Status = SampValidateDbObject(ServerHandle,
407 SamDbServerObject,
408 SAM_SERVER_ENUMERATE_DOMAINS,
409 &ServerObject);
410 if (!NT_SUCCESS(Status))
411 goto done;
412
413 Status = SampRegOpenKey(ServerObject->KeyHandle,
414 L"Domains",
415 KEY_READ,
416 &DomainsKeyHandle);
417 if (!NT_SUCCESS(Status))
418 goto done;
419
420 EnumIndex = *EnumerationContext;
421 EnumCount = 0;
422 RequiredLength = 0;
423
424 while (TRUE)
425 {
426 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
427 EnumIndex,
428 64 * sizeof(WCHAR),
429 DomainKeyName);
430 if (!NT_SUCCESS(Status))
431 break;
432
433 TRACE("EnumIndex: %lu\n", EnumIndex);
434 TRACE("Domain key name: %S\n", DomainKeyName);
435
436 Status = SampRegOpenKey(DomainsKeyHandle,
437 DomainKeyName,
438 KEY_READ,
439 &DomainKeyHandle);
440 TRACE("SampRegOpenKey returned %08lX\n", Status);
441 if (NT_SUCCESS(Status))
442 {
443 DataLength = 0;
444 Status = SampRegQueryValue(DomainKeyHandle,
445 L"Name",
446 NULL,
447 NULL,
448 &DataLength);
449 TRACE("SampRegQueryValue returned %08lX\n", Status);
450 if (NT_SUCCESS(Status))
451 {
452 TRACE("Data length: %lu\n", DataLength);
453
454 if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
455 break;
456
457 RequiredLength += (DataLength + sizeof(UNICODE_STRING));
458 EnumCount++;
459 }
460
461 SampRegCloseKey(&DomainKeyHandle);
462 }
463
464 EnumIndex++;
465 }
466
467 TRACE("EnumCount: %lu\n", EnumCount);
468 TRACE("RequiredLength: %lu\n", RequiredLength);
469
470 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
471 if (EnumBuffer == NULL)
472 {
473 Status = STATUS_INSUFFICIENT_RESOURCES;
474 goto done;
475 }
476
477 EnumBuffer->EntriesRead = EnumCount;
478 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
479 if (EnumBuffer->Buffer == NULL)
480 {
481 Status = STATUS_INSUFFICIENT_RESOURCES;
482 goto done;
483 }
484
485 EnumIndex = *EnumerationContext;
486 for (i = 0; i < EnumCount; i++, EnumIndex++)
487 {
488 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
489 EnumIndex,
490 64 * sizeof(WCHAR),
491 DomainKeyName);
492 if (!NT_SUCCESS(Status))
493 break;
494
495 TRACE("EnumIndex: %lu\n", EnumIndex);
496 TRACE("Domain key name: %S\n", DomainKeyName);
497
498 Status = SampRegOpenKey(DomainsKeyHandle,
499 DomainKeyName,
500 KEY_READ,
501 &DomainKeyHandle);
502 TRACE("SampRegOpenKey returned %08lX\n", Status);
503 if (NT_SUCCESS(Status))
504 {
505 DataLength = 0;
506 Status = SampRegQueryValue(DomainKeyHandle,
507 L"Name",
508 NULL,
509 NULL,
510 &DataLength);
511 TRACE("SampRegQueryValue returned %08lX\n", Status);
512 if (NT_SUCCESS(Status))
513 {
514 EnumBuffer->Buffer[i].RelativeId = 0;
515 EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
516 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
517 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
518 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
519 {
520 SampRegCloseKey(&DomainKeyHandle);
521 Status = STATUS_INSUFFICIENT_RESOURCES;
522 goto done;
523 }
524
525 Status = SampRegQueryValue(DomainKeyHandle,
526 L"Name",
527 NULL,
528 EnumBuffer->Buffer[i].Name.Buffer,
529 &DataLength);
530 TRACE("SampRegQueryValue returned %08lX\n", Status);
531 if (NT_SUCCESS(Status))
532 {
533 TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
534 }
535 }
536
537 SampRegCloseKey(&DomainKeyHandle);
538
539 if (!NT_SUCCESS(Status))
540 goto done;
541 }
542 }
543
544 if (NT_SUCCESS(Status))
545 {
546 *EnumerationContext += EnumCount;
547 *Buffer = EnumBuffer;
548 *CountReturned = EnumCount;
549 }
550
551 done:
552 SampRegCloseKey(&DomainKeyHandle);
553 SampRegCloseKey(&DomainsKeyHandle);
554
555 if (!NT_SUCCESS(Status))
556 {
557 *EnumerationContext = 0;
558 *Buffer = NULL;
559 *CountReturned = 0;
560
561 if (EnumBuffer != NULL)
562 {
563 if (EnumBuffer->Buffer != NULL)
564 {
565 if (EnumBuffer->EntriesRead != 0)
566 {
567 for (i = 0; i < EnumBuffer->EntriesRead; i++)
568 {
569 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
570 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
571 }
572 }
573
574 midl_user_free(EnumBuffer->Buffer);
575 }
576
577 midl_user_free(EnumBuffer);
578 }
579 }
580
581 RtlReleaseResource(&SampResource);
582
583 return Status;
584 }
585
586
587 /* Function 7 */
588 NTSTATUS
589 NTAPI
590 SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
591 IN ACCESS_MASK DesiredAccess,
592 IN PRPC_SID DomainId,
593 OUT SAMPR_HANDLE *DomainHandle)
594 {
595 PSAM_DB_OBJECT ServerObject;
596 PSAM_DB_OBJECT DomainObject;
597 NTSTATUS Status;
598
599 TRACE("SamrOpenDomain(%p %lx %p %p)\n",
600 ServerHandle, DesiredAccess, DomainId, DomainHandle);
601
602 /* Map generic access rights */
603 RtlMapGenericMask(&DesiredAccess,
604 &DomainMapping);
605
606 RtlAcquireResourceShared(&SampResource,
607 TRUE);
608
609 /* Validate the server handle */
610 Status = SampValidateDbObject(ServerHandle,
611 SamDbServerObject,
612 SAM_SERVER_LOOKUP_DOMAIN,
613 &ServerObject);
614 if (!NT_SUCCESS(Status))
615 return Status;
616
617 /* Validate the Domain SID */
618 if ((DomainId->Revision != SID_REVISION) ||
619 (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
620 (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
621 return STATUS_INVALID_PARAMETER;
622
623 /* Open the domain object */
624 if ((DomainId->SubAuthorityCount == 1) &&
625 (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
626 {
627 /* Builtin domain object */
628 TRACE("Opening the builtin domain object.\n");
629
630 Status = SampOpenDbObject(ServerObject,
631 L"Domains",
632 L"Builtin",
633 0,
634 SamDbDomainObject,
635 DesiredAccess,
636 &DomainObject);
637 }
638 else if ((DomainId->SubAuthorityCount == 4) &&
639 (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
640 {
641 /* Account domain object */
642 TRACE("Opening the account domain object.\n");
643
644 /* FIXME: Check the account domain sub authorities!!! */
645
646 Status = SampOpenDbObject(ServerObject,
647 L"Domains",
648 L"Account",
649 0,
650 SamDbDomainObject,
651 DesiredAccess,
652 &DomainObject);
653 }
654 else
655 {
656 /* No vaild domain SID */
657 Status = STATUS_INVALID_PARAMETER;
658 }
659
660 if (NT_SUCCESS(Status))
661 *DomainHandle = (SAMPR_HANDLE)DomainObject;
662
663 RtlReleaseResource(&SampResource);
664
665 TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
666
667 return Status;
668 }
669
670
671 static NTSTATUS
672 SampQueryDomainPassword(PSAM_DB_OBJECT DomainObject,
673 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
674 {
675 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
676 SAM_DOMAIN_FIXED_DATA FixedData;
677 ULONG Length = 0;
678 NTSTATUS Status;
679
680 *Buffer = NULL;
681
682 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
683 if (InfoBuffer == NULL)
684 return STATUS_INSUFFICIENT_RESOURCES;
685
686 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
687 Status = SampGetObjectAttribute(DomainObject,
688 L"F",
689 NULL,
690 (PVOID)&FixedData,
691 &Length);
692 if (!NT_SUCCESS(Status))
693 goto done;
694
695 InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
696 InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
697 InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
698 InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
699 InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
700 InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
701 InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
702
703 *Buffer = InfoBuffer;
704
705 done:
706 if (!NT_SUCCESS(Status))
707 {
708 if (InfoBuffer != NULL)
709 {
710 midl_user_free(InfoBuffer);
711 }
712 }
713
714 return Status;
715 }
716
717
718 static NTSTATUS
719 SampGetNumberOfAccounts(PSAM_DB_OBJECT DomainObject,
720 LPCWSTR AccountType,
721 PULONG Count)
722 {
723 HANDLE AccountKeyHandle = NULL;
724 HANDLE NamesKeyHandle = NULL;
725 NTSTATUS Status;
726
727 *Count = 0;
728
729 Status = SampRegOpenKey(DomainObject->KeyHandle,
730 AccountType,
731 KEY_READ,
732 &AccountKeyHandle);
733 if (!NT_SUCCESS(Status))
734 return Status;
735
736 Status = SampRegOpenKey(AccountKeyHandle,
737 L"Names",
738 KEY_READ,
739 &NamesKeyHandle);
740 if (!NT_SUCCESS(Status))
741 goto done;
742
743 Status = SampRegQueryKeyInfo(NamesKeyHandle,
744 NULL,
745 Count);
746
747 done:
748 SampRegCloseKey(&NamesKeyHandle);
749 SampRegCloseKey(&AccountKeyHandle);
750
751 return Status;
752 }
753
754
755 static NTSTATUS
756 SampQueryDomainGeneral(PSAM_DB_OBJECT DomainObject,
757 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
758 {
759 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
760 SAM_DOMAIN_FIXED_DATA FixedData;
761 ULONG Length = 0;
762 NTSTATUS Status;
763
764 *Buffer = NULL;
765
766 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
767 if (InfoBuffer == NULL)
768 return STATUS_INSUFFICIENT_RESOURCES;
769
770 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
771 Status = SampGetObjectAttribute(DomainObject,
772 L"F",
773 NULL,
774 (PVOID)&FixedData,
775 &Length);
776 if (!NT_SUCCESS(Status))
777 goto done;
778
779 InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
780 InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
781 InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
782 InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
783 InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
784 InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
785 InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
786
787 /* Get the OemInformation string */
788 Status = SampGetObjectAttributeString(DomainObject,
789 L"OemInformation",
790 &InfoBuffer->General.OemInformation);
791 if (!NT_SUCCESS(Status))
792 {
793 TRACE("Status 0x%08lx\n", Status);
794 goto done;
795 }
796
797 /* Get the Name string */
798 Status = SampGetObjectAttributeString(DomainObject,
799 L"Name",
800 &InfoBuffer->General.DomainName);
801 if (!NT_SUCCESS(Status))
802 {
803 TRACE("Status 0x%08lx\n", Status);
804 goto done;
805 }
806
807 /* Get the ReplicaSourceNodeName string */
808 Status = SampGetObjectAttributeString(DomainObject,
809 L"ReplicaSourceNodeName",
810 &InfoBuffer->General.ReplicaSourceNodeName);
811 if (!NT_SUCCESS(Status))
812 {
813 TRACE("Status 0x%08lx\n", Status);
814 goto done;
815 }
816
817 /* Get the number of Users in the Domain */
818 Status = SampGetNumberOfAccounts(DomainObject,
819 L"Users",
820 &InfoBuffer->General.UserCount);
821 if (!NT_SUCCESS(Status))
822 {
823 TRACE("Status 0x%08lx\n", Status);
824 goto done;
825 }
826
827 /* Get the number of Groups in the Domain */
828 Status = SampGetNumberOfAccounts(DomainObject,
829 L"Groups",
830 &InfoBuffer->General.GroupCount);
831 if (!NT_SUCCESS(Status))
832 {
833 TRACE("Status 0x%08lx\n", Status);
834 goto done;
835 }
836
837 /* Get the number of Aliases in the Domain */
838 Status = SampGetNumberOfAccounts(DomainObject,
839 L"Aliases",
840 &InfoBuffer->General.AliasCount);
841 if (!NT_SUCCESS(Status))
842 {
843 TRACE("Status 0x%08lx\n", Status);
844 goto done;
845 }
846
847 *Buffer = InfoBuffer;
848
849 done:
850 if (!NT_SUCCESS(Status))
851 {
852 if (InfoBuffer != NULL)
853 {
854 if (InfoBuffer->General.OemInformation.Buffer != NULL)
855 midl_user_free(InfoBuffer->General.OemInformation.Buffer);
856
857 if (InfoBuffer->General.DomainName.Buffer != NULL)
858 midl_user_free(InfoBuffer->General.DomainName.Buffer);
859
860 if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
861 midl_user_free(InfoBuffer->General.ReplicaSourceNodeName.Buffer);
862
863 midl_user_free(InfoBuffer);
864 }
865 }
866
867 return Status;
868 }
869
870
871 static NTSTATUS
872 SampQueryDomainLogoff(PSAM_DB_OBJECT DomainObject,
873 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
874 {
875 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
876 SAM_DOMAIN_FIXED_DATA FixedData;
877 ULONG Length = 0;
878 NTSTATUS Status;
879
880 *Buffer = NULL;
881
882 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
883 if (InfoBuffer == NULL)
884 return STATUS_INSUFFICIENT_RESOURCES;
885
886 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
887 Status = SampGetObjectAttribute(DomainObject,
888 L"F",
889 NULL,
890 (PVOID)&FixedData,
891 &Length);
892 if (!NT_SUCCESS(Status))
893 goto done;
894
895 InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
896 InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
897
898 *Buffer = InfoBuffer;
899
900 done:
901 if (!NT_SUCCESS(Status))
902 {
903 if (InfoBuffer != NULL)
904 {
905 midl_user_free(InfoBuffer);
906 }
907 }
908
909 return Status;
910 }
911
912
913 static NTSTATUS
914 SampQueryDomainOem(PSAM_DB_OBJECT DomainObject,
915 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
916 {
917 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
918 NTSTATUS Status;
919
920 *Buffer = NULL;
921
922 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
923 if (InfoBuffer == NULL)
924 return STATUS_INSUFFICIENT_RESOURCES;
925
926 /* Get the OemInformation string */
927 Status = SampGetObjectAttributeString(DomainObject,
928 L"OemInformation",
929 &InfoBuffer->Oem.OemInformation);
930 if (!NT_SUCCESS(Status))
931 {
932 TRACE("Status 0x%08lx\n", Status);
933 goto done;
934 }
935
936 *Buffer = InfoBuffer;
937
938 done:
939 if (!NT_SUCCESS(Status))
940 {
941 if (InfoBuffer != NULL)
942 {
943 if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
944 midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
945
946 midl_user_free(InfoBuffer);
947 }
948 }
949
950 return Status;
951 }
952
953
954 static NTSTATUS
955 SampQueryDomainName(PSAM_DB_OBJECT DomainObject,
956 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
957 {
958 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
959 NTSTATUS Status;
960
961 *Buffer = NULL;
962
963 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
964 if (InfoBuffer == NULL)
965 return STATUS_INSUFFICIENT_RESOURCES;
966
967 /* Get the Name string */
968 Status = SampGetObjectAttributeString(DomainObject,
969 L"Name",
970 &InfoBuffer->Name.DomainName);
971 if (!NT_SUCCESS(Status))
972 {
973 TRACE("Status 0x%08lx\n", Status);
974 goto done;
975 }
976
977 *Buffer = InfoBuffer;
978
979 done:
980 if (!NT_SUCCESS(Status))
981 {
982 if (InfoBuffer != NULL)
983 {
984 if (InfoBuffer->Name.DomainName.Buffer != NULL)
985 midl_user_free(InfoBuffer->Name.DomainName.Buffer);
986
987 midl_user_free(InfoBuffer);
988 }
989 }
990
991 return Status;
992 }
993
994
995 static NTSTATUS
996 SampQueryDomainReplication(PSAM_DB_OBJECT DomainObject,
997 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
998 {
999 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1000 NTSTATUS Status;
1001
1002 *Buffer = NULL;
1003
1004 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1005 if (InfoBuffer == NULL)
1006 return STATUS_INSUFFICIENT_RESOURCES;
1007
1008 /* Get the ReplicaSourceNodeName string */
1009 Status = SampGetObjectAttributeString(DomainObject,
1010 L"ReplicaSourceNodeName",
1011 &InfoBuffer->Replication.ReplicaSourceNodeName);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 TRACE("Status 0x%08lx\n", Status);
1015 goto done;
1016 }
1017
1018 *Buffer = InfoBuffer;
1019
1020 done:
1021 if (!NT_SUCCESS(Status))
1022 {
1023 if (InfoBuffer != NULL)
1024 {
1025 if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
1026 midl_user_free(InfoBuffer->Replication.ReplicaSourceNodeName.Buffer);
1027
1028 midl_user_free(InfoBuffer);
1029 }
1030 }
1031
1032 return Status;
1033 }
1034
1035
1036 static NTSTATUS
1037 SampQueryDomainServerRole(PSAM_DB_OBJECT DomainObject,
1038 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1039 {
1040 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1041 SAM_DOMAIN_FIXED_DATA FixedData;
1042 ULONG Length = 0;
1043 NTSTATUS Status;
1044
1045 *Buffer = NULL;
1046
1047 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1048 if (InfoBuffer == NULL)
1049 return STATUS_INSUFFICIENT_RESOURCES;
1050
1051 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1052 Status = SampGetObjectAttribute(DomainObject,
1053 L"F",
1054 NULL,
1055 (PVOID)&FixedData,
1056 &Length);
1057 if (!NT_SUCCESS(Status))
1058 goto done;
1059
1060 InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
1061
1062 *Buffer = InfoBuffer;
1063
1064 done:
1065 if (!NT_SUCCESS(Status))
1066 {
1067 if (InfoBuffer != NULL)
1068 {
1069 midl_user_free(InfoBuffer);
1070 }
1071 }
1072
1073 return Status;
1074 }
1075
1076
1077 static NTSTATUS
1078 SampQueryDomainModified(PSAM_DB_OBJECT DomainObject,
1079 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1080 {
1081 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1082 SAM_DOMAIN_FIXED_DATA FixedData;
1083 ULONG Length = 0;
1084 NTSTATUS Status;
1085
1086 *Buffer = NULL;
1087
1088 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1089 if (InfoBuffer == NULL)
1090 return STATUS_INSUFFICIENT_RESOURCES;
1091
1092 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1093 Status = SampGetObjectAttribute(DomainObject,
1094 L"F",
1095 NULL,
1096 (PVOID)&FixedData,
1097 &Length);
1098 if (!NT_SUCCESS(Status))
1099 goto done;
1100
1101 InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1102 InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1103 InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1104 InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1105
1106 *Buffer = InfoBuffer;
1107
1108 done:
1109 if (!NT_SUCCESS(Status))
1110 {
1111 if (InfoBuffer != NULL)
1112 {
1113 midl_user_free(InfoBuffer);
1114 }
1115 }
1116
1117 return Status;
1118 }
1119
1120
1121 static NTSTATUS
1122 SampQueryDomainState(PSAM_DB_OBJECT DomainObject,
1123 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1124 {
1125 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1126 SAM_DOMAIN_FIXED_DATA FixedData;
1127 ULONG Length = 0;
1128 NTSTATUS Status;
1129
1130 *Buffer = NULL;
1131
1132 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1133 if (InfoBuffer == NULL)
1134 return STATUS_INSUFFICIENT_RESOURCES;
1135
1136 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1137 Status = SampGetObjectAttribute(DomainObject,
1138 L"F",
1139 NULL,
1140 (PVOID)&FixedData,
1141 &Length);
1142 if (!NT_SUCCESS(Status))
1143 goto done;
1144
1145 InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1146
1147 *Buffer = InfoBuffer;
1148
1149 done:
1150 if (!NT_SUCCESS(Status))
1151 {
1152 if (InfoBuffer != NULL)
1153 {
1154 midl_user_free(InfoBuffer);
1155 }
1156 }
1157
1158 return Status;
1159 }
1160
1161
1162 static NTSTATUS
1163 SampQueryDomainGeneral2(PSAM_DB_OBJECT DomainObject,
1164 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1165 {
1166 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1167 SAM_DOMAIN_FIXED_DATA FixedData;
1168 ULONG Length = 0;
1169 NTSTATUS Status;
1170
1171 *Buffer = NULL;
1172
1173 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1174 if (InfoBuffer == NULL)
1175 return STATUS_INSUFFICIENT_RESOURCES;
1176
1177 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1178 Status = SampGetObjectAttribute(DomainObject,
1179 L"F",
1180 NULL,
1181 (PVOID)&FixedData,
1182 &Length);
1183 if (!NT_SUCCESS(Status))
1184 goto done;
1185
1186 InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1187 InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1188 InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1189 InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1190 InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1191 InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1192 InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1193
1194 InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1195 InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1196 InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1197
1198 /* Get the OemInformation string */
1199 Status = SampGetObjectAttributeString(DomainObject,
1200 L"OemInformation",
1201 &InfoBuffer->General2.I1.OemInformation);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 TRACE("Status 0x%08lx\n", Status);
1205 goto done;
1206 }
1207
1208 /* Get the Name string */
1209 Status = SampGetObjectAttributeString(DomainObject,
1210 L"Name",
1211 &InfoBuffer->General2.I1.DomainName);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 TRACE("Status 0x%08lx\n", Status);
1215 goto done;
1216 }
1217
1218 /* Get the ReplicaSourceNodeName string */
1219 Status = SampGetObjectAttributeString(DomainObject,
1220 L"ReplicaSourceNodeName",
1221 &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1222 if (!NT_SUCCESS(Status))
1223 {
1224 TRACE("Status 0x%08lx\n", Status);
1225 goto done;
1226 }
1227
1228 /* Get the number of Users in the Domain */
1229 Status = SampGetNumberOfAccounts(DomainObject,
1230 L"Users",
1231 &InfoBuffer->General2.I1.UserCount);
1232 if (!NT_SUCCESS(Status))
1233 {
1234 TRACE("Status 0x%08lx\n", Status);
1235 goto done;
1236 }
1237
1238 /* Get the number of Groups in the Domain */
1239 Status = SampGetNumberOfAccounts(DomainObject,
1240 L"Groups",
1241 &InfoBuffer->General2.I1.GroupCount);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 TRACE("Status 0x%08lx\n", Status);
1245 goto done;
1246 }
1247
1248 /* Get the number of Aliases in the Domain */
1249 Status = SampGetNumberOfAccounts(DomainObject,
1250 L"Aliases",
1251 &InfoBuffer->General2.I1.AliasCount);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 TRACE("Status 0x%08lx\n", Status);
1255 goto done;
1256 }
1257
1258 *Buffer = InfoBuffer;
1259
1260 done:
1261 if (!NT_SUCCESS(Status))
1262 {
1263 if (InfoBuffer != NULL)
1264 {
1265 if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1266 midl_user_free(InfoBuffer->General2.I1.OemInformation.Buffer);
1267
1268 if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1269 midl_user_free(InfoBuffer->General2.I1.DomainName.Buffer);
1270
1271 if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1272 midl_user_free(InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer);
1273
1274 midl_user_free(InfoBuffer);
1275 }
1276 }
1277
1278 return Status;
1279 }
1280
1281
1282 static NTSTATUS
1283 SampQueryDomainLockout(PSAM_DB_OBJECT DomainObject,
1284 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1285 {
1286 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1287 SAM_DOMAIN_FIXED_DATA FixedData;
1288 ULONG Length = 0;
1289 NTSTATUS Status;
1290
1291 *Buffer = NULL;
1292
1293 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1294 if (InfoBuffer == NULL)
1295 return STATUS_INSUFFICIENT_RESOURCES;
1296
1297 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1298 Status = SampGetObjectAttribute(DomainObject,
1299 L"F",
1300 NULL,
1301 (PVOID)&FixedData,
1302 &Length);
1303 if (!NT_SUCCESS(Status))
1304 goto done;
1305
1306 InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1307 InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1308 InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1309
1310 *Buffer = InfoBuffer;
1311
1312 done:
1313 if (!NT_SUCCESS(Status))
1314 {
1315 if (InfoBuffer != NULL)
1316 {
1317 midl_user_free(InfoBuffer);
1318 }
1319 }
1320
1321 return Status;
1322 }
1323
1324
1325 static NTSTATUS
1326 SampQueryDomainModified2(PSAM_DB_OBJECT DomainObject,
1327 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1328 {
1329 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1330 SAM_DOMAIN_FIXED_DATA FixedData;
1331 ULONG Length = 0;
1332 NTSTATUS Status;
1333
1334 *Buffer = NULL;
1335
1336 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1337 if (InfoBuffer == NULL)
1338 return STATUS_INSUFFICIENT_RESOURCES;
1339
1340 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1341 Status = SampGetObjectAttribute(DomainObject,
1342 L"F",
1343 NULL,
1344 (PVOID)&FixedData,
1345 &Length);
1346 if (!NT_SUCCESS(Status))
1347 goto done;
1348
1349 InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1350 InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1351 InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1352 InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1353 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1354 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1355
1356 *Buffer = InfoBuffer;
1357
1358 done:
1359 if (!NT_SUCCESS(Status))
1360 {
1361 if (InfoBuffer != NULL)
1362 {
1363 midl_user_free(InfoBuffer);
1364 }
1365 }
1366
1367 return Status;
1368 }
1369
1370
1371 /* Function 8 */
1372 NTSTATUS
1373 NTAPI
1374 SamrQueryInformationDomain(IN SAMPR_HANDLE DomainHandle,
1375 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1376 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1377 {
1378 PSAM_DB_OBJECT DomainObject;
1379 ACCESS_MASK DesiredAccess;
1380 NTSTATUS Status;
1381
1382 TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1383 DomainHandle, DomainInformationClass, Buffer);
1384
1385 switch (DomainInformationClass)
1386 {
1387 case DomainPasswordInformation:
1388 case DomainLockoutInformation:
1389 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
1390 break;
1391
1392 case DomainGeneralInformation:
1393 case DomainLogoffInformation:
1394 case DomainOemInformation:
1395 case DomainNameInformation:
1396 case DomainReplicationInformation:
1397 case DomainServerRoleInformation:
1398 case DomainModifiedInformation:
1399 case DomainStateInformation:
1400 case DomainModifiedInformation2:
1401 DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
1402 break;
1403
1404 case DomainGeneralInformation2:
1405 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS |
1406 DOMAIN_READ_OTHER_PARAMETERS;
1407 break;
1408
1409 default:
1410 return STATUS_INVALID_INFO_CLASS;
1411 }
1412
1413 RtlAcquireResourceShared(&SampResource,
1414 TRUE);
1415
1416 /* Validate the server handle */
1417 Status = SampValidateDbObject(DomainHandle,
1418 SamDbDomainObject,
1419 DesiredAccess,
1420 &DomainObject);
1421 if (!NT_SUCCESS(Status))
1422 goto done;
1423
1424 switch (DomainInformationClass)
1425 {
1426 case DomainPasswordInformation:
1427 Status = SampQueryDomainPassword(DomainObject,
1428 Buffer);
1429 break;
1430
1431 case DomainGeneralInformation:
1432 Status = SampQueryDomainGeneral(DomainObject,
1433 Buffer);
1434 break;
1435
1436 case DomainLogoffInformation:
1437 Status = SampQueryDomainLogoff(DomainObject,
1438 Buffer);
1439 break;
1440
1441 case DomainOemInformation:
1442 Status = SampQueryDomainOem(DomainObject,
1443 Buffer);
1444 break;
1445
1446 case DomainNameInformation:
1447 Status = SampQueryDomainName(DomainObject,
1448 Buffer);
1449 break;
1450
1451 case DomainReplicationInformation:
1452 Status = SampQueryDomainReplication(DomainObject,
1453 Buffer);
1454 break;
1455
1456 case DomainServerRoleInformation:
1457 Status = SampQueryDomainServerRole(DomainObject,
1458 Buffer);
1459 break;
1460
1461 case DomainModifiedInformation:
1462 Status = SampQueryDomainModified(DomainObject,
1463 Buffer);
1464 break;
1465
1466 case DomainStateInformation:
1467 Status = SampQueryDomainState(DomainObject,
1468 Buffer);
1469 break;
1470
1471 case DomainGeneralInformation2:
1472 Status = SampQueryDomainGeneral2(DomainObject,
1473 Buffer);
1474 break;
1475
1476 case DomainLockoutInformation:
1477 Status = SampQueryDomainLockout(DomainObject,
1478 Buffer);
1479 break;
1480
1481 case DomainModifiedInformation2:
1482 Status = SampQueryDomainModified2(DomainObject,
1483 Buffer);
1484 break;
1485
1486 default:
1487 Status = STATUS_NOT_IMPLEMENTED;
1488 }
1489
1490 done:
1491 RtlReleaseResource(&SampResource);
1492
1493 return Status;
1494 }
1495
1496
1497 static NTSTATUS
1498 SampSetDomainPassword(PSAM_DB_OBJECT DomainObject,
1499 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1500 {
1501 SAM_DOMAIN_FIXED_DATA FixedData;
1502 ULONG Length = 0;
1503 NTSTATUS Status;
1504
1505 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1506 Status = SampGetObjectAttribute(DomainObject,
1507 L"F",
1508 NULL,
1509 (PVOID)&FixedData,
1510 &Length);
1511 if (!NT_SUCCESS(Status))
1512 goto done;
1513
1514 FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1515 FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1516 FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1517 FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1518 FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1519 FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1520 FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1521
1522 Status = SampSetObjectAttribute(DomainObject,
1523 L"F",
1524 REG_BINARY,
1525 &FixedData,
1526 Length);
1527
1528 done:
1529 return Status;
1530 }
1531
1532
1533 static NTSTATUS
1534 SampSetDomainLogoff(PSAM_DB_OBJECT DomainObject,
1535 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1536 {
1537 SAM_DOMAIN_FIXED_DATA FixedData;
1538 ULONG Length = 0;
1539 NTSTATUS Status;
1540
1541 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1542 Status = SampGetObjectAttribute(DomainObject,
1543 L"F",
1544 NULL,
1545 (PVOID)&FixedData,
1546 &Length);
1547 if (!NT_SUCCESS(Status))
1548 goto done;
1549
1550 FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1551 FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1552
1553 Status = SampSetObjectAttribute(DomainObject,
1554 L"F",
1555 REG_BINARY,
1556 &FixedData,
1557 Length);
1558
1559 done:
1560 return Status;
1561 }
1562
1563
1564 static NTSTATUS
1565 SampSetDomainServerRole(PSAM_DB_OBJECT DomainObject,
1566 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1567 {
1568 SAM_DOMAIN_FIXED_DATA FixedData;
1569 ULONG Length = 0;
1570 NTSTATUS Status;
1571
1572 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1573 Status = SampGetObjectAttribute(DomainObject,
1574 L"F",
1575 NULL,
1576 (PVOID)&FixedData,
1577 &Length);
1578 if (!NT_SUCCESS(Status))
1579 goto done;
1580
1581 FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1582
1583 Status = SampSetObjectAttribute(DomainObject,
1584 L"F",
1585 REG_BINARY,
1586 &FixedData,
1587 Length);
1588
1589 done:
1590 return Status;
1591 }
1592
1593
1594 static NTSTATUS
1595 SampSetDomainState(PSAM_DB_OBJECT DomainObject,
1596 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1597 {
1598 SAM_DOMAIN_FIXED_DATA FixedData;
1599 ULONG Length = 0;
1600 NTSTATUS Status;
1601
1602 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1603 Status = SampGetObjectAttribute(DomainObject,
1604 L"F",
1605 NULL,
1606 (PVOID)&FixedData,
1607 &Length);
1608 if (!NT_SUCCESS(Status))
1609 goto done;
1610
1611 FixedData.DomainServerState = Buffer->State.DomainServerState;
1612
1613 Status = SampSetObjectAttribute(DomainObject,
1614 L"F",
1615 REG_BINARY,
1616 &FixedData,
1617 Length);
1618
1619 done:
1620 return Status;
1621 }
1622
1623
1624 static NTSTATUS
1625 SampSetDomainLockout(PSAM_DB_OBJECT DomainObject,
1626 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1627 {
1628 SAM_DOMAIN_FIXED_DATA FixedData;
1629 ULONG Length = 0;
1630 NTSTATUS Status;
1631
1632 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1633 Status = SampGetObjectAttribute(DomainObject,
1634 L"F",
1635 NULL,
1636 (PVOID)&FixedData,
1637 &Length);
1638 if (!NT_SUCCESS(Status))
1639 goto done;
1640
1641 FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1642 FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1643 FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1644
1645 Status = SampSetObjectAttribute(DomainObject,
1646 L"F",
1647 REG_BINARY,
1648 &FixedData,
1649 Length);
1650
1651 done:
1652 return Status;
1653 }
1654
1655
1656 /* Function 9 */
1657 NTSTATUS
1658 NTAPI
1659 SamrSetInformationDomain(IN SAMPR_HANDLE DomainHandle,
1660 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1661 IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1662 {
1663 PSAM_DB_OBJECT DomainObject;
1664 ACCESS_MASK DesiredAccess;
1665 NTSTATUS Status;
1666
1667 TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1668 DomainHandle, DomainInformationClass, DomainInformation);
1669
1670 switch (DomainInformationClass)
1671 {
1672 case DomainPasswordInformation:
1673 case DomainLockoutInformation:
1674 DesiredAccess = DOMAIN_WRITE_PASSWORD_PARAMS;
1675 break;
1676
1677 case DomainLogoffInformation:
1678 case DomainOemInformation:
1679 case DomainNameInformation:
1680 DesiredAccess = DOMAIN_WRITE_OTHER_PARAMETERS;
1681 break;
1682
1683 case DomainReplicationInformation:
1684 case DomainServerRoleInformation:
1685 case DomainStateInformation:
1686 DesiredAccess = DOMAIN_ADMINISTER_SERVER;
1687 break;
1688
1689 default:
1690 return STATUS_INVALID_INFO_CLASS;
1691 }
1692
1693 RtlAcquireResourceExclusive(&SampResource,
1694 TRUE);
1695
1696 /* Validate the server handle */
1697 Status = SampValidateDbObject(DomainHandle,
1698 SamDbDomainObject,
1699 DesiredAccess,
1700 &DomainObject);
1701 if (!NT_SUCCESS(Status))
1702 goto done;
1703
1704 switch (DomainInformationClass)
1705 {
1706 case DomainPasswordInformation:
1707 Status = SampSetDomainPassword(DomainObject,
1708 DomainInformation);
1709 break;
1710
1711 case DomainLogoffInformation:
1712 Status = SampSetDomainLogoff(DomainObject,
1713 DomainInformation);
1714 break;
1715
1716 case DomainOemInformation:
1717 Status = SampSetObjectAttributeString(DomainObject,
1718 L"OemInformation",
1719 &DomainInformation->Oem.OemInformation);
1720 break;
1721
1722 case DomainNameInformation:
1723 Status = SampSetObjectAttributeString(DomainObject,
1724 L"Name",
1725 &DomainInformation->Name.DomainName);
1726 break;
1727
1728 case DomainReplicationInformation:
1729 Status = SampSetObjectAttributeString(DomainObject,
1730 L"ReplicaSourceNodeName",
1731 &DomainInformation->Replication.ReplicaSourceNodeName);
1732 break;
1733
1734 case DomainServerRoleInformation:
1735 Status = SampSetDomainServerRole(DomainObject,
1736 DomainInformation);
1737 break;
1738
1739 case DomainStateInformation:
1740 Status = SampSetDomainState(DomainObject,
1741 DomainInformation);
1742 break;
1743
1744 case DomainLockoutInformation:
1745 Status = SampSetDomainLockout(DomainObject,
1746 DomainInformation);
1747 break;
1748
1749 default:
1750 Status = STATUS_NOT_IMPLEMENTED;
1751 }
1752
1753 done:
1754 RtlReleaseResource(&SampResource);
1755
1756 return Status;
1757 }
1758
1759
1760 /* Function 10 */
1761 NTSTATUS
1762 NTAPI
1763 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1764 IN PRPC_UNICODE_STRING Name,
1765 IN ACCESS_MASK DesiredAccess,
1766 OUT SAMPR_HANDLE *GroupHandle,
1767 OUT unsigned long *RelativeId)
1768 {
1769 SAM_DOMAIN_FIXED_DATA FixedDomainData;
1770 SAM_GROUP_FIXED_DATA FixedGroupData;
1771 PSAM_DB_OBJECT DomainObject;
1772 PSAM_DB_OBJECT GroupObject;
1773 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 PSECURITY_DESCRIPTOR Sd = NULL;
2178 ULONG SdSize = 0;
2179 PSID UserSid = NULL;
2180 NTSTATUS Status;
2181
2182 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2183 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2184
2185 if (Name == NULL ||
2186 Name->Length == 0 ||
2187 Name->Buffer == NULL ||
2188 UserHandle == NULL ||
2189 RelativeId == NULL)
2190 return STATUS_INVALID_PARAMETER;
2191
2192 /* Map generic access rights */
2193 RtlMapGenericMask(&DesiredAccess,
2194 &UserMapping);
2195
2196 RtlAcquireResourceExclusive(&SampResource,
2197 TRUE);
2198
2199 /* Validate the domain handle */
2200 Status = SampValidateDbObject(DomainHandle,
2201 SamDbDomainObject,
2202 DOMAIN_CREATE_USER,
2203 &DomainObject);
2204 if (!NT_SUCCESS(Status))
2205 {
2206 TRACE("failed with status 0x%08lx\n", Status);
2207 goto done;
2208 }
2209
2210 /* Check the user account name */
2211 Status = SampCheckAccountName(Name, 20);
2212 if (!NT_SUCCESS(Status))
2213 {
2214 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2215 goto done;
2216 }
2217
2218 /* Check if the user name already exists in the domain */
2219 Status = SampCheckAccountNameInDomain(DomainObject,
2220 Name->Buffer);
2221 if (!NT_SUCCESS(Status))
2222 {
2223 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2224 Name->Buffer, Status);
2225 goto done;
2226 }
2227
2228 /* Get the fixed domain attributes */
2229 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2230 Status = SampGetObjectAttribute(DomainObject,
2231 L"F",
2232 NULL,
2233 (PVOID)&FixedDomainData,
2234 &ulSize);
2235 if (!NT_SUCCESS(Status))
2236 {
2237 TRACE("failed with status 0x%08lx\n", Status);
2238 goto done;
2239 }
2240
2241 /* Increment the NextRid attribute */
2242 ulRid = FixedDomainData.NextRid;
2243 FixedDomainData.NextRid++;
2244
2245 TRACE("RID: %lx\n", ulRid);
2246
2247 /* Create the user SID */
2248 Status = SampCreateAccountSid(DomainObject,
2249 ulRid,
2250 &UserSid);
2251 if (!NT_SUCCESS(Status))
2252 {
2253 TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
2254 goto done;
2255 }
2256
2257 /* Create the security descriptor */
2258 Status = SampCreateUserSD(UserSid,
2259 &Sd,
2260 &SdSize);
2261 if (!NT_SUCCESS(Status))
2262 {
2263 TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
2264 goto done;
2265 }
2266
2267 /* Store the fixed domain attributes */
2268 Status = SampSetObjectAttribute(DomainObject,
2269 L"F",
2270 REG_BINARY,
2271 &FixedDomainData,
2272 ulSize);
2273 if (!NT_SUCCESS(Status))
2274 {
2275 TRACE("failed with status 0x%08lx\n", Status);
2276 goto done;
2277 }
2278
2279 /* Convert the RID into a string (hex) */
2280 swprintf(szRid, L"%08lX", ulRid);
2281
2282 /* Create the user object */
2283 Status = SampCreateDbObject(DomainObject,
2284 L"Users",
2285 szRid,
2286 ulRid,
2287 SamDbUserObject,
2288 DesiredAccess,
2289 &UserObject);
2290 if (!NT_SUCCESS(Status))
2291 {
2292 TRACE("failed with status 0x%08lx\n", Status);
2293 goto done;
2294 }
2295
2296 /* Add the account name for the user object */
2297 Status = SampSetAccountNameInDomain(DomainObject,
2298 L"Users",
2299 Name->Buffer,
2300 ulRid);
2301 if (!NT_SUCCESS(Status))
2302 {
2303 TRACE("failed with status 0x%08lx\n", Status);
2304 goto done;
2305 }
2306
2307 /* Initialize fixed user data */
2308 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2309 FixedUserData.Version = 1;
2310 FixedUserData.Reserved = 0;
2311 FixedUserData.LastLogon.QuadPart = 0;
2312 FixedUserData.LastLogoff.QuadPart = 0;
2313 FixedUserData.PasswordLastSet.QuadPart = 0;
2314 FixedUserData.AccountExpires.LowPart = MAXULONG;
2315 FixedUserData.AccountExpires.HighPart = MAXLONG;
2316 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2317 FixedUserData.UserId = ulRid;
2318 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2319 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2320 USER_PASSWORD_NOT_REQUIRED |
2321 USER_NORMAL_ACCOUNT;
2322 FixedUserData.CountryCode = 0;
2323 FixedUserData.CodePage = 0;
2324 FixedUserData.BadPasswordCount = 0;
2325 FixedUserData.LogonCount = 0;
2326 FixedUserData.AdminCount = 0;
2327 FixedUserData.OperatorCount = 0;
2328
2329 /* Set fixed user data attribute */
2330 Status = SampSetObjectAttribute(UserObject,
2331 L"F",
2332 REG_BINARY,
2333 (LPVOID)&FixedUserData,
2334 sizeof(SAM_USER_FIXED_DATA));
2335 if (!NT_SUCCESS(Status))
2336 {
2337 TRACE("failed with status 0x%08lx\n", Status);
2338 goto done;
2339 }
2340
2341 /* Set the Name attribute */
2342 Status = SampSetObjectAttributeString(UserObject,
2343 L"Name",
2344 Name);
2345 if (!NT_SUCCESS(Status))
2346 {
2347 TRACE("failed with status 0x%08lx\n", Status);
2348 goto done;
2349 }
2350
2351 /* Set the FullName attribute */
2352 Status = SampSetObjectAttributeString(UserObject,
2353 L"FullName",
2354 NULL);
2355 if (!NT_SUCCESS(Status))
2356 {
2357 TRACE("failed with status 0x%08lx\n", Status);
2358 goto done;
2359 }
2360
2361 /* Set the HomeDirectory attribute */
2362 Status = SampSetObjectAttributeString(UserObject,
2363 L"HomeDirectory",
2364 NULL);
2365 if (!NT_SUCCESS(Status))
2366 {
2367 TRACE("failed with status 0x%08lx\n", Status);
2368 goto done;
2369 }
2370
2371 /* Set the HomeDirectoryDrive attribute */
2372 Status = SampSetObjectAttributeString(UserObject,
2373 L"HomeDirectoryDrive",
2374 NULL);
2375 if (!NT_SUCCESS(Status))
2376 {
2377 TRACE("failed with status 0x%08lx\n", Status);
2378 goto done;
2379 }
2380
2381 /* Set the ScriptPath attribute */
2382 Status = SampSetObjectAttributeString(UserObject,
2383 L"ScriptPath",
2384 NULL);
2385 if (!NT_SUCCESS(Status))
2386 {
2387 TRACE("failed with status 0x%08lx\n", Status);
2388 goto done;
2389 }
2390
2391 /* Set the ProfilePath attribute */
2392 Status = SampSetObjectAttributeString(UserObject,
2393 L"ProfilePath",
2394 NULL);
2395 if (!NT_SUCCESS(Status))
2396 {
2397 TRACE("failed with status 0x%08lx\n", Status);
2398 goto done;
2399 }
2400
2401 /* Set the AdminComment attribute */
2402 Status = SampSetObjectAttributeString(UserObject,
2403 L"AdminComment",
2404 NULL);
2405 if (!NT_SUCCESS(Status))
2406 {
2407 TRACE("failed with status 0x%08lx\n", Status);
2408 goto done;
2409 }
2410
2411 /* Set the UserComment attribute */
2412 Status = SampSetObjectAttributeString(UserObject,
2413 L"UserComment",
2414 NULL);
2415 if (!NT_SUCCESS(Status))
2416 {
2417 TRACE("failed with status 0x%08lx\n", Status);
2418 goto done;
2419 }
2420
2421 /* Set the WorkStations attribute */
2422 Status = SampSetObjectAttributeString(UserObject,
2423 L"WorkStations",
2424 NULL);
2425 if (!NT_SUCCESS(Status))
2426 {
2427 TRACE("failed with status 0x%08lx\n", Status);
2428 goto done;
2429 }
2430
2431 /* Set the Parameters attribute */
2432 Status = SampSetObjectAttributeString(UserObject,
2433 L"Parameters",
2434 NULL);
2435 if (!NT_SUCCESS(Status))
2436 {
2437 TRACE("failed with status 0x%08lx\n", Status);
2438 goto done;
2439 }
2440
2441 /* Set LogonHours attribute*/
2442 *((PUSHORT)LogonHours) = 168;
2443 memset(&(LogonHours[2]), 0xff, 21);
2444
2445 Status = SampSetObjectAttribute(UserObject,
2446 L"LogonHours",
2447 REG_BINARY,
2448 &LogonHours,
2449 sizeof(LogonHours));
2450 if (!NT_SUCCESS(Status))
2451 {
2452 TRACE("failed with status 0x%08lx\n", Status);
2453 goto done;
2454 }
2455
2456 /* Set Groups attribute*/
2457 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2458 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2459 SE_GROUP_ENABLED |
2460 SE_GROUP_ENABLED_BY_DEFAULT;
2461
2462 Status = SampSetObjectAttribute(UserObject,
2463 L"Groups",
2464 REG_BINARY,
2465 &GroupMembership,
2466 sizeof(GROUP_MEMBERSHIP));
2467 if (!NT_SUCCESS(Status))
2468 {
2469 TRACE("failed with status 0x%08lx\n", Status);
2470 goto done;
2471 }
2472
2473 /* Set LMPwd attribute*/
2474 Status = SampSetObjectAttribute(UserObject,
2475 L"LMPwd",
2476 REG_BINARY,
2477 &EmptyLmHash,
2478 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2479 if (!NT_SUCCESS(Status))
2480 {
2481 TRACE("failed with status 0x%08lx\n", Status);
2482 goto done;
2483 }
2484
2485 /* Set NTPwd attribute*/
2486 Status = SampSetObjectAttribute(UserObject,
2487 L"NTPwd",
2488 REG_BINARY,
2489 &EmptyNtHash,
2490 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2491 if (!NT_SUCCESS(Status))
2492 {
2493 TRACE("failed with status 0x%08lx\n", Status);
2494 goto done;
2495 }
2496
2497 /* Set LMPwdHistory attribute*/
2498 Status = SampSetObjectAttribute(UserObject,
2499 L"LMPwdHistory",
2500 REG_BINARY,
2501 NULL,
2502 0);
2503 if (!NT_SUCCESS(Status))
2504 {
2505 TRACE("failed with status 0x%08lx\n", Status);
2506 goto done;
2507 }
2508
2509 /* Set NTPwdHistory attribute*/
2510 Status = SampSetObjectAttribute(UserObject,
2511 L"NTPwdHistory",
2512 REG_BINARY,
2513 NULL,
2514 0);
2515 if (!NT_SUCCESS(Status))
2516 {
2517 TRACE("failed with status 0x%08lx\n", Status);
2518 goto done;
2519 }
2520
2521 /* Set the PrivateData attribute */
2522 Status = SampSetObjectAttributeString(UserObject,
2523 L"PrivateData",
2524 NULL);
2525 if (!NT_SUCCESS(Status))
2526 {
2527 TRACE("failed with status 0x%08lx\n", Status);
2528 goto done;
2529 }
2530
2531 /* Set the SecDesc attribute*/
2532 Status = SampSetObjectAttribute(UserObject,
2533 L"SecDesc",
2534 REG_BINARY,
2535 Sd,
2536 SdSize);
2537 if (!NT_SUCCESS(Status))
2538 {
2539 TRACE("failed with status 0x%08lx\n", Status);
2540 goto done;
2541 }
2542
2543 if (NT_SUCCESS(Status))
2544 {
2545 *UserHandle = (SAMPR_HANDLE)UserObject;
2546 *RelativeId = ulRid;
2547 }
2548
2549 done:
2550 if (Sd != NULL)
2551 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2552
2553 if (UserSid != NULL)
2554 RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2555
2556 RtlReleaseResource(&SampResource);
2557
2558 TRACE("returns with status 0x%08lx\n", Status);
2559
2560 return Status;
2561 }
2562
2563
2564 /* Function 13 */
2565 NTSTATUS
2566 NTAPI
2567 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2568 IN OUT unsigned long *EnumerationContext,
2569 IN unsigned long UserAccountControl,
2570 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2571 IN unsigned long PreferedMaximumLength,
2572 OUT unsigned long *CountReturned)
2573 {
2574 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2575 PSAM_DB_OBJECT DomainObject;
2576 HANDLE UsersKeyHandle = NULL;
2577 HANDLE NamesKeyHandle = NULL;
2578 WCHAR UserName[64];
2579 ULONG EnumIndex;
2580 ULONG EnumCount = 0;
2581 ULONG RequiredLength = 0;
2582 ULONG NameLength;
2583 ULONG DataLength;
2584 ULONG Rid;
2585 ULONG i;
2586 BOOLEAN MoreEntries = FALSE;
2587 NTSTATUS Status;
2588
2589 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2590 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2591 PreferedMaximumLength, CountReturned);
2592
2593 RtlAcquireResourceShared(&SampResource,
2594 TRUE);
2595
2596 /* Validate the domain handle */
2597 Status = SampValidateDbObject(DomainHandle,
2598 SamDbDomainObject,
2599 DOMAIN_LIST_ACCOUNTS,
2600 &DomainObject);
2601 if (!NT_SUCCESS(Status))
2602 goto done;
2603
2604 Status = SampRegOpenKey(DomainObject->KeyHandle,
2605 L"Users",
2606 KEY_READ,
2607 &UsersKeyHandle);
2608 if (!NT_SUCCESS(Status))
2609 goto done;
2610
2611 Status = SampRegOpenKey(UsersKeyHandle,
2612 L"Names",
2613 KEY_READ,
2614 &NamesKeyHandle);
2615 if (!NT_SUCCESS(Status))
2616 goto done;
2617
2618 TRACE("Part 1\n");
2619
2620 EnumIndex = *EnumerationContext;
2621
2622 while (TRUE)
2623 {
2624 NameLength = 64 * sizeof(WCHAR);
2625 Status = SampRegEnumerateValue(NamesKeyHandle,
2626 EnumIndex,
2627 UserName,
2628 &NameLength,
2629 NULL,
2630 NULL,
2631 NULL);
2632 if (!NT_SUCCESS(Status))
2633 {
2634 if (Status == STATUS_NO_MORE_ENTRIES)
2635 Status = STATUS_SUCCESS;
2636 break;
2637 }
2638
2639 TRACE("EnumIndex: %lu\n", EnumIndex);
2640 TRACE("User name: %S\n", UserName);
2641 TRACE("Name length: %lu\n", NameLength);
2642
2643 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2644 {
2645 MoreEntries = TRUE;
2646 break;
2647 }
2648
2649 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2650 EnumCount++;
2651
2652 EnumIndex++;
2653 }
2654
2655 TRACE("EnumCount: %lu\n", EnumCount);
2656 TRACE("RequiredLength: %lu\n", RequiredLength);
2657
2658 if (!NT_SUCCESS(Status))
2659 goto done;
2660
2661 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2662 if (EnumBuffer == NULL)
2663 {
2664 Status = STATUS_INSUFFICIENT_RESOURCES;
2665 goto done;
2666 }
2667
2668 EnumBuffer->EntriesRead = EnumCount;
2669 if (EnumCount == 0)
2670 goto done;
2671
2672 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2673 if (EnumBuffer->Buffer == NULL)
2674 {
2675 Status = STATUS_INSUFFICIENT_RESOURCES;
2676 goto done;
2677 }
2678
2679 TRACE("Part 2\n");
2680
2681 EnumIndex = *EnumerationContext;
2682 for (i = 0; i < EnumCount; i++, EnumIndex++)
2683 {
2684 NameLength = 64 * sizeof(WCHAR);
2685 DataLength = sizeof(ULONG);
2686 Status = SampRegEnumerateValue(NamesKeyHandle,
2687 EnumIndex,
2688 UserName,
2689 &NameLength,
2690 NULL,
2691 &Rid,
2692 &DataLength);
2693 if (!NT_SUCCESS(Status))
2694 {
2695 if (Status == STATUS_NO_MORE_ENTRIES)
2696 Status = STATUS_SUCCESS;
2697 break;
2698 }
2699
2700 TRACE("EnumIndex: %lu\n", EnumIndex);
2701 TRACE("User name: %S\n", UserName);
2702 TRACE("Name length: %lu\n", NameLength);
2703 TRACE("RID: %lu\n", Rid);
2704
2705 EnumBuffer->Buffer[i].RelativeId = Rid;
2706
2707 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2708 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2709
2710 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2711 #if 0
2712 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2713 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2714 {
2715 Status = STATUS_INSUFFICIENT_RESOURCES;
2716 goto done;
2717 }
2718
2719 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2720 UserName,
2721 EnumBuffer->Buffer[i].Name.Length);
2722 #endif
2723 }
2724
2725 done:
2726 if (NT_SUCCESS(Status))
2727 {
2728 *EnumerationContext += EnumCount;
2729 *Buffer = EnumBuffer;
2730 *CountReturned = EnumCount;
2731 }
2732 else
2733 {
2734 *EnumerationContext = 0;
2735 *Buffer = NULL;
2736 *CountReturned = 0;
2737
2738 if (EnumBuffer != NULL)
2739 {
2740 if (EnumBuffer->Buffer != NULL)
2741 {
2742 if (EnumBuffer->EntriesRead != 0)
2743 {
2744 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2745 {
2746 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2747 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2748 }
2749 }
2750
2751 midl_user_free(EnumBuffer->Buffer);
2752 }
2753
2754 midl_user_free(EnumBuffer);
2755 }
2756 }
2757
2758 SampRegCloseKey(&NamesKeyHandle);
2759 SampRegCloseKey(&UsersKeyHandle);
2760
2761 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2762 Status = STATUS_MORE_ENTRIES;
2763
2764 RtlReleaseResource(&SampResource);
2765
2766 return Status;
2767 }
2768
2769
2770 /* Function 14 */
2771 NTSTATUS
2772 NTAPI
2773 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2774 IN PRPC_UNICODE_STRING AccountName,
2775 IN ACCESS_MASK DesiredAccess,
2776 OUT SAMPR_HANDLE *AliasHandle,
2777 OUT unsigned long *RelativeId)
2778 {
2779 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2780 PSAM_DB_OBJECT DomainObject;
2781 PSAM_DB_OBJECT AliasObject;
2782 PSECURITY_DESCRIPTOR Sd = NULL;
2783 ULONG SdSize = 0;
2784 ULONG ulSize;
2785 ULONG ulRid;
2786 WCHAR szRid[9];
2787 NTSTATUS Status;
2788
2789 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2790 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2791
2792 /* Map generic access rights */
2793 RtlMapGenericMask(&DesiredAccess,
2794 &AliasMapping);
2795
2796 RtlAcquireResourceExclusive(&SampResource,
2797 TRUE);
2798
2799 /* Validate the domain handle */
2800 Status = SampValidateDbObject(DomainHandle,
2801 SamDbDomainObject,
2802 DOMAIN_CREATE_ALIAS,
2803 &DomainObject);
2804 if (!NT_SUCCESS(Status))
2805 {
2806 TRACE("failed with status 0x%08lx\n", Status);
2807 goto done;
2808 }
2809
2810 /* Check the alias acoount name */
2811 Status = SampCheckAccountName(AccountName, 256);
2812 if (!NT_SUCCESS(Status))
2813 {
2814 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2815 goto done;
2816 }
2817
2818 /* Check if the alias name already exists in the domain */
2819 Status = SampCheckAccountNameInDomain(DomainObject,
2820 AccountName->Buffer);
2821 if (!NT_SUCCESS(Status))
2822 {
2823 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2824 AccountName->Buffer, Status);
2825 goto done;
2826 }
2827
2828 /* Create the security descriptor */
2829 Status = SampCreateAliasSD(&Sd,
2830 &SdSize);
2831 if (!NT_SUCCESS(Status))
2832 {
2833 TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
2834 goto done;
2835 }
2836
2837 /* Get the fixed domain attributes */
2838 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2839 Status = SampGetObjectAttribute(DomainObject,
2840 L"F",
2841 NULL,
2842 (PVOID)&FixedDomainData,
2843 &ulSize);
2844 if (!NT_SUCCESS(Status))
2845 {
2846 TRACE("failed with status 0x%08lx\n", Status);
2847 goto done;
2848 }
2849
2850 /* Increment the NextRid attribute */
2851 ulRid = FixedDomainData.NextRid;
2852 FixedDomainData.NextRid++;
2853
2854 /* Store the fixed domain attributes */
2855 Status = SampSetObjectAttribute(DomainObject,
2856 L"F",
2857 REG_BINARY,
2858 &FixedDomainData,
2859 ulSize);
2860 if (!NT_SUCCESS(Status))
2861 {
2862 TRACE("failed with status 0x%08lx\n", Status);
2863 goto done;
2864 }
2865
2866 TRACE("RID: %lx\n", ulRid);
2867
2868 /* Convert the RID into a string (hex) */
2869 swprintf(szRid, L"%08lX", ulRid);
2870
2871 /* Create the alias object */
2872 Status = SampCreateDbObject(DomainObject,
2873 L"Aliases",
2874 szRid,
2875 ulRid,
2876 SamDbAliasObject,
2877 DesiredAccess,
2878 &AliasObject);
2879 if (!NT_SUCCESS(Status))
2880 {
2881 TRACE("failed with status 0x%08lx\n", Status);
2882 goto done;
2883 }
2884
2885 /* Add the account name for the alias object */
2886 Status = SampSetAccountNameInDomain(DomainObject,
2887 L"Aliases",
2888 AccountName->Buffer,
2889 ulRid);
2890 if (!NT_SUCCESS(Status))
2891 {
2892 TRACE("failed with status 0x%08lx\n", Status);
2893 goto done;
2894 }
2895
2896 /* Set the Name attribute */
2897 Status = SampSetObjectAttributeString(AliasObject,
2898 L"Name",
2899 AccountName);
2900 if (!NT_SUCCESS(Status))
2901 {
2902 TRACE("failed with status 0x%08lx\n", Status);
2903 goto done;
2904 }
2905
2906 /* Set the Description attribute */
2907 Status = SampSetObjectAttributeString(AliasObject,
2908 L"Description",
2909 NULL);
2910 if (!NT_SUCCESS(Status))
2911 {
2912 TRACE("failed with status 0x%08lx\n", Status);
2913 goto done;
2914 }
2915
2916 /* Set the SecDesc attribute*/
2917 Status = SampSetObjectAttribute(AliasObject,
2918 L"SecDesc",
2919 REG_BINARY,
2920 Sd,
2921 SdSize);
2922 if (!NT_SUCCESS(Status))
2923 {
2924 TRACE("failed with status 0x%08lx\n", Status);
2925 goto done;
2926 }
2927
2928 if (NT_SUCCESS(Status))
2929 {
2930 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2931 *RelativeId = ulRid;
2932 }
2933
2934 done:
2935 if (Sd != NULL)
2936 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2937
2938 RtlReleaseResource(&SampResource);
2939
2940 TRACE("returns with status 0x%08lx\n", Status);
2941
2942 return Status;
2943 }
2944
2945
2946 /* Function 15 */
2947 NTSTATUS
2948 NTAPI
2949 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2950 IN OUT unsigned long *EnumerationContext,
2951 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2952 IN unsigned long PreferedMaximumLength,
2953 OUT unsigned long *CountReturned)
2954 {
2955 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2956 PSAM_DB_OBJECT DomainObject;
2957 HANDLE AliasesKeyHandle = NULL;
2958 HANDLE NamesKeyHandle = NULL;
2959 WCHAR AliasName[64];
2960 ULONG EnumIndex;
2961 ULONG EnumCount = 0;
2962 ULONG RequiredLength = 0;
2963 ULONG NameLength;
2964 ULONG DataLength;
2965 ULONG Rid;
2966 ULONG i;
2967 BOOLEAN MoreEntries = FALSE;
2968 NTSTATUS Status;
2969
2970 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2971 DomainHandle, EnumerationContext, Buffer,
2972 PreferedMaximumLength, CountReturned);
2973
2974 RtlAcquireResourceShared(&SampResource,
2975 TRUE);
2976
2977 /* Validate the domain handle */
2978 Status = SampValidateDbObject(DomainHandle,
2979 SamDbDomainObject,
2980 DOMAIN_LIST_ACCOUNTS,
2981 &DomainObject);
2982 if (!NT_SUCCESS(Status))
2983 goto done;
2984
2985 Status = SampRegOpenKey(DomainObject->KeyHandle,
2986 L"Aliases",
2987 KEY_READ,
2988 &AliasesKeyHandle);
2989 if (!NT_SUCCESS(Status))
2990 goto done;
2991
2992 Status = SampRegOpenKey(AliasesKeyHandle,
2993 L"Names",
2994 KEY_READ,
2995 &NamesKeyHandle);
2996 if (!NT_SUCCESS(Status))
2997 goto done;
2998
2999 TRACE("Part 1\n");
3000
3001 EnumIndex = *EnumerationContext;
3002
3003 while (TRUE)
3004 {
3005 NameLength = 64 * sizeof(WCHAR);
3006 Status = SampRegEnumerateValue(NamesKeyHandle,
3007 EnumIndex,
3008 AliasName,
3009 &NameLength,
3010 NULL,
3011 NULL,
3012 NULL);
3013 if (!NT_SUCCESS(Status))
3014 {
3015 if (Status == STATUS_NO_MORE_ENTRIES)
3016 Status = STATUS_SUCCESS;
3017 break;
3018 }
3019
3020 TRACE("EnumIndex: %lu\n", EnumIndex);
3021 TRACE("Alias name: %S\n", AliasName);
3022 TRACE("Name length: %lu\n", NameLength);
3023
3024 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3025 {
3026 MoreEntries = TRUE;
3027 break;
3028 }
3029
3030 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3031 EnumCount++;
3032
3033 EnumIndex++;
3034 }
3035
3036 TRACE("EnumCount: %lu\n", EnumCount);
3037 TRACE("RequiredLength: %lu\n", RequiredLength);
3038
3039 if (!NT_SUCCESS(Status))
3040 goto done;
3041
3042 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3043 if (EnumBuffer == NULL)
3044 {
3045 Status = STATUS_INSUFFICIENT_RESOURCES;
3046 goto done;
3047 }
3048
3049 EnumBuffer->EntriesRead = EnumCount;
3050 if (EnumCount == 0)
3051 goto done;
3052
3053 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3054 if (EnumBuffer->Buffer == NULL)
3055 {
3056 Status = STATUS_INSUFFICIENT_RESOURCES;
3057 goto done;
3058 }
3059
3060 TRACE("Part 2\n");
3061
3062 EnumIndex = *EnumerationContext;
3063 for (i = 0; i < EnumCount; i++, EnumIndex++)
3064 {
3065 NameLength = 64 * sizeof(WCHAR);
3066 DataLength = sizeof(ULONG);
3067 Status = SampRegEnumerateValue(NamesKeyHandle,
3068 EnumIndex,
3069 AliasName,
3070 &NameLength,
3071 NULL,
3072 &Rid,
3073 &DataLength);
3074 if (!NT_SUCCESS(Status))
3075 {
3076 if (Status == STATUS_NO_MORE_ENTRIES)
3077 Status = STATUS_SUCCESS;
3078 break;
3079 }
3080
3081 TRACE("EnumIndex: %lu\n", EnumIndex);
3082 TRACE("Alias name: %S\n", AliasName);
3083 TRACE("Name length: %lu\n", NameLength);
3084 TRACE("RID: %lu\n", Rid);
3085
3086 EnumBuffer->Buffer[i].RelativeId = Rid;
3087
3088 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3089 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
3090
3091 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3092 #if 0
3093 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3094 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3095 {
3096 Status = STATUS_INSUFFICIENT_RESOURCES;
3097 goto done;
3098 }
3099
3100 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3101 AliasName,
3102 EnumBuffer->Buffer[i].Name.Length);
3103 #endif
3104 }
3105
3106 done:
3107 if (NT_SUCCESS(Status))
3108 {
3109 *EnumerationContext += EnumCount;
3110 *Buffer = EnumBuffer;
3111 *CountReturned = EnumCount;
3112 }
3113 else
3114 {
3115 *EnumerationContext = 0;
3116 *Buffer = NULL;
3117 *CountReturned = 0;
3118
3119 if (EnumBuffer != NULL)
3120 {
3121 if (EnumBuffer->Buffer != NULL)
3122 {
3123 if (EnumBuffer->EntriesRead != 0)
3124 {
3125 for (i = 0; i < EnumBuffer->EntriesRead; i++)
3126 {
3127 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3128 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3129 }
3130 }
3131
3132 midl_user_free(EnumBuffer->Buffer);
3133 }
3134
3135 midl_user_free(EnumBuffer);
3136 }
3137 }
3138
3139 SampRegCloseKey(&NamesKeyHandle);
3140 SampRegCloseKey(&AliasesKeyHandle);
3141
3142 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
3143 Status = STATUS_MORE_ENTRIES;
3144
3145 RtlReleaseResource(&SampResource);
3146
3147 return Status;
3148 }
3149
3150
3151 /* Function 16 */
3152 NTSTATUS
3153 NTAPI
3154 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3155 IN PSAMPR_PSID_ARRAY SidArray,
3156 OUT PSAMPR_ULONG_ARRAY Membership)
3157 {
3158 PSAM_DB_OBJECT DomainObject;
3159 HANDLE AliasesKeyHandle = NULL;
3160 HANDLE MembersKeyHandle = NULL;
3161 HANDLE MemberKeyHandle = NULL;
3162 LPWSTR MemberSidString = NULL;
3163 PULONG RidArray = NULL;
3164 ULONG MaxSidCount = 0;
3165 ULONG ValueCount;
3166 ULONG DataLength;
3167 ULONG i, j;
3168 NTSTATUS Status;
3169 WCHAR NameBuffer[9];
3170
3171 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3172 DomainHandle, SidArray, Membership);
3173
3174 RtlAcquireResourceShared(&SampResource,
3175 TRUE);
3176
3177 /* Validate the domain handle */
3178 Status = SampValidateDbObject(DomainHandle,
3179 SamDbDomainObject,
3180 DOMAIN_GET_ALIAS_MEMBERSHIP,
3181 &DomainObject);
3182 if (!NT_SUCCESS(Status))
3183 goto done;
3184
3185 Status = SampRegOpenKey(DomainObject->KeyHandle,
3186 L"Aliases",
3187 KEY_READ,
3188 &AliasesKeyHandle);
3189 TRACE("SampRegOpenKey returned %08lX\n", Status);
3190 if (!NT_SUCCESS(Status))
3191 goto done;
3192
3193 Status = SampRegOpenKey(AliasesKeyHandle,
3194 L"Members",
3195 KEY_READ,
3196 &MembersKeyHandle);
3197 TRACE("SampRegOpenKey returned %08lX\n", Status);
3198
3199 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3200 {
3201 Status = STATUS_SUCCESS;
3202 goto done;
3203 }
3204
3205 if (!NT_SUCCESS(Status))
3206 goto done;
3207
3208 for (i = 0; i < SidArray->Count; i++)
3209 {
3210 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3211 TRACE("Open %S\n", MemberSidString);
3212
3213 Status = SampRegOpenKey(MembersKeyHandle,
3214 MemberSidString,
3215 KEY_READ,
3216 &MemberKeyHandle);
3217 TRACE("SampRegOpenKey returned %08lX\n", Status);
3218 if (NT_SUCCESS(Status))
3219 {
3220 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3221 NULL,
3222 &ValueCount);
3223 if (NT_SUCCESS(Status))
3224 {
3225 TRACE("Found %lu values\n", ValueCount);
3226 MaxSidCount += ValueCount;
3227 }
3228
3229 SampRegCloseKey(&MemberKeyHandle);
3230 }
3231
3232 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3233 Status = STATUS_SUCCESS;
3234
3235 LocalFree(MemberSidString);
3236 }
3237
3238 if (MaxSidCount == 0)
3239 {
3240 Status = STATUS_SUCCESS;
3241 goto done;
3242 }
3243
3244 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3245 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3246 if (RidArray == NULL)
3247 {
3248 Status = STATUS_INSUFFICIENT_RESOURCES;
3249 goto done;
3250 }
3251
3252 for (i = 0; i < SidArray->Count; i++)
3253 {
3254 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3255 TRACE("Open %S\n", MemberSidString);
3256
3257 Status = SampRegOpenKey(MembersKeyHandle,
3258 MemberSidString,
3259 KEY_READ,
3260 &MemberKeyHandle);
3261 TRACE("SampRegOpenKey returned %08lX\n", Status);
3262 if (NT_SUCCESS(Status))
3263 {
3264 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3265 NULL,
3266 &ValueCount);
3267 if (NT_SUCCESS(Status))
3268 {
3269 TRACE("Found %lu values\n", ValueCount);
3270
3271 for (j = 0; j < ValueCount; j++)
3272 {
3273 DataLength = 9 * sizeof(WCHAR);
3274 Status = SampRegEnumerateValue(MemberKeyHandle,
3275 j,
3276 NameBuffer,
3277 &DataLength,
3278 NULL,
3279 NULL,
3280 NULL);
3281 if (NT_SUCCESS(Status))
3282 {
3283 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3284 }
3285 }
3286 }
3287
3288 SampRegCloseKey(&MemberKeyHandle);
3289 }
3290
3291 LocalFree(MemberSidString);
3292 }
3293
3294 done:
3295 SampRegCloseKey(&MembersKeyHandle);
3296 SampRegCloseKey(&AliasesKeyHandle);
3297
3298 if (NT_SUCCESS(Status))
3299 {
3300 Membership->Count = MaxSidCount;
3301 Membership->Element = RidArray;
3302 }
3303 else
3304 {
3305 if (RidArray != NULL)
3306 midl_user_free(RidArray);
3307 }
3308
3309 RtlReleaseResource(&SampResource);
3310
3311 return Status;
3312 }
3313
3314
3315 /* Function 17 */
3316 NTSTATUS
3317 NTAPI
3318 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3319 IN ULONG Count,
3320 IN RPC_UNICODE_STRING Names[],
3321 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3322 OUT PSAMPR_ULONG_ARRAY Use)
3323 {
3324 PSAM_DB_OBJECT DomainObject;
3325 HANDLE AccountsKeyHandle = NULL;
3326 HANDLE NamesKeyHandle = NULL;
3327 ULONG MappedCount = 0;
3328 ULONG DataLength;