[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: Security Account Manager (SAM) Server
4 * FILE: reactos/dll/win32/samsrv/samrpc.c
5 * PURPOSE: RPC interface functions
6 *
7 * PROGRAMMERS: Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "samsrv.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
15
16 /* GLOBALS *******************************************************************/
17
18 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
19
20 static GENERIC_MAPPING ServerMapping =
21 {
22 SAM_SERVER_READ,
23 SAM_SERVER_WRITE,
24 SAM_SERVER_EXECUTE,
25 SAM_SERVER_ALL_ACCESS
26 };
27
28 static GENERIC_MAPPING DomainMapping =
29 {
30 DOMAIN_READ,
31 DOMAIN_WRITE,
32 DOMAIN_EXECUTE,
33 DOMAIN_ALL_ACCESS
34 };
35
36 static GENERIC_MAPPING AliasMapping =
37 {
38 ALIAS_READ,
39 ALIAS_WRITE,
40 ALIAS_EXECUTE,
41 ALIAS_ALL_ACCESS
42 };
43
44 static GENERIC_MAPPING GroupMapping =
45 {
46 GROUP_READ,
47 GROUP_WRITE,
48 GROUP_EXECUTE,
49 GROUP_ALL_ACCESS
50 };
51
52 static GENERIC_MAPPING UserMapping =
53 {
54 USER_READ,
55 USER_WRITE,
56 USER_EXECUTE,
57 USER_ALL_ACCESS
58 };
59
60
61 /* FUNCTIONS *****************************************************************/
62
63 VOID
64 SampStartRpcServer(VOID)
65 {
66 RPC_STATUS Status;
67
68 TRACE("SampStartRpcServer() called\n");
69
70 Status = RpcServerUseProtseqEpW(L"ncacn_np",
71 10,
72 L"\\pipe\\samr",
73 NULL);
74 if (Status != RPC_S_OK)
75 {
76 WARN("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
77 return;
78 }
79
80 Status = RpcServerRegisterIf(samr_v1_0_s_ifspec,
81 NULL,
82 NULL);
83 if (Status != RPC_S_OK)
84 {
85 WARN("RpcServerRegisterIf() failed (Status %lx)\n", Status);
86 return;
87 }
88
89 Status = RpcServerListen(1, 20, TRUE);
90 if (Status != RPC_S_OK)
91 {
92 WARN("RpcServerListen() failed (Status %lx)\n", Status);
93 return;
94 }
95
96 TRACE("SampStartRpcServer() done\n");
97 }
98
99
100 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
101 {
102 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
103 }
104
105
106 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
107 {
108 HeapFree(GetProcessHeap(), 0, ptr);
109 }
110
111
112 void __RPC_USER SAMPR_HANDLE_rundown(SAMPR_HANDLE hHandle)
113 {
114 }
115
116
117 /* Function 0 */
118 NTSTATUS
119 NTAPI
120 SamrConnect(IN PSAMPR_SERVER_NAME ServerName,
121 OUT SAMPR_HANDLE *ServerHandle,
122 IN ACCESS_MASK DesiredAccess)
123 {
124 PSAM_DB_OBJECT ServerObject;
125 NTSTATUS Status;
126
127 TRACE("SamrConnect(%p %p %lx)\n",
128 ServerName, ServerHandle, DesiredAccess);
129
130 /* Map generic access rights */
131 RtlMapGenericMask(&DesiredAccess,
132 &ServerMapping);
133
134 /* Open the Server Object */
135 Status = SampOpenDbObject(NULL,
136 NULL,
137 L"SAM",
138 0,
139 SamDbServerObject,
140 DesiredAccess,
141 &ServerObject);
142 if (NT_SUCCESS(Status))
143 *ServerHandle = (SAMPR_HANDLE)ServerObject;
144
145 TRACE("SamrConnect done (Status 0x%08lx)\n", Status);
146
147 return Status;
148 }
149
150
151 /* Function 1 */
152 NTSTATUS
153 NTAPI
154 SamrCloseHandle(IN OUT SAMPR_HANDLE *SamHandle)
155 {
156 PSAM_DB_OBJECT DbObject;
157 NTSTATUS Status = STATUS_SUCCESS;
158
159 TRACE("SamrCloseHandle(%p)\n", SamHandle);
160
161 Status = SampValidateDbObject(*SamHandle,
162 SamDbIgnoreObject,
163 0,
164 &DbObject);
165 if (Status == STATUS_SUCCESS)
166 {
167 Status = SampCloseDbObject(DbObject);
168 *SamHandle = NULL;
169 }
170
171 TRACE("SamrCloseHandle done (Status 0x%08lx)\n", Status);
172
173 return Status;
174 }
175
176
177 /* Function 2 */
178 NTSTATUS
179 NTAPI
180 SamrSetSecurityObject(IN SAMPR_HANDLE ObjectHandle,
181 IN SECURITY_INFORMATION SecurityInformation,
182 IN PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor)
183 {
184 UNIMPLEMENTED;
185 return STATUS_NOT_IMPLEMENTED;
186 }
187
188
189 /* Function 3 */
190 NTSTATUS
191 NTAPI
192 SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
193 IN SECURITY_INFORMATION SecurityInformation,
194 OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
195 {
196 UNIMPLEMENTED;
197 return STATUS_NOT_IMPLEMENTED;
198 }
199
200
201 /* Function 4 */
202 NTSTATUS
203 NTAPI
204 SamrShutdownSamServer(IN SAMPR_HANDLE ServerHandle)
205 {
206 UNIMPLEMENTED;
207 return STATUS_NOT_IMPLEMENTED;
208 }
209
210
211 /* Function 5 */
212 NTSTATUS
213 NTAPI
214 SamrLookupDomainInSamServer(IN SAMPR_HANDLE ServerHandle,
215 IN PRPC_UNICODE_STRING Name,
216 OUT PRPC_SID *DomainId)
217 {
218 PSAM_DB_OBJECT ServerObject;
219 HANDLE DomainsKeyHandle = NULL;
220 HANDLE DomainKeyHandle = NULL;
221 WCHAR DomainKeyName[64];
222 ULONG Index;
223 WCHAR DomainNameString[MAX_COMPUTERNAME_LENGTH + 1];
224 UNICODE_STRING DomainName;
225 ULONG Length;
226 BOOL Found = FALSE;
227 NTSTATUS Status;
228
229 TRACE("SamrLookupDomainInSamServer(%p %p %p)\n",
230 ServerHandle, Name, DomainId);
231
232 /* Validate the server handle */
233 Status = SampValidateDbObject(ServerHandle,
234 SamDbServerObject,
235 SAM_SERVER_LOOKUP_DOMAIN,
236 &ServerObject);
237 if (!NT_SUCCESS(Status))
238 return Status;
239
240 *DomainId = NULL;
241
242 Status = SampRegOpenKey(ServerObject->KeyHandle,
243 L"Domains",
244 KEY_READ,
245 &DomainsKeyHandle);
246 if (!NT_SUCCESS(Status))
247 return Status;
248
249 Index = 0;
250 while (Found == FALSE)
251 {
252 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
253 Index,
254 64,
255 DomainKeyName);
256 if (!NT_SUCCESS(Status))
257 {
258 if (Status == STATUS_NO_MORE_ENTRIES)
259 Status = STATUS_NO_SUCH_DOMAIN;
260 break;
261 }
262
263 TRACE("Domain key name: %S\n", DomainKeyName);
264
265 Status = SampRegOpenKey(DomainsKeyHandle,
266 DomainKeyName,
267 KEY_READ,
268 &DomainKeyHandle);
269 if (NT_SUCCESS(Status))
270 {
271 Length = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
272 Status = SampRegQueryValue(DomainKeyHandle,
273 L"Name",
274 NULL,
275 (PVOID)&DomainNameString,
276 &Length);
277 if (NT_SUCCESS(Status))
278 {
279 TRACE("Domain name: %S\n", DomainNameString);
280
281 RtlInitUnicodeString(&DomainName,
282 DomainNameString);
283 if (RtlEqualUnicodeString(&DomainName, (PUNICODE_STRING)Name, TRUE))
284 {
285 TRACE("Found it!\n");
286 Found = TRUE;
287
288 Status = SampRegQueryValue(DomainKeyHandle,
289 L"SID",
290 NULL,
291 NULL,
292 &Length);
293 if (NT_SUCCESS(Status))
294 {
295 *DomainId = midl_user_allocate(Length);
296
297 SampRegQueryValue(DomainKeyHandle,
298 L"SID",
299 NULL,
300 (PVOID)*DomainId,
301 &Length);
302
303 Status = STATUS_SUCCESS;
304 break;
305 }
306 }
307 }
308
309 NtClose(DomainKeyHandle);
310 }
311
312 Index++;
313 }
314
315 NtClose(DomainsKeyHandle);
316
317 return Status;
318 }
319
320
321 /* Function 6 */
322 NTSTATUS
323 NTAPI
324 SamrEnumerateDomainsInSamServer(IN SAMPR_HANDLE ServerHandle,
325 IN OUT unsigned long *EnumerationContext,
326 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
327 IN ULONG PreferedMaximumLength,
328 OUT PULONG CountReturned)
329 {
330 PSAM_DB_OBJECT ServerObject;
331 WCHAR DomainKeyName[64];
332 HANDLE DomainsKeyHandle;
333 HANDLE DomainKeyHandle;
334 ULONG EnumIndex;
335 ULONG EnumCount;
336 ULONG RequiredLength;
337 ULONG DataLength;
338 ULONG i;
339 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
340 NTSTATUS Status;
341
342 TRACE("SamrEnumerateDomainsInSamServer(%p %p %p %lu %p)\n",
343 ServerHandle, EnumerationContext, Buffer, PreferedMaximumLength,
344 CountReturned);
345
346 /* Validate the server handle */
347 Status = SampValidateDbObject(ServerHandle,
348 SamDbServerObject,
349 SAM_SERVER_ENUMERATE_DOMAINS,
350 &ServerObject);
351 if (!NT_SUCCESS(Status))
352 return Status;
353
354 Status = SampRegOpenKey(ServerObject->KeyHandle,
355 L"Domains",
356 KEY_READ,
357 &DomainsKeyHandle);
358 if (!NT_SUCCESS(Status))
359 return Status;
360
361 EnumIndex = *EnumerationContext;
362 EnumCount = 0;
363 RequiredLength = 0;
364
365 while (TRUE)
366 {
367 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
368 EnumIndex,
369 64 * sizeof(WCHAR),
370 DomainKeyName);
371 if (!NT_SUCCESS(Status))
372 break;
373
374 TRACE("EnumIndex: %lu\n", EnumIndex);
375 TRACE("Domain key name: %S\n", DomainKeyName);
376
377 Status = SampRegOpenKey(DomainsKeyHandle,
378 DomainKeyName,
379 KEY_READ,
380 &DomainKeyHandle);
381 TRACE("SampRegOpenKey returned %08lX\n", Status);
382 if (NT_SUCCESS(Status))
383 {
384 DataLength = 0;
385 Status = SampRegQueryValue(DomainKeyHandle,
386 L"Name",
387 NULL,
388 NULL,
389 &DataLength);
390 TRACE("SampRegQueryValue returned %08lX\n", Status);
391 if (NT_SUCCESS(Status))
392 {
393 TRACE("Data length: %lu\n", DataLength);
394
395 if ((RequiredLength + DataLength + sizeof(UNICODE_STRING)) > PreferedMaximumLength)
396 break;
397
398 RequiredLength += (DataLength + sizeof(UNICODE_STRING));
399 EnumCount++;
400 }
401
402 NtClose(DomainKeyHandle);
403 }
404
405 EnumIndex++;
406 }
407
408 TRACE("EnumCount: %lu\n", EnumCount);
409 TRACE("RequiredLength: %lu\n", RequiredLength);
410
411 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
412 if (EnumBuffer == NULL)
413 {
414 Status = STATUS_INSUFFICIENT_RESOURCES;
415 goto done;
416 }
417
418 EnumBuffer->EntriesRead = EnumCount;
419 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
420 if (EnumBuffer->Buffer == NULL)
421 {
422 Status = STATUS_INSUFFICIENT_RESOURCES;
423 goto done;
424 }
425
426 EnumIndex = *EnumerationContext;
427 for (i = 0; i < EnumCount; i++, EnumIndex++)
428 {
429 Status = SampRegEnumerateSubKey(DomainsKeyHandle,
430 EnumIndex,
431 64 * sizeof(WCHAR),
432 DomainKeyName);
433 if (!NT_SUCCESS(Status))
434 break;
435
436 TRACE("EnumIndex: %lu\n", EnumIndex);
437 TRACE("Domain key name: %S\n", DomainKeyName);
438
439 Status = SampRegOpenKey(DomainsKeyHandle,
440 DomainKeyName,
441 KEY_READ,
442 &DomainKeyHandle);
443 TRACE("SampRegOpenKey returned %08lX\n", Status);
444 if (NT_SUCCESS(Status))
445 {
446 DataLength = 0;
447 Status = SampRegQueryValue(DomainKeyHandle,
448 L"Name",
449 NULL,
450 NULL,
451 &DataLength);
452 TRACE("SampRegQueryValue returned %08lX\n", Status);
453 if (NT_SUCCESS(Status))
454 {
455 EnumBuffer->Buffer[i].RelativeId = 0;
456 EnumBuffer->Buffer[i].Name.Length = (USHORT)DataLength - sizeof(WCHAR);
457 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)DataLength;
458 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(DataLength);
459 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
460 {
461 NtClose(DomainKeyHandle);
462 Status = STATUS_INSUFFICIENT_RESOURCES;
463 goto done;
464 }
465
466 Status = SampRegQueryValue(DomainKeyHandle,
467 L"Name",
468 NULL,
469 EnumBuffer->Buffer[i].Name.Buffer,
470 &DataLength);
471 TRACE("SampRegQueryValue returned %08lX\n", Status);
472 if (NT_SUCCESS(Status))
473 {
474 TRACE("Domain name: %S\n", EnumBuffer->Buffer[i].Name.Buffer);
475 }
476 }
477
478 NtClose(DomainKeyHandle);
479
480 if (!NT_SUCCESS(Status))
481 goto done;
482 }
483 }
484
485 if (NT_SUCCESS(Status))
486 {
487 *EnumerationContext += EnumCount;
488 *Buffer = EnumBuffer;
489 *CountReturned = EnumCount;
490 }
491
492 done:
493 if (!NT_SUCCESS(Status))
494 {
495 *EnumerationContext = 0;
496 *Buffer = NULL;
497 *CountReturned = 0;
498
499 if (EnumBuffer != NULL)
500 {
501 if (EnumBuffer->Buffer != NULL)
502 {
503 if (EnumBuffer->EntriesRead != 0)
504 {
505 for (i = 0; i < EnumBuffer->EntriesRead; i++)
506 {
507 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
508 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
509 }
510 }
511
512 midl_user_free(EnumBuffer->Buffer);
513 }
514
515 midl_user_free(EnumBuffer);
516 }
517 }
518
519 NtClose(DomainsKeyHandle);
520
521 return Status;
522 }
523
524
525 /* Function 7 */
526 NTSTATUS
527 NTAPI
528 SamrOpenDomain(IN SAMPR_HANDLE ServerHandle,
529 IN ACCESS_MASK DesiredAccess,
530 IN PRPC_SID DomainId,
531 OUT SAMPR_HANDLE *DomainHandle)
532 {
533 PSAM_DB_OBJECT ServerObject;
534 PSAM_DB_OBJECT DomainObject;
535 NTSTATUS Status;
536
537 TRACE("SamrOpenDomain(%p %lx %p %p)\n",
538 ServerHandle, DesiredAccess, DomainId, DomainHandle);
539
540 /* Map generic access rights */
541 RtlMapGenericMask(&DesiredAccess,
542 &DomainMapping);
543
544 /* Validate the server handle */
545 Status = SampValidateDbObject(ServerHandle,
546 SamDbServerObject,
547 SAM_SERVER_LOOKUP_DOMAIN,
548 &ServerObject);
549 if (!NT_SUCCESS(Status))
550 return Status;
551
552 /* Validate the Domain SID */
553 if ((DomainId->Revision != SID_REVISION) ||
554 (DomainId->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) ||
555 (memcmp(&DomainId->IdentifierAuthority, &NtSidAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) != 0))
556 return STATUS_INVALID_PARAMETER;
557
558 /* Open the domain object */
559 if ((DomainId->SubAuthorityCount == 1) &&
560 (DomainId->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID))
561 {
562 /* Builtin domain object */
563 TRACE("Opening the builtin domain object.\n");
564
565 Status = SampOpenDbObject(ServerObject,
566 L"Domains",
567 L"Builtin",
568 0,
569 SamDbDomainObject,
570 DesiredAccess,
571 &DomainObject);
572 }
573 else if ((DomainId->SubAuthorityCount == 4) &&
574 (DomainId->SubAuthority[0] == SECURITY_NT_NON_UNIQUE))
575 {
576 /* Account domain object */
577 TRACE("Opening the account domain object.\n");
578
579 /* FIXME: Check the account domain sub authorities!!! */
580
581 Status = SampOpenDbObject(ServerObject,
582 L"Domains",
583 L"Account",
584 0,
585 SamDbDomainObject,
586 DesiredAccess,
587 &DomainObject);
588 }
589 else
590 {
591 /* No vaild domain SID */
592 Status = STATUS_INVALID_PARAMETER;
593 }
594
595 if (NT_SUCCESS(Status))
596 *DomainHandle = (SAMPR_HANDLE)DomainObject;
597
598 TRACE("SamrOpenDomain done (Status 0x%08lx)\n", Status);
599
600 return Status;
601 }
602
603
604 static NTSTATUS
605 SampQueryDomainPassword(PSAM_DB_OBJECT DomainObject,
606 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
607 {
608 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
609 SAM_DOMAIN_FIXED_DATA FixedData;
610 ULONG Length = 0;
611 NTSTATUS Status;
612
613 *Buffer = NULL;
614
615 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
616 if (InfoBuffer == NULL)
617 return STATUS_INSUFFICIENT_RESOURCES;
618
619 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
620 Status = SampGetObjectAttribute(DomainObject,
621 L"F",
622 NULL,
623 (PVOID)&FixedData,
624 &Length);
625 if (!NT_SUCCESS(Status))
626 goto done;
627
628 InfoBuffer->Password.MinPasswordLength = FixedData.MinPasswordLength;
629 InfoBuffer->Password.PasswordHistoryLength = FixedData.PasswordHistoryLength;
630 InfoBuffer->Password.PasswordProperties = FixedData.PasswordProperties;
631 InfoBuffer->Password.MaxPasswordAge.LowPart = FixedData.MaxPasswordAge.LowPart;
632 InfoBuffer->Password.MaxPasswordAge.HighPart = FixedData.MaxPasswordAge.HighPart;
633 InfoBuffer->Password.MinPasswordAge.LowPart = FixedData.MinPasswordAge.LowPart;
634 InfoBuffer->Password.MinPasswordAge.HighPart = FixedData.MinPasswordAge.HighPart;
635
636 *Buffer = InfoBuffer;
637
638 done:
639 if (!NT_SUCCESS(Status))
640 {
641 if (InfoBuffer != NULL)
642 {
643 midl_user_free(InfoBuffer);
644 }
645 }
646
647 return Status;
648 }
649
650
651 static NTSTATUS
652 SampGetNumberOfAccounts(PSAM_DB_OBJECT DomainObject,
653 LPCWSTR AccountType,
654 PULONG Count)
655 {
656 HANDLE AccountKeyHandle = NULL;
657 HANDLE NamesKeyHandle = NULL;
658 NTSTATUS Status;
659
660 *Count = 0;
661
662 Status = SampRegOpenKey(DomainObject->KeyHandle,
663 AccountType,
664 KEY_READ,
665 &AccountKeyHandle);
666 if (!NT_SUCCESS(Status))
667 return Status;
668
669 Status = SampRegOpenKey(AccountKeyHandle,
670 L"Names",
671 KEY_READ,
672 &NamesKeyHandle);
673 if (!NT_SUCCESS(Status))
674 goto done;
675
676 Status = SampRegQueryKeyInfo(NamesKeyHandle,
677 NULL,
678 Count);
679 done:
680 if (NamesKeyHandle != NULL)
681 SampRegCloseKey(NamesKeyHandle);
682
683 if (AccountKeyHandle != NULL)
684 SampRegCloseKey(AccountKeyHandle);
685
686 return Status;
687 }
688
689
690 static NTSTATUS
691 SampQueryDomainGeneral(PSAM_DB_OBJECT DomainObject,
692 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
693 {
694 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
695 SAM_DOMAIN_FIXED_DATA FixedData;
696 ULONG Length = 0;
697 NTSTATUS Status;
698
699 *Buffer = NULL;
700
701 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
702 if (InfoBuffer == NULL)
703 return STATUS_INSUFFICIENT_RESOURCES;
704
705 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
706 Status = SampGetObjectAttribute(DomainObject,
707 L"F",
708 NULL,
709 (PVOID)&FixedData,
710 &Length);
711 if (!NT_SUCCESS(Status))
712 goto done;
713
714 InfoBuffer->General.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
715 InfoBuffer->General.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
716 InfoBuffer->General.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
717 InfoBuffer->General.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
718 InfoBuffer->General.DomainServerState = FixedData.DomainServerState;
719 InfoBuffer->General.DomainServerRole = FixedData.DomainServerRole;
720 InfoBuffer->General.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
721
722 /* Get the OemInformation string */
723 Status = SampGetObjectAttributeString(DomainObject,
724 L"OemInformation",
725 &InfoBuffer->General.OemInformation);
726 if (!NT_SUCCESS(Status))
727 {
728 TRACE("Status 0x%08lx\n", Status);
729 goto done;
730 }
731
732 /* Get the Name string */
733 Status = SampGetObjectAttributeString(DomainObject,
734 L"Name",
735 &InfoBuffer->General.DomainName);
736 if (!NT_SUCCESS(Status))
737 {
738 TRACE("Status 0x%08lx\n", Status);
739 goto done;
740 }
741
742 /* Get the ReplicaSourceNodeName string */
743 Status = SampGetObjectAttributeString(DomainObject,
744 L"ReplicaSourceNodeName",
745 &InfoBuffer->General.ReplicaSourceNodeName);
746 if (!NT_SUCCESS(Status))
747 {
748 TRACE("Status 0x%08lx\n", Status);
749 goto done;
750 }
751
752 /* Get the number of Users in the Domain */
753 Status = SampGetNumberOfAccounts(DomainObject,
754 L"Users",
755 &InfoBuffer->General.UserCount);
756 if (!NT_SUCCESS(Status))
757 {
758 TRACE("Status 0x%08lx\n", Status);
759 goto done;
760 }
761
762 /* Get the number of Groups in the Domain */
763 Status = SampGetNumberOfAccounts(DomainObject,
764 L"Groups",
765 &InfoBuffer->General.GroupCount);
766 if (!NT_SUCCESS(Status))
767 {
768 TRACE("Status 0x%08lx\n", Status);
769 goto done;
770 }
771
772 /* Get the number of Aliases in the Domain */
773 Status = SampGetNumberOfAccounts(DomainObject,
774 L"Aliases",
775 &InfoBuffer->General.AliasCount);
776 if (!NT_SUCCESS(Status))
777 {
778 TRACE("Status 0x%08lx\n", Status);
779 goto done;
780 }
781
782 *Buffer = InfoBuffer;
783
784 done:
785 if (!NT_SUCCESS(Status))
786 {
787 if (InfoBuffer != NULL)
788 {
789 if (InfoBuffer->General.OemInformation.Buffer != NULL)
790 midl_user_free(InfoBuffer->General.OemInformation.Buffer);
791
792 if (InfoBuffer->General.DomainName.Buffer != NULL)
793 midl_user_free(InfoBuffer->General.DomainName.Buffer);
794
795 if (InfoBuffer->General.ReplicaSourceNodeName.Buffer != NULL)
796 midl_user_free(InfoBuffer->General.ReplicaSourceNodeName.Buffer);
797
798 midl_user_free(InfoBuffer);
799 }
800 }
801
802 return Status;
803 }
804
805
806 static NTSTATUS
807 SampQueryDomainLogoff(PSAM_DB_OBJECT DomainObject,
808 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
809 {
810 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
811 SAM_DOMAIN_FIXED_DATA FixedData;
812 ULONG Length = 0;
813 NTSTATUS Status;
814
815 *Buffer = NULL;
816
817 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
818 if (InfoBuffer == NULL)
819 return STATUS_INSUFFICIENT_RESOURCES;
820
821 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
822 Status = SampGetObjectAttribute(DomainObject,
823 L"F",
824 NULL,
825 (PVOID)&FixedData,
826 &Length);
827 if (!NT_SUCCESS(Status))
828 goto done;
829
830 InfoBuffer->Logoff.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
831 InfoBuffer->Logoff.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
832
833 *Buffer = InfoBuffer;
834
835 done:
836 if (!NT_SUCCESS(Status))
837 {
838 if (InfoBuffer != NULL)
839 {
840 midl_user_free(InfoBuffer);
841 }
842 }
843
844 return Status;
845 }
846
847
848 static NTSTATUS
849 SampQueryDomainOem(PSAM_DB_OBJECT DomainObject,
850 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
851 {
852 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
853 NTSTATUS Status;
854
855 *Buffer = NULL;
856
857 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
858 if (InfoBuffer == NULL)
859 return STATUS_INSUFFICIENT_RESOURCES;
860
861 /* Get the OemInformation string */
862 Status = SampGetObjectAttributeString(DomainObject,
863 L"OemInformation",
864 &InfoBuffer->Oem.OemInformation);
865 if (!NT_SUCCESS(Status))
866 {
867 TRACE("Status 0x%08lx\n", Status);
868 goto done;
869 }
870
871 *Buffer = InfoBuffer;
872
873 done:
874 if (!NT_SUCCESS(Status))
875 {
876 if (InfoBuffer != NULL)
877 {
878 if (InfoBuffer->Oem.OemInformation.Buffer != NULL)
879 midl_user_free(InfoBuffer->Oem.OemInformation.Buffer);
880
881 midl_user_free(InfoBuffer);
882 }
883 }
884
885 return Status;
886 }
887
888
889 static NTSTATUS
890 SampQueryDomainName(PSAM_DB_OBJECT DomainObject,
891 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
892 {
893 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
894 NTSTATUS Status;
895
896 *Buffer = NULL;
897
898 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
899 if (InfoBuffer == NULL)
900 return STATUS_INSUFFICIENT_RESOURCES;
901
902 /* Get the Name string */
903 Status = SampGetObjectAttributeString(DomainObject,
904 L"Name",
905 &InfoBuffer->Name.DomainName);
906 if (!NT_SUCCESS(Status))
907 {
908 TRACE("Status 0x%08lx\n", Status);
909 goto done;
910 }
911
912 *Buffer = InfoBuffer;
913
914 done:
915 if (!NT_SUCCESS(Status))
916 {
917 if (InfoBuffer != NULL)
918 {
919 if (InfoBuffer->Name.DomainName.Buffer != NULL)
920 midl_user_free(InfoBuffer->Name.DomainName.Buffer);
921
922 midl_user_free(InfoBuffer);
923 }
924 }
925
926 return Status;
927 }
928
929
930 static NTSTATUS
931 SampQueryDomainReplication(PSAM_DB_OBJECT DomainObject,
932 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
933 {
934 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
935 NTSTATUS Status;
936
937 *Buffer = NULL;
938
939 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
940 if (InfoBuffer == NULL)
941 return STATUS_INSUFFICIENT_RESOURCES;
942
943 /* Get the ReplicaSourceNodeName string */
944 Status = SampGetObjectAttributeString(DomainObject,
945 L"ReplicaSourceNodeName",
946 &InfoBuffer->Replication.ReplicaSourceNodeName);
947 if (!NT_SUCCESS(Status))
948 {
949 TRACE("Status 0x%08lx\n", Status);
950 goto done;
951 }
952
953 *Buffer = InfoBuffer;
954
955 done:
956 if (!NT_SUCCESS(Status))
957 {
958 if (InfoBuffer != NULL)
959 {
960 if (InfoBuffer->Replication.ReplicaSourceNodeName.Buffer != NULL)
961 midl_user_free(InfoBuffer->Replication.ReplicaSourceNodeName.Buffer);
962
963 midl_user_free(InfoBuffer);
964 }
965 }
966
967 return Status;
968 }
969
970
971 static NTSTATUS
972 SampQueryDomainServerRole(PSAM_DB_OBJECT DomainObject,
973 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
974 {
975 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
976 SAM_DOMAIN_FIXED_DATA FixedData;
977 ULONG Length = 0;
978 NTSTATUS Status;
979
980 *Buffer = NULL;
981
982 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
983 if (InfoBuffer == NULL)
984 return STATUS_INSUFFICIENT_RESOURCES;
985
986 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
987 Status = SampGetObjectAttribute(DomainObject,
988 L"F",
989 NULL,
990 (PVOID)&FixedData,
991 &Length);
992 if (!NT_SUCCESS(Status))
993 goto done;
994
995 InfoBuffer->Role.DomainServerRole = FixedData.DomainServerRole;
996
997 *Buffer = InfoBuffer;
998
999 done:
1000 if (!NT_SUCCESS(Status))
1001 {
1002 if (InfoBuffer != NULL)
1003 {
1004 midl_user_free(InfoBuffer);
1005 }
1006 }
1007
1008 return Status;
1009 }
1010
1011
1012 static NTSTATUS
1013 SampQueryDomainModified(PSAM_DB_OBJECT DomainObject,
1014 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1015 {
1016 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1017 SAM_DOMAIN_FIXED_DATA FixedData;
1018 ULONG Length = 0;
1019 NTSTATUS Status;
1020
1021 *Buffer = NULL;
1022
1023 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1024 if (InfoBuffer == NULL)
1025 return STATUS_INSUFFICIENT_RESOURCES;
1026
1027 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1028 Status = SampGetObjectAttribute(DomainObject,
1029 L"F",
1030 NULL,
1031 (PVOID)&FixedData,
1032 &Length);
1033 if (!NT_SUCCESS(Status))
1034 goto done;
1035
1036 InfoBuffer->Modified.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1037 InfoBuffer->Modified.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1038 InfoBuffer->Modified.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1039 InfoBuffer->Modified.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1040
1041 *Buffer = InfoBuffer;
1042
1043 done:
1044 if (!NT_SUCCESS(Status))
1045 {
1046 if (InfoBuffer != NULL)
1047 {
1048 midl_user_free(InfoBuffer);
1049 }
1050 }
1051
1052 return Status;
1053 }
1054
1055
1056 static NTSTATUS
1057 SampQueryDomainState(PSAM_DB_OBJECT DomainObject,
1058 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1059 {
1060 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1061 SAM_DOMAIN_FIXED_DATA FixedData;
1062 ULONG Length = 0;
1063 NTSTATUS Status;
1064
1065 *Buffer = NULL;
1066
1067 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1068 if (InfoBuffer == NULL)
1069 return STATUS_INSUFFICIENT_RESOURCES;
1070
1071 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1072 Status = SampGetObjectAttribute(DomainObject,
1073 L"F",
1074 NULL,
1075 (PVOID)&FixedData,
1076 &Length);
1077 if (!NT_SUCCESS(Status))
1078 goto done;
1079
1080 InfoBuffer->State.DomainServerState = FixedData.DomainServerState;
1081
1082 *Buffer = InfoBuffer;
1083
1084 done:
1085 if (!NT_SUCCESS(Status))
1086 {
1087 if (InfoBuffer != NULL)
1088 {
1089 midl_user_free(InfoBuffer);
1090 }
1091 }
1092
1093 return Status;
1094 }
1095
1096
1097 static NTSTATUS
1098 SampQueryDomainGeneral2(PSAM_DB_OBJECT DomainObject,
1099 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1100 {
1101 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1102 SAM_DOMAIN_FIXED_DATA FixedData;
1103 ULONG Length = 0;
1104 NTSTATUS Status;
1105
1106 *Buffer = NULL;
1107
1108 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1109 if (InfoBuffer == NULL)
1110 return STATUS_INSUFFICIENT_RESOURCES;
1111
1112 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1113 Status = SampGetObjectAttribute(DomainObject,
1114 L"F",
1115 NULL,
1116 (PVOID)&FixedData,
1117 &Length);
1118 if (!NT_SUCCESS(Status))
1119 goto done;
1120
1121 InfoBuffer->General2.I1.ForceLogoff.LowPart = FixedData.ForceLogoff.LowPart;
1122 InfoBuffer->General2.I1.ForceLogoff.HighPart = FixedData.ForceLogoff.HighPart;
1123 InfoBuffer->General2.I1.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1124 InfoBuffer->General2.I1.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1125 InfoBuffer->General2.I1.DomainServerState = FixedData.DomainServerState;
1126 InfoBuffer->General2.I1.DomainServerRole = FixedData.DomainServerRole;
1127 InfoBuffer->General2.I1.UasCompatibilityRequired = FixedData.UasCompatibilityRequired;
1128
1129 InfoBuffer->General2.LockoutDuration = FixedData.LockoutDuration;
1130 InfoBuffer->General2.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1131 InfoBuffer->General2.LockoutThreshold = FixedData.LockoutThreshold;
1132
1133 /* Get the OemInformation string */
1134 Status = SampGetObjectAttributeString(DomainObject,
1135 L"OemInformation",
1136 &InfoBuffer->General2.I1.OemInformation);
1137 if (!NT_SUCCESS(Status))
1138 {
1139 TRACE("Status 0x%08lx\n", Status);
1140 goto done;
1141 }
1142
1143 /* Get the Name string */
1144 Status = SampGetObjectAttributeString(DomainObject,
1145 L"Name",
1146 &InfoBuffer->General2.I1.DomainName);
1147 if (!NT_SUCCESS(Status))
1148 {
1149 TRACE("Status 0x%08lx\n", Status);
1150 goto done;
1151 }
1152
1153 /* Get the ReplicaSourceNodeName string */
1154 Status = SampGetObjectAttributeString(DomainObject,
1155 L"ReplicaSourceNodeName",
1156 &InfoBuffer->General2.I1.ReplicaSourceNodeName);
1157 if (!NT_SUCCESS(Status))
1158 {
1159 TRACE("Status 0x%08lx\n", Status);
1160 goto done;
1161 }
1162
1163 /* Get the number of Users in the Domain */
1164 Status = SampGetNumberOfAccounts(DomainObject,
1165 L"Users",
1166 &InfoBuffer->General2.I1.UserCount);
1167 if (!NT_SUCCESS(Status))
1168 {
1169 TRACE("Status 0x%08lx\n", Status);
1170 goto done;
1171 }
1172
1173 /* Get the number of Groups in the Domain */
1174 Status = SampGetNumberOfAccounts(DomainObject,
1175 L"Groups",
1176 &InfoBuffer->General2.I1.GroupCount);
1177 if (!NT_SUCCESS(Status))
1178 {
1179 TRACE("Status 0x%08lx\n", Status);
1180 goto done;
1181 }
1182
1183 /* Get the number of Aliases in the Domain */
1184 Status = SampGetNumberOfAccounts(DomainObject,
1185 L"Aliases",
1186 &InfoBuffer->General2.I1.AliasCount);
1187 if (!NT_SUCCESS(Status))
1188 {
1189 TRACE("Status 0x%08lx\n", Status);
1190 goto done;
1191 }
1192
1193 *Buffer = InfoBuffer;
1194
1195 done:
1196 if (!NT_SUCCESS(Status))
1197 {
1198 if (InfoBuffer != NULL)
1199 {
1200 if (InfoBuffer->General2.I1.OemInformation.Buffer != NULL)
1201 midl_user_free(InfoBuffer->General2.I1.OemInformation.Buffer);
1202
1203 if (InfoBuffer->General2.I1.DomainName.Buffer != NULL)
1204 midl_user_free(InfoBuffer->General2.I1.DomainName.Buffer);
1205
1206 if (InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer != NULL)
1207 midl_user_free(InfoBuffer->General2.I1.ReplicaSourceNodeName.Buffer);
1208
1209 midl_user_free(InfoBuffer);
1210 }
1211 }
1212
1213 return Status;
1214 }
1215
1216
1217 static NTSTATUS
1218 SampQueryDomainLockout(PSAM_DB_OBJECT DomainObject,
1219 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1220 {
1221 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1222 SAM_DOMAIN_FIXED_DATA FixedData;
1223 ULONG Length = 0;
1224 NTSTATUS Status;
1225
1226 *Buffer = NULL;
1227
1228 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1229 if (InfoBuffer == NULL)
1230 return STATUS_INSUFFICIENT_RESOURCES;
1231
1232 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1233 Status = SampGetObjectAttribute(DomainObject,
1234 L"F",
1235 NULL,
1236 (PVOID)&FixedData,
1237 &Length);
1238 if (!NT_SUCCESS(Status))
1239 goto done;
1240
1241 InfoBuffer->Lockout.LockoutDuration = FixedData.LockoutDuration;
1242 InfoBuffer->Lockout.LockoutObservationWindow = FixedData.LockoutObservationWindow;
1243 InfoBuffer->Lockout.LockoutThreshold = FixedData.LockoutThreshold;
1244
1245 *Buffer = InfoBuffer;
1246
1247 done:
1248 if (!NT_SUCCESS(Status))
1249 {
1250 if (InfoBuffer != NULL)
1251 {
1252 midl_user_free(InfoBuffer);
1253 }
1254 }
1255
1256 return Status;
1257 }
1258
1259
1260 static NTSTATUS
1261 SampQueryDomainModified2(PSAM_DB_OBJECT DomainObject,
1262 PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1263 {
1264 PSAMPR_DOMAIN_INFO_BUFFER InfoBuffer = NULL;
1265 SAM_DOMAIN_FIXED_DATA FixedData;
1266 ULONG Length = 0;
1267 NTSTATUS Status;
1268
1269 *Buffer = NULL;
1270
1271 InfoBuffer = midl_user_allocate(sizeof(SAMPR_DOMAIN_INFO_BUFFER));
1272 if (InfoBuffer == NULL)
1273 return STATUS_INSUFFICIENT_RESOURCES;
1274
1275 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1276 Status = SampGetObjectAttribute(DomainObject,
1277 L"F",
1278 NULL,
1279 (PVOID)&FixedData,
1280 &Length);
1281 if (!NT_SUCCESS(Status))
1282 goto done;
1283
1284 InfoBuffer->Modified2.DomainModifiedCount.LowPart = FixedData.DomainModifiedCount.LowPart;
1285 InfoBuffer->Modified2.DomainModifiedCount.HighPart = FixedData.DomainModifiedCount.HighPart;
1286 InfoBuffer->Modified2.CreationTime.LowPart = FixedData.CreationTime.LowPart;
1287 InfoBuffer->Modified2.CreationTime.HighPart = FixedData.CreationTime.HighPart;
1288 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.LowPart = FixedData.ModifiedCountAtLastPromotion.LowPart;
1289 InfoBuffer->Modified2.ModifiedCountAtLastPromotion.HighPart = FixedData.ModifiedCountAtLastPromotion.HighPart;
1290
1291 *Buffer = InfoBuffer;
1292
1293 done:
1294 if (!NT_SUCCESS(Status))
1295 {
1296 if (InfoBuffer != NULL)
1297 {
1298 midl_user_free(InfoBuffer);
1299 }
1300 }
1301
1302 return Status;
1303 }
1304
1305
1306 /* Function 8 */
1307 NTSTATUS
1308 NTAPI
1309 SamrQueryInformationDomain(IN SAMPR_HANDLE DomainHandle,
1310 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1311 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
1312 {
1313 PSAM_DB_OBJECT DomainObject;
1314 ACCESS_MASK DesiredAccess;
1315 NTSTATUS Status;
1316
1317 TRACE("SamrQueryInformationDomain(%p %lu %p)\n",
1318 DomainHandle, DomainInformationClass, Buffer);
1319
1320 switch (DomainInformationClass)
1321 {
1322 case DomainPasswordInformation:
1323 case DomainLockoutInformation:
1324 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS;
1325 break;
1326
1327 case DomainGeneralInformation:
1328 case DomainLogoffInformation:
1329 case DomainOemInformation:
1330 case DomainNameInformation:
1331 case DomainReplicationInformation:
1332 case DomainServerRoleInformation:
1333 case DomainModifiedInformation:
1334 case DomainStateInformation:
1335 case DomainModifiedInformation2:
1336 DesiredAccess = DOMAIN_READ_OTHER_PARAMETERS;
1337 break;
1338
1339 case DomainGeneralInformation2:
1340 DesiredAccess = DOMAIN_READ_PASSWORD_PARAMETERS |
1341 DOMAIN_READ_OTHER_PARAMETERS;
1342 break;
1343
1344 default:
1345 return STATUS_INVALID_INFO_CLASS;
1346 }
1347
1348 /* Validate the server handle */
1349 Status = SampValidateDbObject(DomainHandle,
1350 SamDbDomainObject,
1351 DesiredAccess,
1352 &DomainObject);
1353 if (!NT_SUCCESS(Status))
1354 return Status;
1355
1356 switch (DomainInformationClass)
1357 {
1358 case DomainPasswordInformation:
1359 Status = SampQueryDomainPassword(DomainObject,
1360 Buffer);
1361 break;
1362
1363 case DomainGeneralInformation:
1364 Status = SampQueryDomainGeneral(DomainObject,
1365 Buffer);
1366 break;
1367
1368 case DomainLogoffInformation:
1369 Status = SampQueryDomainLogoff(DomainObject,
1370 Buffer);
1371 break;
1372
1373 case DomainOemInformation:
1374 Status = SampQueryDomainOem(DomainObject,
1375 Buffer);
1376 break;
1377
1378 case DomainNameInformation:
1379 Status = SampQueryDomainName(DomainObject,
1380 Buffer);
1381 break;
1382
1383 case DomainReplicationInformation:
1384 Status = SampQueryDomainReplication(DomainObject,
1385 Buffer);
1386 break;
1387
1388 case DomainServerRoleInformation:
1389 Status = SampQueryDomainServerRole(DomainObject,
1390 Buffer);
1391 break;
1392
1393 case DomainModifiedInformation:
1394 Status = SampQueryDomainModified(DomainObject,
1395 Buffer);
1396 break;
1397
1398 case DomainStateInformation:
1399 Status = SampQueryDomainState(DomainObject,
1400 Buffer);
1401 break;
1402
1403 case DomainGeneralInformation2:
1404 Status = SampQueryDomainGeneral2(DomainObject,
1405 Buffer);
1406 break;
1407
1408 case DomainLockoutInformation:
1409 Status = SampQueryDomainLockout(DomainObject,
1410 Buffer);
1411 break;
1412
1413 case DomainModifiedInformation2:
1414 Status = SampQueryDomainModified2(DomainObject,
1415 Buffer);
1416 break;
1417
1418 default:
1419 Status = STATUS_NOT_IMPLEMENTED;
1420 }
1421
1422 return Status;
1423 }
1424
1425
1426 static NTSTATUS
1427 SampSetDomainPassword(PSAM_DB_OBJECT DomainObject,
1428 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1429 {
1430 SAM_DOMAIN_FIXED_DATA FixedData;
1431 ULONG Length = 0;
1432 NTSTATUS Status;
1433
1434 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1435 Status = SampGetObjectAttribute(DomainObject,
1436 L"F",
1437 NULL,
1438 (PVOID)&FixedData,
1439 &Length);
1440 if (!NT_SUCCESS(Status))
1441 goto done;
1442
1443 FixedData.MinPasswordLength = Buffer->Password.MinPasswordLength;
1444 FixedData.PasswordHistoryLength = Buffer->Password.PasswordHistoryLength;
1445 FixedData.PasswordProperties = Buffer->Password.PasswordProperties;
1446 FixedData.MaxPasswordAge.LowPart = Buffer->Password.MaxPasswordAge.LowPart;
1447 FixedData.MaxPasswordAge.HighPart = Buffer->Password.MaxPasswordAge.HighPart;
1448 FixedData.MinPasswordAge.LowPart = Buffer->Password.MinPasswordAge.LowPart;
1449 FixedData.MinPasswordAge.HighPart = Buffer->Password.MinPasswordAge.HighPart;
1450
1451 Status = SampSetObjectAttribute(DomainObject,
1452 L"F",
1453 REG_BINARY,
1454 &FixedData,
1455 Length);
1456
1457 done:
1458 return Status;
1459 }
1460
1461
1462 static NTSTATUS
1463 SampSetDomainLogoff(PSAM_DB_OBJECT DomainObject,
1464 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1465 {
1466 SAM_DOMAIN_FIXED_DATA FixedData;
1467 ULONG Length = 0;
1468 NTSTATUS Status;
1469
1470 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1471 Status = SampGetObjectAttribute(DomainObject,
1472 L"F",
1473 NULL,
1474 (PVOID)&FixedData,
1475 &Length);
1476 if (!NT_SUCCESS(Status))
1477 goto done;
1478
1479 FixedData.ForceLogoff.LowPart = Buffer->Logoff.ForceLogoff.LowPart;
1480 FixedData.ForceLogoff.HighPart = Buffer->Logoff.ForceLogoff.HighPart;
1481
1482 Status = SampSetObjectAttribute(DomainObject,
1483 L"F",
1484 REG_BINARY,
1485 &FixedData,
1486 Length);
1487
1488 done:
1489 return Status;
1490 }
1491
1492
1493 static NTSTATUS
1494 SampSetDomainServerRole(PSAM_DB_OBJECT DomainObject,
1495 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1496 {
1497 SAM_DOMAIN_FIXED_DATA FixedData;
1498 ULONG Length = 0;
1499 NTSTATUS Status;
1500
1501 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1502 Status = SampGetObjectAttribute(DomainObject,
1503 L"F",
1504 NULL,
1505 (PVOID)&FixedData,
1506 &Length);
1507 if (!NT_SUCCESS(Status))
1508 goto done;
1509
1510 FixedData.DomainServerRole = Buffer->Role.DomainServerRole;
1511
1512 Status = SampSetObjectAttribute(DomainObject,
1513 L"F",
1514 REG_BINARY,
1515 &FixedData,
1516 Length);
1517
1518 done:
1519 return Status;
1520 }
1521
1522
1523 static NTSTATUS
1524 SampSetDomainState(PSAM_DB_OBJECT DomainObject,
1525 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1526 {
1527 SAM_DOMAIN_FIXED_DATA FixedData;
1528 ULONG Length = 0;
1529 NTSTATUS Status;
1530
1531 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1532 Status = SampGetObjectAttribute(DomainObject,
1533 L"F",
1534 NULL,
1535 (PVOID)&FixedData,
1536 &Length);
1537 if (!NT_SUCCESS(Status))
1538 goto done;
1539
1540 FixedData.DomainServerState = Buffer->State.DomainServerState;
1541
1542 Status = SampSetObjectAttribute(DomainObject,
1543 L"F",
1544 REG_BINARY,
1545 &FixedData,
1546 Length);
1547
1548 done:
1549 return Status;
1550 }
1551
1552
1553 static NTSTATUS
1554 SampSetDomainLockout(PSAM_DB_OBJECT DomainObject,
1555 PSAMPR_DOMAIN_INFO_BUFFER Buffer)
1556 {
1557 SAM_DOMAIN_FIXED_DATA FixedData;
1558 ULONG Length = 0;
1559 NTSTATUS Status;
1560
1561 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
1562 Status = SampGetObjectAttribute(DomainObject,
1563 L"F",
1564 NULL,
1565 (PVOID)&FixedData,
1566 &Length);
1567 if (!NT_SUCCESS(Status))
1568 goto done;
1569
1570 FixedData.LockoutDuration = Buffer->Lockout.LockoutDuration;
1571 FixedData.LockoutObservationWindow = Buffer->Lockout.LockoutObservationWindow;
1572 FixedData.LockoutThreshold = Buffer->Lockout.LockoutThreshold;
1573
1574 Status = SampSetObjectAttribute(DomainObject,
1575 L"F",
1576 REG_BINARY,
1577 &FixedData,
1578 Length);
1579
1580 done:
1581 return Status;
1582 }
1583
1584
1585 /* Function 9 */
1586 NTSTATUS
1587 NTAPI
1588 SamrSetInformationDomain(IN SAMPR_HANDLE DomainHandle,
1589 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
1590 IN PSAMPR_DOMAIN_INFO_BUFFER DomainInformation)
1591 {
1592 PSAM_DB_OBJECT DomainObject;
1593 ACCESS_MASK DesiredAccess;
1594 NTSTATUS Status;
1595
1596 TRACE("SamrSetInformationDomain(%p %lu %p)\n",
1597 DomainHandle, DomainInformationClass, DomainInformation);
1598
1599 switch (DomainInformationClass)
1600 {
1601 case DomainPasswordInformation:
1602 case DomainLockoutInformation:
1603 DesiredAccess = DOMAIN_WRITE_PASSWORD_PARAMS;
1604 break;
1605
1606 case DomainLogoffInformation:
1607 case DomainOemInformation:
1608 case DomainNameInformation:
1609 DesiredAccess = DOMAIN_WRITE_OTHER_PARAMETERS;
1610 break;
1611
1612 case DomainReplicationInformation:
1613 case DomainServerRoleInformation:
1614 case DomainStateInformation:
1615 DesiredAccess = DOMAIN_ADMINISTER_SERVER;
1616 break;
1617
1618 default:
1619 return STATUS_INVALID_INFO_CLASS;
1620 }
1621
1622 /* Validate the server handle */
1623 Status = SampValidateDbObject(DomainHandle,
1624 SamDbDomainObject,
1625 DesiredAccess,
1626 &DomainObject);
1627 if (!NT_SUCCESS(Status))
1628 return Status;
1629
1630 switch (DomainInformationClass)
1631 {
1632 case DomainPasswordInformation:
1633 Status = SampSetDomainPassword(DomainObject,
1634 DomainInformation);
1635 break;
1636
1637 case DomainLogoffInformation:
1638 Status = SampSetDomainLogoff(DomainObject,
1639 DomainInformation);
1640 break;
1641
1642 case DomainOemInformation:
1643 Status = SampSetObjectAttribute(DomainObject,
1644 L"OemInformation",
1645 REG_SZ,
1646 DomainInformation->Oem.OemInformation.Buffer,
1647 DomainInformation->Oem.OemInformation.Length + sizeof(WCHAR));
1648 break;
1649
1650 case DomainNameInformation:
1651 Status = SampSetObjectAttribute(DomainObject,
1652 L"Name",
1653 REG_SZ,
1654 DomainInformation->Name.DomainName.Buffer,
1655 DomainInformation->Name.DomainName.Length + sizeof(WCHAR));
1656 break;
1657
1658 case DomainReplicationInformation:
1659 Status = SampSetObjectAttribute(DomainObject,
1660 L"ReplicaSourceNodeName",
1661 REG_SZ,
1662 DomainInformation->Replication.ReplicaSourceNodeName.Buffer,
1663 DomainInformation->Replication.ReplicaSourceNodeName.Length + sizeof(WCHAR));
1664 break;
1665
1666 case DomainServerRoleInformation:
1667 Status = SampSetDomainServerRole(DomainObject,
1668 DomainInformation);
1669 break;
1670
1671 case DomainStateInformation:
1672 Status = SampSetDomainState(DomainObject,
1673 DomainInformation);
1674 break;
1675
1676 case DomainLockoutInformation:
1677 Status = SampSetDomainLockout(DomainObject,
1678 DomainInformation);
1679 break;
1680
1681 default:
1682 Status = STATUS_NOT_IMPLEMENTED;
1683 }
1684
1685 return Status;
1686 }
1687
1688
1689 /* Function 10 */
1690 NTSTATUS
1691 NTAPI
1692 SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
1693 IN PRPC_UNICODE_STRING Name,
1694 IN ACCESS_MASK DesiredAccess,
1695 OUT SAMPR_HANDLE *GroupHandle,
1696 OUT unsigned long *RelativeId)
1697 {
1698 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
1699 SAM_DOMAIN_FIXED_DATA FixedDomainData;
1700 SAM_GROUP_FIXED_DATA FixedGroupData;
1701 PSAM_DB_OBJECT DomainObject;
1702 PSAM_DB_OBJECT GroupObject;
1703 ULONG ulSize;
1704 ULONG ulRid;
1705 WCHAR szRid[9];
1706 NTSTATUS Status;
1707
1708 TRACE("SamrCreateGroupInDomain(%p %p %lx %p %p)\n",
1709 DomainHandle, Name, DesiredAccess, GroupHandle, RelativeId);
1710
1711 /* Map generic access rights */
1712 RtlMapGenericMask(&DesiredAccess,
1713 &GroupMapping);
1714
1715 /* Validate the domain handle */
1716 Status = SampValidateDbObject(DomainHandle,
1717 SamDbDomainObject,
1718 DOMAIN_CREATE_GROUP,
1719 &DomainObject);
1720 if (!NT_SUCCESS(Status))
1721 {
1722 TRACE("failed with status 0x%08lx\n", Status);
1723 return Status;
1724 }
1725
1726 /* Check if the group name already exists in the domain */
1727 Status = SampCheckAccountNameInDomain(DomainObject,
1728 Name->Buffer);
1729 if (!NT_SUCCESS(Status))
1730 {
1731 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
1732 Name->Buffer, Status);
1733 return Status;
1734 }
1735
1736 /* Get the fixed domain attributes */
1737 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
1738 Status = SampGetObjectAttribute(DomainObject,
1739 L"F",
1740 NULL,
1741 (PVOID)&FixedDomainData,
1742 &ulSize);
1743 if (!NT_SUCCESS(Status))
1744 {
1745 TRACE("failed with status 0x%08lx\n", Status);
1746 return Status;
1747 }
1748
1749 /* Increment the NextRid attribute */
1750 ulRid = FixedDomainData.NextRid;
1751 FixedDomainData.NextRid++;
1752
1753 /* Store the fixed domain attributes */
1754 Status = SampSetObjectAttribute(DomainObject,
1755 L"F",
1756 REG_BINARY,
1757 &FixedDomainData,
1758 ulSize);
1759 if (!NT_SUCCESS(Status))
1760 {
1761 TRACE("failed with status 0x%08lx\n", Status);
1762 return Status;
1763 }
1764
1765 TRACE("RID: %lx\n", ulRid);
1766
1767 /* Convert the RID into a string (hex) */
1768 swprintf(szRid, L"%08lX", ulRid);
1769
1770 /* Create the group object */
1771 Status = SampCreateDbObject(DomainObject,
1772 L"Groups",
1773 szRid,
1774 ulRid,
1775 SamDbGroupObject,
1776 DesiredAccess,
1777 &GroupObject);
1778 if (!NT_SUCCESS(Status))
1779 {
1780 TRACE("failed with status 0x%08lx\n", Status);
1781 return Status;
1782 }
1783
1784 /* Add the account name of the user object */
1785 Status = SampSetAccountNameInDomain(DomainObject,
1786 L"Groups",
1787 Name->Buffer,
1788 ulRid);
1789 if (!NT_SUCCESS(Status))
1790 {
1791 TRACE("failed with status 0x%08lx\n", Status);
1792 return Status;
1793 }
1794
1795 /* Initialize fixed user data */
1796 memset(&FixedGroupData, 0, sizeof(SAM_GROUP_FIXED_DATA));
1797 FixedGroupData.Version = 1;
1798
1799 FixedGroupData.GroupId = ulRid;
1800
1801 /* Set fixed user data attribute */
1802 Status = SampSetObjectAttribute(GroupObject,
1803 L"F",
1804 REG_BINARY,
1805 (LPVOID)&FixedGroupData,
1806 sizeof(SAM_GROUP_FIXED_DATA));
1807 if (!NT_SUCCESS(Status))
1808 {
1809 TRACE("failed with status 0x%08lx\n", Status);
1810 return Status;
1811 }
1812
1813 /* Set the Name attribute */
1814 Status = SampSetObjectAttribute(GroupObject,
1815 L"Name",
1816 REG_SZ,
1817 (LPVOID)Name->Buffer,
1818 Name->MaximumLength);
1819 if (!NT_SUCCESS(Status))
1820 {
1821 TRACE("failed with status 0x%08lx\n", Status);
1822 return Status;
1823 }
1824
1825 /* Set the AdminComment attribute */
1826 Status = SampSetObjectAttribute(GroupObject,
1827 L"AdminComment",
1828 REG_SZ,
1829 EmptyString.Buffer,
1830 EmptyString.MaximumLength);
1831 if (!NT_SUCCESS(Status))
1832 {
1833 TRACE("failed with status 0x%08lx\n", Status);
1834 return Status;
1835 }
1836
1837 if (NT_SUCCESS(Status))
1838 {
1839 *GroupHandle = (SAMPR_HANDLE)GroupObject;
1840 *RelativeId = ulRid;
1841 }
1842
1843 TRACE("returns with status 0x%08lx\n", Status);
1844
1845 return Status;
1846 }
1847
1848
1849 /* Function 11 */
1850 NTSTATUS
1851 NTAPI
1852 SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
1853 IN OUT unsigned long *EnumerationContext,
1854 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
1855 IN unsigned long PreferedMaximumLength,
1856 OUT unsigned long *CountReturned)
1857 {
1858 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
1859 PSAM_DB_OBJECT DomainObject;
1860 HANDLE GroupsKeyHandle = NULL;
1861 HANDLE NamesKeyHandle = NULL;
1862 WCHAR GroupName[64];
1863 ULONG EnumIndex;
1864 ULONG EnumCount = 0;
1865 ULONG RequiredLength = 0;
1866 ULONG NameLength;
1867 ULONG DataLength;
1868 ULONG Rid;
1869 ULONG i;
1870 BOOLEAN MoreEntries = FALSE;
1871 NTSTATUS Status;
1872
1873 TRACE("SamrEnumerateUsersInDomain(%p %p %p %lu %p)\n",
1874 DomainHandle, EnumerationContext, Buffer,
1875 PreferedMaximumLength, CountReturned);
1876
1877 /* Validate the domain handle */
1878 Status = SampValidateDbObject(DomainHandle,
1879 SamDbDomainObject,
1880 DOMAIN_LIST_ACCOUNTS,
1881 &DomainObject);
1882 if (!NT_SUCCESS(Status))
1883 return Status;
1884
1885 Status = SampRegOpenKey(DomainObject->KeyHandle,
1886 L"Groups",
1887 KEY_READ,
1888 &GroupsKeyHandle);
1889 if (!NT_SUCCESS(Status))
1890 return Status;
1891
1892 Status = SampRegOpenKey(GroupsKeyHandle,
1893 L"Names",
1894 KEY_READ,
1895 &NamesKeyHandle);
1896 if (!NT_SUCCESS(Status))
1897 goto done;
1898
1899 TRACE("Part 1\n");
1900
1901 EnumIndex = *EnumerationContext;
1902
1903 while (TRUE)
1904 {
1905 NameLength = 64 * sizeof(WCHAR);
1906 Status = SampRegEnumerateValue(NamesKeyHandle,
1907 EnumIndex,
1908 GroupName,
1909 &NameLength,
1910 NULL,
1911 NULL,
1912 NULL);
1913 if (!NT_SUCCESS(Status))
1914 {
1915 if (Status == STATUS_NO_MORE_ENTRIES)
1916 Status = STATUS_SUCCESS;
1917 break;
1918 }
1919
1920 TRACE("EnumIndex: %lu\n", EnumIndex);
1921 TRACE("Group name: %S\n", GroupName);
1922 TRACE("Name length: %lu\n", NameLength);
1923
1924 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
1925 {
1926 MoreEntries = TRUE;
1927 break;
1928 }
1929
1930 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
1931 EnumCount++;
1932
1933 EnumIndex++;
1934 }
1935
1936 TRACE("EnumCount: %lu\n", EnumCount);
1937 TRACE("RequiredLength: %lu\n", RequiredLength);
1938
1939 if (!NT_SUCCESS(Status))
1940 goto done;
1941
1942 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
1943 if (EnumBuffer == NULL)
1944 {
1945 Status = STATUS_INSUFFICIENT_RESOURCES;
1946 goto done;
1947 }
1948
1949 EnumBuffer->EntriesRead = EnumCount;
1950 if (EnumCount == 0)
1951 goto done;
1952
1953 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
1954 if (EnumBuffer->Buffer == NULL)
1955 {
1956 Status = STATUS_INSUFFICIENT_RESOURCES;
1957 goto done;
1958 }
1959
1960 TRACE("Part 2\n");
1961
1962 EnumIndex = *EnumerationContext;
1963 for (i = 0; i < EnumCount; i++, EnumIndex++)
1964 {
1965 NameLength = 64 * sizeof(WCHAR);
1966 DataLength = sizeof(ULONG);
1967 Status = SampRegEnumerateValue(NamesKeyHandle,
1968 EnumIndex,
1969 GroupName,
1970 &NameLength,
1971 NULL,
1972 &Rid,
1973 &DataLength);
1974 if (!NT_SUCCESS(Status))
1975 {
1976 if (Status == STATUS_NO_MORE_ENTRIES)
1977 Status = STATUS_SUCCESS;
1978 break;
1979 }
1980
1981 TRACE("EnumIndex: %lu\n", EnumIndex);
1982 TRACE("Group name: %S\n", GroupName);
1983 TRACE("Name length: %lu\n", NameLength);
1984 TRACE("RID: %lu\n", Rid);
1985
1986 EnumBuffer->Buffer[i].RelativeId = Rid;
1987
1988 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
1989 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
1990
1991 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
1992 #if 0
1993 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
1994 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
1995 {
1996 Status = STATUS_INSUFFICIENT_RESOURCES;
1997 goto done;
1998 }
1999
2000 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2001 GroupName,
2002 EnumBuffer->Buffer[i].Name.Length);
2003 #endif
2004 }
2005
2006 done:
2007 if (NT_SUCCESS(Status))
2008 {
2009 *EnumerationContext += EnumCount;
2010 *Buffer = EnumBuffer;
2011 *CountReturned = EnumCount;
2012 }
2013 else
2014 {
2015 *EnumerationContext = 0;
2016 *Buffer = NULL;
2017 *CountReturned = 0;
2018
2019 if (EnumBuffer != NULL)
2020 {
2021 if (EnumBuffer->Buffer != NULL)
2022 {
2023 if (EnumBuffer->EntriesRead != 0)
2024 {
2025 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2026 {
2027 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2028 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2029 }
2030 }
2031
2032 midl_user_free(EnumBuffer->Buffer);
2033 }
2034
2035 midl_user_free(EnumBuffer);
2036 }
2037 }
2038
2039 if (NamesKeyHandle != NULL)
2040 SampRegCloseKey(NamesKeyHandle);
2041
2042 if (GroupsKeyHandle != NULL)
2043 SampRegCloseKey(GroupsKeyHandle);
2044
2045 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2046 Status = STATUS_MORE_ENTRIES;
2047
2048 return Status;
2049 }
2050
2051
2052 /* Function 12 */
2053 NTSTATUS
2054 NTAPI
2055 SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
2056 IN PRPC_UNICODE_STRING Name,
2057 IN ACCESS_MASK DesiredAccess,
2058 OUT SAMPR_HANDLE *UserHandle,
2059 OUT unsigned long *RelativeId)
2060 {
2061 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2062 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2063 SAM_USER_FIXED_DATA FixedUserData;
2064 PSAM_DB_OBJECT DomainObject;
2065 PSAM_DB_OBJECT UserObject;
2066 ULONG ulSize;
2067 ULONG ulRid;
2068 WCHAR szRid[9];
2069 NTSTATUS Status;
2070
2071 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
2072 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
2073
2074 if (Name == NULL ||
2075 Name->Length == 0 ||
2076 Name->Buffer == NULL ||
2077 UserHandle == NULL ||
2078 RelativeId == NULL)
2079 return STATUS_INVALID_PARAMETER;
2080
2081 /* Map generic access rights */
2082 RtlMapGenericMask(&DesiredAccess,
2083 &UserMapping);
2084
2085 /* Validate the domain handle */
2086 Status = SampValidateDbObject(DomainHandle,
2087 SamDbDomainObject,
2088 DOMAIN_CREATE_USER,
2089 &DomainObject);
2090 if (!NT_SUCCESS(Status))
2091 {
2092 TRACE("failed with status 0x%08lx\n", Status);
2093 return Status;
2094 }
2095
2096 /* Check if the user name already exists in the domain */
2097 Status = SampCheckAccountNameInDomain(DomainObject,
2098 Name->Buffer);
2099 if (!NT_SUCCESS(Status))
2100 {
2101 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
2102 Name->Buffer, Status);
2103 return Status;
2104 }
2105
2106 /* Get the fixed domain attributes */
2107 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2108 Status = SampGetObjectAttribute(DomainObject,
2109 L"F",
2110 NULL,
2111 (PVOID)&FixedDomainData,
2112 &ulSize);
2113 if (!NT_SUCCESS(Status))
2114 {
2115 TRACE("failed with status 0x%08lx\n", Status);
2116 return Status;
2117 }
2118
2119 /* Increment the NextRid attribute */
2120 ulRid = FixedDomainData.NextRid;
2121 FixedDomainData.NextRid++;
2122
2123 /* Store the fixed domain attributes */
2124 Status = SampSetObjectAttribute(DomainObject,
2125 L"F",
2126 REG_BINARY,
2127 &FixedDomainData,
2128 ulSize);
2129 if (!NT_SUCCESS(Status))
2130 {
2131 TRACE("failed with status 0x%08lx\n", Status);
2132 return Status;
2133 }
2134
2135 TRACE("RID: %lx\n", ulRid);
2136
2137 /* Convert the RID into a string (hex) */
2138 swprintf(szRid, L"%08lX", ulRid);
2139
2140 /* Create the user object */
2141 Status = SampCreateDbObject(DomainObject,
2142 L"Users",
2143 szRid,
2144 ulRid,
2145 SamDbUserObject,
2146 DesiredAccess,
2147 &UserObject);
2148 if (!NT_SUCCESS(Status))
2149 {
2150 TRACE("failed with status 0x%08lx\n", Status);
2151 return Status;
2152 }
2153
2154 /* Add the account name for the user object */
2155 Status = SampSetAccountNameInDomain(DomainObject,
2156 L"Users",
2157 Name->Buffer,
2158 ulRid);
2159 if (!NT_SUCCESS(Status))
2160 {
2161 TRACE("failed with status 0x%08lx\n", Status);
2162 return Status;
2163 }
2164
2165 /* Initialize fixed user data */
2166 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
2167 FixedUserData.Version = 1;
2168 FixedUserData.LastLogon.QuadPart = 0;
2169 FixedUserData.LastLogoff.QuadPart = 0;
2170 FixedUserData.PasswordLastSet.QuadPart = 0;
2171 FixedUserData.AccountExpires.LowPart = MAXULONG;
2172 FixedUserData.AccountExpires.HighPart = MAXLONG;
2173 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2174 FixedUserData.UserId = ulRid;
2175 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2176 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2177 USER_PASSWORD_NOT_REQUIRED |
2178 USER_NORMAL_ACCOUNT;
2179
2180 /* Set fixed user data attribute */
2181 Status = SampSetObjectAttribute(UserObject,
2182 L"F",
2183 REG_BINARY,
2184 (LPVOID)&FixedUserData,
2185 sizeof(SAM_USER_FIXED_DATA));
2186 if (!NT_SUCCESS(Status))
2187 {
2188 TRACE("failed with status 0x%08lx\n", Status);
2189 return Status;
2190 }
2191
2192 /* Set the Name attribute */
2193 Status = SampSetObjectAttribute(UserObject,
2194 L"Name",
2195 REG_SZ,
2196 (LPVOID)Name->Buffer,
2197 Name->MaximumLength);
2198 if (!NT_SUCCESS(Status))
2199 {
2200 TRACE("failed with status 0x%08lx\n", Status);
2201 return Status;
2202 }
2203
2204 /* Set the FullName attribute */
2205 Status = SampSetObjectAttribute(UserObject,
2206 L"FullName",
2207 REG_SZ,
2208 EmptyString.Buffer,
2209 EmptyString.MaximumLength);
2210 if (!NT_SUCCESS(Status))
2211 {
2212 TRACE("failed with status 0x%08lx\n", Status);
2213 return Status;
2214 }
2215
2216 /* Set the HomeDirectory attribute */
2217 Status = SampSetObjectAttribute(UserObject,
2218 L"HomeDirectory",
2219 REG_SZ,
2220 EmptyString.Buffer,
2221 EmptyString.MaximumLength);
2222 if (!NT_SUCCESS(Status))
2223 {
2224 TRACE("failed with status 0x%08lx\n", Status);
2225 return Status;
2226 }
2227
2228 /* Set the HomeDirectoryDrive attribute */
2229 Status = SampSetObjectAttribute(UserObject,
2230 L"HomeDirectoryDrive",
2231 REG_SZ,
2232 EmptyString.Buffer,
2233 EmptyString.MaximumLength);
2234 if (!NT_SUCCESS(Status))
2235 {
2236 TRACE("failed with status 0x%08lx\n", Status);
2237 return Status;
2238 }
2239
2240 /* Set the ScriptPath attribute */
2241 Status = SampSetObjectAttribute(UserObject,
2242 L"ScriptPath",
2243 REG_SZ,
2244 EmptyString.Buffer,
2245 EmptyString.MaximumLength);
2246 if (!NT_SUCCESS(Status))
2247 {
2248 TRACE("failed with status 0x%08lx\n", Status);
2249 return Status;
2250 }
2251
2252 /* Set the ProfilePath attribute */
2253 Status = SampSetObjectAttribute(UserObject,
2254 L"ProfilePath",
2255 REG_SZ,
2256 EmptyString.Buffer,
2257 EmptyString.MaximumLength);
2258 if (!NT_SUCCESS(Status))
2259 {
2260 TRACE("failed with status 0x%08lx\n", Status);
2261 return Status;
2262 }
2263
2264 /* Set the AdminComment attribute */
2265 Status = SampSetObjectAttribute(UserObject,
2266 L"AdminComment",
2267 REG_SZ,
2268 EmptyString.Buffer,
2269 EmptyString.MaximumLength);
2270 if (!NT_SUCCESS(Status))
2271 {
2272 TRACE("failed with status 0x%08lx\n", Status);
2273 return Status;
2274 }
2275
2276 /* Set the UserComment attribute */
2277 Status = SampSetObjectAttribute(UserObject,
2278 L"UserComment",
2279 REG_SZ,
2280 EmptyString.Buffer,
2281 EmptyString.MaximumLength);
2282 if (!NT_SUCCESS(Status))
2283 {
2284 TRACE("failed with status 0x%08lx\n", Status);
2285 return Status;
2286 }
2287
2288 /* Set the WorkStations attribute */
2289 Status = SampSetObjectAttribute(UserObject,
2290 L"WorkStations",
2291 REG_SZ,
2292 EmptyString.Buffer,
2293 EmptyString.MaximumLength);
2294 if (!NT_SUCCESS(Status))
2295 {
2296 TRACE("failed with status 0x%08lx\n", Status);
2297 return Status;
2298 }
2299
2300 /* Set the Parameters attribute */
2301 Status = SampSetObjectAttribute(UserObject,
2302 L"Parameters",
2303 REG_SZ,
2304 EmptyString.Buffer,
2305 EmptyString.MaximumLength);
2306 if (!NT_SUCCESS(Status))
2307 {
2308 TRACE("failed with status 0x%08lx\n", Status);
2309 return Status;
2310 }
2311
2312 /* FIXME: Set default user attributes */
2313
2314 if (NT_SUCCESS(Status))
2315 {
2316 *UserHandle = (SAMPR_HANDLE)UserObject;
2317 *RelativeId = ulRid;
2318 }
2319
2320 TRACE("returns with status 0x%08lx\n", Status);
2321
2322 return Status;
2323 }
2324
2325
2326 /* Function 13 */
2327 NTSTATUS
2328 NTAPI
2329 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2330 IN OUT unsigned long *EnumerationContext,
2331 IN unsigned long UserAccountControl,
2332 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2333 IN unsigned long PreferedMaximumLength,
2334 OUT unsigned long *CountReturned)
2335 {
2336 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2337 PSAM_DB_OBJECT DomainObject;
2338 HANDLE UsersKeyHandle = NULL;
2339 HANDLE NamesKeyHandle = NULL;
2340 WCHAR UserName[64];
2341 ULONG EnumIndex;
2342 ULONG EnumCount = 0;
2343 ULONG RequiredLength = 0;
2344 ULONG NameLength;
2345 ULONG DataLength;
2346 ULONG Rid;
2347 ULONG i;
2348 BOOLEAN MoreEntries = FALSE;
2349 NTSTATUS Status;
2350
2351 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2352 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2353 PreferedMaximumLength, CountReturned);
2354
2355 /* Validate the domain handle */
2356 Status = SampValidateDbObject(DomainHandle,
2357 SamDbDomainObject,
2358 DOMAIN_LIST_ACCOUNTS,
2359 &DomainObject);
2360 if (!NT_SUCCESS(Status))
2361 return Status;
2362
2363 Status = SampRegOpenKey(DomainObject->KeyHandle,
2364 L"Users",
2365 KEY_READ,
2366 &UsersKeyHandle);
2367 if (!NT_SUCCESS(Status))
2368 return Status;
2369
2370 Status = SampRegOpenKey(UsersKeyHandle,
2371 L"Names",
2372 KEY_READ,
2373 &NamesKeyHandle);
2374 if (!NT_SUCCESS(Status))
2375 goto done;
2376
2377 TRACE("Part 1\n");
2378
2379 EnumIndex = *EnumerationContext;
2380
2381 while (TRUE)
2382 {
2383 NameLength = 64 * sizeof(WCHAR);
2384 Status = SampRegEnumerateValue(NamesKeyHandle,
2385 EnumIndex,
2386 UserName,
2387 &NameLength,
2388 NULL,
2389 NULL,
2390 NULL);
2391 if (!NT_SUCCESS(Status))
2392 {
2393 if (Status == STATUS_NO_MORE_ENTRIES)
2394 Status = STATUS_SUCCESS;
2395 break;
2396 }
2397
2398 TRACE("EnumIndex: %lu\n", EnumIndex);
2399 TRACE("User name: %S\n", UserName);
2400 TRACE("Name length: %lu\n", NameLength);
2401
2402 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2403 {
2404 MoreEntries = TRUE;
2405 break;
2406 }
2407
2408 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2409 EnumCount++;
2410
2411 EnumIndex++;
2412 }
2413
2414 TRACE("EnumCount: %lu\n", EnumCount);
2415 TRACE("RequiredLength: %lu\n", RequiredLength);
2416
2417 if (!NT_SUCCESS(Status))
2418 goto done;
2419
2420 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2421 if (EnumBuffer == NULL)
2422 {
2423 Status = STATUS_INSUFFICIENT_RESOURCES;
2424 goto done;
2425 }
2426
2427 EnumBuffer->EntriesRead = EnumCount;
2428 if (EnumCount == 0)
2429 goto done;
2430
2431 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2432 if (EnumBuffer->Buffer == NULL)
2433 {
2434 Status = STATUS_INSUFFICIENT_RESOURCES;
2435 goto done;
2436 }
2437
2438 TRACE("Part 2\n");
2439
2440 EnumIndex = *EnumerationContext;
2441 for (i = 0; i < EnumCount; i++, EnumIndex++)
2442 {
2443 NameLength = 64 * sizeof(WCHAR);
2444 DataLength = sizeof(ULONG);
2445 Status = SampRegEnumerateValue(NamesKeyHandle,
2446 EnumIndex,
2447 UserName,
2448 &NameLength,
2449 NULL,
2450 &Rid,
2451 &DataLength);
2452 if (!NT_SUCCESS(Status))
2453 {
2454 if (Status == STATUS_NO_MORE_ENTRIES)
2455 Status = STATUS_SUCCESS;
2456 break;
2457 }
2458
2459 TRACE("EnumIndex: %lu\n", EnumIndex);
2460 TRACE("User name: %S\n", UserName);
2461 TRACE("Name length: %lu\n", NameLength);
2462 TRACE("RID: %lu\n", Rid);
2463
2464 EnumBuffer->Buffer[i].RelativeId = Rid;
2465
2466 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2467 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2468
2469 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2470 #if 0
2471 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2472 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2473 {
2474 Status = STATUS_INSUFFICIENT_RESOURCES;
2475 goto done;
2476 }
2477
2478 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2479 UserName,
2480 EnumBuffer->Buffer[i].Name.Length);
2481 #endif
2482 }
2483
2484 done:
2485 if (NT_SUCCESS(Status))
2486 {
2487 *EnumerationContext += EnumCount;
2488 *Buffer = EnumBuffer;
2489 *CountReturned = EnumCount;
2490 }
2491 else
2492 {
2493 *EnumerationContext = 0;
2494 *Buffer = NULL;
2495 *CountReturned = 0;
2496
2497 if (EnumBuffer != NULL)
2498 {
2499 if (EnumBuffer->Buffer != NULL)
2500 {
2501 if (EnumBuffer->EntriesRead != 0)
2502 {
2503 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2504 {
2505 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2506 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2507 }
2508 }
2509
2510 midl_user_free(EnumBuffer->Buffer);
2511 }
2512
2513 midl_user_free(EnumBuffer);
2514 }
2515 }
2516
2517 if (NamesKeyHandle != NULL)
2518 SampRegCloseKey(NamesKeyHandle);
2519
2520 if (UsersKeyHandle != NULL)
2521 SampRegCloseKey(UsersKeyHandle);
2522
2523 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2524 Status = STATUS_MORE_ENTRIES;
2525
2526 return Status;
2527 }
2528
2529
2530 /* Function 14 */
2531 NTSTATUS
2532 NTAPI
2533 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
2534 IN PRPC_UNICODE_STRING AccountName,
2535 IN ACCESS_MASK DesiredAccess,
2536 OUT SAMPR_HANDLE *AliasHandle,
2537 OUT unsigned long *RelativeId)
2538 {
2539 SAM_DOMAIN_FIXED_DATA FixedDomainData;
2540 PSAM_DB_OBJECT DomainObject;
2541 PSAM_DB_OBJECT AliasObject;
2542 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
2543 ULONG ulSize;
2544 ULONG ulRid;
2545 WCHAR szRid[9];
2546 NTSTATUS Status;
2547
2548 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
2549 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
2550
2551 /* Map generic access rights */
2552 RtlMapGenericMask(&DesiredAccess,
2553 &AliasMapping);
2554
2555 /* Validate the domain handle */
2556 Status = SampValidateDbObject(DomainHandle,
2557 SamDbDomainObject,
2558 DOMAIN_CREATE_ALIAS,
2559 &DomainObject);
2560 if (!NT_SUCCESS(Status))
2561 {
2562 TRACE("failed with status 0x%08lx\n", Status);
2563 return Status;
2564 }
2565
2566 /* Check if the alias name already exists in the domain */
2567 Status = SampCheckAccountNameInDomain(DomainObject,
2568 AccountName->Buffer);
2569 if (!NT_SUCCESS(Status))
2570 {
2571 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
2572 AccountName->Buffer, Status);
2573 return Status;
2574 }
2575
2576 /* Get the fixed domain attributes */
2577 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
2578 Status = SampGetObjectAttribute(DomainObject,
2579 L"F",
2580 NULL,
2581 (PVOID)&FixedDomainData,
2582 &ulSize);
2583 if (!NT_SUCCESS(Status))
2584 {
2585 TRACE("failed with status 0x%08lx\n", Status);
2586 return Status;
2587 }
2588
2589 /* Increment the NextRid attribute */
2590 ulRid = FixedDomainData.NextRid;
2591 FixedDomainData.NextRid++;
2592
2593 /* Store the fixed domain attributes */
2594 Status = SampSetObjectAttribute(DomainObject,
2595 L"F",
2596 REG_BINARY,
2597 &FixedDomainData,
2598 ulSize);
2599 if (!NT_SUCCESS(Status))
2600 {
2601 TRACE("failed with status 0x%08lx\n", Status);
2602 return Status;
2603 }
2604
2605 TRACE("RID: %lx\n", ulRid);
2606
2607 /* Convert the RID into a string (hex) */
2608 swprintf(szRid, L"%08lX", ulRid);
2609
2610 /* Create the alias object */
2611 Status = SampCreateDbObject(DomainObject,
2612 L"Aliases",
2613 szRid,
2614 ulRid,
2615 SamDbAliasObject,
2616 DesiredAccess,
2617 &AliasObject);
2618 if (!NT_SUCCESS(Status))
2619 {
2620 TRACE("failed with status 0x%08lx\n", Status);
2621 return Status;
2622 }
2623
2624 /* Add the account name for the alias object */
2625 Status = SampSetAccountNameInDomain(DomainObject,
2626 L"Aliases",
2627 AccountName->Buffer,
2628 ulRid);
2629 if (!NT_SUCCESS(Status))
2630 {
2631 TRACE("failed with status 0x%08lx\n", Status);
2632 return Status;
2633 }
2634
2635 /* Set the Name attribute */
2636 Status = SampSetObjectAttribute(AliasObject,
2637 L"Name",
2638 REG_SZ,
2639 (LPVOID)AccountName->Buffer,
2640 AccountName->MaximumLength);
2641 if (!NT_SUCCESS(Status))
2642 {
2643 TRACE("failed with status 0x%08lx\n", Status);
2644 return Status;
2645 }
2646
2647 /* Set the Description attribute */
2648 Status = SampSetObjectAttribute(AliasObject,
2649 L"Description",
2650 REG_SZ,
2651 EmptyString.Buffer,
2652 EmptyString.MaximumLength);
2653 if (!NT_SUCCESS(Status))
2654 {
2655 TRACE("failed with status 0x%08lx\n", Status);
2656 return Status;
2657 }
2658
2659 if (NT_SUCCESS(Status))
2660 {
2661 *AliasHandle = (SAMPR_HANDLE)AliasObject;
2662 *RelativeId = ulRid;
2663 }
2664
2665 TRACE("returns with status 0x%08lx\n", Status);
2666
2667 return Status;
2668 }
2669
2670
2671 /* Function 15 */
2672 NTSTATUS
2673 NTAPI
2674 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
2675 IN OUT unsigned long *EnumerationContext,
2676 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2677 IN unsigned long PreferedMaximumLength,
2678 OUT unsigned long *CountReturned)
2679 {
2680 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2681 PSAM_DB_OBJECT DomainObject;
2682 HANDLE AliasesKeyHandle = NULL;
2683 HANDLE NamesKeyHandle = NULL;
2684 WCHAR AliasName[64];
2685 ULONG EnumIndex;
2686 ULONG EnumCount = 0;
2687 ULONG RequiredLength = 0;
2688 ULONG NameLength;
2689 ULONG DataLength;
2690 ULONG Rid;
2691 ULONG i;
2692 BOOLEAN MoreEntries = FALSE;
2693 NTSTATUS Status;
2694
2695 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
2696 DomainHandle, EnumerationContext, Buffer,
2697 PreferedMaximumLength, CountReturned);
2698
2699 /* Validate the domain handle */
2700 Status = SampValidateDbObject(DomainHandle,
2701 SamDbDomainObject,
2702 DOMAIN_LIST_ACCOUNTS,
2703 &DomainObject);
2704 if (!NT_SUCCESS(Status))
2705 return Status;
2706
2707 Status = SampRegOpenKey(DomainObject->KeyHandle,
2708 L"Aliases",
2709 KEY_READ,
2710 &AliasesKeyHandle);
2711 if (!NT_SUCCESS(Status))
2712 return Status;
2713
2714 Status = SampRegOpenKey(AliasesKeyHandle,
2715 L"Names",
2716 KEY_READ,
2717 &NamesKeyHandle);
2718 if (!NT_SUCCESS(Status))
2719 goto done;
2720
2721 TRACE("Part 1\n");
2722
2723 EnumIndex = *EnumerationContext;
2724
2725 while (TRUE)
2726 {
2727 NameLength = 64 * sizeof(WCHAR);
2728 Status = SampRegEnumerateValue(NamesKeyHandle,
2729 EnumIndex,
2730 AliasName,
2731 &NameLength,
2732 NULL,
2733 NULL,
2734 NULL);
2735 if (!NT_SUCCESS(Status))
2736 {
2737 if (Status == STATUS_NO_MORE_ENTRIES)
2738 Status = STATUS_SUCCESS;
2739 break;
2740 }
2741
2742 TRACE("EnumIndex: %lu\n", EnumIndex);
2743 TRACE("Alias name: %S\n", AliasName);
2744 TRACE("Name length: %lu\n", NameLength);
2745
2746 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2747 {
2748 MoreEntries = TRUE;
2749 break;
2750 }
2751
2752 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2753 EnumCount++;
2754
2755 EnumIndex++;
2756 }
2757
2758 TRACE("EnumCount: %lu\n", EnumCount);
2759 TRACE("RequiredLength: %lu\n", RequiredLength);
2760
2761 if (!NT_SUCCESS(Status))
2762 goto done;
2763
2764 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2765 if (EnumBuffer == NULL)
2766 {
2767 Status = STATUS_INSUFFICIENT_RESOURCES;
2768 goto done;
2769 }
2770
2771 EnumBuffer->EntriesRead = EnumCount;
2772 if (EnumCount == 0)
2773 goto done;
2774
2775 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2776 if (EnumBuffer->Buffer == NULL)
2777 {
2778 Status = STATUS_INSUFFICIENT_RESOURCES;
2779 goto done;
2780 }
2781
2782 TRACE("Part 2\n");
2783
2784 EnumIndex = *EnumerationContext;
2785 for (i = 0; i < EnumCount; i++, EnumIndex++)
2786 {
2787 NameLength = 64 * sizeof(WCHAR);
2788 DataLength = sizeof(ULONG);
2789 Status = SampRegEnumerateValue(NamesKeyHandle,
2790 EnumIndex,
2791 AliasName,
2792 &NameLength,
2793 NULL,
2794 &Rid,
2795 &DataLength);
2796 if (!NT_SUCCESS(Status))
2797 {
2798 if (Status == STATUS_NO_MORE_ENTRIES)
2799 Status = STATUS_SUCCESS;
2800 break;
2801 }
2802
2803 TRACE("EnumIndex: %lu\n", EnumIndex);
2804 TRACE("Alias name: %S\n", AliasName);
2805 TRACE("Name length: %lu\n", NameLength);
2806 TRACE("RID: %lu\n", Rid);
2807
2808 EnumBuffer->Buffer[i].RelativeId = Rid;
2809
2810 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2811 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
2812
2813 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2814 #if 0
2815 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2816 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2817 {
2818 Status = STATUS_INSUFFICIENT_RESOURCES;
2819 goto done;
2820 }
2821
2822 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2823 AliasName,
2824 EnumBuffer->Buffer[i].Name.Length);
2825 #endif
2826 }
2827
2828 done:
2829 if (NT_SUCCESS(Status))
2830 {
2831 *EnumerationContext += EnumCount;
2832 *Buffer = EnumBuffer;
2833 *CountReturned = EnumCount;
2834 }
2835 else
2836 {
2837 *EnumerationContext = 0;
2838 *Buffer = NULL;
2839 *CountReturned = 0;
2840
2841 if (EnumBuffer != NULL)
2842 {
2843 if (EnumBuffer->Buffer != NULL)
2844 {
2845 if (EnumBuffer->EntriesRead != 0)
2846 {
2847 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2848 {
2849 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2850 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2851 }
2852 }
2853
2854 midl_user_free(EnumBuffer->Buffer);
2855 }
2856
2857 midl_user_free(EnumBuffer);
2858 }
2859 }
2860
2861 if (NamesKeyHandle != NULL)
2862 SampRegCloseKey(NamesKeyHandle);
2863
2864 if (AliasesKeyHandle != NULL)
2865 SampRegCloseKey(AliasesKeyHandle);
2866
2867 if ((Status == STATUS_SUCCESS) && (MoreEntries == TRUE))
2868 Status = STATUS_MORE_ENTRIES;
2869
2870 return Status;
2871 }
2872
2873
2874 /* Function 16 */
2875 NTSTATUS
2876 NTAPI
2877 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
2878 IN PSAMPR_PSID_ARRAY SidArray,
2879 OUT PSAMPR_ULONG_ARRAY Membership)
2880 {
2881 PSAM_DB_OBJECT DomainObject;
2882 HANDLE AliasesKeyHandle = NULL;
2883 HANDLE MembersKeyHandle = NULL;
2884 HANDLE MemberKeyHandle = NULL;
2885 LPWSTR MemberSidString = NULL;
2886 PULONG RidArray = NULL;
2887 ULONG MaxSidCount = 0;
2888 ULONG ValueCount;
2889 ULONG DataLength;
2890 ULONG i, j;
2891 NTSTATUS Status;
2892 WCHAR NameBuffer[9];
2893
2894 TRACE("SamrGetAliasMembership(%p %p %p)\n",
2895 DomainHandle, SidArray, Membership);
2896
2897 /* Validate the domain handle */
2898 Status = SampValidateDbObject(DomainHandle,
2899 SamDbDomainObject,
2900 DOMAIN_GET_ALIAS_MEMBERSHIP,
2901 &DomainObject);
2902 if (!NT_SUCCESS(Status))
2903 return Status;
2904
2905 Status = SampRegOpenKey(DomainObject->KeyHandle,
2906 L"Aliases",
2907 KEY_READ,
2908 &AliasesKeyHandle);
2909 TRACE("SampRegOpenKey returned %08lX\n", Status);
2910 if (!NT_SUCCESS(Status))
2911 goto done;
2912
2913 Status = SampRegOpenKey(AliasesKeyHandle,
2914 L"Members",
2915 KEY_READ,
2916 &MembersKeyHandle);
2917 TRACE("SampRegOpenKey returned %08lX\n", Status);
2918
2919 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2920 {
2921 Status = STATUS_SUCCESS;
2922 goto done;
2923 }
2924
2925 if (!NT_SUCCESS(Status))
2926 goto done;
2927
2928 for (i = 0; i < SidArray->Count; i++)
2929 {
2930 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
2931 TRACE("Open %S\n", MemberSidString);
2932
2933 Status = SampRegOpenKey(MembersKeyHandle,
2934 MemberSidString,
2935 KEY_READ,
2936 &MemberKeyHandle);
2937 TRACE("SampRegOpenKey returned %08lX\n", Status);
2938 if (NT_SUCCESS(Status))
2939 {
2940 Status = SampRegQueryKeyInfo(MemberKeyHandle,
2941 NULL,
2942 &ValueCount);
2943 if (NT_SUCCESS(Status))
2944 {
2945 TRACE("Found %lu values\n", ValueCount);
2946 MaxSidCount += ValueCount;
2947 }
2948
2949 NtClose(MemberKeyHandle);
2950 }
2951
2952 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2953 Status = STATUS_SUCCESS;
2954
2955 LocalFree(MemberSidString);
2956 }
2957
2958 if (MaxSidCount == 0)
2959 {
2960 Status = STATUS_SUCCESS;
2961 goto done;
2962 }
2963
2964 TRACE("Maximum sid count: %lu\n", MaxSidCount);
2965 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
2966 if (RidArray == NULL)
2967 {
2968 Status = STATUS_INSUFFICIENT_RESOURCES;
2969 goto done;
2970 }
2971
2972 for (i = 0; i < SidArray->Count; i++)
2973 {
2974 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
2975 TRACE("Open %S\n", MemberSidString);
2976
2977 Status = SampRegOpenKey(MembersKeyHandle,
2978 MemberSidString,
2979 KEY_READ,
2980 &MemberKeyHandle);
2981 TRACE("SampRegOpenKey returned %08lX\n", Status);
2982 if (NT_SUCCESS(Status))
2983 {
2984 Status = SampRegQueryKeyInfo(MemberKeyHandle,
2985 NULL,
2986 &ValueCount);
2987 if (NT_SUCCESS(Status))
2988 {
2989 TRACE("Found %lu values\n", ValueCount);
2990
2991 for (j = 0; j < ValueCount; j++)
2992 {
2993 DataLength = 9 * sizeof(WCHAR);
2994 Status = SampRegEnumerateValue(MemberKeyHandle,
2995 j,
2996 NameBuffer,
2997 &DataLength,
2998 NULL,
2999 NULL,
3000 NULL);
3001 if (NT_SUCCESS(Status))
3002 {
3003 RidArray[j] = wcstoul(NameBuffer, NULL, 16);
3004 }
3005 }
3006 }
3007
3008 NtClose(MemberKeyHandle);
3009 }
3010
3011 LocalFree(MemberSidString);
3012 }
3013
3014 done:
3015 if (NT_SUCCESS(Status))
3016 {
3017 Membership->Count = MaxSidCount;
3018 Membership->Element = RidArray;
3019 }
3020 else
3021 {
3022 if (RidArray != NULL)
3023 midl_user_free(RidArray);
3024 }
3025
3026 if (MembersKeyHandle != NULL)
3027 NtClose(MembersKeyHandle);
3028
3029 if (MembersKeyHandle != NULL)
3030 NtClose(MembersKeyHandle);
3031
3032 if (AliasesKeyHandle != NULL)
3033 NtClose(AliasesKeyHandle);
3034
3035 return Status;
3036 }
3037
3038
3039 /* Function 17 */
3040 NTSTATUS
3041 NTAPI
3042 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3043 IN ULONG Count,
3044 IN RPC_UNICODE_STRING Names[],
3045 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3046 OUT PSAMPR_ULONG_ARRAY Use)
3047 {
3048 PSAM_DB_OBJECT DomainObject;
3049 HANDLE AccountsKeyHandle;
3050 HANDLE NamesKeyHandle;
3051 ULONG MappedCount = 0;
3052 ULONG DataLength;
3053 ULONG i;
3054 ULONG RelativeId;
3055 NTSTATUS Status;
3056
3057 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3058 DomainHandle, Count, Names, RelativeIds, Use);
3059
3060 /* Validate the domain handle */
3061 Status = SampValidateDbObject(DomainHandle,
3062 SamDbDomainObject,
3063 DOMAIN_LOOKUP,
3064 &DomainObject);
3065 if (!NT_SUCCESS(Status))
3066 {
3067 TRACE("failed with status 0x%08lx\n", Status);
3068 return Status;
3069 }
3070
3071 RelativeIds->Count = 0;
3072 Use->Count = 0;
3073
3074 if (Count == 0)
3075 return STATUS_SUCCESS;
3076
3077 /* Allocate the relative IDs array */
3078 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3079 if (RelativeIds->Element == NULL)
3080 {
3081 Status = STATUS_INSUFFICIENT_RESOURCES;
3082 goto done;
3083 }
3084
3085 /* Allocate the use array */
3086 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3087 if (Use->Element == NULL)
3088 {
3089 Status = STATUS_INSUFFICIENT_RESOURCES;
3090 goto done;
3091 }
3092
3093 RelativeIds->Count = Count;
3094 Use->Count = Count;
3095
3096 for (i = 0; i < Count; i++)
3097 {
3098 TRACE("Name: %S\n", Names[i].Buffer);
3099
3100 RelativeId = 0;
3101
3102 /* Lookup aliases */
3103 Status = SampRegOpenKey(DomainObject->KeyHandle,
3104 L"Aliases",
3105 KEY_READ,
3106 &AccountsKeyHandle);
3107 if (NT_SUCCESS(Status))
3108 {
3109 Status = SampRegOpenKey(AccountsKeyHandle,
3110 L"Names",
3111 KEY_READ,
3112 &NamesKeyHandle);
3113 if (NT_SUCCESS(Status))
3114 {
3115 DataLength = sizeof(ULONG);
3116 Status = SampRegQueryValue(NamesKeyHandle,
3117 Names[i].Buffer,
3118 NULL,
3119 &RelativeId,
3120 &DataLength);
3121
3122 SampRegCloseKey(NamesKeyHandle);
3123 }
3124
3125 SampRegCloseKey(AccountsKeyHandle);
3126 }
3127
3128 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3129 break;
3130
3131 /* Return alias account */
3132 if (NT_SUCCESS(Status) && RelativeId != 0)
3133 {
3134 TRACE("Rid: %lu\n", RelativeId);
3135 RelativeIds->Element[i] = RelativeId;
3136 Use->Element[i] = SidTypeAlias;
3137 MappedCount++;
3138 continue;
3139 }
3140
3141 /* Lookup groups */
3142 Status = SampRegOpenKey(DomainObject->KeyHandle,
3143 L"Groups",
3144 KEY_READ,
3145 &AccountsKeyHandle);
3146 if (NT_SUCCESS(Status))
3147 {
3148 Status = SampRegOpenKey(AccountsKeyHandle,
3149 L"Names",
3150 KEY_READ,
3151 &NamesKeyHandle);
3152 if (NT_SUCCESS(Status))
3153 {
3154 DataLength = sizeof(ULONG);
3155 Status = SampRegQueryValue(NamesKeyHandle,
3156 Names[i].Buffer,
3157 NULL,
3158 &RelativeId,
3159 &DataLength);
3160
3161 SampRegCloseKey(NamesKeyHandle);
3162 }
3163
3164 SampRegCloseKey(AccountsKeyHandle);
3165 }
3166
3167 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3168 break;
3169
3170 /* Return group account */
3171 if (NT_SUCCESS(Status) && RelativeId != 0)
3172 {
3173 TRACE("Rid: %lu\n", RelativeId);
3174 RelativeIds->Element[i] = RelativeId;
3175 Use->Element[i] = SidTypeGroup;
3176 MappedCount++;
3177 continue;
3178 }
3179
3180 /* Lookup users */
3181 Status = SampRegOpenKey(DomainObject->KeyHandle,
3182 L"Users",
3183 KEY_READ,
3184 &AccountsKeyHandle);
3185 if (NT_SUCCESS(Status))
3186 {
3187 Status = SampRegOpenKey(AccountsKeyHandle,
3188 L"Names",
3189 KEY_READ,
3190 &NamesKeyHandle);
3191 if (NT_SUCCESS(Status))
3192 {
3193 DataLength = sizeof(ULONG);
3194 Status = SampRegQueryValue(NamesKeyHandle,
3195 Names[i].Buffer,
3196 NULL,
3197 &RelativeId,
3198 &DataLength);
3199
3200 SampRegCloseKey(NamesKeyHandle);
3201 }
3202
3203 SampRegCloseKey(AccountsKeyHandle);
3204 }
3205
3206 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3207 break;
3208
3209 /* Return user account */
3210 if (NT_SUCCESS(Status) && RelativeId != 0)
3211 {
3212 TRACE("Rid: %lu\n", RelativeId);
3213 RelativeIds->Element[i] = RelativeId;
3214 Use->Element[i] = SidTypeUser;
3215 MappedCount++;
3216 continue;
3217 }
3218
3219 /* Return unknown account */
3220 RelativeIds->Element[i] = 0;
3221 Use->Element[i] = SidTypeUnknown;
3222 }
3223
3224 done:
3225 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3226 Status = STATUS_SUCCESS;
3227
3228 if (NT_SUCCESS(Status))
3229 {
3230 if (MappedCount == 0)
3231 Status = STATUS_NONE_MAPPED;
3232 else if (MappedCount < Count)
3233 Status = STATUS_SOME_NOT_MAPPED;
3234 }
3235 else
3236 {
3237 if (RelativeIds->Element != NULL)
3238 {
3239 midl_user_free(RelativeIds->Element);
3240 RelativeIds->Element = NULL;
3241 }
3242
3243 RelativeIds->Count = 0;
3244
3245 if (Use->Element != NULL)
3246 {
3247 midl_user_free(Use->Element);
3248 Use->Element = NULL;
3249 }
3250
3251 Use->Count = 0;
3252 }
3253
3254 TRACE("Returned Status %lx\n", Status);
3255
3256 return Status;
3257 }
3258
3259
3260 /* Function 18 */
3261 NTSTATUS
3262 NTAPI
3263 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3264 IN ULONG Count,
3265 IN ULONG *RelativeIds,
3266 OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3267 OUT PSAMPR_ULONG_ARRAY Use)
3268 {
3269 PSAM_DB_OBJECT DomainObject;
3270 WCHAR RidString[9];
3271 HANDLE AccountsKeyHandle;
3272 HANDLE AccountKeyHandle;
3273 ULONG MappedCount = 0;
3274 ULONG DataLength;
3275 ULONG i;
3276 NTSTATUS Status;
3277
3278 TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3279 DomainHandle, Count, RelativeIds, Names, Use);
3280
3281 /* Validate the domain handle */
3282 Status = SampValidateDbObject(DomainHandle,
3283 SamDbDomainObject,
3284 DOMAIN_LOOKUP,
3285 &DomainObject);
3286 if (!NT_SUCCESS(Status))
3287 {
3288 TRACE("failed with status 0x%08lx\n", Status);
3289 return Status;
3290 }
3291
3292 Names->Count = 0;
3293 Use->Count = 0;
3294
3295 if (Count == 0)
3296 return STATUS_SUCCESS;
3297
3298 /* Allocate the names array */
3299 Names->Element = midl_user_allocate(Count * sizeof(ULONG));
3300 if (Names->Element == NULL)
3301 {
3302 Status = STATUS_INSUFFICIENT_RESOURCES;
3303 goto done;
3304 }
3305
3306 /* Allocate the use array */
3307 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3308 if (Use->Element == NULL)
3309 {
3310 Status = STATUS_INSUFFICIENT_RESOURCES;
3311 goto done;
3312 }
3313
3314 Names->Count = Count;
3315 Use->Count = Count;
3316
3317 for (i = 0; i < Count; i++)
3318 {
3319 TRACE("RID: %lu\n", RelativeIds[i]);
3320
3321 swprintf(RidString, L"%08lx", RelativeIds[i]);
3322
3323 /* Lookup aliases */
3324 Status = SampRegOpenKey(DomainObject->KeyHandle,
3325 L"Aliases",
3326 KEY_READ,
3327 &AccountsKeyHandle);
3328 if (NT_SUCCESS(Status))
3329 {
3330 Status = SampRegOpenKey(AccountsKeyHandle,
3331 RidString,
3332 KEY_READ,
3333 &AccountKeyHandle);
3334 if (NT_SUCCESS(Status))
3335 {
3336 DataLength = 0;
3337 Status = SampRegQueryValue(AccountKeyHandle,
3338 L"Name",
3339 NULL,
3340 NULL,
3341 &DataLength);
3342 if (NT_SUCCESS(Status))
3343 {
3344 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3345 if (Names->Element[i].Buffer == NULL)
3346 Status = STATUS_INSUFFICIENT_RESOURCES;
3347
3348 if (NT_SUCCESS(Status))
3349 {
3350 Names->Element[i].MaximumLength = (USHORT)DataLength;
3351 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3352
3353 Status = SampRegQueryValue(AccountKeyHandle,
3354 L"Name",
3355 NULL,
3356 Names->Element[i].Buffer,
3357 &DataLength);
3358 }
3359 }
3360
3361 SampRegCloseKey(AccountKeyHandle);
3362 }
3363
3364 SampRegCloseKey(AccountsKeyHandle);
3365 }
3366
3367 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3368 break;
3369
3370 /* Return alias account */
3371 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3372 {
3373 TRACE("Name: %S\n", Names->Element[i].Buffer);
3374 Use->Element[i] = SidTypeAlias;
3375 MappedCount++;
3376 continue;
3377 }
3378
3379 /* Lookup groups */
3380 Status = SampRegOpenKey(DomainObject->KeyHandle,
3381 L"Groups",
3382 KEY_READ,
3383 &AccountsKeyHandle);
3384 if (NT_SUCCESS(Status))
3385 {
3386 Status = SampRegOpenKey(AccountsKeyHandle,
3387 RidString,
3388 KEY_READ,
3389 &AccountKeyHandle);
3390 if (NT_SUCCESS(Status))
3391 {
3392 DataLength = 0;
3393 Status = SampRegQueryValue(AccountKeyHandle,
3394 L"Name",
3395 NULL,
3396 NULL,
3397 &DataLength);
3398 if (NT_SUCCESS(Status))
3399 {
3400 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3401 if (Names->Element[i].Buffer == NULL)
3402 Status = STATUS_INSUFFICIENT_RESOURCES;
3403
3404 if (NT_SUCCESS(Status))
3405 {
3406 Names->Element[i].MaximumLength = (USHORT)DataLength;
3407 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3408
3409 Status = SampRegQueryValue(AccountKeyHandle,
3410 L"Name",
3411 NULL,
3412 Names->Element[i].Buffer,
3413 &DataLength);
3414 }
3415 }
3416
3417 SampRegCloseKey(AccountKeyHandle);
3418 }
3419
3420 SampRegCloseKey(AccountsKeyHandle);
3421 }
3422
3423 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3424 break;
3425
3426 /* Return group account */
3427 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3428 {
3429 TRACE("Name: %S\n", Names->Element[i].Buffer);
3430 Use->Element[i] = SidTypeGroup;
3431 MappedCount++;
3432 continue;
3433 }
3434
3435 /* Lookup users */
3436 Status = SampRegOpenKey(DomainObject->KeyHandle,
3437 L"Users",
3438 KEY_READ,
3439 &AccountsKeyHandle);
3440 if (NT_SUCCESS(Status))
3441 {
3442 Status = SampRegOpenKey(AccountsKeyHandle,
3443 RidString,
3444 KEY_READ,
3445 &AccountKeyHandle);
3446 if (NT_SUCCESS(Status))
3447 {
3448 DataLength = 0;
3449 Status = SampRegQueryValue(AccountKeyHandle,
3450 L"Name",
3451 NULL,
3452 NULL,
3453 &DataLength);
3454 if (NT_SUCCESS(Status))
3455 {
3456 TRACE("DataLength: %lu\n", DataLength);
3457
3458 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3459 if (Names->Element[i].Buffer == NULL)
3460 Status = STATUS_INSUFFICIENT_RESOURCES;
3461
3462 if (NT_SUCCESS(Status))
3463 {
3464 Names->Element[i].MaximumLength = (USHORT)DataLength;
3465 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3466
3467 Status = SampRegQueryValue(AccountKeyHandle,
3468 L"Name",
3469 NULL,
3470 Names->Element[i].Buffer,
3471 &DataLength);
3472 }
3473 }
3474
3475 SampRegCloseKey(AccountKeyHandle);
3476 }
3477
3478 SampRegCloseKey(AccountsKeyHandle);
3479 }
3480
3481 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3482 break;
3483
3484 /* Return user account */
3485 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3486 {
3487 TRACE("Name: %S\n", Names->Element[i].Buffer);
3488 Use->Element[i] = SidTypeUser;
3489 MappedCount++;
3490 continue;
3491 }
3492
3493 /* Return unknown account */
3494 Use->Element[i] = SidTypeUnknown;
3495 }
3496
3497 done:
3498 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3499 Status = STATUS_SUCCESS;
3500
3501 if (NT_SUCCESS(Status))
3502 {
3503 if (MappedCount == 0)
3504 Status = STATUS_NONE_MAPPED;
3505 else if (MappedCount < Count)
3506 Status = STATUS_SOME_NOT_MAPPED;
3507 }
3508 else
3509 {
3510 if (Names->Element != NULL)
3511 {
3512 for (i = 0; i < Count; i++)
3513 {
3514 if (Names->Element[i].Buffer != NULL)
3515 midl_user_free(Names->Element[i].Buffer);
3516 }
3517
3518 midl_user_free(Names->Element);
3519 Names->Element = NULL;
3520 }
3521
3522 Names->Count = 0;
3523
3524 if (Use->Element != NULL)
3525 {
3526 midl_user_free(Use->Element);
3527 Use->Element = NULL;
3528 }
3529
3530 Use->Count = 0;
3531 }
3532
3533 return Status;
3534 }
3535
3536
3537 /* Function 19 */
3538 NTSTATUS
3539 NTAPI
3540 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
3541 IN ACCESS_MASK DesiredAccess,
3542 IN unsigned long GroupId,
3543 OUT SAMPR_HANDLE *GroupHandle)
3544 {
3545 PSAM_DB_OBJECT DomainObject;
3546 PSAM_DB_OBJECT GroupObject;
3547 WCHAR szRid[9];
3548 NTSTATUS Status;
3549
3550 TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
3551 DomainHandle, DesiredAccess, GroupId, GroupHandle);
3552
3553 /* Map generic access rights */
3554 RtlMapGenericMask(&DesiredAccess,
3555 &GroupMapping);
3556
3557 /* Validate the domain handle */
3558 Status = SampValidateDbObject(DomainHandle,
3559 SamDbDomainObject,
3560 DOMAIN_LOOKUP,
3561 &DomainObject);
3562 if (!NT_SUCCESS(Status))
3563 {
3564 TRACE("failed with status 0x%08lx\n", Status);
3565 return Status;
3566 }
3567
3568 /* Convert the RID into a string (hex) */
3569 swprintf(szRid, L"%08lX", GroupId);
3570
3571 /* Create the group object */
3572 Status = SampOpenDbObject(DomainObject,
3573 L"Groups",
3574 szRid,
3575 GroupId,
3576 SamDbGroupObject,
3577 DesiredAccess,
3578 &GroupObject);
3579 if (!NT_SUCCESS(Status))
3580 {
3581 TRACE("failed with status 0x%08lx\n", Status);
3582 return Status;
3583 }
3584
3585 *GroupHandle = (SAMPR_HANDLE)GroupObject;
3586
3587 return STATUS_SUCCESS;
3588 }
3589
3590
3591 static NTSTATUS
3592 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
3593 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3594 {
3595 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3596 SAM_GROUP_FIXED_DATA FixedData;
3597 ULONG MembersLength = 0;
3598 ULONG Length = 0;
3599 NTSTATUS Status;
3600
3601 *Buffer = NULL;
3602
3603 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3604 if (InfoBuffer == NULL)
3605 return STATUS_INSUFFICIENT_RESOURCES;
3606
3607 Status = SampGetObjectAttributeString(GroupObject,
3608 L"Name",
3609 &InfoBuffer->General.Name);
3610 if (!NT_SUCCESS(Status))
3611 {
3612 TRACE("Status 0x%08lx\n", Status);
3613 goto done;
3614 }
3615
3616 Status = SampGetObjectAttributeString(GroupObject,
3617 L"Description",
3618 &InfoBuffer->General.AdminComment);
3619 if (!NT_SUCCESS(Status))
3620 {
3621 TRACE("Status 0x%08lx\n", Status);
3622 goto done;
3623 }
3624
3625 Length = sizeof(SAM_GROUP_FIXED_DATA);
3626 Status = SampGetObjectAttribute(GroupObject,
3627 L"F",
3628 NULL,
3629 (PVOID)&FixedData,
3630 &Length);
3631 if (!NT_SUCCESS(Status))
3632 goto done;
3633
3634 InfoBuffer->General.Attributes = FixedData.Attributes;
3635
3636 Status = SampGetObjectAttribute(GroupObject,
3637 L"Members",
3638 NULL,
3639 NULL,
3640 &MembersLength);
3641 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3642 goto done;
3643
3644 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3645 InfoBuffer->General.MemberCount = 0;
3646 else
3647 InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
3648
3649 *Buffer = InfoBuffer;
3650
3651 done:
3652 if (!NT_SUCCESS(Status))
3653 {
3654 if (InfoBuffer != NULL)
3655 {
3656 if (InfoBuffer->General.Name.Buffer != NULL)
3657 midl_user_free(InfoBuffer->General.Name.Buffer);
3658
3659 if (InfoBuffer->General.AdminComment.Buffer != NULL)
3660 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
3661
3662 midl_user_free(InfoBuffer);
3663 }
3664 }
3665
3666 return Status;
3667 }
3668
3669
3670 static NTSTATUS
3671 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
3672 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3673 {
3674 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3675 NTSTATUS Status;
3676
3677 *Buffer = NULL;
3678
3679 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3680 if (InfoBuffer == NULL)
3681 return STATUS_INSUFFICIENT_RESOURCES;
3682
3683 Status = SampGetObjectAttributeString(GroupObject,
3684 L"Name",
3685 &InfoBuffer->Name.Name);
3686 if (!NT_SUCCESS(Status))
3687 {
3688 TRACE("Status 0x%08lx\n", Status);
3689 goto done;
3690 }
3691
3692 *Buffer = InfoBuffer;
3693
3694 done:
3695 if (!NT_SUCCESS(Status))
3696 {
3697 if (InfoBuffer != NULL)
3698 {
3699 if (InfoBuffer->Name.Name.Buffer != NULL)
3700 midl_user_free(InfoBuffer->Name.Name.Buffer);
3701
3702 midl_user_free(InfoBuffer);
3703 }
3704 }
3705
3706 return Status;
3707 }
3708
3709
3710 static NTSTATUS
3711 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
3712 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3713 {
3714 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3715 SAM_GROUP_FIXED_DATA FixedData;
3716 ULONG Length = 0;
3717 NTSTATUS Status;
3718
3719 *Buffer = NULL;
3720
3721 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3722 if (InfoBuffer == NULL)
3723 return STATUS_INSUFFICIENT_RESOURCES;
3724
3725 Length = sizeof(SAM_GROUP_FIXED_DATA);
3726 Status = SampGetObjectAttribute(GroupObject,
3727 L"F",
3728 NULL,
3729 (PVOID)&FixedData,
3730 &Length);
3731 if (!NT_SUCCESS(Status))
3732 goto done;
3733
3734 InfoBuffer->Attribute.Attributes = FixedData.Attributes;
3735
3736 *Buffer = InfoBuffer;
3737
3738 done:
3739 if (!NT_SUCCESS(Status))
3740 {
3741 if (InfoBuffer != NULL)
3742 {
3743 midl_user_free(InfoBuffer);
3744 }
3745 }
3746
3747 return Status;
3748 }
3749
3750
3751 static NTSTATUS
3752 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
3753 PSAMPR_GROUP_INFO_BUFFER *Buffer)
3754 {
3755 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
3756 NTSTATUS Status;
3757
3758 *Buffer = NULL;
3759
3760 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
3761 if (InfoBuffer == NULL)
3762 return STATUS_INSUFFICIENT_RESOURCES;
3763
3764 Status = SampGetObjectAttributeString(GroupObject,
3765 L"Description",
3766 &InfoBuffer->AdminComment.AdminComment);
3767 if (!NT_SUCCESS(Status))
3768 {
3769 TRACE("Status 0x%08lx\n", Status);
3770 goto done;
3771 }
3772
3773 *Buffer = InfoBuffer;
3774
3775 done:
3776 if (!NT_SUCCESS(Status))
3777 {
3778 if (InfoBuffer != NULL)
3779 {
3780 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
3781 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
3782
3783 midl_user_free(InfoBuffer);
3784 }
3785 }
3786
3787 return Status;
3788 }
3789
3790
3791 /* Function 20 */
3792 NTSTATUS
3793 NTAPI
3794 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
3795 IN GROUP_INFORMATION_CLASS GroupInformationClass,
3796 OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
3797 {
3798 PSAM_DB_OBJECT GroupObject;
3799 NTSTATUS Status;
3800
3801 TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
3802 GroupHandle, GroupInformationClass, Buffer);
3803
3804 /* Validate the group handle */
3805 Status = SampValidateDbObject(GroupHandle,
3806 SamDbGroupObject,
3807 GROUP_READ_INFORMATION,
3808 &GroupObject);
3809 if (!NT_SUCCESS(Status))
3810 return Status;
3811
3812 switch (GroupInformationClass)
3813 {
3814 case GroupGeneralInformation:
3815 Status = SampQueryGroupGeneral(GroupObject,
3816 Buffer);
3817 break;
3818
3819 case GroupNameInformation:
3820 Status = SampQueryGroupName(GroupObject,
3821 Buffer);
3822 break;
3823
3824 case GroupAttributeInformation:
3825 Status = SampQueryGroupAttribute(GroupObject,
3826 Buffer);
3827 break;
3828
3829 case GroupAdminCommentInformation:
3830 Status = SampQueryGroupAdminComment(GroupObject,
3831 Buffer);
3832 break;
3833
3834 default:
3835 Status = STATUS_INVALID_INFO_CLASS;
3836 break;
3837 }
3838
3839 return Status;
3840 }
3841
3842
3843 static NTSTATUS
3844 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
3845 PSAMPR_GROUP_INFO_BUFFER Buffer)
3846 {
3847 SAM_GROUP_FIXED_DATA FixedData;
3848 ULONG Length = 0;
3849 NTSTATUS Status;
3850
3851 Length = sizeof(SAM_GROUP_FIXED_DATA);
3852 Status = SampGetObjectAttribute(GroupObject,
3853 L"F",
3854 NULL,
3855 (PVOID)&FixedData,
3856 &Length);
3857 if (!NT_SUCCESS(Status))
3858 goto done;
3859
3860 FixedData.Attributes = Buffer->Attribute.Attributes;
3861
3862 Status = SampSetObjectAttribute(GroupObject,
3863 L"F",
3864 REG_BINARY,
3865 &FixedData,
3866 Length);
3867
3868 done:
3869 return Status;
3870 }
3871
3872
3873 /* Function 21 */
3874 NTSTATUS
3875 NTAPI
3876 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
3877 IN GROUP_INFORMATION_CLASS GroupInformationClass,
3878 IN PSAMPR_GROUP_INFO_BUFFER Buffer)
3879 {
3880 PSAM_DB_OBJECT GroupObject;
3881 NTSTATUS Status;
3882
3883 TRACE("SamrSetInformationGroup(%p %lu %p)\n",
3884 GroupHandle, GroupInformationClass, Buffer);
3885
3886 /* Validate the group handle */
3887 Status = SampValidateDbObject(GroupHandle,
3888 SamDbGroupObject,
3889 GROUP_WRITE_ACCOUNT,
3890 &GroupObject);
3891 if (!NT_SUCCESS(Status))
3892 return Status;
3893
3894 switch (GroupInformationClass)
3895 {
3896 case GroupNameInformation:
3897 Status = SampSetObjectAttribute(GroupObject,
3898 L"Name",
3899 REG_SZ,
3900 Buffer->Name.Name.Buffer,
3901 Buffer->Name.Name.Length + sizeof(WCHAR));
3902 break;
3903
3904 case GroupAttributeInformation:
3905 Status = SampSetGroupAttribute(GroupObject,
3906 Buffer);
3907 break;
3908
3909 case GroupAdminCommentInformation:
3910 Status = SampSetObjectAttribute(GroupObject,
3911 L"Description",
3912 REG_SZ,
3913 Buffer->AdminComment.AdminComment.Buffer,
3914 Buffer->AdminComment.AdminComment.Length + sizeof(WCHAR));
3915 break;
3916
3917 default:
3918 Status = STATUS_INVALID_INFO_CLASS;
3919 break;
3920 }
3921
3922 return Status;
3923 }
3924
3925
3926 /* Function 22 */
3927 NTSTATUS
3928 NTAPI
3929 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
3930 IN unsigned long MemberId,
3931 IN unsigned long Attributes)
3932 {
3933 PSAM_DB_OBJECT GroupObject;
3934 PSAM_DB_OBJECT UserObject = NULL;
3935 NTSTATUS Status;
3936
3937 TRACE("(%p %lu %lx)\n",
3938 GroupHandle, MemberId, Attributes);
3939
3940 /* Validate the group handle */
3941 Status = SampValidateDbObject(GroupHandle,
3942 SamDbGroupObject,
3943 GROUP_ADD_MEMBER,
3944 &GroupObject);
3945 if (!NT_SUCCESS(Status))
3946 return Status;
3947
3948 /* Open the user object in the same domain */
3949 Status = SampOpenUserObject(GroupObject->ParentObject,
3950 MemberId,
3951 0,
3952 &UserObject);
3953 if (!NT_SUCCESS(Status))
3954 {
3955 TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
3956 goto done;
3957 }
3958
3959 /* Add group membership to the user object */
3960 Status = SampAddGroupMembershipToUser(UserObject,
3961 GroupObject->RelativeId,
3962 Attributes);
3963 if (!NT_SUCCESS(Status))
3964 {
3965 TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
3966 goto done;
3967 }
3968
3969 /* Add the member to the group object */
3970 Status = SampAddMemberToGroup(GroupObject,
3971 MemberId);
3972 if (!NT_SUCCESS(Status))
3973 {
3974 TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
3975 }
3976
3977 done:
3978 if (UserObject)
3979 SampCloseDbObject(UserObject);
3980
3981 return Status;
3982 }
3983
3984
3985 /* Function 21 */
3986 NTSTATUS
3987 NTAPI
3988 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
3989 {
3990 PSAM_DB_OBJECT GroupObject;
3991 ULONG Length = 0;
3992 NTSTATUS Status;
3993
3994 TRACE("(%p)\n", GroupHandle);
3995
3996 /* Validate the group handle */
3997 Status = SampValidateDbObject(*GroupHandle,
3998 SamDbGroupObject,
3999 DELETE,
4000 &GroupObject);
4001 if (!NT_SUCCESS(Status))
4002 {
4003 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4004 return Status;
4005 }
4006
4007 /* Fail, if the group is built-in */
4008 if (GroupObject->RelativeId < 1000)
4009 {
4010 TRACE("You can not delete a special account!\n");
4011 return STATUS_SPECIAL_ACCOUNT;
4012 }
4013
4014 /* Get the length of the Members attribute */
4015 SampGetObjectAttribute(GroupObject,
4016 L"Members",
4017 NULL,
4018 NULL,
4019 &Length);
4020
4021 /* Fail, if the group has members */
4022 if (Length != 0)
4023 {
4024 TRACE("There are still members in the group!\n");
4025 return STATUS_MEMBER_IN_GROUP;
4026 }
4027
4028 /* FIXME: Remove the group from all aliases */
4029
4030 /* Delete the group from the database */
4031 Status = SampDeleteAccountDbObject(GroupObject);
4032 if (!NT_SUCCESS(Status))
4033 {
4034 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4035 return Status;
4036 }
4037
4038 /* Invalidate the handle */
4039 *GroupHandle = NULL;
4040
4041 return STATUS_SUCCESS;
4042 }
4043
4044
4045 /* Function 24 */
4046 NTSTATUS
4047 NTAPI
4048 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4049 IN unsigned long MemberId)
4050 {
4051 PSAM_DB_OBJECT GroupObject;
4052 PSAM_DB_OBJECT UserObject = NULL;
4053 NTSTATUS Status;
4054
4055 TRACE("(%p %lu)\n",
4056 GroupHandle, MemberId);
4057
4058 /* Validate the group handle */
4059 Status = SampValidateDbObject(GroupHandle,
4060 SamDbGroupObject,
4061 GROUP_REMOVE_MEMBER,
4062 &GroupObject);
4063 if (!NT_SUCCESS(Status))
4064 return Status;
4065
4066 /* Open the user object in the same domain */
4067 Status = SampOpenUserObject(GroupObject->ParentObject,
4068 MemberId,
4069 0,
4070 &UserObject);
4071 if (!NT_SUCCESS(Status))
4072 {
4073 ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4074 goto done;
4075 }
4076
4077 /* Remove group membership from the user object */
4078 Status = SampRemoveGroupMembershipFromUser(UserObject,
4079 GroupObject->RelativeId);
4080 if (!NT_SUCCESS(Status))
4081 {
4082 ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4083 goto done;
4084 }
4085
4086 /* Remove the member from the group object */
4087 Status = SampRemoveMemberFromGroup(GroupObject,
4088 MemberId);
4089 if (!NT_SUCCESS(Status))
4090 {
4091 ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4092 }
4093
4094 done:
4095 if (UserObject)
4096 SampCloseDbObject(UserObject);
4097
4098 return Status;
4099 }
4100
4101
4102 /* Function 25 */
4103 NTSTATUS
4104 NTAPI
4105 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4106 OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4107 {
4108 PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4109 PSAM_DB_OBJECT GroupObject;
4110 ULONG Length = 0;
4111 ULONG i;
4112 NTSTATUS Status;
4113
4114 /* Validate the group handle */
4115 Status = SampValidateDbObject(GroupHandle,
4116 SamDbGroupObject,
4117 GROUP_LIST_MEMBERS,
4118 &GroupObject);
4119 if (!NT_SUCCESS(Status))
4120 return Status;
4121
4122 MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4123 if (MembersBuffer == NULL)
4124 return STATUS_INSUFFICIENT_RESOURCES;
4125
4126 SampGetObjectAttribute(GroupObject,
4127 L"Members",
4128 NULL,
4129 NULL,
4130 &Length);
4131
4132 if (Length == 0)
4133 {
4134 MembersBuffer->MemberCount = 0;
4135 MembersBuffer->Members = NULL;
4136 MembersBuffer->Attributes = NULL;
4137
4138 *Members = MembersBuffer;
4139
4140 return STATUS_SUCCESS;
4141 }
4142
4143 MembersBuffer->Members = midl_user_allocate(Length);
4144 if (MembersBuffer->Members == NULL)
4145 {
4146 Status = STATUS_INSUFFICIENT_RESOURCES;
4147 goto done;
4148 }
4149
4150 MembersBuffer->Attributes = midl_user_allocate(Length);
4151 if (MembersBuffer->Attributes == NULL)
4152 {
4153 Status = STATUS_INSUFFICIENT_RESOURCES;
4154 goto done;
4155 }
4156
4157 Status = SampGetObjectAttribute(GroupObject,
4158 L"Members",
4159 NULL,
4160 MembersBuffer->Members,
4161 &Length);
4162 if (!NT_SUCCESS(Status))
4163 {
4164 TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4165 goto done;
4166 }
4167
4168 MembersBuffer->MemberCount = Length / sizeof(ULONG);
4169
4170 for (i = 0; i < MembersBuffer->MemberCount; i++)
4171 {
4172 Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4173 MembersBuffer->Members[i],
4174 GroupObject->RelativeId,
4175 &(MembersBuffer->Attributes[i]));
4176 if (!NT_SUCCESS(Status))
4177 {
4178 TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4179 goto done;
4180 }
4181 }
4182
4183 *Members = MembersBuffer;
4184
4185 done:
4186 if (!NT_SUCCESS(Status))
4187 {
4188 if (MembersBuffer != NULL)
4189 {
4190 if (MembersBuffer->Members != NULL)
4191 midl_user_free(MembersBuffer->Members);
4192
4193 if (MembersBuffer->Attributes != NULL)
4194 midl_user_free(MembersBuffer->Attributes);
4195
4196 midl_user_free(MembersBuffer);
4197 }
4198 }
4199
4200 return Status;
4201 }
4202
4203
4204 /* Function 26 */
4205 NTSTATUS
4206 NTAPI
4207 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4208 IN unsigned long MemberId,
4209 IN unsigned long Attributes)
4210 {
4211 PSAM_DB_OBJECT GroupObject;
4212 NTSTATUS Status;
4213
4214 /* Validate the group handle */
4215 Status = SampValidateDbObject(GroupHandle,
4216 SamDbGroupObject,
4217 GROUP_ADD_MEMBER,
4218 &GroupObject);
4219 if (!NT_SUCCESS(Status))
4220 {
4221 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4222 return Status;
4223 }
4224
4225 Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4226 MemberId,
4227 GroupObject->RelativeId,
4228 Attributes);
4229 if (!NT_SUCCESS(Status))
4230 {
4231 TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4232 }
4233
4234 return Status;
4235 }
4236
4237
4238 /* Function 27 */
4239 NTSTATUS
4240 NTAPI
4241 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4242 IN ACCESS_MASK DesiredAccess,
4243 IN ULONG AliasId,
4244 OUT SAMPR_HANDLE *AliasHandle)
4245 {
4246 PSAM_DB_OBJECT DomainObject;
4247 PSAM_DB_OBJECT AliasObject;
4248 WCHAR szRid[9];
4249 NTSTATUS Status;
4250
4251 TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4252 DomainHandle, DesiredAccess, AliasId, AliasHandle);
4253
4254 /* Map generic access rights */
4255 RtlMapGenericMask(&DesiredAccess,
4256 &AliasMapping);
4257
4258 /* Validate the domain handle */
4259 Status = SampValidateDbObject(DomainHandle,
4260 SamDbDomainObject,
4261 DOMAIN_LOOKUP,
4262 &DomainObject);
4263 if (!NT_SUCCESS(Status))
4264 {
4265 TRACE("failed with status 0x%08lx\n", Status);
4266 return Status;
4267 }
4268
4269 /* Convert the RID into a string (hex) */
4270 swprintf(szRid, L"%08lX", AliasId);
4271
4272 /* Create the alias object */
4273 Status = SampOpenDbObject(DomainObject,
4274 L"Aliases",
4275 szRid,
4276 AliasId,
4277 SamDbAliasObject,
4278 DesiredAccess,
4279 &AliasObject);
4280 if (!NT_SUCCESS(Status))
4281 {
4282 TRACE("failed with status 0x%08lx\n", Status);
4283 return Status;
4284 }
4285
4286 *AliasHandle = (SAMPR_HANDLE)AliasObject;
4287
4288 return STATUS_SUCCESS;
4289 }
4290
4291
4292 static NTSTATUS
4293 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4294 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4295 {
4296 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4297 HANDLE MembersKeyHandle = NULL;
4298 NTSTATUS Status;
4299
4300 *Buffer = NULL;
4301
4302 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4303 if (InfoBuffer == NULL)
4304 return STATUS_INSUFFICIENT_RESOURCES;
4305
4306 Status = SampGetObjectAttributeString(AliasObject,
4307 L"Name",
4308 &InfoBuffer->General.Name);
4309 if (!NT_SUCCESS(Status))
4310 {
4311 TRACE("Status 0x%08lx\n", Status);
4312 goto done;
4313 }
4314
4315 Status = SampGetObjectAttributeString(AliasObject,
4316 L"Description",
4317 &InfoBuffer->General.AdminComment);
4318 if (!NT_SUCCESS(Status))
4319 {
4320 TRACE("Status 0x%08lx\n", Status);
4321 goto done;
4322 }
4323
4324 /* Open the Members subkey */
4325 Status = SampRegOpenKey(AliasObject->KeyHandle,
4326 L"Members",
4327 KEY_READ,
4328 &MembersKeyHandle);
4329 if (NT_SUCCESS(Status))
4330 {
4331 /* Retrieve the number of members of the alias */
4332 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4333 NULL,
4334 &InfoBuffer->General.MemberCount);
4335 if (!NT_SUCCESS(Status))
4336 {
4337 TRACE("Status 0x%08lx\n", Status);
4338 goto done;
4339 }
4340 }
4341 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4342 {
4343 InfoBuffer->General.MemberCount = 0;
4344 Status = STATUS_SUCCESS;
4345 }
4346 else
4347 {
4348 TRACE("Status 0x%08lx\n", Status);
4349 goto done;
4350 }
4351
4352 *Buffer = InfoBuffer;
4353
4354 done:
4355 if (MembersKeyHandle != NULL)
4356 SampRegCloseKey(MembersKeyHandle);
4357
4358 if (!NT_SUCCESS(Status))
4359 {
4360 if (InfoBuffer != NULL)
4361 {
4362 if (InfoBuffer->General.Name.Buffer != NULL)
4363 midl_user_free(InfoBuffer->General.Name.Buffer);
4364
4365 if (InfoBuffer->General.AdminComment.Buffer != NULL)
4366 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4367
4368 midl_user_free(InfoBuffer);
4369 }
4370 }
4371
4372 return Status;
4373 }
4374
4375
4376 static NTSTATUS
4377 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
4378 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4379 {
4380 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4381 NTSTATUS Status;
4382
4383 *Buffer = NULL;
4384
4385 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4386 if (InfoBuffer == NULL)
4387 return STATUS_INSUFFICIENT_RESOURCES;
4388
4389 Status = SampGetObjectAttributeString(AliasObject,
4390 L"Name",
4391 &InfoBuffer->Name.Name);
4392 if (!NT_SUCCESS(Status))
4393 {
4394 TRACE("Status 0x%08lx\n", Status);
4395 goto done;
4396 }
4397
4398 *Buffer = InfoBuffer;
4399
4400 done:
4401 if (!NT_SUCCESS(Status))
4402 {
4403 if (InfoBuffer != NULL)
4404 {
4405 if (InfoBuffer->Name.Name.Buffer != NULL)
4406 midl_user_free(InfoBuffer->Name.Name.Buffer);
4407
4408 midl_user_free(InfoBuffer);
4409 }
4410 }
4411
4412 return Status;
4413 }
4414
4415
4416 static NTSTATUS
4417 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
4418 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4419 {
4420 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4421 NTSTATUS Status;
4422
4423 *Buffer = NULL;
4424
4425 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4426 if (InfoBuffer == NULL)
4427 return STATUS_INSUFFICIENT_RESOURCES;
4428
4429 Status = SampGetObjectAttributeString(AliasObject,
4430 L"Description",
4431 &InfoBuffer->AdminComment.AdminComment);
4432 if (!NT_SUCCESS(Status))
4433 {
4434 TRACE("Status 0x%08lx\n", Status);
4435 goto done;
4436 }
4437
4438 *Buffer = InfoBuffer;
4439
4440 done:
4441 if (!NT_SUCCESS(Status))
4442 {
4443 if (InfoBuffer != NULL)
4444 {
4445 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4446 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4447
4448 midl_user_free(InfoBuffer);
4449 }
4450 }
4451
4452 return Status;
4453 }
4454
4455
4456 /* Function 28 */
4457 NTSTATUS
4458 NTAPI
4459 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
4460 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4461 OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4462 {
4463 PSAM_DB_OBJECT AliasObject;
4464 NTSTATUS Status;
4465
4466 TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
4467 AliasHandle, AliasInformationClass, Buffer);
4468
4469 /* Validate the alias handle */
4470 Status = SampValidateDbObject(AliasHandle,
4471 SamDbAliasObject,
4472 ALIAS_READ_INFORMATION,
4473 &AliasObject);
4474 if (!NT_SUCCESS(Status))
4475 return Status;
4476
4477 switch (AliasInformationClass)
4478 {
4479 case AliasGeneralInformation:
4480 Status = SampQueryAliasGeneral(AliasObject,
4481 Buffer);
4482 break;
4483
4484 case AliasNameInformation:
4485 Status = SampQueryAliasName(AliasObject,
4486 Buffer);
4487 break;
4488
4489 case AliasAdminCommentInformation:
4490 Status = SampQueryAliasAdminComment(AliasObject,
4491 Buffer);
4492 break;
4493
4494 default:
4495 Status = STATUS_INVALID_INFO_CLASS;
4496 break;
4497 }
4498
4499 return Status;
4500 }
4501
4502
4503 /* Function 29 */
4504 NTSTATUS
4505 NTAPI
4506 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
4507 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4508 IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
4509 {
4510 PSAM_DB_OBJECT AliasObject;
4511 NTSTATUS Status;
4512
4513 TRACE("SamrSetInformationAlias(%p %lu %p)\n",
4514 AliasHandle, AliasInformationClass, Buffer);
4515
4516 /* Validate the alias handle */
4517 Status = SampValidateDbObject(AliasHandle,
4518 SamDbAliasObject,
4519 ALIAS_WRITE_ACCOUNT,
4520 &AliasObject);
4521 if (!NT_SUCCESS(Status))
4522 return Status;
4523
4524 switch (AliasInformationClass)
4525 {
4526 case AliasNameInformation:
4527 Status = SampSetObjectAttribute(AliasObject,
4528 L"Name",
4529 REG_SZ,
4530 Buffer->Name.Name.Buffer,
4531 Buffer->Name.Name.Length + sizeof(WCHAR));
4532 break;
4533
4534 case AliasAdminCommentInformation:
4535 Status = SampSetObjectAttribute(AliasObject,
4536 L"Description",
4537 REG_SZ,
4538 Buffer->AdminComment.AdminComment.Buffer,
4539 Buffer->AdminComment.AdminComment.Length + sizeof(WCHAR));
4540 break;
4541
4542 default:
4543 Status = STATUS_INVALID_INFO_CLASS;
4544 break;
4545 }
4546
4547 return Status;
4548 }
4549
4550
4551 /* Function 30 */
4552 NTSTATUS
4553 NTAPI
4554 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
4555 {
4556 PSAM_DB_OBJECT AliasObject;
4557 NTSTATUS Status;
4558
4559 /* Validate the alias handle */
4560 Status = SampValidateDbObject(AliasHandle,
4561 SamDbAliasObject,
4562 DELETE,
4563 &AliasObject);
4564 if (!NT_SUCCESS(Status))
4565 {
4566 TRACE("failed with status 0x%08lx\n", Status);
4567 return Status;
4568 }
4569
4570 /* Fail, if the alias is built-in */
4571 if (AliasObject->RelativeId < 1000)
4572 {
4573 TRACE("You can not delete a special account!\n");
4574 return STATUS_SPECIAL_ACCOUNT;
4575 }
4576
4577 /* FIXME: Remove all members from the alias */
4578
4579 /* Delete the alias from the database */
4580 Status = SampDeleteAccountDbObject(AliasObject);
4581 if (!NT_SUCCESS(Status))
4582 {
4583 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4584 return Status;
4585 }
4586
4587 /* Invalidate the handle */
4588 *AliasHandle = NULL;
4589
4590 return Status;
4591 }
4592
4593
4594 /* Function 31 */
4595 NTSTATUS
4596 NTAPI
4597 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
4598 IN PRPC_SID MemberId)
4599 {
4600 PSAM_DB_OBJECT AliasObject;
4601 LPWSTR MemberIdString = NULL;
4602 HANDLE MembersKeyHandle = NULL;
4603 HANDLE MemberKeyHandle = NULL;
4604 ULONG MemberIdLength;
4605 NTSTATUS Status;
4606
4607 TRACE("SamrAddMemberToAlias(%p %p)\n",
4608 AliasHandle, MemberId);
4609
4610 /* Validate the alias handle */
4611 Status = SampValidateDbObject(AliasHandle,
4612 SamDbAliasObject,
4613 ALIAS_ADD_MEMBER,
4614 &AliasObject);
4615 if (!NT_SUCCESS(Status))
4616 {
4617 TRACE("failed with status 0x%08lx\n", Status);
4618 return Status;
4619 }
4620
4621 ConvertSidToStringSidW(MemberId, &MemberIdString);
4622 TRACE("Member SID: %S\n", MemberIdString);
4623
4624 MemberIdLength = RtlLengthSid(MemberId);
4625
4626 Status = SampRegCreateKey(AliasObject->KeyHandle,
4627 L"Members",
4628 KEY_WRITE,
4629 &MembersKeyHandle);
4630 if (!NT_SUCCESS(Status))
4631 {
4632 TRACE("SampRegCreateKey failed with status 0x%08lx\n", Status);
4633 goto done;
4634 }
4635
4636 Status = SampRegSetValue(MembersKeyHandle,
4637 MemberIdString,
4638 REG_BINARY,
4639 MemberId,
4640 MemberIdLength);
4641 if (!NT_SUCCESS(Status))
4642 {
4643 TRACE("SampRegSetValue failed with status 0x%08lx\n", Status);
4644 goto done;
4645 }
4646
4647 Status = SampRegCreateKey(AliasObject->MembersKeyHandle,
4648 MemberIdString,
4649 KEY_WRITE,
4650 &MemberKeyHandle);
4651 if (!NT_SUCCESS(Status))
4652 {
4653 TRACE("SampRegCreateKey failed with status 0x%08lx\n", Status);
4654 goto done;
4655 }
4656
4657 Status = SampRegSetValue(MemberKeyHandle,
4658 AliasObject->Name,
4659 REG_BINARY,
4660 MemberId,
4661 MemberIdLength);
4662 if (!NT_SUCCESS(Status))
4663 {
4664 TRACE("SampRegSetValue failed with status 0x%08lx\n", Status);
4665 goto done;
4666 }
4667
4668 done:
4669 if (MemberKeyHandle != NULL)
4670 SampRegCloseKey(MemberKeyHandle);
4671
4672 if (MembersKeyHandle != NULL)
4673 SampRegCloseKey(MembersKeyHandle);
4674
4675 if (MemberIdString != NULL)
4676 LocalFree(MemberIdString);
4677
4678 return Status;
4679 }
4680
4681
4682 /* Function 32 */
4683 NTSTATUS
4684 NTAPI
4685 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
4686 IN PRPC_SID MemberId)
4687 {
4688 PSAM_DB_OBJECT AliasObject;
4689 LPWSTR MemberIdString = NULL;
4690 HANDLE MembersKeyHandle = NULL;
4691 HANDLE MemberKeyHandle = NULL;
4692 ULONG ulValueCount;
4693 NTSTATUS Status;
4694
4695 TRACE("SamrRemoveMemberFromAlias(%p %p)\n",
4696 AliasHandle, MemberId);
4697
4698 /* Validate the alias handle */
4699 Status = SampValidateDbObject(AliasHandle,
4700 SamDbAliasObject,
4701 ALIAS_REMOVE_MEMBER,
4702 &AliasObject);
4703 if (!NT_SUCCESS(Status))
4704 {
4705 TRACE("failed with status 0x%08lx\n", Status);
4706 return Status;
4707 }
4708
4709 ConvertSidToStringSidW(MemberId, &MemberIdString);
4710 TRACE("Member SID: %S\n", MemberIdString);
4711
4712 Status = SampRegOpenKey(AliasObject->MembersKeyHandle,
4713 MemberIdString,
4714 KEY_WRITE | KEY_QUERY_VALUE,
4715 &MemberKeyHandle);
4716 if (!NT_SUCCESS(Status))
4717 {
4718 TRACE("SampRegOpenKey failed with status 0x%08lx\n", Status);
4719 goto done;
4720 }
4721
4722 Status = SampRegDeleteValue(MemberKeyHandle,
4723 AliasObject->Name);
4724 if (!NT_SUCCESS(Status))
4725 {
4726 TRACE("SampRegDeleteValue failed with status 0x%08lx\n", Status);
4727 goto done;
4728 }
4729
4730 Status = SampRegQueryKeyInfo(MemberKeyHandle,
4731 NULL,
4732 &ulValueCount);
4733 if (!NT_SUCCESS(Status))
4734 {
4735 TRACE("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
4736 goto done;
4737 }
4738
4739 if (ulValueCount == 0)
4740 {
4741 SampRegCloseKey(MemberKeyHandle);
4742 MemberKeyHandle = NULL;
4743
4744 Status = SampRegDeleteKey(AliasObject->MembersKeyHandle,
4745 MemberIdString);
4746 if (!NT_SUCCESS(Status))
4747 {
4748 TRACE("SampRegDeleteKey failed with status 0x%08lx\n", Status);
4749 goto done;
4750 }
4751 }
4752
4753 Status = SampRegOpenKey(AliasObject->KeyHandle,
4754 L"Members",
4755 KEY_WRITE | KEY_QUERY_VALUE,
4756 &MembersKeyHandle);
4757 if (!NT_SUCCESS(Status))
4758 {
4759 TRACE("SampRegOpenKey failed with status 0x%08lx\n", Status);
4760 goto done;
4761 }
4762
4763 Status = SampRegDeleteValue(MembersKeyHandle,
4764 MemberIdString);
4765 if (!NT_SUCCESS(Status))
4766 {
4767 TRACE("SampRegDeleteValue failed with status 0x%08lx\n", Status);
4768 goto done;
4769 }
4770
4771 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4772 NULL,
4773 &ulValueCount);
4774 if (!NT_SUCCESS(Status))
4775 {
4776 TRACE("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
4777 goto done;
4778 }
4779
4780 if (ulValueCount == 0)
4781 {
4782 SampRegCloseKey(MembersKeyHandle);
4783 MembersKeyHandle = NULL;
4784
4785 Status = SampRegDeleteKey(AliasObject->KeyHandle,
4786 L"Members");
4787 if (!NT_SUCCESS(Status))
4788 {
4789 TRACE("SampRegDeleteKey failed with status 0x%08lx\n", Status);
4790 goto done;
4791 }
4792 }
4793
4794 done:
4795 if (MemberKeyHandle != NULL)
4796 SampRegCloseKey(MemberKeyHandle);
4797
4798 if (MembersKeyHandle != NULL)
4799 SampRegCloseKey(MembersKeyHandle);
4800
4801 if (MemberIdString != NULL)
4802 LocalFree(MemberIdString);
4803
4804 return Status;
4805 }
4806
4807
4808 /* Function 33 */
4809 NTSTATUS
4810 NTAPI
4811 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
4812 OUT PSAMPR_PSID_ARRAY_OUT Members)
4813 {
4814 PSAM_DB_OBJECT AliasObject;
4815 HANDLE MembersKeyHandle = NULL;
4816 PSAMPR_SID_INFORMATION MemberArray = NULL;
4817 ULONG ValueCount = 0;
4818 ULONG DataLength;
4819 ULONG Index;
4820 NTSTATUS Status;
4821
4822 TRACE("SamrGetMembersInAlias(%p %p %p)\n",
4823 AliasHandle, Members);
4824
4825 /* Validate the alias handle */
4826 Status = SampValidateDbObject(AliasHandle,
4827 SamDbAliasObject,
4828 ALIAS_LIST_MEMBERS,
4829 &AliasObject);
4830 if (!NT_SUCCESS(Status))
4831 {
4832 ERR("failed with status 0x%08lx\n", Status);
4833 return Status;
4834 }
4835
4836 /* Open the members key of the alias objct */
4837 Status = SampRegOpenKey(AliasObject->KeyHandle,
4838 L"Members",
4839 KEY_READ,
4840 &MembersKeyHandle);
4841 if (!NT_SUCCESS(Status))
4842 {
4843 ERR("SampRegOpenKey failed with status 0x%08lx\n", Status);
4844 return Status;
4845 }
4846
4847 /* Get the number of members */
4848 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4849 NULL,
4850 &ValueCount);
4851 if (!NT_SUCCESS(Status))
4852 {
4853 ERR("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
4854 goto done;
4855 }
4856
4857 /* Allocate the member array */
4858 MemberArray = midl_user_allocate(ValueCount * sizeof(SAMPR_SID_INFORMATION));
4859 if (MemberArray == NULL)
4860 {
4861 Status = STATUS_INSUFFICIENT_RESOURCES;
4862 goto done;
4863 }
4864
4865 /* Enumerate the members */
4866 Index = 0;
4867 while (TRUE)
4868 {
4869 /* Get the size of the next SID */
4870 DataLength = 0;
4871 Status = SampRegEnumerateValue(MembersKeyHandle,
4872 Index,
4873 NULL,
4874 NULL,
4875 NULL,
4876 NULL,
4877 &DataLength);
4878 if (!NT_SUCCESS(Status))
4879 {
4880 if (Status == STATUS_NO_MORE_ENTRIES)
4881 Status = STATUS_SUCCESS;
4882 break;
4883 }
4884
4885 /* Allocate a buffer for the SID */
4886 MemberArray[Index].SidPointer = midl_user_allocate(DataLength);
4887 if (MemberArray[Index].SidPointer == NULL)
4888 {
4889 Status = STATUS_INSUFFICIENT_RESOURCES;
4890 goto done;
4891 }
4892
4893 /* Read the SID into the buffer */
4894 Status = SampRegEnumerateValue(MembersKeyHandle,
4895 Index,
4896 NULL,
4897 NULL,
4898 NULL,
4899 (PVOID)MemberArray[Index].SidPointer,
4900 &DataLength);
4901 if (!NT_SUCCESS(Status))
4902 {
4903 goto done;
4904 }
4905
4906 Index++;
4907 }
4908
4909 /* Return the number of members and the member array */
4910 if (NT_SUCCESS(Status))
4911 {
4912 Members->Count = ValueCount;
4913 Members->Sids = MemberArray;
4914 }
4915
4916 done:
4917 /* Clean up the members array and the SID buffers if something failed */
4918 if (!NT_SUCCESS(Status))
4919 {
4920 if (MemberArray != NULL)
4921 {
4922 for (Index = 0; Index < ValueCount; Index++)
4923 {
4924 if (MemberArray[Index].SidPointer != NULL)
4925 midl_user_free(MemberArray[Index].SidPointer);
4926 }
4927
4928 midl_user_free(MemberArray);
4929 }
4930 }
4931
4932 /* Close the members key */
4933 if (MembersKeyHandle != NULL)
4934 SampRegCloseKey(MembersKeyHandle);
4935
4936 return Status;
4937 }
4938
4939
4940 /* Function 34 */
4941 NTSTATUS
4942 NTAPI
4943 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
4944 IN ACCESS_MASK DesiredAccess,
4945 IN unsigned long UserId,
4946 OUT SAMPR_HANDLE *UserHandle)
4947 {
4948 PSAM_DB_OBJECT DomainObject;
4949 PSAM_DB_OBJECT UserObject;
4950 WCHAR szRid[9];
4951 NTSTATUS Status;
4952
4953 TRACE("SamrOpenUser(%p %lx %lx %p)\n",
4954 DomainHandle, DesiredAccess, UserId, UserHandle);
4955
4956 /* Map generic access rights */
4957 RtlMapGenericMask(&DesiredAccess,
4958 &UserMapping);
4959
4960 /* Validate the domain handle */
4961 Status = SampValidateDbObject(DomainHandle,
4962 SamDbDomainObject,
4963 DOMAIN_LOOKUP,
4964 &DomainObject);
4965 if (!NT_SUCCESS(Status))
4966 {
4967 TRACE("failed with status 0x%08lx\n", Status);
4968 return Status;
4969 }
4970
4971 /* Convert the RID into a string (hex) */
4972 swprintf(szRid, L"%08lX", UserId);
4973
4974 /* Create the user object */
4975 Status = SampOpenDbObject(DomainObject,
4976 L"Users",
4977 szRid,
4978 UserId,
4979 SamDbUserObject,
4980 DesiredAccess,
4981 &UserObject);
4982 if (!NT_SUCCESS(Status))
4983 {
4984 TRACE("failed with status 0x%08lx\n", Status);
4985 return Status;
4986 }
4987
4988 *UserHandle = (SAMPR_HANDLE)UserObject;
4989
4990 return STATUS_SUCCESS;
4991 }
4992
4993
4994 /* Function 35 */
4995 NTSTATUS
4996 NTAPI
4997 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
4998 {
4999 PSAM_DB_OBJECT UserObject;
5000 NTSTATUS Status;
5001
5002 TRACE("(%p)\n", UserHandle);
5003
5004 /* Validate the user handle */
5005 Status = SampValidateDbObject(*UserHandle,
5006 SamDbUserObject,
5007 DELETE,
5008 &UserObject);
5009 if (!NT_SUCCESS(Status))
5010 {
5011 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5012 return Status;
5013 }
5014
5015 /* Fail, if the user is built-in */
5016 if (UserObject->RelativeId < 1000)
5017 {
5018 TRACE("You can not delete a special account!\n");
5019 return STATUS_SPECIAL_ACCOUNT;
5020 }
5021
5022 /* FIXME: Remove the user from all groups */
5023
5024 /* FIXME: Remove the user from all aliases */
5025
5026 /* Delete the user from the database */
5027 Status = SampDeleteAccountDbObject(UserObject);
5028 if (!NT_SUCCESS(Status))
5029 {
5030 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5031 return Status;
5032 }
5033
5034 /* Invalidate the handle */
5035 *UserHandle = NULL;
5036
5037 return STATUS_SUCCESS;
5038 }
5039
5040
5041 static
5042 NTSTATUS
5043 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5044 PSAMPR_USER_INFO_BUFFER *Buffer)
5045 {
5046 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5047 SAM_USER_FIXED_DATA FixedData;
5048 ULONG Length = 0;
5049 NTSTATUS Status;
5050
5051 *Buffer = NULL;
5052
5053 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5054 if (InfoBuffer == NULL)
5055 return STATUS_INSUFFICIENT_RESOURCES;
5056
5057 Length = sizeof(SAM_USER_FIXED_DATA);
5058 Status = SampGetObjectAttribute(UserObject,
5059 L"F",
5060 NULL,
5061 (PVOID)&FixedData,
5062 &Length);
5063 if (!NT_SUCCESS(Status))
5064 goto done;
5065
5066 InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5067
5068 /* Get the Name string */
5069 Status = SampGetObjectAttributeString(UserObject,
5070 L"Name",
5071 &InfoBuffer->General.UserName);
5072 if (!NT_SUCCESS(Status))
5073 {
5074 TRACE("Status 0x%08lx\n", Status);
5075 goto done;
5076 }
5077
5078 /* Get the FullName string */
5079 Status = SampGetObjectAttributeString(UserObject,
5080 L"FullName",
5081 &InfoBuffer->General.FullName);
5082 if (!NT_SUCCESS(Status))
5083 {
5084 TRACE("Status 0x%08lx\n", Status);
5085 goto done;
5086 }
5087
5088 /* Get the AdminComment string */
5089 Status = SampGetObjectAttributeString(UserObject,
5090 L"AdminComment",
5091 &InfoBuffer->General.AdminComment);
5092 if (!NT_SUCCESS(Status))
5093 {
5094 TRACE("Status 0x%08lx\n", Status);
5095 goto done;
5096 }
5097
5098 /* Get the UserComment string */
5099 Status = SampGetObjectAttributeString(UserObject,
5100 L"UserComment",
5101 &InfoBuffer->General.UserComment);
5102 if (!NT_SUCCESS(Status))
5103 {
5104 TRACE("Status 0x%08lx\n", Status);
5105 goto done;
5106 }
5107
5108 *Buffer = InfoBuffer;
5109
5110 done:
5111 if (!NT_SUCCESS(Status))
5112 {
5113 if (InfoBuffer != NULL)
5114 {
5115 if (InfoBuffer->General.UserName.Buffer != NULL)
5116 midl_user_free(InfoBuffer->General.UserName.Buffer);
5117
5118 if (InfoBuffer->General.FullName.Buffer != NULL)
5119 midl_user_free(InfoBuffer->General.FullName.Buffer);
5120
5121 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5122 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5123
5124 if (InfoBuffer->General.UserComment.Buffer != NULL)
5125 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5126
5127 midl_user_free(InfoBuffer);
5128 }
5129 }
5130
5131 return Status;
5132 }
5133
5134
5135 static
5136 NTSTATUS
5137 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5138 PSAMPR_USER_INFO_BUFFER *Buffer)
5139 {
5140 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5141 SAM_USER_FIXED_DATA FixedData;
5142 ULONG Length = 0;
5143 NTSTATUS Status;
5144
5145 *Buffer = NULL;
5146
5147 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5148 if (InfoBuffer == NULL)
5149 return STATUS_INSUFFICIENT_RESOURCES;
5150
5151 Length = sizeof(SAM_USER_FIXED_DATA);
5152 Status = SampGetObjectAttribute(UserObject,
5153 L"F",
5154 NULL,
5155 (PVOID)&FixedData,
5156 &Length);
5157 if (!NT_SUCCESS(Status))
5158 goto done;
5159
5160 InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5161 InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5162
5163 /* Get the UserComment string */
5164 Status = SampGetObjectAttributeString(UserObject,
5165 L"UserComment",
5166 &InfoBuffer->Preferences.UserComment);
5167 if (!NT_SUCCESS(Status))
5168 {
5169 TRACE("Status 0x%08lx\n", Status);
5170 goto done;
5171 }
5172
5173 *Buffer = InfoBuffer;
5174
5175 done:
5176 if (!NT_SUCCESS(Status))
5177 {
5178 if (InfoBuffer != NULL)
5179 {
5180 if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5181 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5182
5183 midl_user_free(InfoBuffer);
5184 }
5185 }
5186
5187 return Status;
5188 }
5189
5190
5191 static
5192 NTSTATUS
5193 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5194 PSAMPR_USER_INFO_BUFFER *Buffer)
5195 {
5196 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5197 SAM_USER_FIXED_DATA FixedData;
5198 ULONG Length = 0;
5199 NTSTATUS Status;
5200
5201 *Buffer = NULL;
5202
5203 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5204 if (InfoBuffer == NULL)
5205 return STATUS_INSUFFICIENT_RESOURCES;
5206
5207 Length = sizeof(SAM_USER_FIXED_DATA);
5208 Status = SampGetObjectAttribute(UserObject,
5209 L"F",
5210 NULL,
5211 (PVOID)&FixedData,
5212 &Length);
5213 if (!NT_SUCCESS(Status))
5214 goto done;
5215
5216 InfoBuffer->Logon.UserId = FixedData.UserId;
5217 InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5218 InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5219 InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5220 InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5221 InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5222 InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5223 InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5224 InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5225 InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5226 InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5227
5228 // OLD_LARGE_INTEGER PasswordCanChange;
5229 // OLD_LARGE_INTEGER PasswordMustChange;
5230
5231 /* Get the Name string */
5232 Status = SampGetObjectAttributeString(UserObject,
5233 L"Name",
5234 &InfoBuffer->Logon.UserName);
5235 if (!NT_SUCCESS(Status))
5236 {
5237 TRACE("Status 0x%08lx\n", Status);
5238 goto done;
5239 }
5240
5241 /* Get the FullName string */
5242 Status = SampGetObjectAttributeString(UserObject,
5243 L"FullName",
5244 &InfoBuffer->Logon.FullName);
5245 if (!NT_SUCCESS(Status))
5246 {
5247 TRACE("Status 0x%08lx\n", Status);
5248 goto done;
5249 }
5250
5251 /* Get the HomeDirectory string */
5252 Status = SampGetObjectAttributeString(UserObject,
5253 L"HomeDirectory",
5254 &InfoBuffer->Logon.HomeDirectory);
5255 if (!NT_SUCCESS(Status))
5256 {
5257 TRACE("Status 0x%08lx\n", Status);
5258 goto done;
5259 }
5260
5261 /* Get the HomeDirectoryDrive string */
5262 Status = SampGetObjectAttributeString(UserObject,
5263 L"HomeDirectoryDrive",
5264 &InfoBuffer->Logon.HomeDirectoryDrive);
5265 if (!NT_SUCCESS(Status))
5266 {
5267 TRACE("Status 0x%08lx\n", Status);
5268 goto done;
5269 }
5270
5271 /* Get the ScriptPath string */
5272 Status = SampGetObjectAttributeString(UserObject,
5273 L"ScriptPath",
5274 &InfoBuffer->Logon.ScriptPath);
5275 if (!NT_SUCCESS(Status))
5276 {
5277 TRACE("Status 0x%08lx\n", Status);
5278 goto done;
5279 }
5280
5281 /* Get the ProfilePath string */
5282 Status = SampGetObjectAttributeString(UserObject,
5283 L"ProfilePath",
5284 &InfoBuffer->Logon.ProfilePath);
5285 if (!NT_SUCCESS(Status))
5286 {
5287 TRACE("Status 0x%08lx\n", Status);
5288 goto done;
5289 }
5290
5291 /* Get the WorkStations string */
5292 Status = SampGetObjectAttributeString(UserObject,
5293 L"WorkStations",
5294 &InfoBuffer->Logon.WorkStations);
5295 if (!NT_SUCCESS(Status))
5296 {
5297 TRACE("Status 0x%08lx\n", Status);
5298 goto done;
5299 }
5300
5301 /* FIXME: LogonHours */
5302
5303 *Buffer = InfoBuffer;
5304
5305 done:
5306 if (!NT_SUCCESS(Status))
5307 {
5308 if (InfoBuffer != NULL)
5309 {
5310 if (InfoBuffer->Logon.UserName.Buffer != NULL)
5311 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5312
5313 if (InfoBuffer->Logon.FullName.Buffer != NULL)
5314 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5315
5316 if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5317 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5318
5319 if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5320 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5321
5322 if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5323 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5324
5325 if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5326 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5327
5328 if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5329 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5330
5331 if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5332 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5333
5334 midl_user_free(InfoBuffer);
5335 }
5336 }
5337
5338 return Status;
5339 }
5340
5341
5342 static
5343 NTSTATUS
5344 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5345 PSAMPR_USER_INFO_BUFFER *Buffer)
5346 {
5347 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5348 SAM_USER_FIXED_DATA FixedData;
5349 ULONG Length = 0;
5350 NTSTATUS Status;
5351
5352 *Buffer = NULL;
5353
5354 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5355 if (InfoBuffer == NULL)
5356 return STATUS_INSUFFICIENT_RESOURCES;
5357
5358 Length = sizeof(SAM_USER_FIXED_DATA);
5359 Status = SampGetObjectAttribute(UserObject,
5360 L"F",
5361 NULL,
5362 (PVOID)&FixedData,
5363 &Length);
5364 if (!NT_SUCCESS(Status))
5365 goto done;
5366
5367 InfoBuffer->Account.UserId = FixedData.UserId;
5368 InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5369 InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5370 InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5371 InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5372 InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5373 InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5374 InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5375 InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5376 InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5377 InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
5378 InfoBuffer->Account.LogonCount = FixedData.LogonCount;
5379 InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
5380
5381 /* Get the Name string */
5382 Status = SampGetObjectAttributeString(UserObject,
5383 L"Name",
5384 &InfoBuffer->Account.UserName);
5385 if (!NT_SUCCESS(Status))
5386 {
5387 TRACE("Status 0x%08lx\n", Status);
5388 goto done;
5389 }
5390
5391 /* Get the FullName string */
5392 Status = SampGetObjectAttributeString(UserObject,
5393 L"FullName",
5394 &InfoBuffer->Account.FullName);
5395 if (!NT_SUCCESS(Status))
5396 {
5397 TRACE("Status 0x%08lx\n", Status);
5398 goto done;
5399 }
5400
5401 /* Get the HomeDirectory string */
5402 Status = SampGetObjectAttributeString(UserObject,
5403 L"HomeDirectory",
5404 &InfoBuffer->Account.HomeDirectory);
5405 if (!NT_SUCCESS(Status))
5406 {
5407 TRACE("Status 0x%08lx\n", Status);
5408 goto done;
5409 }
5410
5411 /* Get the HomeDirectoryDrive string */
5412 Status = SampGetObjectAttributeString(UserObject,
5413 L"HomeDirectoryDrive",
5414 &InfoBuffer->Account.HomeDirectoryDrive);
5415 if (!NT_SUCCESS(Status))
5416 {
5417 TRACE("Status 0x%08lx\n", Status);
5418 goto done;
5419 }
5420
5421 /* Get the ScriptPath string */
5422 Status = SampGetObjectAttributeString(UserObject,
5423 L"ScriptPath",
5424 &InfoBuffer->Account.ScriptPath);
5425 if (!NT_SUCCESS(Status))
5426 {
5427 TRACE("Status 0x%08lx\n", Status);
5428 goto done;
5429 }
5430
5431 /* Get the ProfilePath string */
5432 Status = SampGetObjectAttributeString(UserObject,
5433 L"ProfilePath",
5434 &InfoBuffer->Account.ProfilePath);
5435 if (!NT_SUCCESS(Status))
5436 {
5437 TRACE("Status 0x%08lx\n", Status);
5438 goto done;
5439 }
5440
5441 /* Get the AdminComment string */
5442 Status = SampGetObjectAttributeString(UserObject,
5443 L"AdminComment",
5444 &InfoBuffer->Account.AdminComment);
5445 if (!NT_SUCCESS(Status))
5446 {
5447 TRACE("Status 0x%08lx\n", Status);
5448 goto done;
5449 }
5450
5451 /* Get the WorkStations string */
5452 Status = SampGetObjectAttributeString(UserObject,
5453 L"WorkStations",
5454 &InfoBuffer->Account.WorkStations);
5455 if (!NT_SUCCESS(Status))
5456 {
5457 TRACE("Status 0x%08lx\n", Status);
5458 goto done;
5459 }
5460
5461 /* FIXME: LogonHours */
5462
5463 *Buffer = InfoBuffer;
5464
5465 done:
5466 if (!NT_SUCCESS(Status))
5467 {
5468 if (InfoBuffer != NULL)
5469 {
5470 if (InfoBuffer->Account.UserName.Buffer != NULL)
5471 midl_user_free(InfoBuffer->Account.UserName.Buffer);
5472
5473 if (InfoBuffer->Account.FullName.Buffer != NULL)
5474 midl_user_free(InfoBuffer->Account.FullName.Buffer);
5475
5476 if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
5477 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
5478
5479 if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
5480 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
5481
5482 if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
5483 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
5484
5485 if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
5486 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
5487
5488 if (InfoBuffer->Account.AdminComment.Buffer != NULL)
5489 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
5490
5491 if (InfoBuffer->Account.WorkStations.Buffer != NULL)
5492 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
5493
5494 if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
5495 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
5496
5497 midl_user_free(InfoBuffer);
5498 }
5499 }
5500
5501 return Status;
5502 }
5503
5504 /* FIXME: SampQueryUserLogonHours */
5505
5506 static
5507 NTSTATUS
5508 SampQueryUserName(PSAM_DB_OBJECT UserObject,
5509 PSAMPR_USER_INFO_BUFFER *Buffer)
5510 {
5511 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5512 NTSTATUS Status;
5513
5514 *Buffer = NULL;
5515
5516 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5517 if (InfoBuffer == NULL)
5518 return STATUS_INSUFFICIENT_RESOURCES;
5519
5520 /* Get the Name string */
5521 Status = SampGetObjectAttributeString(UserObject,
5522 L"Name",
5523 &InfoBuffer->Name.UserName);
5524 if (!NT_SUCCESS(Status))
5525 {
5526 TRACE("Status 0x%08lx\n", Status);
5527 goto done;
5528 }
5529
5530 /* Get the FullName string */
5531 Status = SampGetObjectAttributeString(UserObject,
5532 L"FullName",
5533 &InfoBuffer->Name.FullName);
5534 if (!NT_SUCCESS(Status))
5535 {
5536 TRACE("Status 0x%08lx\n", Status);
5537 goto done;
5538 }
5539
5540 *Buffer = InfoBuffer;
5541
5542 done:
5543 if (!NT_SUCCESS(Status))
5544 {
5545 if (InfoBuffer != NULL)
5546 {
5547 if (InfoBuffer->Name.UserName.Buffer != NULL)
5548 midl_user_free(InfoBuffer->Name.UserName.Buffer);
5549
5550 if (InfoBuffer->Name.FullName.Buffer != NULL)
5551 midl_user_free(InfoBuffer->Name.FullName.Buffer);
5552
5553 midl_user_free(InfoBuffer);
5554 }
5555 }
5556
5557 return Status;
5558 }
5559
5560
5561 static NTSTATUS
5562 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
5563 PSAMPR_USER_INFO_BUFFER *Buffer)
5564 {
5565 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5566 NTSTATUS Status;
5567
5568 *Buffer = NULL;
5569
5570 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5571 if (InfoBuffer == NULL)
5572 return STATUS_INSUFFICIENT_RESOURCES;
5573
5574 /* Get the Name string */
5575 Status = SampGetObjectAttributeString(UserObject,
5576 L"Name",
5577 &InfoBuffer->AccountName.UserName);
5578 if (!NT_SUCCESS(Status))
5579 {
5580 TRACE("Status 0x%08lx\n", Status);
5581 goto done;
5582 }
5583
5584 *Buffer = InfoBuffer;
5585
5586 done:
5587 if (!NT_SUCCESS(Status))
5588 {
5589 if (InfoBuffer != NULL)
5590 {
5591 if (InfoBuffer->AccountName.UserName.Buffer != NULL)
5592 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
5593
5594 midl_user_free(InfoBuffer);
5595 }
5596 }
5597
5598 return Status;
5599 }
5600
5601
5602 static NTSTATUS
5603 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
5604 PSAMPR_USER_INFO_BUFFER *Buffer)
5605 {
5606 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5607 NTSTATUS Status;
5608
5609 *Buffer = NULL;
5610
5611 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5612 if (InfoBuffer == NULL)
5613 return STATUS_INSUFFICIENT_RESOURCES;
5614
5615 /* Get the FullName string */
5616 Status = SampGetObjectAttributeString(UserObject,
5617 L"FullName",
5618 &InfoBuffer->FullName.FullName);
5619 if (!NT_SUCCESS(Status))
5620 {
5621 TRACE("Status 0x%08lx\n", Status);
5622 goto done;
5623 }
5624
5625 *Buffer = InfoBuffer;
5626
5627 done:
5628 if (!NT_SUCCESS(Status))
5629 {
5630 if (InfoBuffer != NULL)
5631 {
5632 if (InfoBuffer->FullName.FullName.Buffer != NULL)
5633 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
5634
5635 midl_user_free(InfoBuffer);
5636 }
5637 }
5638
5639 return Status;
5640 }
5641
5642
5643 static
5644 NTSTATUS
5645 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
5646 PSAMPR_USER_INFO_BUFFER *Buffer)
5647 {
5648 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5649 SAM_USER_FIXED_DATA FixedData;
5650 ULONG Length = 0;
5651 NTSTATUS Status;
5652
5653 *Buffer = NULL;
5654
5655 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5656 if (InfoBuffer == NULL)
5657 return STATUS_INSUFFICIENT_RESOURCES;
5658
5659 Length = sizeof(SAM_USER_FIXED_DATA);
5660 Status = SampGetObjectAttribute(UserObject,
5661 L"F",
5662 NULL,
5663 (PVOID)&FixedData,
5664 &Length);
5665 if (!NT_SUCCESS(Status))
5666 goto done;
5667
5668 InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
5669
5670 *Buffer = InfoBuffer;
5671
5672 done:
5673 if (!NT_SUCCESS(Status))
5674 {
5675 if (InfoBuffer != NULL)
5676 {
5677 midl_user_free(InfoBuffer);
5678 }
5679 }
5680
5681 return Status;
5682 }
5683
5684
5685 static NTSTATUS
5686 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
5687 PSAMPR_USER_INFO_BUFFER *Buffer)
5688 {
5689 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5690 NTSTATUS Status;
5691
5692 *Buffer = NULL;
5693
5694 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5695 if (InfoBuffer == NULL)
5696 return STATUS_INSUFFICIENT_RESOURCES;
5697
5698 /* Get the HomeDirectory string */
5699 Status = SampGetObjectAttributeString(UserObject,
5700 L"HomeDirectory",
5701 &InfoBuffer->Home.HomeDirectory);
5702 if (!NT_SUCCESS(Status))
5703 {
5704 TRACE("Status 0x%08lx\n", Status);
5705 goto done;
5706 }
5707
5708 /* Get the HomeDirectoryDrive string */
5709 Status = SampGetObjectAttributeString(UserObject,
5710 L"HomeDirectoryDrive",
5711 &InfoBuffer->Home.HomeDirectoryDrive);
5712 if (!NT_SUCCESS(Status))
5713 {
5714 TRACE("Status 0x%08lx\n", Status);
5715 goto done;
5716 }
5717
5718 *Buffer = InfoBuffer;
5719
5720 done:
5721 if (!NT_SUCCESS(Status))
5722 {
5723 if (InfoBuffer != NULL)
5724 {
5725 if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
5726 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
5727
5728 if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
5729 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
5730
5731 midl_user_free(InfoBuffer);
5732 }
5733 }
5734
5735 return Status;
5736 }
5737
5738
5739 static NTSTATUS
5740 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
5741 PSAMPR_USER_INFO_BUFFER *Buffer)
5742 {
5743 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5744 NTSTATUS Status;
5745
5746 *Buffer = NULL;
5747
5748 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5749 if (InfoBuffer == NULL)
5750 return STATUS_INSUFFICIENT_RESOURCES;
5751
5752 /* Get the ScriptPath string */
5753 Status = SampGetObjectAttributeString(UserObject,
5754 L"ScriptPath",
5755 &InfoBuffer->Script.ScriptPath);
5756 if (!NT_SUCCESS(Status))
5757 {
5758 TRACE("Status 0x%08lx\n", Status);
5759 goto done;
5760 }
5761
5762 *Buffer = InfoBuffer;
5763
5764 done:
5765 if (!NT_SUCCESS(Status))
5766 {
5767 if (InfoBuffer != NULL)
5768 {
5769 if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
5770 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
5771
5772 midl_user_free(InfoBuffer);
5773 }
5774 }
5775
5776 return Status;
5777 }
5778
5779
5780 static NTSTATUS
5781 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
5782 PSAMPR_USER_INFO_BUFFER *Buffer)
5783 {
5784 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5785 NTSTATUS Status;
5786
5787 *Buffer = NULL;
5788
5789 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5790 if (InfoBuffer == NULL)
5791 return STATUS_INSUFFICIENT_RESOURCES;
5792
5793 /* Get the ProfilePath string */
5794 Status = SampGetObjectAttributeString(UserObject,
5795 L"ProfilePath",
5796 &InfoBuffer->Profile.ProfilePath);
5797 if (!NT_SUCCESS(Status))
5798 {
5799 TRACE("Status 0x%08lx\n", Status);
5800 goto done;
5801 }
5802
5803 *Buffer = InfoBuffer;
5804
5805 done:
5806 if (!NT_SUCCESS(Status))
5807 {
5808 if (InfoBuffer != NULL)
5809 {
5810 if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
5811 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
5812
5813 midl_user_free(InfoBuffer);
5814 }
5815 }
5816
5817 return Status;
5818 }
5819
5820
5821 static NTSTATUS
5822 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
5823 PSAMPR_USER_INFO_BUFFER *Buffer)
5824 {
5825 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5826 NTSTATUS Status;
5827
5828 *Buffer = NULL;
5829
5830 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5831 if (InfoBuffer == NULL)
5832 return STATUS_INSUFFICIENT_RESOURCES;
5833
5834 /* Get the AdminComment string */
5835 Status = SampGetObjectAttributeString(UserObject,
5836 L"AdminComment",
5837 &InfoBuffer->AdminComment.AdminComment);
5838 if (!NT_SUCCESS(Status))
5839 {
5840 TRACE("Status 0x%08lx\n", Status);
5841 goto done;
5842 }
5843
5844 *Buffer = InfoBuffer;
5845
5846 done:
5847 if (!NT_SUCCESS(Status))
5848 {
5849 if (InfoBuffer != NULL)
5850 {
5851 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
5852 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
5853
5854 midl_user_free(InfoBuffer);
5855 }
5856 }
5857
5858 return Status;
5859 }
5860
5861
5862 static NTSTATUS
5863 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
5864 PSAMPR_USER_INFO_BUFFER *Buffer)
5865 {
5866 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5867 NTSTATUS Status;
5868
5869 *Buffer = NULL;
5870
5871 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5872 if (InfoBuffer == NULL)
5873 return STATUS_INSUFFICIENT_RESOURCES;
5874
5875 /* Get the WorkStations string */
5876 Status = SampGetObjectAttributeString(UserObject,
5877 L"WorkStations",
5878 &InfoBuffer->WorkStations.WorkStations);
5879 if (!NT_SUCCESS(Status))
5880 {
5881 TRACE("Status 0x%08lx\n", Status);
5882 goto done;
5883 }
5884
5885 *Buffer = InfoBuffer;
5886
5887 done:
5888 if (!NT_SUCCESS(Status))
5889 {
5890 if (InfoBuffer != NULL)
5891 {
5892 if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
5893 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
5894
5895 midl_user_free(InfoBuffer);
5896 }
5897 }
5898
5899 return Status;
5900 }
5901
5902
5903 static
5904 NTSTATUS
5905 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
5906 PSAMPR_USER_INFO_BUFFER *Buffer)
5907 {
5908 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5909 SAM_USER_FIXED_DATA FixedData;
5910 ULONG Length = 0;
5911 NTSTATUS Status;
5912
5913 *Buffer = NULL;
5914
5915 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5916 if (InfoBuffer == NULL)
5917 return STATUS_INSUFFICIENT_RESOURCES;
5918
5919 Length = sizeof(SAM_USER_FIXED_DATA);
5920 Status = SampGetObjectAttribute(UserObject,
5921 L"F",
5922 NULL,
5923 (PVOID)&FixedData,
5924 &Length);
5925 if (!NT_SUCCESS(Status))
5926 goto done;
5927
5928 InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
5929
5930 *Buffer = InfoBuffer;
5931
5932 done:
5933 if (!NT_SUCCESS(Status))
5934 {
5935 if (InfoBuffer != NULL)
5936 {
5937 midl_user_free(InfoBuffer);
5938 }
5939 }
5940
5941 return Status;
5942 }
5943
5944
5945 static
5946 NTSTATUS
5947 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
5948 PSAMPR_USER_INFO_BUFFER *Buffer)
5949 {
5950 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5951 SAM_USER_FIXED_DATA FixedData;
5952 ULONG Length = 0;
5953 NTSTATUS Status;
5954
5955 *Buffer = NULL;
5956
5957 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5958 if (InfoBuffer == NULL)
5959 return STATUS_INSUFFICIENT_RESOURCES;
5960
5961 Length = sizeof(SAM_USER_FIXED_DATA);
5962 Status = SampGetObjectAttribute(UserObject,
5963 L"F",
5964 NULL,
5965 (PVOID)&FixedData,
5966 &Length);
5967 if (!NT_SUCCESS(Status))
5968 goto done;
5969
5970 InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5971 InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5972
5973 *Buffer = InfoBuffer;
5974
5975 done:
5976 if (!NT_SUCCESS(Status))
5977 {
5978 if (InfoBuffer != NULL)
5979 {
5980 midl_user_free(InfoBuffer);
5981 }
5982 }
5983
5984 return Status;
5985 }
5986
5987
5988 static NTSTATUS
5989 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
5990 PSAMPR_USER_INFO_BUFFER *Buffer)
5991 {
5992 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5993 NTSTATUS Status;
5994
5995 *Buffer = NULL;
5996
5997 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5998 if (InfoBuffer == NULL)
5999 return STATUS_INSUFFICIENT_RESOURCES;
6000
6001 /* Get the Parameters string */
6002 Status = SampGetObjectAttributeString(UserObject,
6003 L"Parameters",
6004 &InfoBuffer->Parameters.Parameters);
6005 if (!NT_SUCCESS(Status))
6006 {
6007 TRACE("Status 0x%08lx\n", Status);
6008 goto done;
6009 }
6010
6011 *Buffer = InfoBuffer;
6012
6013 done:
6014 if (!NT_SUCCESS(Status))
6015 {
6016 if (InfoBuffer != NULL)
6017 {
6018 if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6019 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6020
6021 midl_user_free(InfoBuffer);
6022 }
6023 }
6024
6025 return Status;
6026 }
6027
6028
6029 /* Function 36 */
6030 NTSTATUS
6031 NTAPI
6032 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
6033 IN USER_INFORMATION_CLASS UserInformationClass,
6034 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
6035 {
6036 PSAM_DB_OBJECT UserObject;
6037 ACCESS_MASK DesiredAccess;
6038 NTSTATUS Status;
6039
6040 TRACE("SamrQueryInformationUser(%p %lu %p)\n",
6041 UserHandle, UserInformationClass, Buffer);
6042
6043 switch (UserInformationClass)
6044 {
6045 case UserGeneralInformation:
6046 case UserNameInformation:
6047 case UserAccountNameInformation:
6048 case UserFullNameInformation:
6049 case UserPrimaryGroupInformation:
6050 case UserAdminCommentInformation:
6051 DesiredAccess = USER_READ_GENERAL;
6052 break;
6053
6054 case UserLogonHoursInformation:
6055 case UserHomeInformation:
6056 case UserScriptInformation:
6057 case UserProfileInformation:
6058 case UserWorkStationsInformation:
6059 DesiredAccess = USER_READ_LOGON;
6060 break;
6061
6062 case UserControlInformation:
6063 case UserExpiresInformation:
6064 case UserParametersInformation:
6065 DesiredAccess = USER_READ_ACCOUNT;
6066 break;
6067
6068 case UserPreferencesInformation:
6069 DesiredAccess = USER_READ_GENERAL |
6070 USER_READ_PREFERENCES;
6071 break;
6072
6073 case UserLogonInformation:
6074 case UserAccountInformation:
6075 DesiredAccess = USER_READ_GENERAL |
6076 USER_READ_PREFERENCES |
6077 USER_READ_LOGON |
6078 USER_READ_ACCOUNT;
6079 break;
6080
6081 default:
6082 return STATUS_INVALID_INFO_CLASS;
6083 }
6084
6085 /* Validate the domain handle */
6086 Status = SampValidateDbObject(UserHandle,
6087 SamDbUserObject,
6088 DesiredAccess,
6089 &UserObject);
6090 if (!NT_SUCCESS(Status))
6091 {
6092 TRACE("failed with status 0x%08lx\n", Status);
6093 return Status;
6094 }
6095
6096 switch (UserInformationClass)
6097 {
6098 case UserGeneralInformation:
6099 Status = SampQueryUserGeneral(UserObject,
6100 Buffer);
6101 break;
6102
6103 case UserPreferencesInformation:
6104 Status = SampQueryUserPreferences(UserObject,
6105 Buffer);
6106 break;
6107
6108 case UserLogonInformation:
6109 Status = SampQueryUserLogon(UserObject,
6110 Buffer);
6111 break;
6112
6113 // case UserLogonHoursInformation:
6114 // Status = SampQueryUserLogonHours(UserObject,
6115 // Buffer);
6116 // break;
6117
6118 case UserAccountInformation:
6119 Status = SampQueryUserAccount(UserObject,
6120 Buffer);
6121 break;
6122
6123 case UserNameInformation:
6124 Status = SampQueryUserName(UserObject,
6125 Buffer);
6126 break;
6127
6128 case UserAccountNameInformation:
6129 Status = SampQueryUserAccountName(UserObject,
6130 Buffer);
6131 break;
6132
6133 case UserFullNameInformation:
6134 Status = SampQueryUserFullName(UserObject,
6135 Buffer);
6136 break;
6137
6138 case UserPrimaryGroupInformation:
6139 Status = SampQueryUserPrimaryGroup(UserObject,
6140 Buffer);
6141 break;
6142
6143 case UserHomeInformation:
6144 Status = SampQueryUserHome(UserObject,
6145 Buffer);
6146
6147 case UserScriptInformation:
6148 Status = SampQueryUserScript(UserObject,
6149 Buffer);
6150 break;
6151
6152 case UserProfileInformation:
6153 Status = SampQueryUserProfile(UserObject,
6154 Buffer);
6155 break;
6156
6157 case UserAdminCommentInformation:
6158 Status = SampQueryUserAdminComment(UserObject,
6159 Buffer);
6160 break;
6161
6162 case UserWorkStationsInformation:
6163 Status = SampQueryUserWorkStations(UserObject,
6164 Buffer);
6165 break;
6166
6167 case UserControlInformation:
6168 Status = SampQueryUserControl(UserObject,
6169 Buffer);
6170 break;
6171
6172 case UserExpiresInformation:
6173 Status = SampQueryUserExpires(UserObject,
6174 Buffer);
6175 break;
6176
6177 // case UserInternal1Information:
6178
6179 case UserParametersInformation:
6180 Status = SampQueryUserParameters(UserObject,
6181 Buffer);
6182 break;
6183
6184 // case UserAllInformation:
6185 // case UserInternal4Information:
6186 // case UserInternal5Information:
6187 // case UserInternal4InformationNew:
6188 // case UserInternal5InformationNew:
6189
6190 default:
6191 Status = STATUS_INVALID_INFO_CLASS;
6192 }
6193
6194 return Status;
6195 }
6196
6197
6198 static NTSTATUS
6199 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
6200 PSAMPR_USER_INFO_BUFFER Buffer)
6201 {
6202 SAM_USER_FIXED_DATA FixedData;
6203 ULONG Length = 0;
6204 NTSTATUS Status;
6205
6206 Length = sizeof(SAM_USER_FIXED_DATA);
6207 Status = SampGetObjectAttribute(UserObject,
6208 L"F",
6209 NULL,
6210 (PVOID)&FixedData,
6211 &Length);
6212 if (!NT_SUCCESS(Status))
6213 goto done;
6214
6215 FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
6216
6217 Status = SampSetObjectAttribute(UserObject,
6218 L"F",
6219 REG_BINARY,
6220 &FixedData,
6221 Length);
6222 if (!NT_SUCCESS(Status))
6223 goto done;
6224
6225 Status = SampSetObjectAttribute(UserObject,
6226 L"Name",
6227 REG_SZ,
6228 Buffer->General.UserName.Buffer,
6229 Buffer->General.UserName.MaximumLength);
6230 if (!NT_SUCCESS(Status))
6231 goto done;
6232
6233 Status = SampSetObjectAttribute(UserObject,
6234 L"FullName",
6235 REG_SZ,
6236 Buffer->General.FullName.Buffer,
6237 Buffer->General.FullName.MaximumLength);
6238 if (!NT_SUCCESS(Status))
6239 goto done;
6240
6241 Status = SampSetObjectAttribute(UserObject,
6242 L"AdminComment",
6243 REG_SZ,
6244 Buffer->General.AdminComment.Buffer,
6245 Buffer->General.AdminComment.MaximumLength);
6246 if (!NT_SUCCESS(Status))
6247 goto done;
6248
6249 Status = SampSetObjectAttribute(UserObject,
6250 L"UserComment",
6251 REG_SZ,
6252 Buffer->General.UserComment.Buffer,
6253 Buffer->General.UserComment.MaximumLength);
6254
6255 done:
6256 return Status;
6257 }
6258
6259
6260 static NTSTATUS
6261 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
6262 PSAMPR_USER_INFO_BUFFER Buffer)
6263 {
6264 SAM_USER_FIXED_DATA FixedData;
6265 ULONG Length = 0;
6266 NTSTATUS Status;
6267
6268 Length = sizeof(SAM_USER_FIXED_DATA);
6269 Status = SampGetObjectAttribute(UserObject,
6270 L"F",
6271 NULL,
6272 (PVOID)&FixedData,
6273 &Length);
6274 if (!NT_SUCCESS(Status))
6275 goto done;
6276
6277 FixedData.CountryCode = Buffer->Preferences.CountryCode;
6278 FixedData.CodePage = Buffer->Preferences.CodePage;
6279
6280 Status = SampSetObjectAttribute(UserObject,
6281 L"F",
6282 REG_BINARY,
6283 &FixedData,
6284 Length);
6285 if (!NT_SUCCESS(Status))
6286 goto done;
6287
6288 Status = SampSetObjectAttribute(UserObject,
6289 L"UserComment",
6290 REG_SZ,
6291 Buffer->Preferences.UserComment.Buffer,
6292 Buffer->Preferences.UserComment.MaximumLength);
6293
6294 done:
6295 return Status;
6296 }
6297
6298
6299 static NTSTATUS
6300 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6301 PSAMPR_USER_INFO_BUFFER Buffer)
6302 {
6303 SAM_USER_FIXED_DATA FixedData;
6304 ULONG Length = 0;
6305 NTSTATUS Status;
6306
6307 Length = sizeof(SAM_USER_FIXED_DATA);
6308 Status = SampGetObjectAttribute(UserObject,
6309 L"F",
6310 NULL,
6311 (PVOID)&FixedData,
6312 &Length);
6313 if (!NT_SUCCESS(Status))
6314 goto done;
6315
6316 FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
6317
6318 Status = SampSetObjectAttribute(UserObject,
6319 L"F",
6320 REG_BINARY,
6321 &FixedData,
6322 Length);
6323
6324 done:
6325 return Status;
6326 }
6327
6328
6329 static NTSTATUS
6330 SampSetUserControl(PSAM_DB_OBJECT UserObject,
6331 PSAMPR_USER_INFO_BUFFER Buffer)
6332 {
6333 SAM_USER_FIXED_DATA FixedData;
6334 ULONG Length = 0;
6335 NTSTATUS Status;
6336
6337 Length = sizeof(SAM_USER_FIXED_DATA);
6338 Status = SampGetObjectAttribute(UserObject,
6339 L"F",
6340 NULL,
6341 (PVOID)&FixedData,
6342 &Length);
6343 if (!NT_SUCCESS(Status))
6344 goto done;
6345
6346 FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
6347
6348 Status = SampSetObjectAttribute(UserObject,
6349 L"F",
6350 REG_BINARY,
6351 &FixedData,
6352 Length);
6353
6354 done:
6355 return Status;
6356 }
6357
6358
6359 static NTSTATUS
6360 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
6361 PSAMPR_USER_INFO_BUFFER Buffer)
6362 {
6363 SAM_USER_FIXED_DATA FixedData;
6364 ULONG Length = 0;
6365 NTSTATUS Status;
6366
6367 Length = sizeof(SAM_USER_FIXED_DATA);
6368 Status = SampGetObjectAttribute(UserObject,
6369 L"F",
6370 NULL,
6371 (PVOID)&FixedData,
6372 &Length);
6373 if (!NT_SUCCESS(Status))
6374 goto done;
6375
6376 FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
6377 FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
6378
6379 Status = SampSetObjectAttribute(UserObject,
6380 L"F",
6381 REG_BINARY,
6382 &FixedData,
6383 Length);
6384
6385 done:
6386 return Status;
6387 }
6388
6389
6390 static NTSTATUS
6391 SampSetUserAll(PSAM_DB_OBJECT UserObject,
6392 PSAMPR_USER_INFO_BUFFER Buffer)
6393 {
6394 SAM_USER_FIXED_DATA FixedData;
6395 ULONG Length = 0;
6396 ULONG WhichFields;
6397 NTSTATUS Status = STATUS_SUCCESS;
6398
6399 WhichFields = Buffer->All.WhichFields;
6400
6401 if (WhichFields & USER_ALL_USERNAME)
6402 {
6403 Status = SampSetObjectAttribute(UserObject,
6404 L"Name",
6405 REG_SZ,
6406 Buffer->All.UserName.Buffer,
6407 Buffer->All.UserName.MaximumLength);
6408 if (!NT_SUCCESS(Status))
6409 goto done;
6410 }
6411
6412 if (WhichFields & USER_ALL_FULLNAME)
6413 {
6414 Status = SampSetObjectAttribute(UserObject,
6415 L"FullName",
6416 REG_SZ,
6417 Buffer->All.FullName.Buffer,
6418 Buffer->All.FullName.MaximumLength);
6419 if (!NT_SUCCESS(Status))
6420 goto done;
6421 }
6422
6423 if (WhichFields & USER_ALL_ADMINCOMMENT)
6424 {
6425 Status = SampSetObjectAttribute(UserObject,
6426 L"AdminComment",
6427 REG_SZ,
6428 Buffer->All.AdminComment.Buffer,
6429 Buffer->All.AdminComment.MaximumLength);
6430 if (!NT_SUCCESS(Status))
6431 goto done;
6432 }
6433
6434 if (WhichFields & USER_ALL_USERCOMMENT)
6435 {
6436 Status = SampSetObjectAttribute(UserObject,
6437 L"UserComment",
6438 REG_SZ,
6439 Buffer->All.UserComment.Buffer,
6440 Buffer->All.UserComment.MaximumLength);
6441 if (!NT_SUCCESS(Status))
6442 goto done;
6443 }
6444
6445 if (WhichFields & USER_ALL_HOMEDIRECTORY)
6446 {
6447 Status = SampSetObjectAttribute(UserObject,
6448 L"HomeDirectory",
6449 REG_SZ,
6450 Buffer->All.HomeDirectory.Buffer,
6451 Buffer->All.HomeDirectory.MaximumLength);
6452 if (!NT_SUCCESS(Status))
6453 goto done;
6454 }
6455
6456 if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
6457 {
6458 Status = SampSetObjectAttribute(UserObject,
6459 L"HomeDirectoryDrive",
6460 REG_SZ,
6461 Buffer->All.HomeDirectoryDrive.Buffer,
6462 Buffer->All.HomeDirectoryDrive.MaximumLength);
6463 if (!NT_SUCCESS(Status))
6464 goto done;
6465 }
6466
6467 if (WhichFields & USER_ALL_SCRIPTPATH)
6468 {
6469 Status = SampSetObjectAttribute(UserObject,
6470 L"ScriptPath",
6471 REG_SZ,
6472 Buffer->All.ScriptPath.Buffer,
6473 Buffer->All.ScriptPath.MaximumLength);
6474 if (!NT_SUCCESS(Status))
6475 goto done;
6476 }
6477
6478 if (WhichFields & USER_ALL_PROFILEPATH)
6479 {
6480 Status = SampSetObjectAttribute(UserObject,
6481 L"ProfilePath",
6482 REG_SZ,
6483 Buffer->All.ProfilePath.Buffer,
6484 Buffer->All.ProfilePath.MaximumLength);
6485 if (!NT_SUCCESS(Status))
6486 goto done;
6487 }
6488
6489 if (WhichFields & USER_ALL_WORKSTATIONS)
6490 {
6491 Status = SampSetObjectAttribute(UserObject,
6492 L"WorkStations",
6493 REG_SZ,
6494 Buffer->All.WorkStations.Buffer,
6495 Buffer->All.WorkStations.MaximumLength);
6496 if (!NT_SUCCESS(Status))
6497 goto done;
6498 }
6499
6500 if (WhichFields & USER_ALL_PARAMETERS)
6501 {
6502 Status = SampSetObjectAttribute(UserObject,
6503 L"Parameters",
6504 REG_SZ,
6505 Buffer->All.Parameters.Buffer,
6506 Buffer->All.Parameters.MaximumLength);
6507 }
6508
6509 if (WhichFields & (USER_ALL_PRIMARYGROUPID |
6510 USER_ALL_ACCOUNTEXPIRES |
6511 USER_ALL_USERACCOUNTCONTROL |
6512 USER_ALL_COUNTRYCODE |
6513 USER_ALL_CODEPAGE))
6514 {
6515 Length = sizeof(SAM_USER_FIXED_DATA);
6516 Status = SampGetObjectAttribute(UserObject,
6517 L"F",
6518 NULL,
6519 (PVOID)&FixedData,
6520 &Length);
6521 if (!NT_SUCCESS(Status))
6522 goto done;
6523
6524 if (WhichFields & USER_ALL_PRIMARYGROUPID)
6525 FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
6526
6527 if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
6528 {
6529 FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
6530 FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
6531 }
6532
6533 if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
6534 FixedData.UserAccountControl = Buffer->All.UserAccountControl;
6535
6536 if (WhichFields & USER_ALL_COUNTRYCODE)
6537 FixedData.CountryCode = Buffer->Preferences.CountryCode;
6538
6539 if (WhichFields & USER_ALL_CODEPAGE)
6540 FixedData.CodePage = Buffer->Preferences.CodePage;
6541
6542 Status = SampSetObjectAttribute(UserObject,
6543 L"F",
6544 REG_BINARY,
6545 &FixedData,
6546 Length);
6547 if (!NT_SUCCESS(Status))
6548 goto done;
6549 }
6550
6551 /*
6552 FIXME:
6553 USER_ALL_LOGONHOURS
6554 USER_ALL_NTPASSWORDPRESENT
6555 USER_ALL_LMPASSWORDPRESENT
6556 USER_ALL_PASSWORDEXPIRED
6557 */
6558
6559 done:
6560
6561 return Status;
6562 }
6563
6564
6565 /* Function 37 */
6566 NTSTATUS
6567 NTAPI
6568 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
6569 IN USER_INFORMATION_CLASS UserInformationClass,
6570 IN PSAMPR_USER_INFO_BUFFER Buffer)
6571 {
6572 PSAM_DB_OBJECT UserObject;
6573 ACCESS_MASK DesiredAccess;
6574 NTSTATUS Status;
6575
6576 TRACE("SamrSetInformationUser(%p %lu %p)\n",
6577 UserHandle, UserInformationClass, Buffer);
6578
6579 switch (UserInformationClass)
6580 {
6581 case UserLogonHoursInformation:
6582 case UserNameInformation:
6583 case UserAccountNameInformation:
6584 case UserFullNameInformation:
6585 case UserPrimaryGroupInformation:
6586 case UserHomeInformation:
6587 case UserScriptInformation:
6588 case UserProfileInformation:
6589 case UserAdminCommentInformation:
6590 case UserWorkStationsInformation:
6591 case UserControlInformation:
6592 case UserExpiresInformation:
6593 case UserParametersInformation:
6594 DesiredAccess = USER_WRITE_ACCOUNT;
6595 break;
6596
6597 case UserGeneralInformation:
6598 DesiredAccess = USER_WRITE_ACCOUNT |
6599 USER_WRITE_PREFERENCES;
6600 break;
6601
6602 case UserPreferencesInformation:
6603 DesiredAccess = USER_WRITE_PREFERENCES;
6604 break;
6605
6606 case UserSetPasswordInformation:
6607 DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
6608 break;
6609
6610 case UserAllInformation:
6611 DesiredAccess = 0; /* FIXME */
6612 break;
6613
6614 default:
6615 return STATUS_INVALID_INFO_CLASS;
6616 }
6617
6618 /* Validate the domain handle */
6619 Status = SampValidateDbObject(UserHandle,
6620 SamDbUserObject,
6621 DesiredAccess,
6622 &UserObject);
6623 if (!NT_SUCCESS(Status))
6624 {
6625 TRACE("failed with status 0x%08lx\n", Status);
6626 return Status;
6627 }
6628
6629 switch (UserInformationClass)
6630 {
6631 case UserGeneralInformation:
6632 Status = SampSetUserGeneral(UserObject,
6633 Buffer);
6634 break;
6635
6636 case UserPreferencesInformation:
6637 Status = SampSetUserPreferences(UserObject,
6638 Buffer);
6639 break;
6640 /*
6641 case UserLogonHoursInformation:
6642 Status = SampSetUserLogonHours(UserObject,
6643 Buffer);
6644 break;
6645 */
6646 case UserNameInformation:
6647 Status = SampSetObjectAttribute(UserObject,
6648 L"Name",
6649 REG_SZ,
6650 Buffer->Name.UserName.Buffer,
6651 Buffer->Name.UserName.MaximumLength);
6652 if (!NT_SUCCESS(Status))
6653 break;
6654
6655 Status = SampSetObjectAttribute(UserObject,
6656 L"FullName",
6657 REG_SZ,
6658 Buffer->Name.FullName.Buffer,
6659 Buffer->Name.FullName.MaximumLength);
6660 break;
6661
6662 case UserAccountNameInformation:
6663 Status = SampSetObjectAttribute(UserObject,
6664 L"Name",
6665 REG_SZ,
6666 Buffer->AccountName.UserName.Buffer,
6667 Buffer->AccountName.UserName.MaximumLength);
6668 break;
6669
6670 case UserFullNameInformation:
6671 Status = SampSetObjectAttribute(UserObject,
6672 L"FullName",
6673 REG_SZ,
6674 Buffer->FullName.FullName.Buffer,
6675 Buffer->FullName.FullName.MaximumLength);
6676 break;
6677
6678 case UserPrimaryGroupInformation:
6679 Status = SampSetUserPrimaryGroup(UserObject,
6680 Buffer);
6681 break;
6682
6683 case UserHomeInformation:
6684 Status = SampSetObjectAttribute(UserObject,
6685 L"HomeDirectory",
6686 REG_SZ,
6687 Buffer->Home.HomeDirectory.Buffer,
6688 Buffer->Home.HomeDirectory.MaximumLength);
6689 if (!NT_SUCCESS(Status))
6690 break;
6691
6692 Status = SampSetObjectAttribute(UserObject,
6693 L"HomeDirectoryDrive",
6694 REG_SZ,
6695 Buffer->Home.HomeDirectoryDrive.Buffer,
6696 Buffer->Home.HomeDirectoryDrive.MaximumLength);
6697 break;
6698
6699 case UserScriptInformation:
6700 Status = SampSetObjectAttribute(UserObject,
6701 L"ScriptPath",
6702 REG_SZ,
6703 Buffer->Script.ScriptPath.Buffer,
6704 Buffer->Script.ScriptPath.MaximumLength);
6705 break;
6706
6707 case UserProfileInformation:
6708 Status = SampSetObjectAttribute(UserObject,
6709 L"ProfilePath",
6710 REG_SZ,
6711 Buffer->Profile.ProfilePath.Buffer,
6712 Buffer->Profile.ProfilePath.MaximumLength);
6713 break;
6714
6715 case UserAdminCommentInformation:
6716 Status = SampSetObjectAttribute(UserObject,
6717 L"AdminComment",
6718 REG_SZ,
6719 Buffer->AdminComment.AdminComment.Buffer,
6720 Buffer->AdminComment.AdminComment.MaximumLength);
6721 break;
6722
6723 case UserWorkStationsInformation:
6724 Status = SampSetObjectAttribute(UserObject,
6725 L"WorkStations",
6726 REG_SZ,
6727 Buffer->WorkStations.WorkStations.Buffer,
6728 Buffer->WorkStations.WorkStations.MaximumLength);
6729 break;
6730
6731 case UserSetPasswordInformation:
6732 TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
6733 TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
6734
6735 Status = SampSetObjectAttribute(UserObject,
6736 L"Password",
6737 REG_SZ,
6738 Buffer->SetPassword.Password.Buffer,
6739 Buffer->SetPassword.Password.MaximumLength);
6740 break;
6741
6742 case UserControlInformation:
6743 Status = SampSetUserControl(UserObject,
6744 Buffer);
6745 break;
6746
6747 case UserExpiresInformation:
6748 Status = SampSetUserExpires(UserObject,
6749 Buffer);
6750 break;
6751
6752 // case UserInternal1Information:
6753
6754 case UserParametersInformation:
6755 Status = SampSetObjectAttribute(UserObject,
6756 L"Parameters",
6757 REG_SZ,
6758 Buffer->Parameters.Parameters.Buffer,
6759 Buffer->Parameters.Parameters.MaximumLength);
6760 break;
6761
6762 case UserAllInformation:
6763 Status = SampSetUserAll(UserObject,
6764 Buffer);
6765 break;
6766
6767 // case UserInternal4Information:
6768 // case UserInternal5Information:
6769 // case UserInternal4InformationNew:
6770 // case UserInternal5InformationNew:
6771
6772 default:
6773 Status = STATUS_INVALID_INFO_CLASS;
6774 }
6775
6776 return Status;
6777 }
6778
6779
6780 /* Function 38 */
6781 NTSTATUS
6782 NTAPI
6783 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
6784 IN unsigned char LmPresent,
6785 IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
6786 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
6787 IN unsigned char NtPresent,
6788 IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
6789 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
6790 IN unsigned char NtCrossEncryptionPresent,
6791 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
6792 IN unsigned char LmCrossEncryptionPresent,
6793 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
6794 {
6795 UNIMPLEMENTED;
6796 return STATUS_NOT_IMPLEMENTED;
6797 }
6798
6799
6800 /* Function 39 */
6801 NTSTATUS
6802 NTAPI
6803 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
6804 OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
6805 {
6806 PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
6807 PSAM_DB_OBJECT UserObject;
6808 ULONG Length = 0;
6809 NTSTATUS Status;
6810
6811 TRACE("SamrGetGroupsForUser(%p %p)\n",
6812 UserHandle, Groups);
6813
6814 /* Validate the domain handle */
6815 Status = SampValidateDbObject(UserHandle,
6816 SamDbUserObject,
6817 USER_LIST_GROUPS,
6818 &UserObject);
6819 if (!NT_SUCCESS(Status))
6820 {
6821 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
6822 return Status;
6823 }
6824
6825 /* Allocate the groups buffer */
6826 GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
6827 if (GroupsBuffer == NULL)
6828 return STATUS_INSUFFICIENT_RESOURCES;
6829
6830 /*
6831 * Get the size of the Groups attribute.
6832 * Do not check the status code because in case of an error
6833 * Length will be 0. And that is all we need.
6834 */
6835 SampGetObjectAttribute(UserObject,
6836 L"Groups",
6837 NULL,
6838 NULL,
6839 &Length);
6840
6841 /* If there is no Groups attribute, return a groups buffer without an array */
6842 if (Length == 0)
6843 {
6844 GroupsBuffer->MembershipCount = 0;
6845 GroupsBuffer->Groups = NULL;
6846
6847 *Groups = GroupsBuffer;
6848
6849 return STATUS_SUCCESS;
6850 }
6851
6852 /* Allocate a buffer for the Groups attribute */
6853 GroupsBuffer->Groups = midl_user_allocate(Length);
6854 if (GroupsBuffer->Groups == NULL)
6855 {
6856 Status = STATUS_INSUFFICIENT_RESOURCES;
6857 goto done;
6858 }
6859
6860 /* Retrieve the Grous attribute */
6861 Status = SampGetObjectAttribute(UserObject,
6862 L"Groups",
6863 NULL,
6864 GroupsBuffer->Groups,
6865 &Length);
6866 if (!NT_SUCCESS(Status))
6867 {
6868 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
6869 goto done;
6870 }
6871
6872 /* Calculate the membership count */
6873 GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
6874
6875 /* Return the groups buffer to the caller */
6876 *Groups = GroupsBuffer;
6877
6878 done:
6879 if (!NT_SUCCESS(Status))
6880 {
6881 if (GroupsBuffer != NULL)
6882 {
6883 if (GroupsBuffer->Groups != NULL)
6884 midl_user_free(GroupsBuffer->Groups);
6885
6886 midl_user_free(GroupsBuffer);
6887 }
6888 }
6889
6890 return Status;
6891 }
6892
6893
6894 /* Function 40 */
6895 NTSTATUS
6896 NTAPI
6897 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
6898 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
6899 IN unsigned long Index,
6900 IN unsigned long EntryCount,
6901 IN unsigned long PreferredMaximumLength,
6902 OUT unsigned long *TotalAvailable,
6903 OUT unsigned long *TotalReturned,
6904 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
6905 {
6906 UNIMPLEMENTED;
6907 return STATUS_NOT_IMPLEMENTED;
6908 }
6909
6910 /* Function 41 */
6911 NTSTATUS
6912 NTAPI
6913 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
6914 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
6915 IN PRPC_UNICODE_STRING Prefix,
6916 OUT unsigned long *Index)
6917 {
6918 UNIMPLEMENTED;
6919 return STATUS_NOT_IMPLEMENTED;
6920 }
6921
6922 /* Function 42 */
6923 NTSTATUS
6924 NTAPI
6925 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
6926 {
6927 UNIMPLEMENTED;
6928 return STATUS_NOT_IMPLEMENTED;
6929 }
6930
6931 /* Function 43 */
6932 NTSTATUS
6933 NTAPI
6934 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
6935 {
6936 UNIMPLEMENTED;
6937 return STATUS_NOT_IMPLEMENTED;
6938 }
6939
6940 /* Function 44 */
6941 NTSTATUS
6942 NTAPI
6943 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
6944 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
6945 {
6946 UNIMPLEMENTED;
6947 return STATUS_NOT_IMPLEMENTED;
6948 }
6949
6950 /* Function 45 */
6951 NTSTATUS
6952 NTAPI
6953 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
6954 IN PRPC_SID MemberSid)
6955 {
6956 UNIMPLEMENTED;
6957 return STATUS_NOT_IMPLEMENTED;
6958 }
6959
6960 /* Function 46 */
6961 NTSTATUS
6962 NTAPI
6963 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
6964 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
6965 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
6966 {
6967 UNIMPLEMENTED;
6968 return STATUS_NOT_IMPLEMENTED;
6969 }
6970
6971 /* Function 47 */
6972 NTSTATUS
6973 NTAPI
6974 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
6975 IN USER_INFORMATION_CLASS UserInformationClass,
6976 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
6977 {
6978 UNIMPLEMENTED;
6979 return STATUS_NOT_IMPLEMENTED;
6980 }
6981
6982 /* Function 48 */
6983 NTSTATUS
6984 NTAPI
6985 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
6986 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
6987 IN unsigned long Index,
6988 IN unsigned long EntryCount,
6989 IN unsigned long PreferredMaximumLength,
6990 OUT unsigned long *TotalAvailable,
6991 OUT unsigned long *TotalReturned,
6992 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
6993 {
6994 UNIMPLEMENTED;
6995 return STATUS_NOT_IMPLEMENTED;
6996 }
6997
6998 /* Function 49 */
6999 NTSTATUS
7000 NTAPI
7001 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
7002 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7003 IN PRPC_UNICODE_STRING Prefix,
7004 OUT unsigned long *Index)
7005 {
7006 UNIMPLEMENTED;
7007 return STATUS_NOT_IMPLEMENTED;
7008 }
7009
7010
7011 /* Function 50 */
7012 NTSTATUS
7013 NTAPI
7014 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
7015 IN PRPC_UNICODE_STRING Name,
7016 IN unsigned long AccountType,
7017 IN ACCESS_MASK DesiredAccess,
7018 OUT SAMPR_HANDLE *UserHandle,
7019 OUT unsigned long *GrantedAccess,
7020 OUT unsigned long *RelativeId)
7021 {
7022 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
7023 SAM_DOMAIN_FIXED_DATA FixedDomainData;
7024 SAM_USER_FIXED_DATA FixedUserData;
7025 PSAM_DB_OBJECT DomainObject;
7026 PSAM_DB_OBJECT UserObject;
7027 ULONG ulSize;
7028 ULONG ulRid;
7029 WCHAR szRid[9];
7030 NTSTATUS Status;
7031
7032 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
7033 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
7034
7035 if (Name == NULL ||
7036 Name->Length == 0 ||
7037 Name->Buffer == NULL ||
7038 UserHandle == NULL ||
7039 RelativeId == NULL)
7040 return STATUS_INVALID_PARAMETER;
7041
7042 /* Check for valid account type */
7043 if (AccountType != USER_NORMAL_ACCOUNT &&
7044 AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
7045 AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
7046 AccountType != USER_SERVER_TRUST_ACCOUNT &&
7047 AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
7048 return STATUS_INVALID_PARAMETER;
7049
7050 /* Map generic access rights */
7051 RtlMapGenericMask(&DesiredAccess,
7052 &UserMapping);
7053
7054 /* Validate the domain handle */
7055 Status = SampValidateDbObject(DomainHandle,
7056 SamDbDomainObject,
7057 DOMAIN_CREATE_USER,
7058 &DomainObject);
7059 if (!NT_SUCCESS(Status))
7060 {
7061 TRACE("failed with status 0x%08lx\n", Status);
7062 return Status;
7063 }
7064
7065 /* Check if the user name already exists in the domain */
7066 Status = SampCheckAccountNameInDomain(DomainObject,
7067 Name->Buffer);
7068 if (!NT_SUCCESS(Status))
7069 {
7070 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7071 Name->Buffer, Status);
7072 return Status;
7073 }
7074
7075 /* Get the fixed domain attributes */
7076 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
7077 Status = SampGetObjectAttribute(DomainObject,
7078 L"F",
7079 NULL,
7080 (PVOID)&FixedDomainData,
7081 &ulSize);
7082 if (!NT_SUCCESS(Status))
7083 {
7084 TRACE("failed with status 0x%08lx\n", Status);
7085 return Status;
7086 }
7087
7088 /* Increment the NextRid attribute */
7089 ulRid = FixedDomainData.NextRid;
7090 FixedDomainData.NextRid++;
7091
7092 /* Store the fixed domain attributes */
7093 Status = SampSetObjectAttribute(DomainObject,
7094 L"F",
7095 REG_BINARY,
7096 &FixedDomainData,
7097 ulSize);
7098 if (!NT_SUCCESS(Status))
7099 {
7100 TRACE("failed with status 0x%08lx\n", Status);
7101 return Status;
7102 }
7103
7104 TRACE("RID: %lx\n", ulRid);
7105
7106 /* Convert the RID into a string (hex) */
7107 swprintf(szRid, L"%08lX", ulRid);
7108
7109 /* Create the user object */
7110 Status = SampCreateDbObject(DomainObject,
7111 L"Users",
7112 szRid,
7113 ulRid,
7114 SamDbUserObject,
7115 DesiredAccess,
7116 &UserObject);
7117 if (!NT_SUCCESS(Status))
7118 {
7119 TRACE("failed with status 0x%08lx\n", Status);
7120 return Status;
7121 }
7122
7123 /* Add the account name for the user object */
7124 Status = SampSetAccountNameInDomain(DomainObject,
7125 L"Users",
7126 Name->Buffer,
7127 ulRid);
7128 if (!NT_SUCCESS(Status))
7129 {
7130 TRACE("failed with status 0x%08lx\n", Status);
7131 return Status;
7132 }
7133
7134 /* Initialize fixed user data */
7135 memset(&FixedUserData, 0, sizeof(SAM_USER_FIXED_DATA));
7136 FixedUserData.Version = 1;
7137 FixedUserData.LastLogon.QuadPart = 0;
7138 FixedUserData.LastLogoff.QuadPart = 0;
7139 FixedUserData.PasswordLastSet.QuadPart = 0;
7140 FixedUserData.AccountExpires.LowPart = MAXULONG;
7141 FixedUserData.AccountExpires.HighPart = MAXLONG;
7142 FixedUserData.LastBadPasswordTime.QuadPart = 0;
7143 FixedUserData.UserId = ulRid;
7144 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
7145 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
7146 USER_PASSWORD_NOT_REQUIRED |
7147 AccountType;
7148
7149 /* Set fixed user data attribute */
7150 Status = SampSetObjectAttribute(UserObject,
7151 L"F",
7152 REG_BINARY,
7153 (LPVOID)&FixedUserData,
7154 sizeof(SAM_USER_FIXED_DATA));
7155 if (!NT_SUCCESS(Status))
7156 {
7157 TRACE("failed with status 0x%08lx\n", Status);
7158 return Status;
7159 }
7160
7161 /* Set the Name attribute */
7162 Status = SampSetObjectAttribute(UserObject,
7163 L"Name",
7164 REG_SZ,
7165 (LPVOID)Name->Buffer,
7166 Name->MaximumLength);
7167 if (!NT_SUCCESS(Status))
7168 {
7169 TRACE("failed with status 0x%08lx\n", Status);
7170 return Status;
7171 }
7172
7173 /* Set the FullName attribute */
7174 Status = SampSetObjectAttribute(UserObject,
7175 L"FullName",
7176 REG_SZ,
7177 EmptyString.Buffer,
7178 EmptyString.MaximumLength);
7179 if (!NT_SUCCESS(Status))
7180 {
7181 TRACE("failed with status 0x%08lx\n", Status);
7182 return Status;
7183 }
7184
7185 /* Set the HomeDirectory attribute */
7186 Status = SampSetObjectAttribute(UserObject,
7187 L"HomeDirectory",
7188 REG_SZ,
7189 EmptyString.Buffer,
7190 EmptyString.MaximumLength);
7191 if (!NT_SUCCESS(Status))
7192 {
7193 TRACE("failed with status 0x%08lx\n", Status);
7194 return Status;
7195 }
7196
7197 /* Set the HomeDirectoryDrive attribute */
7198 Status = SampSetObjectAttribute(UserObject,
7199 L"HomeDirectoryDrive",
7200 REG_SZ,
7201 EmptyString.Buffer,
7202 EmptyString.MaximumLength);
7203 if (!NT_SUCCESS(Status))
7204 {
7205 TRACE("failed with status 0x%08lx\n", Status);
7206 return Status;
7207 }
7208
7209 /* Set the ScriptPath attribute */
7210 Status = SampSetObjectAttribute(UserObject,
7211 L"ScriptPath",
7212 REG_SZ,
7213 EmptyString.Buffer,
7214 EmptyString.MaximumLength);
7215 if (!NT_SUCCESS(Status))
7216 {
7217 TRACE("failed with status 0x%08lx\n", Status);
7218 return Status;
7219 }
7220
7221 /* Set the ProfilePath attribute */
7222 Status = SampSetObjectAttribute(UserObject,
7223 L"ProfilePath",
7224 REG_SZ,
7225 EmptyString.Buffer,
7226 EmptyString.MaximumLength);
7227 if (!NT_SUCCESS(Status))
7228 {
7229 TRACE("failed with status 0x%08lx\n", Status);
7230 return Status;
7231 }
7232
7233 /* Set the AdminComment attribute */
7234 Status = SampSetObjectAttribute(UserObject,
7235 L"AdminComment",
7236 REG_SZ,
7237 EmptyString.Buffer,
7238 EmptyString.MaximumLength);
7239 if (!NT_SUCCESS(Status))
7240 {
7241 TRACE("failed with status 0x%08lx\n", Status);
7242 return Status;
7243 }
7244
7245 /* Set the UserComment attribute */
7246 Status = SampSetObjectAttribute(UserObject,
7247 L"UserComment",
7248 REG_SZ,
7249 EmptyString.Buffer,
7250 EmptyString.MaximumLength);
7251 if (!NT_SUCCESS(Status))
7252 {
7253 TRACE("failed with status 0x%08lx\n", Status);
7254 return Status;
7255 }
7256
7257 /* Set the WorkStations attribute */
7258 Status = SampSetObjectAttribute(UserObject,
7259 L"WorkStations",
7260 REG_SZ,
7261 EmptyString.Buffer,
7262 EmptyString.MaximumLength);
7263 if (!NT_SUCCESS(Status))
7264 {
7265 TRACE("failed with status 0x%08lx\n", Status);
7266 return Status;
7267 }
7268
7269 /* FIXME: Set default user attributes */
7270
7271 if (NT_SUCCESS(Status))
7272 {
7273 *UserHandle = (SAMPR_HANDLE)UserObject;
7274 *RelativeId = ulRid;
7275 *GrantedAccess = UserObject->Access;
7276 }
7277
7278 TRACE("returns with status 0x%08lx\n", Status);
7279
7280 return Status;
7281 }
7282
7283
7284 /* Function 51 */
7285 NTSTATUS
7286 NTAPI
7287 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
7288 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7289 IN unsigned long Index,
7290 IN unsigned long EntryCount,
7291 IN unsigned long PreferredMaximumLength,
7292 OUT unsigned long *TotalAvailable,
7293 OUT unsigned long *TotalReturned,
7294 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
7295 {
7296 UNIMPLEMENTED;
7297 return STATUS_NOT_IMPLEMENTED;
7298 }
7299
7300
7301 /* Function 52 */
7302 NTSTATUS
7303 NTAPI
7304 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
7305 IN PSAMPR_PSID_ARRAY MembersBuffer)
7306 {
7307 ULONG i;
7308 NTSTATUS Status = STATUS_SUCCESS;
7309
7310 TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
7311 AliasHandle, MembersBuffer);
7312
7313 for (i = 0; i < MembersBuffer->Count; i++)
7314 {
7315 Status = SamrAddMemberToAlias(AliasHandle,
7316 ((PSID *)MembersBuffer->Sids)[i]);
7317
7318 if (Status == STATUS_MEMBER_IN_ALIAS)
7319 Status = STATUS_SUCCESS;
7320
7321 if (!NT_SUCCESS(Status))
7322 break;
7323 }
7324
7325 return Status;
7326 }
7327
7328
7329 /* Function 53 */
7330 NTSTATUS
7331 NTAPI
7332 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
7333 IN PSAMPR_PSID_ARRAY MembersBuffer)
7334 {
7335 ULONG i;
7336 NTSTATUS Status = STATUS_SUCCESS;
7337
7338 TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
7339 AliasHandle, MembersBuffer);
7340
7341 for (i = 0; i < MembersBuffer->Count; i++)
7342 {
7343 Status = SamrRemoveMemberFromAlias(AliasHandle,
7344 ((PSID *)MembersBuffer->Sids)[i]);
7345
7346 if (Status == STATUS_MEMBER_IN_ALIAS)
7347 Status = STATUS_SUCCESS;
7348
7349 if (!NT_SUCCESS(Status))
7350 break;
7351 }
7352
7353 return Status;
7354 }
7355
7356
7357 /* Function 54 */
7358 NTSTATUS
7359 NTAPI
7360 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
7361 IN PRPC_STRING ServerName,
7362 IN PRPC_STRING UserName,
7363 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
7364 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
7365 {
7366 UNIMPLEMENTED;
7367 return STATUS_NOT_IMPLEMENTED;
7368 }
7369
7370 /* Function 55 */
7371 NTSTATUS
7372 NTAPI
7373 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
7374 IN PRPC_UNICODE_STRING ServerName,
7375 IN PRPC_UNICODE_STRING UserName,
7376 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
7377 IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
7378 IN unsigned char LmPresent,
7379 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
7380 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
7381 {
7382 UNIMPLEMENTED;
7383 return STATUS_NOT_IMPLEMENTED;
7384 }
7385
7386 /* Function 56 */
7387 NTSTATUS
7388 NTAPI
7389 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
7390 IN PRPC_UNICODE_STRING Unused,
7391 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
7392 {
7393 UNIMPLEMENTED;
7394 return STATUS_NOT_IMPLEMENTED;
7395 }
7396
7397 /* Function 57 */
7398 NTSTATUS
7399 NTAPI
7400 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
7401 OUT SAMPR_HANDLE *ServerHandle,
7402 IN ACCESS_MASK DesiredAccess)
7403 {
7404 UNIMPLEMENTED;
7405 return STATUS_NOT_IMPLEMENTED;
7406 }
7407
7408
7409 /* Function 58 */
7410 NTSTATUS
7411 NTAPI
7412 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
7413 IN USER_INFORMATION_CLASS UserInformationClass,
7414 IN PSAMPR_USER_INFO_BUFFER Buffer)
7415 {
7416 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
7417
7418 return SamrSetInformationUser(UserHandle,
7419 UserInformationClass,
7420 Buffer);
7421 }
7422
7423
7424 /* Function 59 */
7425 NTSTATUS
7426 NTAPI
7427 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
7428 {
7429 UNIMPLEMENTED;
7430 return STATUS_NOT_IMPLEMENTED;
7431 }
7432
7433 /* Function 60 */
7434 NTSTATUS
7435 NTAPI
7436 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
7437 {
7438 UNIMPLEMENTED;
7439 return STATUS_NOT_IMPLEMENTED;
7440 }
7441
7442 /* Function 61 */
7443 NTSTATUS
7444 NTAPI
7445 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
7446 {
7447 UNIMPLEMENTED;
7448 return STATUS_NOT_IMPLEMENTED;
7449 }
7450
7451 /* Function 62 */
7452 NTSTATUS
7453 NTAPI
7454 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
7455 OUT SAMPR_HANDLE *ServerHandle,
7456 IN unsigned long ClientRevision,
7457 IN ACCESS_MASK DesiredAccess)
7458 {
7459 UNIMPLEMENTED;
7460 return STATUS_NOT_IMPLEMENTED;
7461 }
7462
7463 /* Function 63 */
7464 NTSTATUS
7465 NTAPI
7466 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
7467 {
7468 UNIMPLEMENTED;
7469 return STATUS_NOT_IMPLEMENTED;
7470 }
7471
7472 /* Function 64 */
7473 NTSTATUS
7474 NTAPI
7475 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
7476 IN ACCESS_MASK DesiredAccess,
7477 IN unsigned long InVersion,
7478 IN SAMPR_REVISION_INFO *InRevisionInfo,
7479 OUT unsigned long *OutVersion,
7480 OUT SAMPR_REVISION_INFO *OutRevisionInfo,
7481 OUT SAMPR_HANDLE *ServerHandle)
7482 {
7483 UNIMPLEMENTED;
7484 return STATUS_NOT_IMPLEMENTED;
7485 }
7486
7487 /* Function 65 */
7488 NTSTATUS
7489 NTAPI
7490 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
7491 IN unsigned long Rid,
7492 OUT PRPC_SID *Sid)
7493 {
7494 UNIMPLEMENTED;
7495 return STATUS_NOT_IMPLEMENTED;
7496 }
7497
7498 /* Function 66 */
7499 NTSTATUS
7500 NTAPI
7501 SamrSetDSRMPassword(IN handle_t BindingHandle,
7502 IN PRPC_UNICODE_STRING Unused,
7503 IN unsigned long UserId,
7504 IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
7505 {
7506 UNIMPLEMENTED;
7507 return STATUS_NOT_IMPLEMENTED;
7508 }
7509
7510 /* Function 67 */
7511 NTSTATUS
7512 NTAPI
7513 SamrValidatePassword(IN handle_t Handle,
7514 IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
7515 IN PSAM_VALIDATE_INPUT_ARG InputArg,
7516 OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
7517 {
7518 UNIMPLEMENTED;
7519 return STATUS_NOT_IMPLEMENTED;
7520 }
7521
7522 /* EOF */