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