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