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