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