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