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