Synchronize with trunk revision 59781.
[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 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 the group account name */
1760 Status = SampCheckAccountName(Name, 256);
1761 if (!NT_SUCCESS(Status))
1762 {
1763 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
1764 return Status;
1765 }
1766
1767 /* Check if the group name already exists in the domain */
1768 Status = SampCheckAccountNameInDomain(DomainObject,
1769 Name->Buffer);
1770 if (!NT_SUCCESS(Status))
1771 {
1772 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
1773 Name->Buffer, Status);
1774 return Status;
1775 }
1776
1777 /* Get the fixed domain attributes */
1778 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
1779 Status = SampGetObjectAttribute(DomainObject,
1780 L"F",
1781 NULL,
1782 (PVOID)&FixedDomainData,
1783 &ulSize);
1784 if (!NT_SUCCESS(Status))
1785 {
1786 TRACE("failed with status 0x%08lx\n", Status);
1787 return Status;
1788 }
1789
1790 /* Increment the NextRid attribute */
1791 ulRid = FixedDomainData.NextRid;
1792 FixedDomainData.NextRid++;
1793
1794 /* Store the fixed domain attributes */
1795 Status = SampSetObjectAttribute(DomainObject,
1796 L"F",
1797 REG_BINARY,
1798 &FixedDomainData,
1799 ulSize);
1800 if (!NT_SUCCESS(Status))
1801 {
1802 TRACE("failed with status 0x%08lx\n", Status);
1803 return Status;
1804 }
1805
1806 TRACE("RID: %lx\n", ulRid);
1807
1808 /* Convert the RID into a string (hex) */
1809 swprintf(szRid, L"%08lX", ulRid);
1810
1811 /* Create the group object */
1812 Status = SampCreateDbObject(DomainObject,
1813 L"Groups",
1814 szRid,
1815 ulRid,
1816 SamDbGroupObject,
1817 DesiredAccess,
1818 &GroupObject);
1819 if (!NT_SUCCESS(Status))
1820 {
1821 TRACE("failed with status 0x%08lx\n", Status);
1822 return Status;
1823 }
1824
1825 /* Add the account name of the user object */
1826 Status = SampSetAccountNameInDomain(DomainObject,
1827 L"Groups",
1828 Name->Buffer,
1829 ulRid);
1830 if (!NT_SUCCESS(Status))
1831 {
1832 TRACE("failed with status 0x%08lx\n", Status);
1833 return Status;
1834 }
1835
1836 /* Initialize fixed user data */
1837 memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
1838 FixedGroupData.Version = 1;
1839
1840 FixedGroupData.GroupId = ulRid;
1841
1842 /* Set fixed user data attribute */
1843 Status = SampSetObjectAttribute(GroupObject,
1844 L"F",
1845 REG_BINARY,
1846 (LPVOID)&FixedGroupData,
1847 sizeof(SAM_GROUP_FIXED_DATA));
1848 if (!NT_SUCCESS(Status))
1849 {
1850 TRACE("failed with status 0x%08lx\n", Status);
1851 return Status;
1852 }
1853
1854 /* Set the Name attribute */
1855 Status = SampSetObjectAttribute(GroupObject,
1856 L"Name",
1857 REG_SZ,
1858 (LPVOID)Name->Buffer,
1859 Name->MaximumLength);
1860 if (!NT_SUCCESS(Status))
1861 {
1862 TRACE("failed with status 0x%08lx\n", Status);
1863 return Status;
1864 }
1865
1866 /* Set the AdminComment attribute */
1867 Status = SampSetObjectAttribute(GroupObject,
1868 L"AdminComment",
1869 REG_SZ,
1870 EmptyString.Buffer,
1871 EmptyString.MaximumLength);
1872 if (!NT_SUCCESS(Status))
1873 {
1874 TRACE("failed with status 0x%08lx\n", Status);
1875 return Status;
1876 }
1877
1878 if (NT_SUCCESS(Status))
1879 {
1880 *GroupHandle = (SAMPR_HANDLE)GroupObject;
1881 *RelativeId = ulRid;
1882 }
1883
1884 TRACE("returns with status 0x%08lx\n", Status);
1885
1886 return Status;
1887 }
1888
1889
1890 /* Function 11 */
1891 NTSTATUS
1892 NTAPI
1893 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
1894 IN OUT unsigned long *EnumerationContext,
1895 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
1896 IN unsigned long PreferedMaximumLength,
1897 OUT unsigned long *CountReturned)
1898 {
1899 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
1900 PSAM_DB_OBJECT DomainObject;
1901 HANDLE GroupsKeyHandle = NULL;
1902 HANDLE NamesKeyHandle = NULL;
1903 WCHAR GroupName[64];
1904 ULONG EnumIndex;
1905 ULONG EnumCount = 0;
1906 ULONG RequiredLength = 0;
1907 ULONG NameLength;
1908 ULONG DataLength;
1909 ULONG Rid;
1910 ULONG i;
1911 BOOLEAN MoreEntries = FALSE;
1912 NTSTATUS Status;
1913
1914 TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
1915 DomainHandle, EnumerationContext, Buffer,
1916 PreferedMaximumLength, CountReturned);
1917
1918 /* Validate the domain handle */
1919 Status = SampValidateDbObject(DomainHandle,
1920 SamDbDomainObject,
1921 DOMAIN_LIST_ACCOUNTS,
1922 &DomainObject);
1923 if (!NT_SUCCESS(Status))
1924 return Status;
1925
1926 Status = SampRegOpenKey(DomainObject->KeyHandle,
1927 L"Groups",
1928 KEY_READ,
1929 &GroupsKeyHandle);
1930 if (!NT_SUCCESS(Status))
1931 return Status;
1932
1933 Status = SampRegOpenKey(GroupsKeyHandle,
1934 L"Names",
1935 KEY_READ,
1936 &NamesKeyHandle);
1937 if (!NT_SUCCESS(Status))
1938 goto done;
1939
1940 TRACE("Part 1\n");
1941
1942 EnumIndex = *EnumerationContext;
1943
1944 while (TRUE)
1945 {
1946 NameLength = 64 * sizeof(WCHAR);
1947 Status = SampRegEnumerateValue(NamesKeyHandle,
1948 EnumIndex,
1949 GroupName,
1950 &NameLength,
1951 NULL,
1952 NULL,
1953 NULL);
1954 if (!NT_SUCCESS(Status))
1955 {
1956 if (Status == STATUS_NO_MORE_ENTRIES)
1957 Status = STATUS_SUCCESS;
1958 break;
1959 }
1960
1961 TRACE("EnumIndex: %lu\n", EnumIndex);
1962 TRACE("Group name: %S\n", GroupName);
1963 TRACE("Name length: %lu\n", NameLength);
1964
1965 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
1966 {
1967 MoreEntries = TRUE;
1968 break;
1969 }
1970
1971 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
1972 EnumCount++;
1973
1974 EnumIndex++;
1975 }
1976
1977 TRACE("EnumCount: %lu\n", EnumCount);
1978 TRACE("RequiredLength: %lu\n", RequiredLength);
1979
1980 if (!NT_SUCCESS(Status))
1981 goto done;
1982
1983 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
1984 if (EnumBuffer == NULL)
1985 {
1986 Status = STATUS_INSUFFICIENT_RESOURCES;
1987 goto done;
1988 }
1989
1990 EnumBuffer->EntriesRead = EnumCount;
1991 if (EnumCount == 0)
1992 goto done;
1993
1994 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
1995 if (EnumBuffer->Buffer == NULL)
1996 {
1997 Status = STATUS_INSUFFICIENT_RESOURCES;
1998 goto done;
1999 }
2000
2001 TRACE("Part 2\n");
2002
2003 EnumIndex = *EnumerationContext;
2004 for (i = 0; i < EnumCount; i++, EnumIndex++)
2005 {
2006 NameLength = 64 * sizeof(WCHAR);
2007 DataLength = sizeof(ULONG);
2008 Status = SampRegEnumerateValue(NamesKeyHandle,
2009 EnumIndex,
2010 GroupName,
2011 &NameLength,
2012 NULL,
2013 &Rid,
2014 &DataLength);
2015 if (!NT_SUCCESS(Status))
2016 {
2017 if (Status == STATUS_NO_MORE_ENTRIES)
2018 Status = STATUS_SUCCESS;
2019 break;
2020 }
2021
2022 TRACE("EnumIndex: %lu\n", EnumIndex);
2023 TRACE("Group name: %S\n", GroupName);
2024 TRACE("Name length: %lu\n", NameLength);
2025 TRACE("RID: %lu\n", Rid);
2026
2027 EnumBuffer->Buffer[i].RelativeId = Rid;
2028
2029 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2030 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2031
2032 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2033 #if 0
2034 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2035 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2036 {
2037 Status = STATUS_INSUFFICIENT_RESOURCES;
2038 goto done;
2039 }
2040
2041 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2042 GroupName,
2043 EnumBuffer->Buffer[i].Name.Length);
2044 #endif
2045 }
2046
2047 done:
2048 if (NT_SUCCESS(Status))
2049 {
2050 *EnumerationContext += EnumCount;
2051 *Buffer = EnumBuffer;
2052 *CountReturned = EnumCount;
2053 }
2054 else
2055 {
2056 *EnumerationContext = 0;
2057 *Buffer = NULL;
2058 *CountReturned = 0;
2059
2060 if (EnumBuffer != NULL)
2061 {
2062 if (EnumBuffer->Buffer != NULL)
2063 {
2064 if (EnumBuffer->EntriesRead != 0)
2065 {
2066 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2067 {
2068 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2069 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2070 }
2071 }
2072
2073 midl_user_free(EnumBuffer->Buffer);
2074 }
2075
2076 midl_user_free(EnumBuffer);
2077 }
2078 }
2079
2080 if (NamesKeyHandle != NULL)
2081 SampRegCloseKey(NamesKeyHandle);
2082
2083 if (GroupsKeyHandle != NULL)
2084 SampRegCloseKey(GroupsKeyHandle);
2085
2086 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2087 Status = STATUS_MORE_ENTRIES;
2088
2089 return Status;
2090 }
2091
2092
2093 /* Function 12 */
2094 NTSTATUS
2095 NTAPI
2096 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2097 IN PRPC_UNICODE_STRING Name,
2098 IN ACCESS_MASK DesiredAccess,
2099 OUT SAMPR_HANDLE *UserHandle,
2100 OUT unsigned long *RelativeId)
2101 {
2102 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2103 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2104 SAM_USER_FIXED_DATA FixedUserData;
2105 PSAM_DB_OBJECT DomainObject;
2106 PSAM_DB_OBJECT UserObject;
2107 GROUP_MEMBERSHIP GroupMembership;
2108 UCHAR LogonHours[23];
2109 ULONG ulSize;
2110 ULONG ulRid;
2111 WCHAR szRid[9];
2112 NTSTATUS Status;
2113
2114 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2115 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2116
2117 if (Name == NULL ||
2118 Name->Length == 0 ||
2119 Name->Buffer == NULL ||
2120 UserHandle == NULL ||
2121 RelativeId == NULL)
2122 return STATUS_INVALID_PARAMETER;
2123
2124 /* Map generic access rights */
2125 RtlMapGenericMask(&DesiredAccess,
2126 &UserMapping);
2127
2128 /* Validate the domain handle */
2129 Status = SampValidateDbObject(DomainHandle,
2130 SamDbDomainObject,
2131 DOMAIN_CREATE_USER,
2132 &DomainObject);
2133 if (!NT_SUCCESS(Status))
2134 {
2135 TRACE("failed with status 0x%08lx\n", Status);
2136 return Status;
2137 }
2138
2139 /* Check the user account name */
2140 Status = SampCheckAccountName(Name, 20);
2141 if (!NT_SUCCESS(Status))
2142 {
2143 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2144 return Status;
2145 }
2146
2147 /* Check if the user name already exists in the domain */
2148 Status = SampCheckAccountNameInDomain(DomainObject,
2149 Name->Buffer);
2150 if (!NT_SUCCESS(Status))
2151 {
2152 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2153 Name->Buffer, Status);
2154 return Status;
2155 }
2156
2157 /* Get the fixed domain attributes */
2158 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2159 Status = SampGetObjectAttribute(DomainObject,
2160 L"F",
2161 NULL,
2162 (PVOID)&FixedDomainData,
2163 &ulSize);
2164 if (!NT_SUCCESS(Status))
2165 {
2166 TRACE("failed with status 0x%08lx\n", Status);
2167 return Status;
2168 }
2169
2170 /* Increment the NextRid attribute */
2171 ulRid = FixedDomainData.NextRid;
2172 FixedDomainData.NextRid++;
2173
2174 /* Store the fixed domain attributes */
2175 Status = SampSetObjectAttribute(DomainObject,
2176 L"F",
2177 REG_BINARY,
2178 &FixedDomainData,
2179 ulSize);
2180 if (!NT_SUCCESS(Status))
2181 {
2182 TRACE("failed with status 0x%08lx\n", Status);
2183 return Status;
2184 }
2185
2186 TRACE("RID: %lx\n", ulRid);
2187
2188 /* Convert the RID into a string (hex) */
2189 swprintf(szRid, L"%08lX", ulRid);
2190
2191 /* Create the user object */
2192 Status = SampCreateDbObject(DomainObject,
2193 L"Users",
2194 szRid,
2195 ulRid,
2196 SamDbUserObject,
2197 DesiredAccess,
2198 &UserObject);
2199 if (!NT_SUCCESS(Status))
2200 {
2201 TRACE("failed with status 0x%08lx\n", Status);
2202 return Status;
2203 }
2204
2205 /* Add the account name for the user object */
2206 Status = SampSetAccountNameInDomain(DomainObject,
2207 L"Users",
2208 Name->Buffer,
2209 ulRid);
2210 if (!NT_SUCCESS(Status))
2211 {
2212 TRACE("failed with status 0x%08lx\n", Status);
2213 return Status;
2214 }
2215
2216 /* Initialize fixed user data */
2217 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2218 FixedUserData.Version = 1;
2219 FixedUserData.Reserved = 0;
2220 FixedUserData.LastLogon.QuadPart = 0;
2221 FixedUserData.LastLogoff.QuadPart = 0;
2222 FixedUserData.PasswordLastSet.QuadPart = 0;
2223 FixedUserData.AccountExpires.LowPart = MAXULONG;
2224 FixedUserData.AccountExpires.HighPart = MAXLONG;
2225 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2226 FixedUserData.UserId = ulRid;
2227 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2228 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2229 USER_PASSWORD_NOT_REQUIRED |
2230 USER_NORMAL_ACCOUNT;
2231 FixedUserData.CountryCode = 0;
2232 FixedUserData.CodePage = 0;
2233 FixedUserData.BadPasswordCount = 0;
2234 FixedUserData.LogonCount = 0;
2235 FixedUserData.AdminCount = 0;
2236 FixedUserData.OperatorCount = 0;
2237
2238 /* Set fixed user data attribute */
2239 Status = SampSetObjectAttribute(UserObject,
2240 L"F",
2241 REG_BINARY,
2242 (LPVOID)&FixedUserData,
2243 sizeof(SAM_USER_FIXED_DATA));
2244 if (!NT_SUCCESS(Status))
2245 {
2246 TRACE("failed with status 0x%08lx\n", Status);
2247 return Status;
2248 }
2249
2250 /* Set the Name attribute */
2251 Status = SampSetObjectAttribute(UserObject,
2252 L"Name",
2253 REG_SZ,
2254 (LPVOID)Name->Buffer,
2255 Name->MaximumLength);
2256 if (!NT_SUCCESS(Status))
2257 {
2258 TRACE("failed with status 0x%08lx\n", Status);
2259 return Status;
2260 }
2261
2262 /* Set the FullName attribute */
2263 Status = SampSetObjectAttribute(UserObject,
2264 L"FullName",
2265 REG_SZ,
2266 EmptyString.Buffer,
2267 EmptyString.MaximumLength);
2268 if (!NT_SUCCESS(Status))
2269 {
2270 TRACE("failed with status 0x%08lx\n", Status);
2271 return Status;
2272 }
2273
2274 /* Set the HomeDirectory attribute */
2275 Status = SampSetObjectAttribute(UserObject,
2276 L"HomeDirectory",
2277 REG_SZ,
2278 EmptyString.Buffer,
2279 EmptyString.MaximumLength);
2280 if (!NT_SUCCESS(Status))
2281 {
2282 TRACE("failed with status 0x%08lx\n", Status);
2283 return Status;
2284 }
2285
2286 /* Set the HomeDirectoryDrive attribute */
2287 Status = SampSetObjectAttribute(UserObject,
2288 L"HomeDirectoryDrive",
2289 REG_SZ,
2290 EmptyString.Buffer,
2291 EmptyString.MaximumLength);
2292 if (!NT_SUCCESS(Status))
2293 {
2294 TRACE("failed with status 0x%08lx\n", Status);
2295 return Status;
2296 }
2297
2298 /* Set the ScriptPath attribute */
2299 Status = SampSetObjectAttribute(UserObject,
2300 L"ScriptPath",
2301 REG_SZ,
2302 EmptyString.Buffer,
2303 EmptyString.MaximumLength);
2304 if (!NT_SUCCESS(Status))
2305 {
2306 TRACE("failed with status 0x%08lx\n", Status);
2307 return Status;
2308 }
2309
2310 /* Set the ProfilePath attribute */
2311 Status = SampSetObjectAttribute(UserObject,
2312 L"ProfilePath",
2313 REG_SZ,
2314 EmptyString.Buffer,
2315 EmptyString.MaximumLength);
2316 if (!NT_SUCCESS(Status))
2317 {
2318 TRACE("failed with status 0x%08lx\n", Status);
2319 return Status;
2320 }
2321
2322 /* Set the AdminComment attribute */
2323 Status = SampSetObjectAttribute(UserObject,
2324 L"AdminComment",
2325 REG_SZ,
2326 EmptyString.Buffer,
2327 EmptyString.MaximumLength);
2328 if (!NT_SUCCESS(Status))
2329 {
2330 TRACE("failed with status 0x%08lx\n", Status);
2331 return Status;
2332 }
2333
2334 /* Set the UserComment attribute */
2335 Status = SampSetObjectAttribute(UserObject,
2336 L"UserComment",
2337 REG_SZ,
2338 EmptyString.Buffer,
2339 EmptyString.MaximumLength);
2340 if (!NT_SUCCESS(Status))
2341 {
2342 TRACE("failed with status 0x%08lx\n", Status);
2343 return Status;
2344 }
2345
2346 /* Set the WorkStations attribute */
2347 Status = SampSetObjectAttribute(UserObject,
2348 L"WorkStations",
2349 REG_SZ,
2350 EmptyString.Buffer,
2351 EmptyString.MaximumLength);
2352 if (!NT_SUCCESS(Status))
2353 {
2354 TRACE("failed with status 0x%08lx\n", Status);
2355 return Status;
2356 }
2357
2358 /* Set the Parameters attribute */
2359 Status = SampSetObjectAttribute(UserObject,
2360 L"Parameters",
2361 REG_SZ,
2362 EmptyString.Buffer,
2363 EmptyString.MaximumLength);
2364 if (!NT_SUCCESS(Status))
2365 {
2366 TRACE("failed with status 0x%08lx\n", Status);
2367 return Status;
2368 }
2369
2370 /* Set LogonHours attribute*/
2371 *((PUSHORT)LogonHours) = 168;
2372 memset(&(LogonHours[2]), 0xff, 21);
2373
2374 Status = SampSetObjectAttribute(UserObject,
2375 L"LogonHours",
2376 REG_BINARY,
2377 &LogonHours,
2378 sizeof(LogonHours));
2379 if (!NT_SUCCESS(Status))
2380 {
2381 TRACE("failed with status 0x%08lx\n", Status);
2382 return Status;
2383 }
2384
2385 /* Set Groups attribute*/
2386 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2387 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2388 SE_GROUP_ENABLED |
2389 SE_GROUP_ENABLED_BY_DEFAULT;
2390
2391 Status = SampSetObjectAttribute(UserObject,
2392 L"Groups",
2393 REG_BINARY,
2394 &GroupMembership,
2395 sizeof(GROUP_MEMBERSHIP));
2396 if (!NT_SUCCESS(Status))
2397 {
2398 TRACE("failed with status 0x%08lx\n", Status);
2399 return Status;
2400 }
2401
2402 /* Set LMPwd attribute*/
2403 Status = SampSetObjectAttribute(UserObject,
2404 L"LMPwd",
2405 REG_BINARY,
2406 &EmptyLmHash,
2407 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2408 if (!NT_SUCCESS(Status))
2409 {
2410 TRACE("failed with status 0x%08lx\n", Status);
2411 return Status;
2412 }
2413
2414 /* Set NTPwd attribute*/
2415 Status = SampSetObjectAttribute(UserObject,
2416 L"NTPwd",
2417 REG_BINARY,
2418 &EmptyNtHash,
2419 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2420 if (!NT_SUCCESS(Status))
2421 {
2422 TRACE("failed with status 0x%08lx\n", Status);
2423 return Status;
2424 }
2425
2426 /* Set LMPwdHistory attribute*/
2427 Status = SampSetObjectAttribute(UserObject,
2428 L"LMPwdHistory",
2429 REG_BINARY,
2430 NULL,
2431 0);
2432 if (!NT_SUCCESS(Status))
2433 {
2434 TRACE("failed with status 0x%08lx\n", Status);
2435 return Status;
2436 }
2437
2438 /* Set NTPwdHistory attribute*/
2439 Status = SampSetObjectAttribute(UserObject,
2440 L"NTPwdHistory",
2441 REG_BINARY,
2442 NULL,
2443 0);
2444 if (!NT_SUCCESS(Status))
2445 {
2446 TRACE("failed with status 0x%08lx\n", Status);
2447 return Status;
2448 }
2449
2450 /* FIXME: Set SecDesc attribute*/
2451
2452 if (NT_SUCCESS(Status))
2453 {
2454 *UserHandle = (SAMPR_HANDLE)UserObject;
2455 *RelativeId = ulRid;
2456 }
2457
2458 TRACE("returns with status 0x%08lx\n", Status);
2459
2460 return Status;
2461 }
2462
2463
2464 /* Function 13 */
2465 NTSTATUS
2466 NTAPI
2467 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2468 IN OUT unsigned long *EnumerationContext,
2469 IN unsigned long UserAccountControl,
2470 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2471 IN unsigned long PreferedMaximumLength,
2472 OUT unsigned long *CountReturned)
2473 {
2474 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2475 PSAM_DB_OBJECT DomainObject;
2476 HANDLE UsersKeyHandle = NULL;
2477 HANDLE NamesKeyHandle = NULL;
2478 WCHAR UserName[64];
2479 ULONG EnumIndex;
2480 ULONG EnumCount = 0;
2481 ULONG RequiredLength = 0;
2482 ULONG NameLength;
2483 ULONG DataLength;
2484 ULONG Rid;
2485 ULONG i;
2486 BOOLEAN MoreEntries = FALSE;
2487 NTSTATUS Status;
2488
2489 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2490 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2491 PreferedMaximumLength, CountReturned);
2492
2493 /* Validate the domain handle */
2494 Status = SampValidateDbObject(DomainHandle,
2495 SamDbDomainObject,
2496 DOMAIN_LIST_ACCOUNTS,
2497 &DomainObject);
2498 if (!NT_SUCCESS(Status))
2499 return Status;
2500
2501 Status = SampRegOpenKey(DomainObject->KeyHandle,
2502 L"Users",
2503 KEY_READ,
2504 &UsersKeyHandle);
2505 if (!NT_SUCCESS(Status))
2506 return Status;
2507
2508 Status = SampRegOpenKey(UsersKeyHandle,
2509 L"Names",
2510 KEY_READ,
2511 &NamesKeyHandle);
2512 if (!NT_SUCCESS(Status))
2513 goto done;
2514
2515 TRACE("Part 1\n");
2516
2517 EnumIndex = *EnumerationContext;
2518
2519 while (TRUE)
2520 {
2521 NameLength = 64 * sizeof(WCHAR);
2522 Status = SampRegEnumerateValue(NamesKeyHandle,
2523 EnumIndex,
2524 UserName,
2525 &NameLength,
2526 NULL,
2527 NULL,
2528 NULL);
2529 if (!NT_SUCCESS(Status))
2530 {
2531 if (Status == STATUS_NO_MORE_ENTRIES)
2532 Status = STATUS_SUCCESS;
2533 break;
2534 }
2535
2536 TRACE("EnumIndex: %lu\n", EnumIndex);
2537 TRACE("User name: %S\n", UserName);
2538 TRACE("Name length: %lu\n", NameLength);
2539
2540 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2541 {
2542 MoreEntries = TRUE;
2543 break;
2544 }
2545
2546 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2547 EnumCount++;
2548
2549 EnumIndex++;
2550 }
2551
2552 TRACE("EnumCount: %lu\n", EnumCount);
2553 TRACE("RequiredLength: %lu\n", RequiredLength);
2554
2555 if (!NT_SUCCESS(Status))
2556 goto done;
2557
2558 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2559 if (EnumBuffer == NULL)
2560 {
2561 Status = STATUS_INSUFFICIENT_RESOURCES;
2562 goto done;
2563 }
2564
2565 EnumBuffer->EntriesRead = EnumCount;
2566 if (EnumCount == 0)
2567 goto done;
2568
2569 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2570 if (EnumBuffer->Buffer == NULL)
2571 {
2572 Status = STATUS_INSUFFICIENT_RESOURCES;
2573 goto done;
2574 }
2575
2576 TRACE("Part 2\n");
2577
2578 EnumIndex = *EnumerationContext;
2579 for (i = 0; i < EnumCount; i++, EnumIndex++)
2580 {
2581 NameLength = 64 * sizeof(WCHAR);
2582 DataLength = sizeof(ULONG);
2583 Status = SampRegEnumerateValue(NamesKeyHandle,
2584 EnumIndex,
2585 UserName,
2586 &NameLength,
2587 NULL,
2588 &Rid,
2589 &DataLength);
2590 if (!NT_SUCCESS(Status))
2591 {
2592 if (Status == STATUS_NO_MORE_ENTRIES)
2593 Status = STATUS_SUCCESS;
2594 break;
2595 }
2596
2597 TRACE("EnumIndex: %lu\n", EnumIndex);
2598 TRACE("User name: %S\n", UserName);
2599 TRACE("Name length: %lu\n", NameLength);
2600 TRACE("RID: %lu\n", Rid);
2601
2602 EnumBuffer->Buffer[i].RelativeId = Rid;
2603
2604 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2605 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2606
2607 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2608 #if 0
2609 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2610 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2611 {
2612 Status = STATUS_INSUFFICIENT_RESOURCES;
2613 goto done;
2614 }
2615
2616 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2617 UserName,
2618 EnumBuffer->Buffer[i].Name.Length);
2619 #endif
2620 }
2621
2622 done:
2623 if (NT_SUCCESS(Status))
2624 {
2625 *EnumerationContext += EnumCount;
2626 *Buffer = EnumBuffer;
2627 *CountReturned = EnumCount;
2628 }
2629 else
2630 {
2631 *EnumerationContext = 0;
2632 *Buffer = NULL;
2633 *CountReturned = 0;
2634
2635 if (EnumBuffer != NULL)
2636 {
2637 if (EnumBuffer->Buffer != NULL)
2638 {
2639 if (EnumBuffer->EntriesRead != 0)
2640 {
2641 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2642 {
2643 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2644 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2645 }
2646 }
2647
2648 midl_user_free(EnumBuffer->Buffer);
2649 }
2650
2651 midl_user_free(EnumBuffer);
2652 }
2653 }
2654
2655 if (NamesKeyHandle != NULL)
2656 SampRegCloseKey(NamesKeyHandle);
2657
2658 if (UsersKeyHandle != NULL)
2659 SampRegCloseKey(UsersKeyHandle);
2660
2661 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2662 Status = STATUS_MORE_ENTRIES;
2663
2664 return Status;
2665 }
2666
2667
2668 /* Function 14 */
2669 NTSTATUS
2670 NTAPI
2671 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2672 IN PRPC_UNICODE_STRING AccountName,
2673 IN ACCESS_MASK DesiredAccess,
2674 OUT SAMPR_HANDLE *AliasHandle,
2675 OUT unsigned long *RelativeId)
2676 {
2677 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2678 PSAM_DB_OBJECT DomainObject;
2679 PSAM_DB_OBJECT AliasObject;
2680 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2681 ULONG ulSize;
2682 ULONG ulRid;
2683 WCHAR szRid[9];
2684 NTSTATUS Status;
2685
2686 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2687 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2688
2689 /* Map generic access rights */
2690 RtlMapGenericMask(&DesiredAccess,
2691 &AliasMapping);
2692
2693 /* Validate the domain handle */
2694 Status = SampValidateDbObject(DomainHandle,
2695 SamDbDomainObject,
2696 DOMAIN_CREATE_ALIAS,
2697 &DomainObject);
2698 if (!NT_SUCCESS(Status))
2699 {
2700 TRACE("failed with status 0x%08lx\n", Status);
2701 return Status;
2702 }
2703
2704 /* Check the alias acoount name */
2705 Status = SampCheckAccountName(AccountName, 256);
2706 if (!NT_SUCCESS(Status))
2707 {
2708 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
2709 return Status;
2710 }
2711
2712 /* Check if the alias name already exists in the domain */
2713 Status = SampCheckAccountNameInDomain(DomainObject,
2714 AccountName->Buffer);
2715 if (!NT_SUCCESS(Status))
2716 {
2717 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2718 AccountName->Buffer, Status);
2719 return Status;
2720 }
2721
2722 /* Get the fixed domain attributes */
2723 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2724 Status = SampGetObjectAttribute(DomainObject,
2725 L"F",
2726 NULL,
2727 (PVOID)&FixedDomainData,
2728 &ulSize);
2729 if (!NT_SUCCESS(Status))
2730 {
2731 TRACE("failed with status 0x%08lx\n", Status);
2732 return Status;
2733 }
2734
2735 /* Increment the NextRid attribute */
2736 ulRid = FixedDomainData.NextRid;
2737 FixedDomainData.NextRid++;
2738
2739 /* Store the fixed domain attributes */
2740 Status = SampSetObjectAttribute(DomainObject,
2741 L"F",
2742 REG_BINARY,
2743 &FixedDomainData,
2744 ulSize);
2745 if (!NT_SUCCESS(Status))
2746 {
2747 TRACE("failed with status 0x%08lx\n", Status);
2748 return Status;
2749 }
2750
2751 TRACE("RID: %lx\n", ulRid);
2752
2753 /* Convert the RID into a string (hex) */
2754 swprintf(szRid, L"%08lX", ulRid);
2755
2756 /* Create the alias object */
2757 Status = SampCreateDbObject(DomainObject,
2758 L"Aliases",
2759 szRid,
2760 ulRid,
2761 SamDbAliasObject,
2762 DesiredAccess,
2763 &AliasObject);
2764 if (!NT_SUCCESS(Status))
2765 {
2766 TRACE("failed with status 0x%08lx\n", Status);
2767 return Status;
2768 }
2769
2770 /* Add the account name for the alias object */
2771 Status = SampSetAccountNameInDomain(DomainObject,
2772 L"Aliases",
2773 AccountName->Buffer,
2774 ulRid);
2775 if (!NT_SUCCESS(Status))
2776 {
2777 TRACE("failed with status 0x%08lx\n", Status);
2778 return Status;
2779 }
2780
2781 /* Set the Name attribute */
2782 Status = SampSetObjectAttribute(AliasObject,
2783 L"Name",
2784 REG_SZ,
2785 (LPVOID)AccountName->Buffer,
2786 AccountName->MaximumLength);
2787 if (!NT_SUCCESS(Status))
2788 {
2789 TRACE("failed with status 0x%08lx\n", Status);
2790 return Status;
2791 }
2792
2793 /* Set the Description attribute */
2794 Status = SampSetObjectAttribute(AliasObject,
2795 L"Description",
2796 REG_SZ,
2797 EmptyString.Buffer,
2798 EmptyString.MaximumLength);
2799 if (!NT_SUCCESS(Status))
2800 {
2801 TRACE("failed with status 0x%08lx\n", Status);
2802 return Status;
2803 }
2804
2805 if (NT_SUCCESS(Status))
2806 {
2807 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2808 *RelativeId = ulRid;
2809 }
2810
2811 TRACE("returns with status 0x%08lx\n", Status);
2812
2813 return Status;
2814 }
2815
2816
2817 /* Function 15 */
2818 NTSTATUS
2819 NTAPI
2820 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2821 IN OUT unsigned long *EnumerationContext,
2822 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2823 IN unsigned long PreferedMaximumLength,
2824 OUT unsigned long *CountReturned)
2825 {
2826 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2827 PSAM_DB_OBJECT DomainObject;
2828 HANDLE AliasesKeyHandle = NULL;
2829 HANDLE NamesKeyHandle = NULL;
2830 WCHAR AliasName[64];
2831 ULONG EnumIndex;
2832 ULONG EnumCount = 0;
2833 ULONG RequiredLength = 0;
2834 ULONG NameLength;
2835 ULONG DataLength;
2836 ULONG Rid;
2837 ULONG i;
2838 BOOLEAN MoreEntries = FALSE;
2839 NTSTATUS Status;
2840
2841 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2842 DomainHandle, EnumerationContext, Buffer,
2843 PreferedMaximumLength, CountReturned);
2844
2845 /* Validate the domain handle */
2846 Status = SampValidateDbObject(DomainHandle,
2847 SamDbDomainObject,
2848 DOMAIN_LIST_ACCOUNTS,
2849 &DomainObject);
2850 if (!NT_SUCCESS(Status))
2851 return Status;
2852
2853 Status = SampRegOpenKey(DomainObject->KeyHandle,
2854 L"Aliases",
2855 KEY_READ,
2856 &AliasesKeyHandle);
2857 if (!NT_SUCCESS(Status))
2858 return Status;
2859
2860 Status = SampRegOpenKey(AliasesKeyHandle,
2861 L"Names",
2862 KEY_READ,
2863 &NamesKeyHandle);
2864 if (!NT_SUCCESS(Status))
2865 goto done;
2866
2867 TRACE("Part 1\n");
2868
2869 EnumIndex = *EnumerationContext;
2870
2871 while (TRUE)
2872 {
2873 NameLength = 64 * sizeof(WCHAR);
2874 Status = SampRegEnumerateValue(NamesKeyHandle,
2875 EnumIndex,
2876 AliasName,
2877 &NameLength,
2878 NULL,
2879 NULL,
2880 NULL);
2881 if (!NT_SUCCESS(Status))
2882 {
2883 if (Status == STATUS_NO_MORE_ENTRIES)
2884 Status = STATUS_SUCCESS;
2885 break;
2886 }
2887
2888 TRACE("EnumIndex: %lu\n", EnumIndex);
2889 TRACE("Alias name: %S\n", AliasName);
2890 TRACE("Name length: %lu\n", NameLength);
2891
2892 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2893 {
2894 MoreEntries = TRUE;
2895 break;
2896 }
2897
2898 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2899 EnumCount++;
2900
2901 EnumIndex++;
2902 }
2903
2904 TRACE("EnumCount: %lu\n", EnumCount);
2905 TRACE("RequiredLength: %lu\n", RequiredLength);
2906
2907 if (!NT_SUCCESS(Status))
2908 goto done;
2909
2910 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2911 if (EnumBuffer == NULL)
2912 {
2913 Status = STATUS_INSUFFICIENT_RESOURCES;
2914 goto done;
2915 }
2916
2917 EnumBuffer->EntriesRead = EnumCount;
2918 if (EnumCount == 0)
2919 goto done;
2920
2921 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2922 if (EnumBuffer->Buffer == NULL)
2923 {
2924 Status = STATUS_INSUFFICIENT_RESOURCES;
2925 goto done;
2926 }
2927
2928 TRACE("Part 2\n");
2929
2930 EnumIndex = *EnumerationContext;
2931 for (i = 0; i < EnumCount; i++, EnumIndex++)
2932 {
2933 NameLength = 64 * sizeof(WCHAR);
2934 DataLength = sizeof(ULONG);
2935 Status = SampRegEnumerateValue(NamesKeyHandle,
2936 EnumIndex,
2937 AliasName,
2938 &NameLength,
2939 NULL,
2940 &Rid,
2941 &DataLength);
2942 if (!NT_SUCCESS(Status))
2943 {
2944 if (Status == STATUS_NO_MORE_ENTRIES)
2945 Status = STATUS_SUCCESS;
2946 break;
2947 }
2948
2949 TRACE("EnumIndex: %lu\n", EnumIndex);
2950 TRACE("Alias name: %S\n", AliasName);
2951 TRACE("Name length: %lu\n", NameLength);
2952 TRACE("RID: %lu\n", Rid);
2953
2954 EnumBuffer->Buffer[i].RelativeId = Rid;
2955
2956 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2957 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2958
2959 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2960 #if 0
2961 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2962 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2963 {
2964 Status = STATUS_INSUFFICIENT_RESOURCES;
2965 goto done;
2966 }
2967
2968 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2969 AliasName,
2970 EnumBuffer->Buffer[i].Name.Length);
2971 #endif
2972 }
2973
2974 done:
2975 if (NT_SUCCESS(Status))
2976 {
2977 *EnumerationContext += EnumCount;
2978 *Buffer = EnumBuffer;
2979 *CountReturned = EnumCount;
2980 }
2981 else
2982 {
2983 *EnumerationContext = 0;
2984 *Buffer = NULL;
2985 *CountReturned = 0;
2986
2987 if (EnumBuffer != NULL)
2988 {
2989 if (EnumBuffer->Buffer != NULL)
2990 {
2991 if (EnumBuffer->EntriesRead != 0)
2992 {
2993 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2994 {
2995 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2996 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2997 }
2998 }
2999
3000 midl_user_free(EnumBuffer->Buffer);
3001 }
3002
3003 midl_user_free(EnumBuffer);
3004 }
3005 }
3006
3007 if (NamesKeyHandle != NULL)
3008 SampRegCloseKey(NamesKeyHandle);
3009
3010 if (AliasesKeyHandle != NULL)
3011 SampRegCloseKey(AliasesKeyHandle);
3012
3013 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
3014 Status = STATUS_MORE_ENTRIES;
3015
3016 return Status;
3017 }
3018
3019
3020 /* Function 16 */
3021 NTSTATUS
3022 NTAPI
3023 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3024 IN PSAMPR_PSID_ARRAY SidArray,
3025 OUT PSAMPR_ULONG_ARRAY Membership)
3026 {
3027 PSAM_DB_OBJECT DomainObject;
3028 HANDLE AliasesKeyHandle = NULL;
3029 HANDLE MembersKeyHandle = NULL;
3030 HANDLE MemberKeyHandle = NULL;
3031 LPWSTR MemberSidString = NULL;
3032 PULONG RidArray = NULL;
3033 ULONG MaxSidCount = 0;
3034 ULONG ValueCount;
3035 ULONG DataLength;
3036 ULONG i, j;
3037 NTSTATUS Status;
3038 WCHAR NameBuffer[9];
3039
3040 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3041 DomainHandle, SidArray, Membership);
3042
3043 /* Validate the domain handle */
3044 Status = SampValidateDbObject(DomainHandle,
3045 SamDbDomainObject,
3046 DOMAIN_GET_ALIAS_MEMBERSHIP,
3047 &DomainObject);
3048 if (!NT_SUCCESS(Status))
3049 return Status;
3050
3051 Status = SampRegOpenKey(DomainObject->KeyHandle,
3052 L"Aliases",
3053 KEY_READ,
3054 &AliasesKeyHandle);
3055 TRACE("SampRegOpenKey returned %08lX\n", Status);
3056 if (!NT_SUCCESS(Status))
3057 goto done;
3058
3059 Status = SampRegOpenKey(AliasesKeyHandle,
3060 L"Members",
3061 KEY_READ,
3062 &MembersKeyHandle);
3063 TRACE("SampRegOpenKey returned %08lX\n", Status);
3064
3065 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3066 {
3067 Status = STATUS_SUCCESS;
3068 goto done;
3069 }
3070
3071 if (!NT_SUCCESS(Status))
3072 goto done;
3073
3074 for (i = 0; i < SidArray->Count; i++)
3075 {
3076 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3077 TRACE("Open %S\n", MemberSidString);
3078
3079 Status = SampRegOpenKey(MembersKeyHandle,
3080 MemberSidString,
3081 KEY_READ,
3082 &MemberKeyHandle);
3083 TRACE("SampRegOpenKey returned %08lX\n", Status);
3084 if (NT_SUCCESS(Status))
3085 {
3086 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3087 NULL,
3088 &ValueCount);
3089 if (NT_SUCCESS(Status))
3090 {
3091 TRACE("Found %lu values\n", ValueCount);
3092 MaxSidCount += ValueCount;
3093 }
3094
3095 NtClose(MemberKeyHandle);
3096 }
3097
3098 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3099 Status = STATUS_SUCCESS;
3100
3101 LocalFree(MemberSidString);
3102 }
3103
3104 if (MaxSidCount == 0)
3105 {
3106 Status = STATUS_SUCCESS;
3107 goto done;
3108 }
3109
3110 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3111 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3112 if (RidArray == NULL)
3113 {
3114 Status = STATUS_INSUFFICIENT_RESOURCES;
3115 goto done;
3116 }
3117
3118 for (i = 0; i < SidArray->Count; i++)
3119 {
3120 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3121 TRACE("Open %S\n", MemberSidString);
3122
3123 Status = SampRegOpenKey(MembersKeyHandle,
3124 MemberSidString,
3125 KEY_READ,
3126 &MemberKeyHandle);
3127 TRACE("SampRegOpenKey returned %08lX\n", Status);
3128 if (NT_SUCCESS(Status))
3129 {
3130 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3131 NULL,
3132 &ValueCount);
3133 if (NT_SUCCESS(Status))
3134 {
3135 TRACE("Found %lu values\n", ValueCount);
3136
3137 for (j = 0; j < ValueCount; j++)
3138 {
3139 DataLength = 9 * sizeof(WCHAR);
3140 Status = SampRegEnumerateValue(MemberKeyHandle,
3141 j,
3142 NameBuffer,
3143 &DataLength,
3144 NULL,
3145 NULL,
3146 NULL);
3147 if (NT_SUCCESS(Status))
3148 {
3149 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3150 }
3151 }
3152 }
3153
3154 NtClose(MemberKeyHandle);
3155 }
3156
3157 LocalFree(MemberSidString);
3158 }
3159
3160 done:
3161 if (NT_SUCCESS(Status))
3162 {
3163 Membership->Count = MaxSidCount;
3164 Membership->Element = RidArray;
3165 }
3166 else
3167 {
3168 if (RidArray != NULL)
3169 midl_user_free(RidArray);
3170 }
3171
3172 if (MembersKeyHandle != NULL)
3173 NtClose(MembersKeyHandle);
3174
3175 if (MembersKeyHandle != NULL)
3176 NtClose(MembersKeyHandle);
3177
3178 if (AliasesKeyHandle != NULL)
3179 NtClose(AliasesKeyHandle);
3180
3181 return Status;
3182 }
3183
3184
3185 /* Function 17 */
3186 NTSTATUS
3187 NTAPI
3188 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3189 IN ULONG Count,
3190 IN RPC_UNICODE_STRING Names[],
3191 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3192 OUT PSAMPR_ULONG_ARRAY Use)
3193 {
3194 PSAM_DB_OBJECT DomainObject;
3195 HANDLE AccountsKeyHandle;
3196 HANDLE NamesKeyHandle;
3197 ULONG MappedCount = 0;
3198 ULONG DataLength;
3199 ULONG i;
3200 ULONG RelativeId;
3201 NTSTATUS Status;
3202
3203 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3204 DomainHandle, Count, Names, RelativeIds, Use);
3205
3206 /* Validate the domain handle */
3207 Status = SampValidateDbObject(DomainHandle,
3208 SamDbDomainObject,
3209 DOMAIN_LOOKUP,
3210 &DomainObject);
3211 if (!NT_SUCCESS(Status))
3212 {
3213 TRACE("failed with status 0x%08lx\n", Status);
3214 return Status;
3215 }
3216
3217 RelativeIds->Count = 0;
3218 Use->Count = 0;
3219
3220 if (Count == 0)
3221 return STATUS_SUCCESS;
3222
3223 /* Allocate the relative IDs array */
3224 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3225 if (RelativeIds->Element == NULL)
3226 {
3227 Status = STATUS_INSUFFICIENT_RESOURCES;
3228 goto done;
3229 }
3230
3231 /* Allocate the use array */
3232 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3233 if (Use->Element == NULL)
3234 {
3235 Status = STATUS_INSUFFICIENT_RESOURCES;
3236 goto done;
3237 }
3238
3239 RelativeIds->Count = Count;
3240 Use->Count = Count;
3241
3242 for (i = 0; i < Count; i++)
3243 {
3244 TRACE("Name: %S\n", Names[i].Buffer);
3245
3246 RelativeId = 0;
3247
3248 /* Lookup aliases */
3249 Status = SampRegOpenKey(DomainObject->KeyHandle,
3250 L"Aliases",
3251 KEY_READ,
3252 &AccountsKeyHandle);
3253 if (NT_SUCCESS(Status))
3254 {
3255 Status = SampRegOpenKey(AccountsKeyHandle,
3256 L"Names",
3257 KEY_READ,
3258 &NamesKeyHandle);
3259 if (NT_SUCCESS(Status))
3260 {
3261 DataLength = sizeof(ULONG);
3262 Status = SampRegQueryValue(NamesKeyHandle,
3263 Names[i].Buffer,
3264 NULL,
3265 &RelativeId,
3266 &DataLength);
3267
3268 SampRegCloseKey(NamesKeyHandle);
3269 }
3270
3271 SampRegCloseKey(AccountsKeyHandle);
3272 }
3273
3274 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3275 break;
3276
3277 /* Return alias account */
3278 if (NT_SUCCESS(Status) && RelativeId != 0)
3279 {
3280 TRACE("Rid: %lu\n", RelativeId);
3281 RelativeIds->Element[i] = RelativeId;
3282 Use->Element[i] = SidTypeAlias;
3283 MappedCount++;
3284 continue;
3285 }
3286
3287 /* Lookup groups */
3288 Status = SampRegOpenKey(DomainObject->KeyHandle,
3289 L"Groups",
3290 KEY_READ,
3291 &AccountsKeyHandle);
3292 if (NT_SUCCESS(Status))
3293 {
3294 Status = SampRegOpenKey(AccountsKeyHandle,
3295 L"Names",
3296 KEY_READ,
3297 &NamesKeyHandle);
3298 if (NT_SUCCESS(Status))
3299 {
3300 DataLength = sizeof(ULONG);
3301 Status = SampRegQueryValue(NamesKeyHandle,
3302 Names[i].Buffer,
3303 NULL,
3304 &RelativeId,
3305 &DataLength);
3306
3307 SampRegCloseKey(NamesKeyHandle);
3308 }
3309
3310 SampRegCloseKey(AccountsKeyHandle);
3311 }
3312
3313 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3314 break;
3315
3316 /* Return group account */
3317 if (NT_SUCCESS(Status) && RelativeId != 0)
3318 {
3319 TRACE("Rid: %lu\n", RelativeId);
3320 RelativeIds->Element[i] = RelativeId;
3321 Use->Element[i] = SidTypeGroup;
3322 MappedCount++;
3323 continue;
3324 }
3325
3326 /* Lookup users */
3327 Status = SampRegOpenKey(DomainObject->KeyHandle,
3328 L"Users",
3329 KEY_READ,
3330 &AccountsKeyHandle);
3331 if (NT_SUCCESS(Status))
3332 {
3333 Status = SampRegOpenKey(AccountsKeyHandle,
3334 L"Names",
3335 KEY_READ,
3336 &NamesKeyHandle);
3337 if (NT_SUCCESS(Status))
3338 {
3339 DataLength = sizeof(ULONG);
3340 Status = SampRegQueryValue(NamesKeyHandle,
3341 Names[i].Buffer,
3342 NULL,
3343 &RelativeId,
3344 &DataLength);
3345
3346 SampRegCloseKey(NamesKeyHandle);
3347 }
3348
3349 SampRegCloseKey(AccountsKeyHandle);
3350 }
3351
3352 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3353 break;
3354
3355 /* Return user account */
3356 if (NT_SUCCESS(Status) && RelativeId != 0)
3357 {
3358 TRACE("Rid: %lu\n", RelativeId);
3359 RelativeIds->Element[i] = RelativeId;
3360 Use->Element[i] = SidTypeUser;
3361 MappedCount++;
3362 continue;
3363 }
3364
3365 /* Return unknown account */
3366 RelativeIds->Element[i] = 0;
3367 Use->Element[i] = SidTypeUnknown;
3368 }
3369
3370 done:
3371 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3372 Status = STATUS_SUCCESS;
3373
3374 if (NT_SUCCESS(Status))
3375 {
3376 if (MappedCount == 0)
3377 Status = STATUS_NONE_MAPPED;
3378 else if (MappedCount < Count)
3379 Status = STATUS_SOME_NOT_MAPPED;
3380 }
3381 else
3382 {
3383 if (RelativeIds->Element != NULL)
3384 {
3385 midl_user_free(RelativeIds->Element);
3386 RelativeIds->Element = NULL;
3387 }
3388
3389 RelativeIds->Count = 0;
3390
3391 if (Use->Element != NULL)
3392 {
3393 midl_user_free(Use->Element);
3394 Use->Element = NULL;
3395 }
3396
3397 Use->Count = 0;
3398 }
3399
3400 TRACE("Returned Status %lx\n", Status);
3401
3402 return Status;