2f3729d3eb3306e6297b791af6308ff14a3d8a09
[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"Description",
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 goto done;
4183
4184 InfoBuffer->General.Attributes = FixedData.Attributes;
4185
4186 Status = SampGetObjectAttribute(GroupObject,
4187 L"Members",
4188 NULL,
4189 NULL,
4190 &MembersLength);
4191 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4192 goto done;
4193
4194 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4195 InfoBuffer->General.MemberCount = 0;
4196 else
4197 InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4198
4199 *Buffer = InfoBuffer;
4200
4201 done:
4202 if (!NT_SUCCESS(Status))
4203 {
4204 if (InfoBuffer != NULL)
4205 {
4206 if (InfoBuffer->General.Name.Buffer != NULL)
4207 midl_user_free(InfoBuffer->General.Name.Buffer);
4208
4209 if (InfoBuffer->General.AdminComment.Buffer != NULL)
4210 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4211
4212 midl_user_free(InfoBuffer);
4213 }
4214 }
4215
4216 return Status;
4217 }
4218
4219
4220 static NTSTATUS
4221 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
4222 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4223 {
4224 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4225 NTSTATUS Status;
4226
4227 *Buffer = NULL;
4228
4229 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4230 if (InfoBuffer == NULL)
4231 return STATUS_INSUFFICIENT_RESOURCES;
4232
4233 Status = SampGetObjectAttributeString(GroupObject,
4234 L"Name",
4235 &InfoBuffer->Name.Name);
4236 if (!NT_SUCCESS(Status))
4237 {
4238 TRACE("Status 0x%08lx\n", Status);
4239 goto done;
4240 }
4241
4242 *Buffer = InfoBuffer;
4243
4244 done:
4245 if (!NT_SUCCESS(Status))
4246 {
4247 if (InfoBuffer != NULL)
4248 {
4249 if (InfoBuffer->Name.Name.Buffer != NULL)
4250 midl_user_free(InfoBuffer->Name.Name.Buffer);
4251
4252 midl_user_free(InfoBuffer);
4253 }
4254 }
4255
4256 return Status;
4257 }
4258
4259
4260 static NTSTATUS
4261 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
4262 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4263 {
4264 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4265 SAM_GROUP_FIXED_DATA FixedData;
4266 ULONG Length = 0;
4267 NTSTATUS Status;
4268
4269 *Buffer = NULL;
4270
4271 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4272 if (InfoBuffer == NULL)
4273 return STATUS_INSUFFICIENT_RESOURCES;
4274
4275 Length = sizeof(SAM_GROUP_FIXED_DATA);
4276 Status = SampGetObjectAttribute(GroupObject,
4277 L"F",
4278 NULL,
4279 (PVOID)&FixedData,
4280 &Length);
4281 if (!NT_SUCCESS(Status))
4282 goto done;
4283
4284 InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4285
4286 *Buffer = InfoBuffer;
4287
4288 done:
4289 if (!NT_SUCCESS(Status))
4290 {
4291 if (InfoBuffer != NULL)
4292 {
4293 midl_user_free(InfoBuffer);
4294 }
4295 }
4296
4297 return Status;
4298 }
4299
4300
4301 static NTSTATUS
4302 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
4303 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4304 {
4305 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4306 NTSTATUS Status;
4307
4308 *Buffer = NULL;
4309
4310 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4311 if (InfoBuffer == NULL)
4312 return STATUS_INSUFFICIENT_RESOURCES;
4313
4314 Status = SampGetObjectAttributeString(GroupObject,
4315 L"Description",
4316 &InfoBuffer->AdminComment.AdminComment);
4317 if (!NT_SUCCESS(Status))
4318 {
4319 TRACE("Status 0x%08lx\n", Status);
4320 goto done;
4321 }
4322
4323 *Buffer = InfoBuffer;
4324
4325 done:
4326 if (!NT_SUCCESS(Status))
4327 {
4328 if (InfoBuffer != NULL)
4329 {
4330 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4331 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4332
4333 midl_user_free(InfoBuffer);
4334 }
4335 }
4336
4337 return Status;
4338 }
4339
4340
4341 /* Function 20 */
4342 NTSTATUS
4343 NTAPI
4344 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
4345 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4346 OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
4347 {
4348 PSAM_DB_OBJECT GroupObject;
4349 NTSTATUS Status;
4350
4351 TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4352 GroupHandle, GroupInformationClass, Buffer);
4353
4354 RtlAcquireResourceShared(&SampResource,
4355 TRUE);
4356
4357 /* Validate the group handle */
4358 Status = SampValidateDbObject(GroupHandle,
4359 SamDbGroupObject,
4360 GROUP_READ_INFORMATION,
4361 &GroupObject);
4362 if (!NT_SUCCESS(Status))
4363 goto done;
4364
4365 switch (GroupInformationClass)
4366 {
4367 case GroupGeneralInformation:
4368 Status = SampQueryGroupGeneral(GroupObject,
4369 Buffer);
4370 break;
4371
4372 case GroupNameInformation:
4373 Status = SampQueryGroupName(GroupObject,
4374 Buffer);
4375 break;
4376
4377 case GroupAttributeInformation:
4378 Status = SampQueryGroupAttribute(GroupObject,
4379 Buffer);
4380 break;
4381
4382 case GroupAdminCommentInformation:
4383 Status = SampQueryGroupAdminComment(GroupObject,
4384 Buffer);
4385 break;
4386
4387 default:
4388 Status = STATUS_INVALID_INFO_CLASS;
4389 break;
4390 }
4391
4392 done:
4393 RtlReleaseResource(&SampResource);
4394
4395 return Status;
4396 }
4397
4398
4399 static NTSTATUS
4400 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
4401 PSAMPR_GROUP_INFO_BUFFER Buffer)
4402 {
4403 UNICODE_STRING OldGroupName = {0, 0, NULL};
4404 UNICODE_STRING NewGroupName;
4405 NTSTATUS Status;
4406
4407 Status = SampGetObjectAttributeString(GroupObject,
4408 L"Name",
4409 (PRPC_UNICODE_STRING)&OldGroupName);
4410 if (!NT_SUCCESS(Status))
4411 {
4412 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4413 goto done;
4414 }
4415
4416 /* Check the new account name */
4417 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4418 if (!NT_SUCCESS(Status))
4419 {
4420 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4421 return Status;
4422 }
4423
4424 NewGroupName.Length = Buffer->Name.Name.Length;
4425 NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4426 NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4427
4428 if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4429 {
4430 Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
4431 NewGroupName.Buffer);
4432 if (!NT_SUCCESS(Status))
4433 {
4434 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4435 NewGroupName.Buffer, Status);
4436 goto done;
4437 }
4438 }
4439
4440 Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
4441 L"Groups",
4442 NewGroupName.Buffer,
4443 GroupObject->RelativeId);
4444 if (!NT_SUCCESS(Status))
4445 {
4446 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4447 goto done;
4448 }
4449
4450 Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4451 L"Groups",
4452 OldGroupName.Buffer);
4453 if (!NT_SUCCESS(Status))
4454 {
4455 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4456 goto done;
4457 }
4458
4459 Status = SampSetObjectAttributeString(GroupObject,
4460 L"Name",
4461 (PRPC_UNICODE_STRING)&NewGroupName);
4462 if (!NT_SUCCESS(Status))
4463 {
4464 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4465 }
4466
4467 done:
4468 if (OldGroupName.Buffer != NULL)
4469 midl_user_free(OldGroupName.Buffer);
4470
4471 return Status;
4472 }
4473
4474
4475 static NTSTATUS
4476 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4477 PSAMPR_GROUP_INFO_BUFFER Buffer)
4478 {
4479 SAM_GROUP_FIXED_DATA FixedData;
4480 ULONG Length = 0;
4481 NTSTATUS Status;
4482
4483 Length = sizeof(SAM_GROUP_FIXED_DATA);
4484 Status = SampGetObjectAttribute(GroupObject,
4485 L"F",
4486 NULL,
4487 (PVOID)&FixedData,
4488 &Length);
4489 if (!NT_SUCCESS(Status))
4490 goto done;
4491
4492 FixedData.Attributes = Buffer->Attribute.Attributes;
4493
4494 Status = SampSetObjectAttribute(GroupObject,
4495 L"F",
4496 REG_BINARY,
4497 &FixedData,
4498 Length);
4499
4500 done:
4501 return Status;
4502 }
4503
4504
4505 /* Function 21 */
4506 NTSTATUS
4507 NTAPI
4508 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4509 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4510 IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4511 {
4512 PSAM_DB_OBJECT GroupObject;
4513 NTSTATUS Status;
4514
4515 TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4516 GroupHandle, GroupInformationClass, Buffer);
4517
4518 RtlAcquireResourceExclusive(&SampResource,
4519 TRUE);
4520
4521 /* Validate the group handle */
4522 Status = SampValidateDbObject(GroupHandle,
4523 SamDbGroupObject,
4524 GROUP_WRITE_ACCOUNT,
4525 &GroupObject);
4526 if (!NT_SUCCESS(Status))
4527 goto done;
4528
4529 switch (GroupInformationClass)
4530 {
4531 case GroupNameInformation:
4532 Status = SampSetGroupName(GroupObject,
4533 Buffer);
4534 break;
4535
4536 case GroupAttributeInformation:
4537 Status = SampSetGroupAttribute(GroupObject,
4538 Buffer);
4539 break;
4540
4541 case GroupAdminCommentInformation:
4542 Status = SampSetObjectAttributeString(GroupObject,
4543 L"Description",
4544 &Buffer->AdminComment.AdminComment);
4545 break;
4546
4547 default:
4548 Status = STATUS_INVALID_INFO_CLASS;
4549 break;
4550 }
4551
4552 done:
4553 RtlReleaseResource(&SampResource);
4554
4555 return Status;
4556 }
4557
4558
4559 /* Function 22 */
4560 NTSTATUS
4561 NTAPI
4562 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4563 IN unsigned long MemberId,
4564 IN unsigned long Attributes)
4565 {
4566 PSAM_DB_OBJECT GroupObject;
4567 PSAM_DB_OBJECT UserObject = NULL;
4568 NTSTATUS Status;
4569
4570 TRACE("(%p %lu %lx)\n",
4571 GroupHandle, MemberId, Attributes);
4572
4573 RtlAcquireResourceExclusive(&SampResource,
4574 TRUE);
4575
4576 /* Validate the group handle */
4577 Status = SampValidateDbObject(GroupHandle,
4578 SamDbGroupObject,
4579 GROUP_ADD_MEMBER,
4580 &GroupObject);
4581 if (!NT_SUCCESS(Status))
4582 goto done;
4583
4584 /* Open the user object in the same domain */
4585 Status = SampOpenUserObject(GroupObject->ParentObject,
4586 MemberId,
4587 0,
4588 &UserObject);
4589 if (!NT_SUCCESS(Status))
4590 {
4591 TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4592 goto done;
4593 }
4594
4595 /* Add group membership to the user object */
4596 Status = SampAddGroupMembershipToUser(UserObject,
4597 GroupObject->RelativeId,
4598 Attributes);
4599 if (!NT_SUCCESS(Status))
4600 {
4601 TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4602 goto done;
4603 }
4604
4605 /* Add the member to the group object */
4606 Status = SampAddMemberToGroup(GroupObject,
4607 MemberId);
4608 if (!NT_SUCCESS(Status))
4609 {
4610 TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4611 }
4612
4613 done:
4614 if (UserObject)
4615 SampCloseDbObject(UserObject);
4616
4617 RtlReleaseResource(&SampResource);
4618
4619 return Status;
4620 }
4621
4622
4623 /* Function 23 */
4624 NTSTATUS
4625 NTAPI
4626 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4627 {
4628 PSAM_DB_OBJECT GroupObject;
4629 ULONG Length = 0;
4630 NTSTATUS Status;
4631
4632 TRACE("(%p)\n", GroupHandle);
4633
4634 RtlAcquireResourceExclusive(&SampResource,
4635 TRUE);
4636
4637 /* Validate the group handle */
4638 Status = SampValidateDbObject(*GroupHandle,
4639 SamDbGroupObject,
4640 DELETE,
4641 &GroupObject);
4642 if (!NT_SUCCESS(Status))
4643 {
4644 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4645 goto done;
4646 }
4647
4648 /* Fail, if the group is built-in */
4649 if (GroupObject->RelativeId < 1000)
4650 {
4651 TRACE("You can not delete a special account!\n");
4652 Status = STATUS_SPECIAL_ACCOUNT;
4653 goto done;
4654 }
4655
4656 /* Get the length of the Members attribute */
4657 SampGetObjectAttribute(GroupObject,
4658 L"Members",
4659 NULL,
4660 NULL,
4661 &Length);
4662
4663 /* Fail, if the group has members */
4664 if (Length != 0)
4665 {
4666 TRACE("There are still members in the group!\n");
4667 Status = STATUS_MEMBER_IN_GROUP;
4668 goto done;
4669 }
4670
4671 /* FIXME: Remove the group from all aliases */
4672
4673 /* Delete the group from the database */
4674 Status = SampDeleteAccountDbObject(GroupObject);
4675 if (!NT_SUCCESS(Status))
4676 {
4677 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4678 goto done;
4679 }
4680
4681 /* Invalidate the handle */
4682 *GroupHandle = NULL;
4683
4684 done:
4685 RtlReleaseResource(&SampResource);
4686
4687 return Status;
4688 }
4689
4690
4691 /* Function 24 */
4692 NTSTATUS
4693 NTAPI
4694 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4695 IN unsigned long MemberId)
4696 {
4697 PSAM_DB_OBJECT GroupObject;
4698 PSAM_DB_OBJECT UserObject = NULL;
4699 NTSTATUS Status;
4700
4701 TRACE("(%p %lu)\n",
4702 GroupHandle, MemberId);
4703
4704 RtlAcquireResourceExclusive(&SampResource,
4705 TRUE);
4706
4707 /* Validate the group handle */
4708 Status = SampValidateDbObject(GroupHandle,
4709 SamDbGroupObject,
4710 GROUP_REMOVE_MEMBER,
4711 &GroupObject);
4712 if (!NT_SUCCESS(Status))
4713 goto done;
4714
4715 /* Open the user object in the same domain */
4716 Status = SampOpenUserObject(GroupObject->ParentObject,
4717 MemberId,
4718 0,
4719 &UserObject);
4720 if (!NT_SUCCESS(Status))
4721 {
4722 ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4723 goto done;
4724 }
4725
4726 /* Remove group membership from the user object */
4727 Status = SampRemoveGroupMembershipFromUser(UserObject,
4728 GroupObject->RelativeId);
4729 if (!NT_SUCCESS(Status))
4730 {
4731 ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4732 goto done;
4733 }
4734
4735 /* Remove the member from the group object */
4736 Status = SampRemoveMemberFromGroup(GroupObject,
4737 MemberId);
4738 if (!NT_SUCCESS(Status))
4739 {
4740 ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4741 }
4742
4743 done:
4744 if (UserObject)
4745 SampCloseDbObject(UserObject);
4746
4747 RtlReleaseResource(&SampResource);
4748
4749 return Status;
4750 }
4751
4752
4753 /* Function 25 */
4754 NTSTATUS
4755 NTAPI
4756 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4757 OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4758 {
4759 PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4760 PSAM_DB_OBJECT GroupObject;
4761 ULONG Length = 0;
4762 ULONG i;
4763 NTSTATUS Status;
4764
4765 RtlAcquireResourceShared(&SampResource,
4766 TRUE);
4767
4768 /* Validate the group handle */
4769 Status = SampValidateDbObject(GroupHandle,
4770 SamDbGroupObject,
4771 GROUP_LIST_MEMBERS,
4772 &GroupObject);
4773 if (!NT_SUCCESS(Status))
4774 goto done;
4775
4776 MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4777 if (MembersBuffer == NULL)
4778 {
4779 Status = STATUS_INSUFFICIENT_RESOURCES;
4780 goto done;
4781 }
4782
4783 SampGetObjectAttribute(GroupObject,
4784 L"Members",
4785 NULL,
4786 NULL,
4787 &Length);
4788
4789 if (Length == 0)
4790 {
4791 MembersBuffer->MemberCount = 0;
4792 MembersBuffer->Members = NULL;
4793 MembersBuffer->Attributes = NULL;
4794
4795 *Members = MembersBuffer;
4796
4797 Status = STATUS_SUCCESS;
4798 goto done;
4799 }
4800
4801 MembersBuffer->Members = midl_user_allocate(Length);
4802 if (MembersBuffer->Members == NULL)
4803 {
4804 Status = STATUS_INSUFFICIENT_RESOURCES;
4805 goto done;
4806 }
4807
4808 MembersBuffer->Attributes = midl_user_allocate(Length);
4809 if (MembersBuffer->Attributes == NULL)
4810 {
4811 Status = STATUS_INSUFFICIENT_RESOURCES;
4812 goto done;
4813 }
4814
4815 Status = SampGetObjectAttribute(GroupObject,
4816 L"Members",
4817 NULL,
4818 MembersBuffer->Members,
4819 &Length);
4820 if (!NT_SUCCESS(Status))
4821 {
4822 TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4823 goto done;
4824 }
4825
4826 MembersBuffer->MemberCount = Length / sizeof(ULONG);
4827
4828 for (i = 0; i < MembersBuffer->MemberCount; i++)
4829 {
4830 Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4831 MembersBuffer->Members[i],
4832 GroupObject->RelativeId,
4833 &(MembersBuffer->Attributes[i]));
4834 if (!NT_SUCCESS(Status))
4835 {
4836 TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4837 goto done;
4838 }
4839 }
4840
4841 *Members = MembersBuffer;
4842
4843 done:
4844 if (!NT_SUCCESS(Status))
4845 {
4846 if (MembersBuffer != NULL)
4847 {
4848 if (MembersBuffer->Members != NULL)
4849 midl_user_free(MembersBuffer->Members);
4850
4851 if (MembersBuffer->Attributes != NULL)
4852 midl_user_free(MembersBuffer->Attributes);
4853
4854 midl_user_free(MembersBuffer);
4855 }
4856 }
4857
4858 RtlReleaseResource(&SampResource);
4859
4860 return Status;
4861 }
4862
4863
4864 /* Function 26 */
4865 NTSTATUS
4866 NTAPI
4867 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4868 IN unsigned long MemberId,
4869 IN unsigned long Attributes)
4870 {
4871 PSAM_DB_OBJECT GroupObject;
4872 NTSTATUS Status;
4873
4874 RtlAcquireResourceExclusive(&SampResource,
4875 TRUE);
4876
4877 /* Validate the group handle */
4878 Status = SampValidateDbObject(GroupHandle,
4879 SamDbGroupObject,
4880 GROUP_ADD_MEMBER,
4881 &GroupObject);
4882 if (!NT_SUCCESS(Status))
4883 {
4884 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4885 goto done;
4886 }
4887
4888 Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4889 MemberId,
4890 GroupObject->RelativeId,
4891 Attributes);
4892 if (!NT_SUCCESS(Status))
4893 {
4894 TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4895 }
4896
4897 done:
4898 RtlReleaseResource(&SampResource);
4899
4900 return Status;
4901 }
4902
4903
4904 /* Function 27 */
4905 NTSTATUS
4906 NTAPI
4907 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4908 IN ACCESS_MASK DesiredAccess,
4909 IN ULONG AliasId,
4910 OUT SAMPR_HANDLE *AliasHandle)
4911 {
4912 PSAM_DB_OBJECT DomainObject;
4913 PSAM_DB_OBJECT AliasObject;
4914 WCHAR szRid[9];
4915 NTSTATUS Status;
4916
4917 TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4918 DomainHandle, DesiredAccess, AliasId, AliasHandle);
4919
4920 /* Map generic access rights */
4921 RtlMapGenericMask(&DesiredAccess,
4922 &AliasMapping);
4923
4924 RtlAcquireResourceShared(&SampResource,
4925 TRUE);
4926
4927 /* Validate the domain handle */
4928 Status = SampValidateDbObject(DomainHandle,
4929 SamDbDomainObject,
4930 DOMAIN_LOOKUP,
4931 &DomainObject);
4932 if (!NT_SUCCESS(Status))
4933 {
4934 TRACE("failed with status 0x%08lx\n", Status);
4935 goto done;
4936 }
4937
4938 /* Convert the RID into a string (hex) */
4939 swprintf(szRid, L"%08lX", AliasId);
4940
4941 /* Create the alias object */
4942 Status = SampOpenDbObject(DomainObject,
4943 L"Aliases",
4944 szRid,
4945 AliasId,
4946 SamDbAliasObject,
4947 DesiredAccess,
4948 &AliasObject);
4949 if (!NT_SUCCESS(Status))
4950 {
4951 TRACE("failed with status 0x%08lx\n", Status);
4952 goto done;
4953 }
4954
4955 *AliasHandle = (SAMPR_HANDLE)AliasObject;
4956
4957 done:
4958 RtlReleaseResource(&SampResource);
4959
4960 return Status;
4961 }
4962
4963
4964 static NTSTATUS
4965 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4966 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4967 {
4968 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4969 HANDLE MembersKeyHandle = NULL;
4970 NTSTATUS Status;
4971
4972 *Buffer = NULL;
4973
4974 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4975 if (InfoBuffer == NULL)
4976 return STATUS_INSUFFICIENT_RESOURCES;
4977
4978 Status = SampGetObjectAttributeString(AliasObject,
4979 L"Name",
4980 &InfoBuffer->General.Name);
4981 if (!NT_SUCCESS(Status))
4982 {
4983 TRACE("Status 0x%08lx\n", Status);
4984 goto done;
4985 }
4986
4987 Status = SampGetObjectAttributeString(AliasObject,
4988 L"Description",
4989 &InfoBuffer->General.AdminComment);
4990 if (!NT_SUCCESS(Status))
4991 {
4992 TRACE("Status 0x%08lx\n", Status);
4993 goto done;
4994 }
4995
4996 /* Open the Members subkey */
4997 Status = SampRegOpenKey(AliasObject->KeyHandle,
4998 L"Members",
4999 KEY_READ,
5000 &MembersKeyHandle);
5001 if (NT_SUCCESS(Status))
5002 {
5003 /* Retrieve the number of members of the alias */
5004 Status = SampRegQueryKeyInfo(MembersKeyHandle,
5005 NULL,
5006 &InfoBuffer->General.MemberCount);
5007 if (!NT_SUCCESS(Status))
5008 {
5009 TRACE("Status 0x%08lx\n", Status);
5010 goto done;
5011 }
5012 }
5013 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
5014 {
5015 InfoBuffer->General.MemberCount = 0;
5016 Status = STATUS_SUCCESS;
5017 }
5018 else
5019 {
5020 TRACE("Status 0x%08lx\n", Status);
5021 goto done;
5022 }
5023
5024 *Buffer = InfoBuffer;
5025
5026 done:
5027 SampRegCloseKey(&MembersKeyHandle);
5028
5029 if (!NT_SUCCESS(Status))
5030 {
5031 if (InfoBuffer != NULL)
5032 {
5033 if (InfoBuffer->General.Name.Buffer != NULL)
5034 midl_user_free(InfoBuffer->General.Name.Buffer);
5035
5036 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5037 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5038
5039 midl_user_free(InfoBuffer);
5040 }
5041 }
5042
5043 return Status;
5044 }
5045
5046
5047 static NTSTATUS
5048 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
5049 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5050 {
5051 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5052 NTSTATUS Status;
5053
5054 *Buffer = NULL;
5055
5056 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5057 if (InfoBuffer == NULL)
5058 return STATUS_INSUFFICIENT_RESOURCES;
5059
5060 Status = SampGetObjectAttributeString(AliasObject,
5061 L"Name",
5062 &InfoBuffer->Name.Name);
5063 if (!NT_SUCCESS(Status))
5064 {
5065 TRACE("Status 0x%08lx\n", Status);
5066 goto done;
5067 }
5068
5069 *Buffer = InfoBuffer;
5070
5071 done:
5072 if (!NT_SUCCESS(Status))
5073 {
5074 if (InfoBuffer != NULL)
5075 {
5076 if (InfoBuffer->Name.Name.Buffer != NULL)
5077 midl_user_free(InfoBuffer->Name.Name.Buffer);
5078
5079 midl_user_free(InfoBuffer);
5080 }
5081 }
5082
5083 return Status;
5084 }
5085
5086
5087 static NTSTATUS
5088 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
5089 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5090 {
5091 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5092 NTSTATUS Status;
5093
5094 *Buffer = NULL;
5095
5096 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5097 if (InfoBuffer == NULL)
5098 return STATUS_INSUFFICIENT_RESOURCES;
5099
5100 Status = SampGetObjectAttributeString(AliasObject,
5101 L"Description",
5102 &InfoBuffer->AdminComment.AdminComment);
5103 if (!NT_SUCCESS(Status))
5104 {
5105 TRACE("Status 0x%08lx\n", Status);
5106 goto done;
5107 }
5108
5109 *Buffer = InfoBuffer;
5110
5111 done:
5112 if (!NT_SUCCESS(Status))
5113 {
5114 if (InfoBuffer != NULL)
5115 {
5116 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
5117 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
5118
5119 midl_user_free(InfoBuffer);
5120 }
5121 }
5122
5123 return Status;
5124 }
5125
5126
5127 /* Function 28 */
5128 NTSTATUS
5129 NTAPI
5130 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
5131 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5132 OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5133 {
5134 PSAM_DB_OBJECT AliasObject;
5135 NTSTATUS Status;
5136
5137 TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
5138 AliasHandle, AliasInformationClass, Buffer);
5139
5140 RtlAcquireResourceShared(&SampResource,
5141 TRUE);
5142
5143 /* Validate the alias handle */
5144 Status = SampValidateDbObject(AliasHandle,
5145 SamDbAliasObject,
5146 ALIAS_READ_INFORMATION,
5147 &AliasObject);
5148 if (!NT_SUCCESS(Status))
5149 goto done;
5150
5151 switch (AliasInformationClass)
5152 {
5153 case AliasGeneralInformation:
5154 Status = SampQueryAliasGeneral(AliasObject,
5155 Buffer);
5156 break;
5157
5158 case AliasNameInformation:
5159 Status = SampQueryAliasName(AliasObject,
5160 Buffer);
5161 break;
5162
5163 case AliasAdminCommentInformation:
5164 Status = SampQueryAliasAdminComment(AliasObject,
5165 Buffer);
5166 break;
5167
5168 default:
5169 Status = STATUS_INVALID_INFO_CLASS;
5170 break;
5171 }
5172
5173 done:
5174 RtlReleaseResource(&SampResource);
5175
5176 return Status;
5177 }
5178
5179
5180 static NTSTATUS
5181 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
5182 PSAMPR_ALIAS_INFO_BUFFER Buffer)
5183 {
5184 UNICODE_STRING OldAliasName = {0, 0, NULL};
5185 UNICODE_STRING NewAliasName;
5186 NTSTATUS Status;
5187
5188 Status = SampGetObjectAttributeString(AliasObject,
5189 L"Name",
5190 (PRPC_UNICODE_STRING)&OldAliasName);
5191 if (!NT_SUCCESS(Status))
5192 {
5193 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
5194 goto done;
5195 }
5196
5197 /* Check the new account name */
5198 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
5199 if (!NT_SUCCESS(Status))
5200 {
5201 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
5202 return Status;
5203 }
5204
5205 NewAliasName.Length = Buffer->Name.Name.Length;
5206 NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
5207 NewAliasName.Buffer = Buffer->Name.Name.Buffer;
5208
5209 if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
5210 {
5211 Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
5212 NewAliasName.Buffer);
5213 if (!NT_SUCCESS(Status))
5214 {
5215 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
5216 NewAliasName.Buffer, Status);
5217 goto done;
5218 }
5219 }
5220
5221 Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
5222 L"Aliases",
5223 NewAliasName.Buffer,
5224 AliasObject->RelativeId);
5225 if (!NT_SUCCESS(Status))
5226 {
5227 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
5228 goto done;
5229 }
5230
5231 Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
5232 L"Aliases",
5233 OldAliasName.Buffer);
5234 if (!NT_SUCCESS(Status))
5235 {
5236 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
5237 goto done;
5238 }
5239
5240 Status = SampSetObjectAttributeString(AliasObject,
5241 L"Name",
5242 (PRPC_UNICODE_STRING)&NewAliasName);
5243 if (!NT_SUCCESS(Status))
5244 {
5245 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
5246 }
5247
5248 done:
5249 if (OldAliasName.Buffer != NULL)
5250 midl_user_free(OldAliasName.Buffer);
5251
5252 return Status;
5253 }
5254
5255
5256 /* Function 29 */
5257 NTSTATUS
5258 NTAPI
5259 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
5260 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5261 IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
5262 {
5263 PSAM_DB_OBJECT AliasObject;
5264 NTSTATUS Status;
5265
5266 TRACE("SamrSetInformationAlias(%p %lu %p)\n",
5267 AliasHandle, AliasInformationClass, Buffer);
5268
5269 RtlAcquireResourceExclusive(&SampResource,
5270 TRUE);
5271
5272 /* Validate the alias handle */
5273 Status = SampValidateDbObject(AliasHandle,
5274 SamDbAliasObject,
5275 ALIAS_WRITE_ACCOUNT,
5276 &AliasObject);
5277 if (!NT_SUCCESS(Status))
5278 goto done;
5279
5280 switch (AliasInformationClass)
5281 {
5282 case AliasNameInformation:
5283 Status = SampSetAliasName(AliasObject,
5284 Buffer);
5285 break;
5286
5287 case AliasAdminCommentInformation:
5288 Status = SampSetObjectAttributeString(AliasObject,
5289 L"Description",
5290 &Buffer->AdminComment.AdminComment);
5291 break;
5292
5293 default:
5294 Status = STATUS_INVALID_INFO_CLASS;
5295 break;
5296 }
5297
5298 done:
5299 RtlReleaseResource(&SampResource);
5300
5301 return Status;
5302 }
5303
5304
5305 /* Function 30 */
5306 NTSTATUS
5307 NTAPI
5308 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
5309 {
5310 PSAM_DB_OBJECT AliasObject;
5311 NTSTATUS Status;
5312
5313 RtlAcquireResourceExclusive(&SampResource,
5314 TRUE);
5315
5316 /* Validate the alias handle */
5317 Status = SampValidateDbObject(*AliasHandle,
5318 SamDbAliasObject,
5319 DELETE,
5320 &AliasObject);
5321 if (!NT_SUCCESS(Status))
5322 {
5323 TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
5324 goto done;
5325 }
5326
5327 /* Fail, if the alias is built-in */
5328 if (AliasObject->RelativeId < 1000)
5329 {
5330 TRACE("You can not delete a special account!\n");
5331 Status = STATUS_SPECIAL_ACCOUNT;
5332 goto done;
5333 }
5334
5335 /* Remove all members from the alias */
5336 Status = SampRemoveAllMembersFromAlias(AliasObject);
5337 if (!NT_SUCCESS(Status))
5338 {
5339 TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
5340 goto done;
5341 }
5342
5343 /* Delete the alias from the database */
5344 Status = SampDeleteAccountDbObject(AliasObject);
5345 if (!NT_SUCCESS(Status))
5346 {
5347 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5348 goto done;
5349 }
5350
5351 /* Invalidate the handle */
5352 *AliasHandle = NULL;
5353
5354 done:
5355 RtlReleaseResource(&SampResource);
5356
5357 return Status;
5358 }
5359
5360
5361 /* Function 31 */
5362 NTSTATUS
5363 NTAPI
5364 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
5365 IN PRPC_SID MemberId)
5366 {
5367 PSAM_DB_OBJECT AliasObject;
5368 NTSTATUS Status;
5369
5370 TRACE("(%p %p)\n", AliasHandle, MemberId);
5371
5372 RtlAcquireResourceExclusive(&SampResource,
5373 TRUE);
5374
5375 /* Validate the alias handle */
5376 Status = SampValidateDbObject(AliasHandle,
5377 SamDbAliasObject,
5378 ALIAS_ADD_MEMBER,
5379 &AliasObject);
5380 if (!NT_SUCCESS(Status))
5381 {
5382 TRACE("failed with status 0x%08lx\n", Status);
5383 goto done;
5384 }
5385
5386 Status = SampAddMemberToAlias(AliasObject,
5387 MemberId);
5388 if (!NT_SUCCESS(Status))
5389 {
5390 TRACE("failed with status 0x%08lx\n", Status);
5391 }
5392
5393 done:
5394 RtlReleaseResource(&SampResource);
5395
5396 return Status;
5397 }
5398
5399
5400 /* Function 32 */
5401 NTSTATUS
5402 NTAPI
5403 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
5404 IN PRPC_SID MemberId)
5405 {
5406 PSAM_DB_OBJECT AliasObject;
5407 NTSTATUS Status;
5408
5409 TRACE("(%p %p)\n", AliasHandle, MemberId);
5410
5411 RtlAcquireResourceExclusive(&SampResource,
5412 TRUE);
5413
5414 /* Validate the alias handle */
5415 Status = SampValidateDbObject(AliasHandle,
5416 SamDbAliasObject,
5417 ALIAS_REMOVE_MEMBER,
5418 &AliasObject);
5419 if (!NT_SUCCESS(Status))
5420 {
5421 TRACE("failed with status 0x%08lx\n", Status);
5422 goto done;
5423 }
5424
5425 Status = SampRemoveMemberFromAlias(AliasObject,
5426 MemberId);
5427 if (!NT_SUCCESS(Status))
5428 {
5429 TRACE("failed with status 0x%08lx\n", Status);
5430 }
5431
5432 done:
5433 RtlReleaseResource(&SampResource);
5434
5435 return Status;
5436 }
5437
5438
5439 /* Function 33 */
5440 NTSTATUS
5441 NTAPI
5442 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
5443 OUT PSAMPR_PSID_ARRAY_OUT Members)
5444 {
5445 PSAM_DB_OBJECT AliasObject;
5446 PSAMPR_SID_INFORMATION MemberArray = NULL;
5447 ULONG MemberCount = 0;
5448 ULONG Index;
5449 NTSTATUS Status;
5450
5451 TRACE("SamrGetMembersInAlias(%p %p %p)\n",
5452 AliasHandle, Members);
5453
5454 RtlAcquireResourceShared(&SampResource,
5455 TRUE);
5456
5457 /* Validate the alias handle */
5458 Status = SampValidateDbObject(AliasHandle,
5459 SamDbAliasObject,
5460 ALIAS_LIST_MEMBERS,
5461 &AliasObject);
5462 if (!NT_SUCCESS(Status))
5463 {
5464 ERR("failed with status 0x%08lx\n", Status);
5465 goto done;
5466 }
5467
5468 Status = SampGetMembersInAlias(AliasObject,
5469 &MemberCount,
5470 &MemberArray);
5471
5472 /* Return the number of members and the member array */
5473 if (NT_SUCCESS(Status))
5474 {
5475 Members->Count = MemberCount;
5476 Members->Sids = MemberArray;
5477 }
5478
5479 done:
5480 /* Clean up the members array and the SID buffers if something failed */
5481 if (!NT_SUCCESS(Status))
5482 {
5483 if (MemberArray != NULL)
5484 {
5485 for (Index = 0; Index < MemberCount; Index++)
5486 {
5487 if (MemberArray[Index].SidPointer != NULL)
5488 midl_user_free(MemberArray[Index].SidPointer);
5489 }
5490
5491 midl_user_free(MemberArray);
5492 }
5493 }
5494
5495 RtlReleaseResource(&SampResource);
5496
5497 return Status;
5498 }
5499
5500
5501 /* Function 34 */
5502 NTSTATUS
5503 NTAPI
5504 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5505 IN ACCESS_MASK DesiredAccess,
5506 IN unsigned long UserId,
5507 OUT SAMPR_HANDLE *UserHandle)
5508 {
5509 PSAM_DB_OBJECT DomainObject;
5510 PSAM_DB_OBJECT UserObject;
5511 WCHAR szRid[9];
5512 NTSTATUS Status;
5513
5514 TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5515 DomainHandle, DesiredAccess, UserId, UserHandle);
5516
5517 /* Map generic access rights */
5518 RtlMapGenericMask(&DesiredAccess,
5519 &UserMapping);
5520
5521 RtlAcquireResourceShared(&SampResource,
5522 TRUE);
5523
5524 /* Validate the domain handle */
5525 Status = SampValidateDbObject(DomainHandle,
5526 SamDbDomainObject,
5527 DOMAIN_LOOKUP,
5528 &DomainObject);
5529 if (!NT_SUCCESS(Status))
5530 {
5531 TRACE("failed with status 0x%08lx\n", Status);
5532 goto done;
5533 }
5534
5535 /* Convert the RID into a string (hex) */
5536 swprintf(szRid, L"%08lX", UserId);
5537
5538 /* Create the user object */
5539 Status = SampOpenDbObject(DomainObject,
5540 L"Users",
5541 szRid,
5542 UserId,
5543 SamDbUserObject,
5544 DesiredAccess,
5545 &UserObject);
5546 if (!NT_SUCCESS(Status))
5547 {
5548 TRACE("failed with status 0x%08lx\n", Status);
5549 goto done;
5550 }
5551
5552 *UserHandle = (SAMPR_HANDLE)UserObject;
5553
5554 done:
5555 RtlReleaseResource(&SampResource);
5556
5557 return Status;
5558 }
5559
5560
5561 /* Function 35 */
5562 NTSTATUS
5563 NTAPI
5564 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5565 {
5566 PSAM_DB_OBJECT UserObject;
5567 NTSTATUS Status;
5568
5569 TRACE("(%p)\n", UserHandle);
5570
5571 RtlAcquireResourceExclusive(&SampResource,
5572 TRUE);
5573
5574 /* Validate the user handle */
5575 Status = SampValidateDbObject(*UserHandle,
5576 SamDbUserObject,
5577 DELETE,
5578 &UserObject);
5579 if (!NT_SUCCESS(Status))
5580 {
5581 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5582 goto done;
5583 }
5584
5585 /* Fail, if the user is built-in */
5586 if (UserObject->RelativeId < 1000)
5587 {
5588 TRACE("You can not delete a special account!\n");
5589 Status = STATUS_SPECIAL_ACCOUNT;
5590 goto done;
5591 }
5592
5593 /* Remove the user from all groups */
5594 Status = SampRemoveUserFromAllGroups(UserObject);
5595 if (!NT_SUCCESS(Status))
5596 {
5597 TRACE("SampRemoveUserFromAllGroups() failed (Status 0x%08lx)\n", Status);
5598 goto done;
5599 }
5600
5601 /* Remove the user from all aliases */
5602 Status = SampRemoveUserFromAllAliases(UserObject);
5603 if (!NT_SUCCESS(Status))
5604 {
5605 TRACE("SampRemoveUserFromAllAliases() failed (Status 0x%08lx)\n", Status);
5606 goto done;
5607 }
5608
5609 /* Delete the user from the database */
5610 Status = SampDeleteAccountDbObject(UserObject);
5611 if (!NT_SUCCESS(Status))
5612 {
5613 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5614 goto done;
5615 }
5616
5617 /* Invalidate the handle */
5618 *UserHandle = NULL;
5619
5620 done:
5621 RtlReleaseResource(&SampResource);
5622
5623 return Status;
5624 }
5625
5626
5627 static
5628 NTSTATUS
5629 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5630 PSAMPR_USER_INFO_BUFFER *Buffer)
5631 {
5632 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5633 SAM_USER_FIXED_DATA FixedData;
5634 ULONG Length = 0;
5635 NTSTATUS Status;
5636
5637 *Buffer = NULL;
5638
5639 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5640 if (InfoBuffer == NULL)
5641 return STATUS_INSUFFICIENT_RESOURCES;
5642
5643 Length = sizeof(SAM_USER_FIXED_DATA);
5644 Status = SampGetObjectAttribute(UserObject,
5645 L"F",
5646 NULL,
5647 (PVOID)&FixedData,
5648 &Length);
5649 if (!NT_SUCCESS(Status))
5650 goto done;
5651
5652 InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5653
5654 /* Get the Name string */
5655 Status = SampGetObjectAttributeString(UserObject,
5656 L"Name",
5657 &InfoBuffer->General.UserName);
5658 if (!NT_SUCCESS(Status))
5659 {
5660 TRACE("Status 0x%08lx\n", Status);
5661 goto done;
5662 }
5663
5664 /* Get the FullName string */
5665 Status = SampGetObjectAttributeString(UserObject,
5666 L"FullName",
5667 &InfoBuffer->General.FullName);
5668 if (!NT_SUCCESS(Status))
5669 {
5670 TRACE("Status 0x%08lx\n", Status);
5671 goto done;
5672 }
5673
5674 /* Get the AdminComment string */
5675 Status = SampGetObjectAttributeString(UserObject,
5676 L"AdminComment",
5677 &InfoBuffer->General.AdminComment);
5678 if (!NT_SUCCESS(Status))
5679 {
5680 TRACE("Status 0x%08lx\n", Status);
5681 goto done;
5682 }
5683
5684 /* Get the UserComment string */
5685 Status = SampGetObjectAttributeString(UserObject,
5686 L"UserComment",
5687 &InfoBuffer->General.UserComment);
5688 if (!NT_SUCCESS(Status))
5689 {
5690 TRACE("Status 0x%08lx\n", Status);
5691 goto done;
5692 }
5693
5694 *Buffer = InfoBuffer;
5695
5696 done:
5697 if (!NT_SUCCESS(Status))
5698 {
5699 if (InfoBuffer != NULL)
5700 {
5701 if (InfoBuffer->General.UserName.Buffer != NULL)
5702 midl_user_free(InfoBuffer->General.UserName.Buffer);
5703
5704 if (InfoBuffer->General.FullName.Buffer != NULL)
5705 midl_user_free(InfoBuffer->General.FullName.Buffer);
5706
5707 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5708 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5709
5710 if (InfoBuffer->General.UserComment.Buffer != NULL)
5711 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5712
5713 midl_user_free(InfoBuffer);
5714 }
5715 }
5716
5717 return Status;
5718 }
5719
5720
5721 static
5722 NTSTATUS
5723 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5724 PSAMPR_USER_INFO_BUFFER *Buffer)
5725 {
5726 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5727 SAM_USER_FIXED_DATA FixedData;
5728 ULONG Length = 0;
5729 NTSTATUS Status;
5730
5731 *Buffer = NULL;
5732
5733 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5734 if (InfoBuffer == NULL)
5735 return STATUS_INSUFFICIENT_RESOURCES;
5736
5737 Length = sizeof(SAM_USER_FIXED_DATA);
5738 Status = SampGetObjectAttribute(UserObject,
5739 L"F",
5740 NULL,
5741 (PVOID)&FixedData,
5742 &Length);
5743 if (!NT_SUCCESS(Status))
5744 goto done;
5745
5746 InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5747 InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5748
5749 /* Get the UserComment string */
5750 Status = SampGetObjectAttributeString(UserObject,
5751 L"UserComment",
5752 &InfoBuffer->Preferences.UserComment);
5753 if (!NT_SUCCESS(Status))
5754 {
5755 TRACE("Status 0x%08lx\n", Status);
5756 goto done;
5757 }
5758
5759 *Buffer = InfoBuffer;
5760
5761 done:
5762 if (!NT_SUCCESS(Status))
5763 {
5764 if (InfoBuffer != NULL)
5765 {
5766 if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5767 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5768
5769 midl_user_free(InfoBuffer);
5770 }
5771 }
5772
5773 return Status;
5774 }
5775
5776
5777 static
5778 NTSTATUS
5779 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5780 PSAMPR_USER_INFO_BUFFER *Buffer)
5781 {
5782 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5783 SAM_DOMAIN_FIXED_DATA DomainFixedData;
5784 SAM_USER_FIXED_DATA FixedData;
5785 LARGE_INTEGER PasswordCanChange;
5786 LARGE_INTEGER PasswordMustChange;
5787 ULONG Length = 0;
5788 NTSTATUS Status;
5789
5790 *Buffer = NULL;
5791
5792 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5793 if (InfoBuffer == NULL)
5794 return STATUS_INSUFFICIENT_RESOURCES;
5795
5796 /* Get the fixed size domain data */
5797 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5798 Status = SampGetObjectAttribute(UserObject->ParentObject,
5799 L"F",
5800 NULL,
5801 (PVOID)&DomainFixedData,
5802 &Length);
5803 if (!NT_SUCCESS(Status))
5804 goto done;
5805
5806 /* Get the fixed size user data */
5807 Length = sizeof(SAM_USER_FIXED_DATA);
5808 Status = SampGetObjectAttribute(UserObject,
5809 L"F",
5810 NULL,
5811 (PVOID)&FixedData,
5812 &Length);
5813 if (!NT_SUCCESS(Status))
5814 goto done;
5815
5816 InfoBuffer->Logon.UserId = FixedData.UserId;
5817 InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5818 InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5819 InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5820 InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5821 InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5822 InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5823 InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5824 InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5825 InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5826 InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5827
5828 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5829 DomainFixedData.MinPasswordAge);
5830 InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5831 InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5832
5833 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5834 DomainFixedData.MaxPasswordAge);
5835 InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5836 InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5837
5838 /* Get the Name string */
5839 Status = SampGetObjectAttributeString(UserObject,
5840 L"Name",
5841 &InfoBuffer->Logon.UserName);
5842 if (!NT_SUCCESS(Status))
5843 {
5844 TRACE("Status 0x%08lx\n", Status);
5845 goto done;
5846 }
5847
5848 /* Get the FullName string */
5849 Status = SampGetObjectAttributeString(UserObject,
5850 L"FullName",
5851 &InfoBuffer->Logon.FullName);
5852 if (!NT_SUCCESS(Status))
5853 {
5854 TRACE("Status 0x%08lx\n", Status);
5855 goto done;
5856 }
5857
5858 /* Get the HomeDirectory string */
5859 Status = SampGetObjectAttributeString(UserObject,
5860 L"HomeDirectory",
5861 &InfoBuffer->Logon.HomeDirectory);
5862 if (!NT_SUCCESS(Status))
5863 {
5864 TRACE("Status 0x%08lx\n", Status);
5865 goto done;
5866 }
5867
5868 /* Get the HomeDirectoryDrive string */
5869 Status = SampGetObjectAttributeString(UserObject,
5870 L"HomeDirectoryDrive",
5871 &InfoBuffer->Logon.HomeDirectoryDrive);
5872 if (!NT_SUCCESS(Status))
5873 {
5874 TRACE("Status 0x%08lx\n", Status);
5875 goto done;
5876 }
5877
5878 /* Get the ScriptPath string */
5879 Status = SampGetObjectAttributeString(UserObject,
5880 L"ScriptPath",
5881 &InfoBuffer->Logon.ScriptPath);
5882 if (!NT_SUCCESS(Status))
5883 {
5884 TRACE("Status 0x%08lx\n", Status);
5885 goto done;
5886 }
5887
5888 /* Get the ProfilePath string */
5889 Status = SampGetObjectAttributeString(UserObject,
5890 L"ProfilePath",
5891 &InfoBuffer->Logon.ProfilePath);
5892 if (!NT_SUCCESS(Status))
5893 {
5894 TRACE("Status 0x%08lx\n", Status);
5895 goto done;
5896 }
5897
5898 /* Get the WorkStations string */
5899 Status = SampGetObjectAttributeString(UserObject,
5900 L"WorkStations",
5901 &InfoBuffer->Logon.WorkStations);
5902 if (!NT_SUCCESS(Status))
5903 {
5904 TRACE("Status 0x%08lx\n", Status);
5905 goto done;
5906 }
5907
5908 /* Get the LogonHours attribute */
5909 Status = SampGetLogonHoursAttribute(UserObject,
5910 &InfoBuffer->Logon.LogonHours);
5911 if (!NT_SUCCESS(Status))
5912 {
5913 TRACE("Status 0x%08lx\n", Status);
5914 goto done;
5915 }
5916
5917 *Buffer = InfoBuffer;
5918
5919 done:
5920 if (!NT_SUCCESS(Status))
5921 {
5922 if (InfoBuffer != NULL)
5923 {
5924 if (InfoBuffer->Logon.UserName.Buffer != NULL)
5925 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5926
5927 if (InfoBuffer->Logon.FullName.Buffer != NULL)
5928 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5929
5930 if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5931 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5932
5933 if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5934 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5935
5936 if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5937 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5938
5939 if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5940 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5941
5942 if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5943 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5944
5945 if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5946 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5947
5948 midl_user_free(InfoBuffer);
5949 }
5950 }
5951
5952 return Status;
5953 }
5954
5955
5956 static
5957 NTSTATUS
5958 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5959 PSAMPR_USER_INFO_BUFFER *Buffer)
5960 {
5961 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5962 SAM_USER_FIXED_DATA FixedData;
5963 ULONG Length = 0;
5964 NTSTATUS Status;
5965
5966 *Buffer = NULL;
5967
5968 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5969 if (InfoBuffer == NULL)
5970 return STATUS_INSUFFICIENT_RESOURCES;
5971
5972 Length = sizeof(SAM_USER_FIXED_DATA);
5973 Status = SampGetObjectAttribute(UserObject,
5974 L"F",
5975 NULL,
5976 (PVOID)&FixedData,
5977 &Length);
5978 if (!NT_SUCCESS(Status))
5979 goto done;
5980
5981 InfoBuffer->Account.UserId = FixedData.UserId;
5982 InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5983 InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5984 InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5985 InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5986 InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5987 InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5988 InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5989 InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5990 InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5991 InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
5992 InfoBuffer->Account.LogonCount = FixedData.LogonCount;
5993 InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
5994
5995 /* Get the Name string */
5996 Status = SampGetObjectAttributeString(UserObject,
5997 L"Name",
5998 &InfoBuffer->Account.UserName);
5999 if (!NT_SUCCESS(Status))
6000 {
6001 TRACE("Status 0x%08lx\n", Status);
6002 goto done;
6003 }
6004
6005 /* Get the FullName string */
6006 Status = SampGetObjectAttributeString(UserObject,
6007 L"FullName",
6008 &InfoBuffer->Account.FullName);
6009 if (!NT_SUCCESS(Status))
6010 {
6011 TRACE("Status 0x%08lx\n", Status);
6012 goto done;
6013 }
6014
6015 /* Get the HomeDirectory string */
6016 Status = SampGetObjectAttributeString(UserObject,
6017 L"HomeDirectory",
6018 &InfoBuffer->Account.HomeDirectory);
6019 if (!NT_SUCCESS(Status))
6020 {
6021 TRACE("Status 0x%08lx\n", Status);
6022 goto done;
6023 }
6024
6025 /* Get the HomeDirectoryDrive string */
6026 Status = SampGetObjectAttributeString(UserObject,
6027 L"HomeDirectoryDrive",
6028 &InfoBuffer->Account.HomeDirectoryDrive);
6029 if (!NT_SUCCESS(Status))
6030 {
6031 TRACE("Status 0x%08lx\n", Status);
6032 goto done;
6033 }
6034
6035 /* Get the ScriptPath string */
6036 Status = SampGetObjectAttributeString(UserObject,
6037 L"ScriptPath",
6038 &InfoBuffer->Account.ScriptPath);
6039 if (!NT_SUCCESS(Status))
6040 {
6041 TRACE("Status 0x%08lx\n", Status);
6042 goto done;
6043 }
6044
6045 /* Get the ProfilePath string */
6046 Status = SampGetObjectAttributeString(UserObject,
6047 L"ProfilePath",
6048 &InfoBuffer->Account.ProfilePath);
6049 if (!NT_SUCCESS(Status))
6050 {
6051 TRACE("Status 0x%08lx\n", Status);
6052 goto done;
6053 }
6054
6055 /* Get the AdminComment string */
6056 Status = SampGetObjectAttributeString(UserObject,
6057 L"AdminComment",
6058 &InfoBuffer->Account.AdminComment);
6059 if (!NT_SUCCESS(Status))
6060 {
6061 TRACE("Status 0x%08lx\n", Status);
6062 goto done;
6063 }
6064
6065 /* Get the WorkStations string */
6066 Status = SampGetObjectAttributeString(UserObject,
6067 L"WorkStations",
6068 &InfoBuffer->Account.WorkStations);
6069 if (!NT_SUCCESS(Status))
6070 {
6071 TRACE("Status 0x%08lx\n", Status);
6072 goto done;
6073 }
6074
6075 /* Get the LogonHours attribute */
6076 Status = SampGetLogonHoursAttribute(UserObject,
6077 &InfoBuffer->Account.LogonHours);
6078 if (!NT_SUCCESS(Status))
6079 {
6080 TRACE("Status 0x%08lx\n", Status);
6081 goto done;
6082 }
6083
6084 *Buffer = InfoBuffer;
6085
6086 done:
6087 if (!NT_SUCCESS(Status))
6088 {
6089 if (InfoBuffer != NULL)
6090 {
6091 if (InfoBuffer->Account.UserName.Buffer != NULL)
6092 midl_user_free(InfoBuffer->Account.UserName.Buffer);
6093
6094 if (InfoBuffer->Account.FullName.Buffer != NULL)
6095 midl_user_free(InfoBuffer->Account.FullName.Buffer);
6096
6097 if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
6098 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
6099
6100 if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
6101 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
6102
6103 if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
6104 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
6105
6106 if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
6107 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
6108
6109 if (InfoBuffer->Account.AdminComment.Buffer != NULL)
6110 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
6111
6112 if (InfoBuffer->Account.WorkStations.Buffer != NULL)
6113 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
6114
6115 if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
6116 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
6117
6118 midl_user_free(InfoBuffer);
6119 }
6120 }
6121
6122 return Status;
6123 }
6124
6125
6126 static
6127 NTSTATUS
6128 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
6129 PSAMPR_USER_INFO_BUFFER *Buffer)
6130 {
6131 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6132 NTSTATUS Status;
6133
6134 TRACE("(%p %p)\n", UserObject, Buffer);
6135
6136 *Buffer = NULL;
6137
6138 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6139 if (InfoBuffer == NULL)
6140 {
6141 TRACE("Failed to allocate InfoBuffer!\n");
6142 return STATUS_INSUFFICIENT_RESOURCES;
6143 }
6144
6145 Status = SampGetLogonHoursAttribute(UserObject,
6146 &InfoBuffer->LogonHours.LogonHours);
6147 if (!NT_SUCCESS(Status))
6148 {
6149 TRACE("SampGetLogonHoursAttribute failed (Status 0x%08lx)\n", Status);
6150 goto done;
6151 }
6152
6153 *Buffer = InfoBuffer;
6154
6155 done:
6156 if (!NT_SUCCESS(Status))
6157 {
6158 if (InfoBuffer != NULL)
6159 {
6160 if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
6161 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
6162
6163 midl_user_free(InfoBuffer);
6164 }
6165 }
6166
6167 return Status;
6168 }
6169
6170
6171 static
6172 NTSTATUS
6173 SampQueryUserName(PSAM_DB_OBJECT UserObject,
6174 PSAMPR_USER_INFO_BUFFER *Buffer)
6175 {
6176 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6177 NTSTATUS Status;
6178
6179 *Buffer = NULL;
6180
6181 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6182 if (InfoBuffer == NULL)
6183 return STATUS_INSUFFICIENT_RESOURCES;
6184
6185 /* Get the Name string */
6186 Status = SampGetObjectAttributeString(UserObject,
6187 L"Name",
6188 &InfoBuffer->Name.UserName);
6189 if (!NT_SUCCESS(Status))
6190 {
6191 TRACE("Status 0x%08lx\n", Status);
6192 goto done;
6193 }
6194
6195 /* Get the FullName string */
6196 Status = SampGetObjectAttributeString(UserObject,
6197 L"FullName",
6198 &InfoBuffer->Name.FullName);
6199 if (!NT_SUCCESS(Status))
6200 {
6201 TRACE("Status 0x%08lx\n", Status);
6202 goto done;
6203 }
6204
6205 *Buffer = InfoBuffer;
6206
6207 done:
6208 if (!NT_SUCCESS(Status))
6209 {
6210 if (InfoBuffer != NULL)
6211 {
6212 if (InfoBuffer->Name.UserName.Buffer != NULL)
6213 midl_user_free(InfoBuffer->Name.UserName.Buffer);
6214
6215 if (InfoBuffer->Name.FullName.Buffer != NULL)
6216 midl_user_free(InfoBuffer->Name.FullName.Buffer);
6217
6218 midl_user_free(InfoBuffer);
6219 }
6220 }
6221
6222 return Status;
6223 }
6224
6225
6226 static NTSTATUS
6227 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
6228 PSAMPR_USER_INFO_BUFFER *Buffer)
6229 {
6230 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6231 NTSTATUS Status;
6232
6233 *Buffer = NULL;
6234
6235 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6236 if (InfoBuffer == NULL)
6237 return STATUS_INSUFFICIENT_RESOURCES;
6238
6239 /* Get the Name string */
6240 Status = SampGetObjectAttributeString(UserObject,
6241 L"Name",
6242 &InfoBuffer->AccountName.UserName);
6243 if (!NT_SUCCESS(Status))
6244 {
6245 TRACE("Status 0x%08lx\n", Status);
6246 goto done;
6247 }
6248
6249 *Buffer = InfoBuffer;
6250
6251 done:
6252 if (!NT_SUCCESS(Status))
6253 {
6254 if (InfoBuffer != NULL)
6255 {
6256 if (InfoBuffer->AccountName.UserName.Buffer != NULL)
6257 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
6258
6259 midl_user_free(InfoBuffer);
6260 }
6261 }
6262
6263 return Status;
6264 }
6265
6266
6267 static NTSTATUS
6268 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
6269 PSAMPR_USER_INFO_BUFFER *Buffer)
6270 {
6271 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6272 NTSTATUS Status;
6273
6274 *Buffer = NULL;
6275
6276 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6277 if (InfoBuffer == NULL)
6278 return STATUS_INSUFFICIENT_RESOURCES;
6279
6280 /* Get the FullName string */
6281 Status = SampGetObjectAttributeString(UserObject,
6282 L"FullName",
6283 &InfoBuffer->FullName.FullName);
6284 if (!NT_SUCCESS(Status))
6285 {
6286 TRACE("Status 0x%08lx\n", Status);
6287 goto done;
6288 }
6289
6290 *Buffer = InfoBuffer;
6291
6292 done:
6293 if (!NT_SUCCESS(Status))
6294 {
6295 if (InfoBuffer != NULL)
6296 {
6297 if (InfoBuffer->FullName.FullName.Buffer != NULL)
6298 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
6299
6300 midl_user_free(InfoBuffer);
6301 }
6302 }
6303
6304 return Status;
6305 }
6306
6307
6308 static
6309 NTSTATUS
6310 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6311 PSAMPR_USER_INFO_BUFFER *Buffer)
6312 {
6313 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6314 SAM_USER_FIXED_DATA FixedData;
6315 ULONG Length = 0;
6316 NTSTATUS Status;
6317
6318 *Buffer = NULL;
6319
6320 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6321 if (InfoBuffer == NULL)
6322 return STATUS_INSUFFICIENT_RESOURCES;
6323
6324 Length = sizeof(SAM_USER_FIXED_DATA);
6325 Status = SampGetObjectAttribute(UserObject,
6326 L"F",
6327 NULL,
6328 (PVOID)&FixedData,
6329 &Length);
6330 if (!NT_SUCCESS(Status))
6331 goto done;
6332
6333 InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
6334
6335 *Buffer = InfoBuffer;
6336
6337 done:
6338 if (!NT_SUCCESS(Status))
6339 {
6340 if (InfoBuffer != NULL)
6341 {
6342 midl_user_free(InfoBuffer);
6343 }
6344 }
6345
6346 return Status;
6347 }
6348
6349
6350 static NTSTATUS
6351 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
6352 PSAMPR_USER_INFO_BUFFER *Buffer)
6353 {
6354 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6355 NTSTATUS Status;
6356
6357 *Buffer = NULL;
6358
6359 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6360 if (InfoBuffer == NULL)
6361 return STATUS_INSUFFICIENT_RESOURCES;
6362
6363 /* Get the HomeDirectory string */
6364 Status = SampGetObjectAttributeString(UserObject,
6365 L"HomeDirectory",
6366 &InfoBuffer->Home.HomeDirectory);
6367 if (!NT_SUCCESS(Status))
6368 {
6369 TRACE("Status 0x%08lx\n", Status);
6370 goto done;
6371 }
6372
6373 /* Get the HomeDirectoryDrive string */
6374 Status = SampGetObjectAttributeString(UserObject,
6375 L"HomeDirectoryDrive",
6376 &InfoBuffer->Home.HomeDirectoryDrive);
6377 if (!NT_SUCCESS(Status))
6378 {
6379 TRACE("Status 0x%08lx\n", Status);
6380 goto done;
6381 }
6382
6383 *Buffer = InfoBuffer;
6384
6385 done:
6386 if (!NT_SUCCESS(Status))
6387 {
6388 if (InfoBuffer != NULL)
6389 {
6390 if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
6391 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
6392
6393 if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
6394 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
6395
6396 midl_user_free(InfoBuffer);
6397 }
6398 }
6399
6400 return Status;
6401 }
6402
6403
6404 static NTSTATUS
6405 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
6406 PSAMPR_USER_INFO_BUFFER *Buffer)
6407 {
6408 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6409 NTSTATUS Status;
6410
6411 *Buffer = NULL;
6412
6413 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6414 if (InfoBuffer == NULL)
6415 return STATUS_INSUFFICIENT_RESOURCES;
6416
6417 /* Get the ScriptPath string */
6418 Status = SampGetObjectAttributeString(UserObject,
6419 L"ScriptPath",
6420 &InfoBuffer->Script.ScriptPath);
6421 if (!NT_SUCCESS(Status))
6422 {
6423 TRACE("Status 0x%08lx\n", Status);
6424 goto done;
6425 }
6426
6427 *Buffer = InfoBuffer;
6428
6429 done:
6430 if (!NT_SUCCESS(Status))
6431 {
6432 if (InfoBuffer != NULL)
6433 {
6434 if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
6435 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
6436
6437 midl_user_free(InfoBuffer);
6438 }
6439 }
6440
6441 return Status;
6442 }
6443
6444
6445 static NTSTATUS
6446 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
6447 PSAMPR_USER_INFO_BUFFER *Buffer)
6448 {
6449 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6450 NTSTATUS Status;
6451
6452 *Buffer = NULL;
6453
6454 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6455 if (InfoBuffer == NULL)
6456 return STATUS_INSUFFICIENT_RESOURCES;
6457
6458 /* Get the ProfilePath string */
6459 Status = SampGetObjectAttributeString(UserObject,
6460 L"ProfilePath",
6461 &InfoBuffer->Profile.ProfilePath);
6462 if (!NT_SUCCESS(Status))
6463 {
6464 TRACE("Status 0x%08lx\n", Status);
6465 goto done;
6466 }
6467
6468 *Buffer = InfoBuffer;
6469
6470 done:
6471 if (!NT_SUCCESS(Status))
6472 {
6473 if (InfoBuffer != NULL)
6474 {
6475 if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
6476 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
6477
6478 midl_user_free(InfoBuffer);
6479 }
6480 }
6481
6482 return Status;
6483 }
6484
6485
6486 static NTSTATUS
6487 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6488 PSAMPR_USER_INFO_BUFFER *Buffer)
6489 {
6490 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6491 NTSTATUS Status;
6492
6493 *Buffer = NULL;
6494
6495 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6496 if (InfoBuffer == NULL)
6497 return STATUS_INSUFFICIENT_RESOURCES;
6498
6499 /* Get the AdminComment string */
6500 Status = SampGetObjectAttributeString(UserObject,
6501 L"AdminComment",
6502 &InfoBuffer->AdminComment.AdminComment);
6503 if (!NT_SUCCESS(Status))
6504 {
6505 TRACE("Status 0x%08lx\n", Status);
6506 goto done;
6507 }
6508
6509 *Buffer = InfoBuffer;
6510
6511 done:
6512 if (!NT_SUCCESS(Status))
6513 {
6514 if (InfoBuffer != NULL)
6515 {
6516 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6517 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6518
6519 midl_user_free(InfoBuffer);
6520 }
6521 }
6522
6523 return Status;
6524 }
6525
6526
6527 static NTSTATUS
6528 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6529 PSAMPR_USER_INFO_BUFFER *Buffer)
6530 {
6531 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6532 NTSTATUS Status;
6533
6534 *Buffer = NULL;
6535
6536 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6537 if (InfoBuffer == NULL)
6538 return STATUS_INSUFFICIENT_RESOURCES;
6539
6540 /* Get the WorkStations string */
6541 Status = SampGetObjectAttributeString(UserObject,
6542 L"WorkStations",
6543 &InfoBuffer->WorkStations.WorkStations);
6544 if (!NT_SUCCESS(Status))
6545 {
6546 TRACE("Status 0x%08lx\n", Status);
6547 goto done;
6548 }
6549
6550 *Buffer = InfoBuffer;
6551
6552 done:
6553 if (!NT_SUCCESS(Status))
6554 {
6555 if (InfoBuffer != NULL)
6556 {
6557 if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6558 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6559
6560 midl_user_free(InfoBuffer);
6561 }
6562 }
6563
6564 return Status;
6565 }
6566
6567
6568 static
6569 NTSTATUS
6570 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6571 PSAMPR_USER_INFO_BUFFER *Buffer)
6572 {
6573 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6574 SAM_USER_FIXED_DATA FixedData;
6575 ULONG Length = 0;
6576 NTSTATUS Status;
6577
6578 *Buffer = NULL;
6579
6580 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6581 if (InfoBuffer == NULL)
6582 return STATUS_INSUFFICIENT_RESOURCES;
6583
6584 Length = sizeof(SAM_USER_FIXED_DATA);
6585 Status = SampGetObjectAttribute(UserObject,
6586 L"F",
6587 NULL,
6588 (PVOID)&FixedData,
6589 &Length);
6590 if (!NT_SUCCESS(Status))
6591 goto done;
6592
6593 InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6594
6595 *Buffer = InfoBuffer;
6596
6597 done:
6598 if (!NT_SUCCESS(Status))
6599 {
6600 if (InfoBuffer != NULL)
6601 {
6602 midl_user_free(InfoBuffer);
6603 }
6604 }
6605
6606 return Status;
6607 }
6608
6609
6610 static
6611 NTSTATUS
6612 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6613 PSAMPR_USER_INFO_BUFFER *Buffer)
6614 {
6615 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6616 SAM_USER_FIXED_DATA FixedData;
6617 ULONG Length = 0;
6618 NTSTATUS Status;
6619
6620 *Buffer = NULL;
6621
6622 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6623 if (InfoBuffer == NULL)
6624 return STATUS_INSUFFICIENT_RESOURCES;
6625
6626 Length = sizeof(SAM_USER_FIXED_DATA);
6627 Status = SampGetObjectAttribute(UserObject,
6628 L"F",
6629 NULL,
6630 (PVOID)&FixedData,
6631 &Length);
6632 if (!NT_SUCCESS(Status))
6633 goto done;
6634
6635 InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6636 InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6637
6638 *Buffer = InfoBuffer;
6639
6640 done:
6641 if (!NT_SUCCESS(Status))
6642 {
6643 if (InfoBuffer != NULL)
6644 {
6645 midl_user_free(InfoBuffer);
6646 }
6647 }
6648
6649 return Status;
6650 }
6651
6652
6653 static
6654 NTSTATUS
6655 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6656 PSAMPR_USER_INFO_BUFFER *Buffer)
6657 {
6658 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6659 ULONG Length = 0;
6660 NTSTATUS Status = STATUS_SUCCESS;
6661
6662 /* Fail, if the caller is not a trusted caller */
6663 if (UserObject->Trusted == FALSE)
6664 return STATUS_INVALID_INFO_CLASS;
6665
6666 *Buffer = NULL;
6667
6668 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6669 if (InfoBuffer == NULL)
6670 return STATUS_INSUFFICIENT_RESOURCES;
6671
6672 InfoBuffer->Internal1.LmPasswordPresent = FALSE;
6673 InfoBuffer->Internal1.NtPasswordPresent = FALSE;
6674
6675 /* Get the NT password */
6676 Length = 0;
6677 SampGetObjectAttribute(UserObject,
6678 L"NTPwd",
6679 NULL,
6680 NULL,
6681 &Length);
6682
6683 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6684 {
6685 Status = SampGetObjectAttribute(UserObject,
6686 L"NTPwd",
6687 NULL,
6688 (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6689 &Length);
6690 if (!NT_SUCCESS(Status))
6691 goto done;
6692
6693 if (memcmp(&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6694 &EmptyNtHash,
6695 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
6696 InfoBuffer->Internal1.NtPasswordPresent = TRUE;
6697 }
6698
6699
6700 /* Get the LM password */
6701 Length = 0;
6702 SampGetObjectAttribute(UserObject,
6703 L"LMPwd",
6704 NULL,
6705 NULL,
6706 &Length);
6707
6708 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6709 {
6710 Status = SampGetObjectAttribute(UserObject,
6711 L"LMPwd",
6712 NULL,
6713 (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6714 &Length);
6715 if (!NT_SUCCESS(Status))
6716 goto done;
6717
6718 if (memcmp(&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6719 &EmptyLmHash,
6720 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
6721 InfoBuffer->Internal1.LmPasswordPresent = TRUE;
6722 }
6723
6724 InfoBuffer->Internal1.PasswordExpired = FALSE;
6725
6726 *Buffer = InfoBuffer;
6727
6728 done:
6729 if (!NT_SUCCESS(Status))
6730 {
6731 if (InfoBuffer != NULL)
6732 {
6733 midl_user_free(InfoBuffer);
6734 }
6735 }
6736
6737 return Status;
6738 }
6739
6740
6741 static NTSTATUS
6742 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6743 PSAMPR_USER_INFO_BUFFER *Buffer)
6744 {
6745 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6746 NTSTATUS Status;
6747
6748 *Buffer = NULL;
6749
6750 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6751 if (InfoBuffer == NULL)
6752 return STATUS_INSUFFICIENT_RESOURCES;
6753
6754 /* Get the Parameters string */
6755 Status = SampGetObjectAttributeString(UserObject,
6756 L"Parameters",
6757 &InfoBuffer->Parameters.Parameters);
6758 if (!NT_SUCCESS(Status))
6759 {
6760 TRACE("Status 0x%08lx\n", Status);
6761 goto done;
6762 }
6763
6764 *Buffer = InfoBuffer;
6765
6766 done:
6767 if (!NT_SUCCESS(Status))
6768 {
6769 if (InfoBuffer != NULL)
6770 {
6771 if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6772 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6773
6774 midl_user_free(InfoBuffer);
6775 }
6776 }
6777
6778 return Status;
6779 }
6780
6781
6782 static NTSTATUS
6783 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6784 PSAMPR_USER_INFO_BUFFER *Buffer)
6785 {
6786 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6787 SAM_DOMAIN_FIXED_DATA DomainFixedData;
6788 SAM_USER_FIXED_DATA FixedData;
6789 LARGE_INTEGER PasswordCanChange;
6790 LARGE_INTEGER PasswordMustChange;
6791 ULONG Length = 0;
6792 NTSTATUS Status;
6793
6794 *Buffer = NULL;
6795
6796 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6797 if (InfoBuffer == NULL)
6798 return STATUS_INSUFFICIENT_RESOURCES;
6799
6800 /* Get the fixed size domain data */
6801 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6802 Status = SampGetObjectAttribute(UserObject->ParentObject,
6803 L"F",
6804 NULL,
6805 (PVOID)&DomainFixedData,
6806 &Length);
6807 if (!NT_SUCCESS(Status))
6808 goto done;
6809
6810 /* Get the fixed size user data */
6811 Length = sizeof(SAM_USER_FIXED_DATA);
6812 Status = SampGetObjectAttribute(UserObject,
6813 L"F",
6814 NULL,
6815 (PVOID)&FixedData,
6816 &Length);
6817 if (!NT_SUCCESS(Status))
6818 goto done;
6819
6820 /* Set the fields to be returned */
6821 if (UserObject->Trusted)
6822 {
6823 InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
6824 USER_ALL_READ_LOGON_MASK |
6825 USER_ALL_READ_ACCOUNT_MASK |
6826 USER_ALL_READ_PREFERENCES_MASK |
6827 USER_ALL_READ_TRUSTED_MASK;
6828 }
6829 else
6830 {
6831 InfoBuffer->All.WhichFields = 0;
6832
6833 if (UserObject->Access & USER_READ_GENERAL)
6834 InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6835
6836 if (UserObject->Access & USER_READ_LOGON)
6837 InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
6838
6839 if (UserObject->Access & USER_READ_ACCOUNT)
6840 InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6841
6842 if (UserObject->Access & USER_READ_PREFERENCES)
6843 InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6844 }
6845
6846 /* Fail, if no fields are to be returned */
6847 if (InfoBuffer->All.WhichFields == 0)
6848 {
6849 Status = STATUS_ACCESS_DENIED;
6850 goto done;
6851 }
6852
6853 /* Get the UserName attribute */
6854 if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
6855 {
6856 Status = SampGetObjectAttributeString(UserObject,
6857 L"Name",
6858 &InfoBuffer->All.UserName);
6859 if (!NT_SUCCESS(Status))
6860 {
6861 TRACE("Status 0x%08lx\n", Status);
6862 goto done;
6863 }
6864 }
6865
6866 /* Get the FullName attribute */
6867 if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
6868 {
6869 Status = SampGetObjectAttributeString(UserObject,
6870 L"FullName",
6871 &InfoBuffer->All.FullName);
6872 if (!NT_SUCCESS(Status))
6873 {
6874 TRACE("Status 0x%08lx\n", Status);
6875 goto done;
6876 }
6877 }
6878
6879 /* Get the UserId attribute */
6880 if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
6881 {
6882 InfoBuffer->All.UserId = FixedData.UserId;
6883 }
6884
6885 /* Get the PrimaryGroupId attribute */
6886 if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
6887 {
6888 InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6889 }
6890
6891 /* Get the AdminComment attribute */
6892 if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
6893 {
6894 Status = SampGetObjectAttributeString(UserObject,
6895 L"AdminComment",
6896 &InfoBuffer->All.AdminComment);
6897 if (!NT_SUCCESS(Status))
6898 {
6899 TRACE("Status 0x%08lx\n", Status);
6900 goto done;
6901 }
6902 }
6903
6904 /* Get the UserComment attribute */
6905 if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
6906 {
6907 Status = SampGetObjectAttributeString(UserObject,
6908 L"UserComment",
6909 &InfoBuffer->All.UserComment);
6910 if (!NT_SUCCESS(Status))
6911 {
6912 TRACE("Status 0x%08lx\n", Status);
6913 goto done;
6914 }
6915 }
6916
6917 /* Get the HomeDirectory attribute */
6918 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
6919 {
6920 Status = SampGetObjectAttributeString(UserObject,
6921 L"HomeDirectory",
6922 &InfoBuffer->All.HomeDirectory);
6923 if (!NT_SUCCESS(Status))
6924 {
6925 TRACE("Status 0x%08lx\n", Status);
6926 goto done;
6927 }
6928 }
6929
6930 /* Get the HomeDirectoryDrive attribute */
6931 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
6932 {
6933 Status = SampGetObjectAttributeString(UserObject,
6934 L"HomeDirectoryDrive",
6935 &InfoBuffer->Home.HomeDirectoryDrive);
6936 if (!NT_SUCCESS(Status))
6937 {
6938 TRACE("Status 0x%08lx\n", Status);
6939 goto done;
6940 }
6941 }
6942
6943 /* Get the ScriptPath attribute */
6944 if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
6945 {
6946 Status = SampGetObjectAttributeString(UserObject,
6947 L"ScriptPath",
6948 &InfoBuffer->All.ScriptPath);
6949 if (!NT_SUCCESS(Status))
6950 {
6951 TRACE("Status 0x%08lx\n", Status);
6952 goto done;
6953 }
6954 }
6955
6956 /* Get the ProfilePath attribute */
6957 if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
6958 {
6959 Status = SampGetObjectAttributeString(UserObject,
6960 L"ProfilePath",
6961 &InfoBuffer->All.ProfilePath);
6962 if (!NT_SUCCESS(Status))
6963 {
6964 TRACE("Status 0x%08lx\n", Status);
6965 goto done;
6966 }
6967 }
6968
6969 /* Get the WorkStations attribute */
6970 if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
6971 {
6972 Status = SampGetObjectAttributeString(UserObject,
6973 L"WorkStations",
6974 &InfoBuffer->All.WorkStations);
6975 if (!NT_SUCCESS(Status))
6976 {
6977 TRACE("Status 0x%08lx\n", Status);
6978 goto done;
6979 }
6980 }
6981
6982 /* Get the LastLogon attribute */
6983 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
6984 {
6985 InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6986 InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6987 }
6988
6989 /* Get the LastLogoff attribute */
6990 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
6991 {
6992 InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6993 InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6994 }
6995
6996 /* Get the LogonHours attribute */
6997 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
6998 {
6999 Status = SampGetLogonHoursAttribute(UserObject,
7000 &InfoBuffer->All.LogonHours);
7001 if (!NT_SUCCESS(Status))
7002 {
7003 TRACE("Status 0x%08lx\n", Status);
7004 goto done;
7005 }
7006 }
7007
7008 /* Get the BadPasswordCount attribute */
7009 if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
7010 {
7011 InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
7012 }
7013
7014 /* Get the LogonCount attribute */
7015 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
7016 {
7017 InfoBuffer->All.LogonCount = FixedData.LogonCount;
7018 }
7019
7020 /* Get the PasswordCanChange attribute */
7021 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
7022 {
7023 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7024 DomainFixedData.MinPasswordAge);
7025 InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
7026 InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
7027 }
7028
7029 /* Get the PasswordMustChange attribute */
7030 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
7031 {
7032 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7033 DomainFixedData.MaxPasswordAge);
7034 InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
7035 InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
7036 }
7037
7038 /* Get the PasswordLastSet attribute */
7039 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
7040 {
7041 InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
7042 InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
7043 }
7044
7045 /* Get the AccountExpires attribute */
7046 if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
7047 {
7048 InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
7049 InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
7050 }
7051
7052 /* Get the UserAccountControl attribute */
7053 if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
7054 {
7055 InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
7056 }
7057
7058 /* Get the Parameters attribute */
7059 if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
7060 {
7061 Status = SampGetObjectAttributeString(UserObject,
7062 L"Parameters",
7063 &InfoBuffer->All.Parameters);
7064 if (!NT_SUCCESS(Status))
7065 {
7066 TRACE("Status 0x%08lx\n", Status);
7067 goto done;
7068 }
7069 }
7070
7071 /* Get the CountryCode attribute */
7072 if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
7073 {
7074 InfoBuffer->All.CountryCode = FixedData.CountryCode;
7075 }
7076
7077 /* Get the CodePage attribute */
7078 if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
7079 {
7080 InfoBuffer->All.CodePage = FixedData.CodePage;
7081 }
7082
7083 /* Get the LmPassword and NtPassword attributes */
7084 if (InfoBuffer->All.WhichFields & (USER_ALL_NTPASSWORDPRESENT | USER_ALL_LMPASSWORDPRESENT))
7085 {
7086 InfoBuffer->All.LmPasswordPresent = FALSE;
7087 InfoBuffer->All.NtPasswordPresent = FALSE;
7088
7089 /* Get the NT password */
7090 Length = 0;
7091 SampGetObjectAttribute(UserObject,
7092 L"NTPwd",
7093 NULL,
7094 NULL,
7095 &Length);
7096
7097 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
7098 {
7099 InfoBuffer->All.NtOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_NT_OWF_PASSWORD));
7100 if (InfoBuffer->All.NtOwfPassword.Buffer == NULL)
7101 {
7102 Status = STATUS_INSUFFICIENT_RESOURCES;
7103 goto done;
7104 }
7105
7106 InfoBuffer->All.NtOwfPassword.Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7107 InfoBuffer->All.NtOwfPassword.MaximumLength = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7108
7109 Status = SampGetObjectAttribute(UserObject,
7110 L"NTPwd",
7111 NULL,
7112 (PVOID)InfoBuffer->All.NtOwfPassword.Buffer,
7113 &Length);
7114 if (!NT_SUCCESS(Status))
7115 goto done;
7116
7117 if (memcmp(InfoBuffer->All.NtOwfPassword.Buffer,
7118 &EmptyNtHash,
7119 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
7120 InfoBuffer->All.NtPasswordPresent = TRUE;
7121 }
7122
7123 /* Get the LM password */
7124 Length = 0;
7125 SampGetObjectAttribute(UserObject,
7126 L"LMPwd",
7127 NULL,
7128 NULL,
7129 &Length);
7130
7131 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
7132 {
7133 InfoBuffer->All.LmOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_LM_OWF_PASSWORD));
7134 if (InfoBuffer->All.LmOwfPassword.Buffer == NULL)
7135 {
7136 Status = STATUS_INSUFFICIENT_RESOURCES;
7137 goto done;
7138 }
7139
7140 InfoBuffer->All.LmOwfPassword.Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7141 InfoBuffer->All.LmOwfPassword.MaximumLength = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7142
7143 Status = SampGetObjectAttribute(UserObject,
7144 L"LMPwd",
7145 NULL,
7146 (PVOID)InfoBuffer->All.LmOwfPassword.Buffer,
7147 &Length);
7148 if (!NT_SUCCESS(Status))
7149 goto done;
7150
7151 if (memcmp(InfoBuffer->All.LmOwfPassword.Buffer,
7152 &EmptyLmHash,
7153 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7154 InfoBuffer->All.LmPasswordPresent = TRUE;
7155 }
7156 }
7157
7158 if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
7159 {
7160 Status = SampGetObjectAttributeString(UserObject,
7161 L"PrivateData",
7162 &InfoBuffer->All.PrivateData);
7163 if (!NT_SUCCESS(Status))
7164 {
7165 TRACE("Status 0x%08lx\n", Status);
7166 goto done;
7167 }
7168 }
7169
7170 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
7171 {
7172 /* FIXME */
7173 }
7174
7175 if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7176 {
7177 Length = 0;
7178 SampGetObjectAttribute(UserObject,
7179 L"SecDesc",
7180 NULL,
7181 NULL,
7182 &Length);
7183
7184 if (Length > 0)
7185 {
7186 InfoBuffer->All.SecurityDescriptor.SecurityDescriptor = midl_user_allocate(Length);
7187 if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor == NULL)
7188 {
7189 Status = STATUS_INSUFFICIENT_RESOURCES;
7190 goto done;
7191 }
7192
7193 InfoBuffer->All.SecurityDescriptor.Length = Length;
7194
7195 Status = SampGetObjectAttribute(UserObject,
7196 L"SecDesc",
7197 NULL,
7198 (PVOID)InfoBuffer->All.SecurityDescriptor.SecurityDescriptor,
7199 &Length);
7200 if (!NT_SUCCESS(Status))
7201 goto done;
7202 }
7203 }
7204
7205 *Buffer = InfoBuffer;
7206
7207 done:
7208 if (!NT_SUCCESS(Status))
7209 {
7210 if (InfoBuffer != NULL)
7211 {
7212 if (InfoBuffer->All.UserName.Buffer != NULL)
7213 midl_user_free(InfoBuffer->All.UserName.Buffer);
7214
7215 if (InfoBuffer->All.FullName.Buffer != NULL)
7216 midl_user_free(InfoBuffer->All.FullName.Buffer);
7217
7218 if (InfoBuffer->All.AdminComment.Buffer != NULL)
7219 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
7220
7221 if (InfoBuffer->All.UserComment.Buffer != NULL)
7222 midl_user_free(InfoBuffer->All.UserComment.Buffer);
7223
7224 if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
7225 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
7226
7227 if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
7228 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
7229
7230 if (InfoBuffer->All.ScriptPath.Buffer != NULL)
7231 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
7232
7233 if (InfoBuffer->All.ProfilePath.Buffer != NULL)
7234 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
7235
7236 if (InfoBuffer->All.WorkStations.Buffer != NULL)
7237 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
7238
7239 if (InfoBuffer->All.LogonHours.LogonHours != NULL)
7240 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
7241
7242 if (InfoBuffer->All.Parameters.Buffer != NULL)
7243 midl_user_free(InfoBuffer->All.Parameters.Buffer);
7244
7245 if (InfoBuffer->All.LmOwfPassword.Buffer != NULL)
7246 midl_user_free(InfoBuffer->All.LmOwfPassword.Buffer);
7247
7248 if (InfoBuffer->All.NtOwfPassword.Buffer != NULL)
7249 midl_user_free(InfoBuffer->All.NtOwfPassword.Buffer);
7250
7251 if (InfoBuffer->All.PrivateData.Buffer != NULL)
7252 midl_user_free(InfoBuffer->All.PrivateData.Buffer);
7253
7254 if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor != NULL)
7255 midl_user_free(InfoBuffer->All.SecurityDescriptor.SecurityDescriptor);
7256
7257 midl_user_free(InfoBuffer);
7258 }
7259 }
7260
7261 return Status;
7262 }
7263
7264
7265 /* Function 36 */
7266 NTSTATUS
7267 NTAPI
7268 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
7269 IN USER_INFORMATION_CLASS UserInformationClass,
7270 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
7271 {
7272 PSAM_DB_OBJECT UserObject;
7273 ACCESS_MASK DesiredAccess;
7274 NTSTATUS Status;
7275
7276 TRACE("SamrQueryInformationUser(%p %lu %p)\n",
7277 UserHandle, UserInformationClass, Buffer);
7278
7279 switch (UserInformationClass)
7280 {
7281 case UserGeneralInformation:
7282 case UserNameInformation:
7283 case UserAccountNameInformation:
7284 case UserFullNameInformation:
7285 case UserPrimaryGroupInformation:
7286 case UserAdminCommentInformation:
7287 DesiredAccess = USER_READ_GENERAL;
7288 break;
7289
7290 case UserLogonHoursInformation:
7291 case UserHomeInformation:
7292 case UserScriptInformation:
7293 case UserProfileInformation:
7294 case UserWorkStationsInformation:
7295 DesiredAccess = USER_READ_LOGON;
7296 break;
7297
7298 case UserControlInformation:
7299 case UserExpiresInformation:
7300 case UserParametersInformation:
7301 DesiredAccess = USER_READ_ACCOUNT;
7302 break;
7303
7304 case UserPreferencesInformation:
7305 DesiredAccess = USER_READ_GENERAL |
7306 USER_READ_PREFERENCES;
7307 break;
7308
7309 case UserLogonInformation:
7310 case UserAccountInformation:
7311 DesiredAccess = USER_READ_GENERAL |
7312 USER_READ_PREFERENCES |
7313 USER_READ_LOGON |
7314 USER_READ_ACCOUNT;
7315 break;
7316
7317 case UserInternal1Information:
7318 case UserAllInformation:
7319 DesiredAccess = 0;
7320 break;
7321
7322 default:
7323 return STATUS_INVALID_INFO_CLASS;
7324 }
7325
7326 RtlAcquireResourceShared(&SampResource,
7327 TRUE);
7328
7329 /* Validate the domain handle */
7330 Status = SampValidateDbObject(UserHandle,
7331 SamDbUserObject,
7332 DesiredAccess,
7333 &UserObject);
7334 if (!NT_SUCCESS(Status))
7335 {
7336 TRACE("failed with status 0x%08lx\n", Status);
7337 goto done;
7338 }
7339
7340 switch (UserInformationClass)
7341 {
7342 case UserGeneralInformation:
7343 Status = SampQueryUserGeneral(UserObject,
7344 Buffer);
7345 break;
7346
7347 case UserPreferencesInformation:
7348 Status = SampQueryUserPreferences(UserObject,
7349 Buffer);
7350 break;
7351
7352 case UserLogonInformation:
7353 Status = SampQueryUserLogon(UserObject,
7354 Buffer);
7355 break;
7356
7357 case UserLogonHoursInformation:
7358 Status = SampQueryUserLogonHours(UserObject,
7359 Buffer);
7360 break;
7361
7362 case UserAccountInformation:
7363 Status = SampQueryUserAccount(UserObject,
7364 Buffer);
7365 break;
7366
7367 case UserNameInformation:
7368 Status = SampQueryUserName(UserObject,
7369 Buffer);
7370 break;
7371
7372 case UserAccountNameInformation:
7373 Status = SampQueryUserAccountName(UserObject,
7374 Buffer);
7375 break;
7376
7377 case UserFullNameInformation:
7378 Status = SampQueryUserFullName(UserObject,
7379 Buffer);
7380 break;
7381
7382 case UserPrimaryGroupInformation:
7383 Status = SampQueryUserPrimaryGroup(UserObject,
7384 Buffer);
7385 break;
7386
7387 case UserHomeInformation:
7388 Status = SampQueryUserHome(UserObject,
7389 Buffer);
7390
7391 case UserScriptInformation:
7392 Status = SampQueryUserScript(UserObject,
7393 Buffer);
7394 break;
7395
7396 case UserProfileInformation:
7397 Status = SampQueryUserProfile(UserObject,
7398 Buffer);
7399 break;
7400
7401 case UserAdminCommentInformation:
7402 Status = SampQueryUserAdminComment(UserObject,
7403 Buffer);
7404 break;
7405
7406 case UserWorkStationsInformation:
7407 Status = SampQueryUserWorkStations(UserObject,
7408 Buffer);
7409 break;
7410
7411 case UserControlInformation:
7412 Status = SampQueryUserControl(UserObject,
7413 Buffer);
7414 break;
7415
7416 case UserExpiresInformation:
7417 Status = SampQueryUserExpires(UserObject,
7418 Buffer);
7419 break;
7420
7421 case UserInternal1Information:
7422 Status = SampQueryUserInternal1(UserObject,
7423 Buffer);
7424 break;
7425
7426 case UserParametersInformation:
7427 Status = SampQueryUserParameters(UserObject,
7428 Buffer);
7429 break;
7430
7431 case UserAllInformation:
7432 Status = SampQueryUserAll(UserObject,
7433 Buffer);
7434 break;
7435
7436 // case UserInternal4Information:
7437 // case UserInternal5Information:
7438 // case UserInternal4InformationNew:
7439 // case UserInternal5InformationNew:
7440
7441 default:
7442 Status = STATUS_INVALID_INFO_CLASS;
7443 }
7444
7445 done:
7446 RtlReleaseResource(&SampResource);
7447
7448 return Status;
7449 }
7450
7451
7452 static NTSTATUS
7453 SampSetUserName(PSAM_DB_OBJECT UserObject,
7454 PRPC_UNICODE_STRING NewUserName)
7455 {
7456 UNICODE_STRING OldUserName = {0, 0, NULL};
7457 NTSTATUS Status;
7458
7459 /* Check the account name */
7460 Status = SampCheckAccountName(NewUserName, 20);
7461 if (!NT_SUCCESS(Status))
7462 {
7463 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
7464 return Status;
7465 }
7466
7467 Status = SampGetObjectAttributeString(UserObject,
7468 L"Name",
7469 (PRPC_UNICODE_STRING)&OldUserName);
7470 if (!NT_SUCCESS(Status))
7471 {
7472 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
7473 goto done;
7474 }
7475
7476 if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
7477 {
7478 Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
7479 NewUserName->Buffer);
7480 if (!NT_SUCCESS(Status))
7481 {
7482 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7483 NewUserName->Buffer, Status);
7484 goto done;
7485 }
7486 }
7487
7488 Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7489 L"Users",
7490 NewUserName->Buffer,
7491 UserObject->RelativeId);
7492 if (!NT_SUCCESS(Status))
7493 {
7494 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7495 goto done;
7496 }
7497
7498 Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7499 L"Users",
7500 OldUserName.Buffer);
7501 if (!NT_SUCCESS(Status))
7502 {
7503 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7504 goto done;
7505 }
7506
7507 Status = SampSetObjectAttributeString(UserObject,
7508 L"Name",
7509 NewUserName);
7510 if (!NT_SUCCESS(Status))
7511 {
7512 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7513 }
7514
7515 done:
7516 if (OldUserName.Buffer != NULL)
7517 midl_user_free(OldUserName.Buffer);
7518
7519 return Status;
7520 }
7521
7522
7523 static NTSTATUS
7524 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7525 PSAMPR_USER_INFO_BUFFER Buffer)
7526 {
7527 SAM_USER_FIXED_DATA FixedData;
7528 ULONG Length = 0;
7529 NTSTATUS Status;
7530
7531 Length = sizeof(SAM_USER_FIXED_DATA);
7532 Status = SampGetObjectAttribute(UserObject,
7533 L"F",
7534 NULL,
7535 (PVOID)&FixedData,
7536 &Length);
7537 if (!NT_SUCCESS(Status))
7538 goto done;
7539
7540 FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7541
7542 Status = SampSetObjectAttribute(UserObject,
7543 L"F",
7544 REG_BINARY,
7545 &FixedData,
7546 Length);
7547 if (!NT_SUCCESS(Status))
7548 goto done;
7549
7550 Status = SampSetUserName(UserObject,
7551 &Buffer->General.UserName);
7552 if (!NT_SUCCESS(Status))
7553 goto done;
7554
7555 Status = SampSetObjectAttributeString(UserObject,
7556 L"FullName",
7557 &Buffer->General.FullName);
7558 if (!NT_SUCCESS(Status))
7559 goto done;
7560
7561 Status = SampSetObjectAttributeString(UserObject,
7562 L"AdminComment",
7563 &Buffer->General.AdminComment);
7564 if (!NT_SUCCESS(Status))
7565 goto done;
7566
7567 Status = SampSetObjectAttributeString(UserObject,
7568 L"UserComment",
7569 &Buffer->General.UserComment);
7570
7571 done:
7572 return Status;
7573 }
7574
7575
7576 static NTSTATUS
7577 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7578 PSAMPR_USER_INFO_BUFFER Buffer)
7579 {
7580 SAM_USER_FIXED_DATA FixedData;
7581 ULONG Length = 0;
7582 NTSTATUS Status;
7583
7584 Length = sizeof(SAM_USER_FIXED_DATA);
7585 Status = SampGetObjectAttribute(UserObject,
7586 L"F",
7587 NULL,
7588 (PVOID)&FixedData,
7589 &Length);
7590 if (!NT_SUCCESS(Status))
7591 goto done;
7592
7593 FixedData.CountryCode = Buffer->Preferences.CountryCode;
7594 FixedData.CodePage = Buffer->Preferences.CodePage;
7595
7596 Status = SampSetObjectAttribute(UserObject,
7597 L"F",
7598 REG_BINARY,
7599 &FixedData,
7600 Length);
7601 if (!NT_SUCCESS(Status))
7602 goto done;
7603
7604 Status = SampSetObjectAttributeString(UserObject,
7605 L"UserComment",
7606 &Buffer->Preferences.UserComment);
7607
7608 done:
7609 return Status;
7610 }
7611
7612
7613 static NTSTATUS
7614 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7615 PSAMPR_USER_INFO_BUFFER Buffer)
7616 {
7617 SAM_USER_FIXED_DATA FixedData;
7618 ULONG Length = 0;
7619 NTSTATUS Status;
7620
7621 Length = sizeof(SAM_USER_FIXED_DATA);
7622 Status = SampGetObjectAttribute(UserObject,
7623 L"F",
7624 NULL,
7625 (PVOID)&FixedData,
7626 &Length);
7627 if (!NT_SUCCESS(Status))
7628 goto done;
7629
7630 FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7631
7632 Status = SampSetObjectAttribute(UserObject,
7633 L"F",
7634 REG_BINARY,
7635 &FixedData,
7636 Length);
7637
7638 done:
7639 return Status;
7640 }
7641
7642
7643 static NTSTATUS
7644 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7645 PSAMPR_USER_INFO_BUFFER Buffer)
7646 {
7647 SAM_USER_FIXED_DATA FixedData;
7648 ULONG Length = 0;
7649 NTSTATUS Status;
7650
7651 Length = sizeof(SAM_USER_FIXED_DATA);
7652 Status = SampGetObjectAttribute(UserObject,
7653 L"F",
7654 NULL,
7655 (PVOID)&FixedData,
7656 &Length);
7657 if (!NT_SUCCESS(Status))
7658 goto done;
7659
7660 FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7661
7662 Status = SampSetObjectAttribute(UserObject,
7663 L"F",
7664 REG_BINARY,
7665 &FixedData,
7666 Length);
7667
7668 done:
7669 return Status;
7670 }
7671
7672
7673 static NTSTATUS
7674 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7675 PSAMPR_USER_INFO_BUFFER Buffer)
7676 {
7677 SAM_USER_FIXED_DATA FixedData;
7678 ULONG Length = 0;
7679 NTSTATUS Status;
7680
7681 Length = sizeof(SAM_USER_FIXED_DATA);
7682 Status = SampGetObjectAttribute(UserObject,
7683 L"F",
7684 NULL,
7685 (PVOID)&FixedData,
7686 &Length);
7687 if (!NT_SUCCESS(Status))
7688 goto done;
7689
7690 FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7691 FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7692
7693 Status = SampSetObjectAttribute(UserObject,
7694 L"F",
7695 REG_BINARY,
7696 &FixedData,
7697 Length);
7698
7699 done:
7700 return Status;
7701 }
7702
7703
7704 static NTSTATUS
7705 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7706 PSAMPR_USER_INFO_BUFFER Buffer)
7707 {
7708 SAM_USER_FIXED_DATA FixedData;
7709 ULONG Length = 0;
7710 NTSTATUS Status = STATUS_SUCCESS;
7711
7712 /* FIXME: Decrypt NT password */
7713 /* FIXME: Decrypt LM password */
7714
7715 Status = SampSetUserPassword(UserObject,
7716 &Buffer->Internal1.EncryptedNtOwfPassword,
7717 Buffer->Internal1.NtPasswordPresent,
7718 &Buffer->Internal1.EncryptedLmOwfPassword,
7719 Buffer->Internal1.LmPasswordPresent);
7720 if (!NT_SUCCESS(Status))
7721 goto done;
7722
7723 /* Get the fixed user attributes */
7724 Length = sizeof(SAM_USER_FIXED_DATA);
7725 Status = SampGetObjectAttribute(UserObject,
7726 L"F",
7727 NULL,
7728 (PVOID)&FixedData,
7729 &Length);
7730 if (!NT_SUCCESS(Status))
7731 goto done;
7732
7733 if (Buffer->Internal1.PasswordExpired)
7734 {
7735 /* The password was last set ages ago */
7736 FixedData.PasswordLastSet.LowPart = 0;
7737 FixedData.PasswordLastSet.HighPart = 0;
7738 }
7739 else
7740 {
7741 /* The password was last set right now */
7742 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7743 if (!NT_SUCCESS(Status))
7744 goto done;
7745 }
7746
7747 /* Set the fixed user attributes */
7748 Status = SampSetObjectAttribute(UserObject,
7749 L"F",
7750 REG_BINARY,
7751 &FixedData,
7752 Length);
7753
7754 done:
7755 return Status;
7756 }
7757
7758
7759 static NTSTATUS
7760 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7761 PSAMPR_USER_INFO_BUFFER Buffer)
7762 {
7763 SAM_USER_FIXED_DATA FixedData;
7764 ULONG Length = 0;
7765 ULONG WhichFields;
7766 PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7767 PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7768 BOOLEAN NtPasswordPresent = FALSE;
7769 BOOLEAN LmPasswordPresent = FALSE;
7770 BOOLEAN WriteFixedData = FALSE;
7771 NTSTATUS Status = STATUS_SUCCESS;
7772
7773 WhichFields = Buffer->All.WhichFields;
7774
7775 /* Get the fixed size attributes */
7776 Length = sizeof(SAM_USER_FIXED_DATA);
7777 Status = SampGetObjectAttribute(UserObject,
7778 L"F",
7779 NULL,
7780 (PVOID)&FixedData,
7781 &Length);
7782 if (!NT_SUCCESS(Status))
7783 goto done;
7784
7785 if (WhichFields & USER_ALL_USERNAME)
7786 {
7787 Status = SampSetUserName(UserObject,
7788 &Buffer->All.UserName);
7789 if (!NT_SUCCESS(Status))
7790 goto done;
7791 }
7792
7793 if (WhichFields & USER_ALL_FULLNAME)
7794 {
7795 Status = SampSetObjectAttributeString(UserObject,
7796 L"FullName",
7797 &Buffer->All.FullName);
7798 if (!NT_SUCCESS(Status))
7799 goto done;
7800 }
7801
7802 if (WhichFields & USER_ALL_ADMINCOMMENT)
7803 {
7804 Status = SampSetObjectAttributeString(UserObject,
7805 L"AdminComment",
7806 &Buffer->All.AdminComment);
7807 if (!NT_SUCCESS(Status))
7808 goto done;
7809 }
7810
7811 if (WhichFields & USER_ALL_USERCOMMENT)
7812 {
7813 Status = SampSetObjectAttributeString(UserObject,
7814 L"UserComment",
7815 &Buffer->All.UserComment);
7816 if (!NT_SUCCESS(Status))
7817 goto done;
7818 }
7819
7820 if (WhichFields & USER_ALL_HOMEDIRECTORY)
7821 {
7822 Status = SampSetObjectAttributeString(UserObject,
7823 L"HomeDirectory",
7824 &Buffer->All.HomeDirectory);
7825 if (!NT_SUCCESS(Status))
7826 goto done;
7827 }
7828
7829 if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7830 {
7831 Status = SampSetObjectAttributeString(UserObject,
7832 L"HomeDirectoryDrive",
7833 &Buffer->All.HomeDirectoryDrive);
7834 if (!NT_SUCCESS(Status))
7835 goto done;
7836 }
7837
7838 if (WhichFields & USER_ALL_SCRIPTPATH)
7839 {
7840 Status = SampSetObjectAttributeString(UserObject,
7841 L"ScriptPath",
7842 &Buffer->All.ScriptPath);
7843 if (!NT_SUCCESS(Status))
7844 goto done;
7845 }
7846
7847 if (WhichFields & USER_ALL_PROFILEPATH)
7848 {
7849 Status = SampSetObjectAttributeString(UserObject,
7850 L"ProfilePath",
7851 &Buffer->All.ProfilePath);
7852 if (!NT_SUCCESS(Status))
7853 goto done;
7854 }
7855
7856 if (WhichFields & USER_ALL_WORKSTATIONS)
7857 {
7858 Status = SampSetObjectAttributeString(UserObject,
7859 L"WorkStations",
7860 &Buffer->All.WorkStations);
7861 if (!NT_SUCCESS(Status))
7862 goto done;
7863 }
7864
7865 if (WhichFields & USER_ALL_PARAMETERS)
7866 {
7867 Status = SampSetObjectAttributeString(UserObject,
7868 L"Parameters",
7869 &Buffer->All.Parameters);
7870 if (!NT_SUCCESS(Status))
7871 goto done;
7872 }
7873
7874 if (WhichFields & USER_ALL_LOGONHOURS)
7875 {
7876 Status = SampSetLogonHoursAttribute(UserObject,
7877 &Buffer->All.LogonHours);
7878 if (!NT_SUCCESS(Status))
7879 goto done;
7880 }
7881
7882 if (WhichFields & USER_ALL_PRIMARYGROUPID)
7883 {
7884 FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
7885 WriteFixedData = TRUE;
7886 }
7887
7888 if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
7889 {
7890 FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
7891 FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
7892 WriteFixedData = TRUE;
7893 }
7894
7895 if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
7896 {
7897 FixedData.UserAccountControl = Buffer->All.UserAccountControl;
7898 WriteFixedData = TRUE;
7899 }
7900
7901 if (WhichFields & USER_ALL_COUNTRYCODE)
7902 {
7903 FixedData.CountryCode = Buffer->All.CountryCode;
7904 WriteFixedData = TRUE;
7905 }
7906
7907 if (WhichFields & USER_ALL_CODEPAGE)
7908 {
7909 FixedData.CodePage = Buffer->All.CodePage;
7910 WriteFixedData = TRUE;
7911 }
7912
7913 if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
7914 USER_ALL_LMPASSWORDPRESENT))
7915 {
7916 if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
7917 {
7918 NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
7919 NtPasswordPresent = Buffer->All.NtPasswordPresent;
7920 }
7921
7922 if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
7923 {
7924 LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
7925 LmPasswordPresent = Buffer->All.LmPasswordPresent;
7926 }
7927
7928 Status = SampSetUserPassword(UserObject,
7929 NtPassword,
7930 NtPasswordPresent,
7931 LmPassword,
7932 LmPasswordPresent);
7933 if (!NT_SUCCESS(Status))
7934 goto done;
7935
7936 /* The password has just been set */
7937 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7938 if (!NT_SUCCESS(Status))
7939 goto done;
7940
7941 WriteFixedData = TRUE;
7942 }
7943
7944 if (WhichFields & USER_ALL_PRIVATEDATA)
7945 {
7946 Status = SampSetObjectAttributeString(UserObject,
7947 L"PrivateData",
7948 &Buffer->All.PrivateData);
7949 if (!NT_SUCCESS(Status))
7950 goto done;
7951 }
7952
7953 if (WhichFields & USER_ALL_PASSWORDEXPIRED)
7954 {
7955 if (Buffer->All.PasswordExpired)
7956 {
7957 /* The password was last set ages ago */
7958 FixedData.PasswordLastSet.LowPart = 0;
7959 FixedData.PasswordLastSet.HighPart = 0;
7960 }
7961 else
7962 {
7963 /* The password was last set right now */
7964 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7965 if (!NT_SUCCESS(Status))
7966 goto done;
7967 }
7968
7969 WriteFixedData = TRUE;
7970 }
7971
7972 if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7973 {
7974 Status = SampSetObjectAttribute(UserObject,
7975 L"SecDesc",
7976 REG_BINARY,
7977 Buffer->All.SecurityDescriptor.SecurityDescriptor,
7978 Buffer->All.SecurityDescriptor.Length);
7979 }
7980
7981 if (WriteFixedData != FALSE)
7982 {
7983 Status = SampSetObjectAttribute(UserObject,
7984 L"F",
7985 REG_BINARY,
7986 &FixedData,
7987 Length);
7988 if (!NT_SUCCESS(Status))
7989 goto done;
7990 }
7991
7992 done:
7993 return Status;
7994 }
7995
7996
7997 /* Function 37 */
7998 NTSTATUS
7999 NTAPI
8000 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
8001 IN USER_INFORMATION_CLASS UserInformationClass,
8002 IN PSAMPR_USER_INFO_BUFFER Buffer)
8003 {
8004 PSAM_DB_OBJECT UserObject;
8005 ACCESS_MASK DesiredAccess;
8006 NTSTATUS Status;
8007
8008 TRACE("SamrSetInformationUser(%p %lu %p)\n",
8009 UserHandle, UserInformationClass, Buffer);
8010
8011 switch (UserInformationClass)
8012 {
8013 case UserLogonHoursInformation:
8014 case UserNameInformation:
8015 case UserAccountNameInformation:
8016 case UserFullNameInformation:
8017 case UserPrimaryGroupInformation:
8018 case UserHomeInformation:
8019 case UserScriptInformation:
8020 case UserProfileInformation:
8021 case UserAdminCommentInformation:
8022 case UserWorkStationsInformation:
8023 case UserControlInformation:
8024 case UserExpiresInformation:
8025 case UserParametersInformation:
8026 DesiredAccess = USER_WRITE_ACCOUNT;
8027 break;
8028
8029 case UserGeneralInformation:
8030 DesiredAccess = USER_WRITE_ACCOUNT |
8031 USER_WRITE_PREFERENCES;
8032 break;
8033
8034 case UserPreferencesInformation:
8035 DesiredAccess = USER_WRITE_PREFERENCES;
8036 break;
8037
8038 case UserSetPasswordInformation:
8039 case UserInternal1Information:
8040 DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
8041 break;
8042
8043 case UserAllInformation:
8044 DesiredAccess = 0; /* FIXME */
8045 break;
8046
8047 default:
8048 return STATUS_INVALID_INFO_CLASS;
8049 }
8050
8051 RtlAcquireResourceExclusive(&SampResource,
8052 TRUE);
8053
8054 /* Validate the domain handle */
8055 Status = SampValidateDbObject(UserHandle,
8056 SamDbUserObject,
8057 DesiredAccess,
8058 &UserObject);
8059 if (!NT_SUCCESS(Status))
8060 {
8061 TRACE("failed with status 0x%08lx\n", Status);
8062 goto done;
8063 }
8064
8065 switch (UserInformationClass)
8066 {
8067 case UserGeneralInformation:
8068 Status = SampSetUserGeneral(UserObject,
8069 Buffer);
8070 break;
8071
8072 case UserPreferencesInformation:
8073 Status = SampSetUserPreferences(UserObject,
8074 Buffer);
8075 break;
8076
8077 case UserLogonHoursInformation:
8078 Status = SampSetLogonHoursAttribute(UserObject,
8079 &Buffer->LogonHours.LogonHours);
8080 break;
8081
8082 case UserNameInformation:
8083 Status = SampSetUserName(UserObject,
8084 &Buffer->Name.UserName);
8085 if (!NT_SUCCESS(Status))
8086 break;
8087
8088 Status = SampSetObjectAttributeString(UserObject,
8089 L"FullName",
8090 &Buffer->Name.FullName);
8091 break;
8092
8093 case UserAccountNameInformation:
8094 Status = SampSetUserName(UserObject,
8095 &Buffer->AccountName.UserName);
8096 break;
8097
8098 case UserFullNameInformation:
8099 Status = SampSetObjectAttributeString(UserObject,
8100 L"FullName",
8101 &Buffer->FullName.FullName);
8102 break;
8103
8104 case UserPrimaryGroupInformation:
8105 Status = SampSetUserPrimaryGroup(UserObject,
8106 Buffer);
8107 break;
8108
8109 case UserHomeInformation:
8110 Status = SampSetObjectAttributeString(UserObject,
8111 L"HomeDirectory",
8112 &Buffer->Home.HomeDirectory);
8113 if (!NT_SUCCESS(Status))
8114 break;
8115
8116 Status = SampSetObjectAttributeString(UserObject,
8117 L"HomeDirectoryDrive",
8118 &Buffer->Home.HomeDirectoryDrive);
8119 break;
8120
8121 case UserScriptInformation:
8122 Status = SampSetObjectAttributeString(UserObject,
8123 L"ScriptPath",
8124 &Buffer->Script.ScriptPath);
8125 break;
8126
8127 case UserProfileInformation:
8128 Status = SampSetObjectAttributeString(UserObject,
8129 L"ProfilePath",
8130 &Buffer->Profile.ProfilePath);
8131 break;
8132
8133 case UserAdminCommentInformation:
8134 Status = SampSetObjectAttributeString(UserObject,
8135 L"AdminComment",
8136 &Buffer->AdminComment.AdminComment);
8137 break;
8138
8139 case UserWorkStationsInformation:
8140 Status = SampSetObjectAttributeString(UserObject,
8141 L"WorkStations",
8142 &Buffer->WorkStations.WorkStations);
8143 break;
8144
8145 case UserSetPasswordInformation:
8146 TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
8147 TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
8148
8149 Status = SampSetObjectAttributeString(UserObject,
8150 L"Password",
8151 &Buffer->SetPassword.Password);
8152 break;
8153
8154 case UserControlInformation:
8155 Status = SampSetUserControl(UserObject,
8156 Buffer);
8157 break;
8158
8159 case UserExpiresInformation:
8160 Status = SampSetUserExpires(UserObject,
8161 Buffer);
8162 break;
8163
8164 case UserInternal1Information:
8165 Status = SampSetUserInternal1(UserObject,
8166 Buffer);
8167 break;
8168
8169 case UserParametersInformation:
8170 Status = SampSetObjectAttributeString(UserObject,
8171 L"Parameters",
8172 &Buffer->Parameters.Parameters);
8173 break;
8174
8175 case UserAllInformation:
8176 Status = SampSetUserAll(UserObject,
8177 Buffer);
8178 break;
8179
8180 // case UserInternal4Information:
8181 // case UserInternal5Information:
8182 // case UserInternal4InformationNew:
8183 // case UserInternal5InformationNew:
8184
8185 default:
8186 Status = STATUS_INVALID_INFO_CLASS;
8187 }
8188
8189 done:
8190 RtlReleaseResource(&SampResource);
8191
8192 return Status;
8193 }
8194
8195
8196 /* Function 38 */
8197 NTSTATUS
8198 NTAPI
8199 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
8200 IN unsigned char LmPresent,
8201 IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
8202 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
8203 IN unsigned char NtPresent,
8204 IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
8205 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
8206 IN unsigned char NtCrossEncryptionPresent,
8207 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
8208 IN unsigned char LmCrossEncryptionPresent,
8209 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
8210 {
8211 ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
8212 ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
8213 LM_OWF_PASSWORD OldLmPassword;
8214 LM_OWF_PASSWORD NewLmPassword;
8215 NT_OWF_PASSWORD OldNtPassword;
8216 NT_OWF_PASSWORD NewNtPassword;
8217 BOOLEAN StoredLmPresent = FALSE;
8218 BOOLEAN StoredNtPresent = FALSE;
8219 BOOLEAN StoredLmEmpty = TRUE;
8220 BOOLEAN StoredNtEmpty = TRUE;
8221 PSAM_DB_OBJECT UserObject;
8222 ULONG Length;
8223 SAM_USER_FIXED_DATA UserFixedData;
8224 SAM_DOMAIN_FIXED_DATA DomainFixedData;
8225 LARGE_INTEGER SystemTime;
8226 NTSTATUS Status;
8227
8228 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
8229 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
8230 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
8231
8232 TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
8233 UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
8234 NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
8235 NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
8236
8237 RtlAcquireResourceExclusive(&SampResource,
8238 TRUE);
8239
8240 /* Validate the user handle */
8241 Status = SampValidateDbObject(UserHandle,
8242 SamDbUserObject,
8243 USER_CHANGE_PASSWORD,
8244 &UserObject);
8245 if (!NT_SUCCESS(Status))
8246 {
8247 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8248 goto done;
8249 }
8250
8251 /* Get the current time */
8252 Status = NtQuerySystemTime(&SystemTime);
8253 if (!NT_SUCCESS(Status))
8254 {
8255 TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
8256 goto done;
8257 }
8258
8259 /* Retrieve the LM password */
8260 Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
8261 Status = SampGetObjectAttribute(UserObject,
8262 L"LMPwd",
8263 NULL,
8264 &StoredLmPassword,
8265 &Length);
8266 if (NT_SUCCESS(Status))
8267 {
8268 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
8269 {
8270 StoredLmPresent = TRUE;
8271 if (!RtlEqualMemory(&StoredLmPassword,
8272 &EmptyLmHash,
8273 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8274 StoredLmEmpty = FALSE;
8275 }
8276 }
8277
8278 /* Retrieve the NT password */
8279 Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
8280 Status = SampGetObjectAttribute(UserObject,
8281 L"NTPwd",
8282 NULL,
8283 &StoredNtPassword,
8284 &Length);
8285 if (NT_SUCCESS(Status))
8286 {
8287 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
8288 {
8289 StoredNtPresent = TRUE;
8290 if (!RtlEqualMemory(&StoredNtPassword,
8291 &EmptyNtHash,
8292 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
8293 StoredNtEmpty = FALSE;
8294 }
8295 }
8296
8297 /* Retrieve the fixed size user data */
8298 Length = sizeof(SAM_USER_FIXED_DATA);
8299 Status = SampGetObjectAttribute(UserObject,
8300 L"F",
8301 NULL,
8302 &UserFixedData,
8303 &Length);
8304 if (!NT_SUCCESS(Status))
8305 {
8306 TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
8307 goto done;
8308 }
8309
8310 /* Check if we can change the password at this time */
8311 if ((StoredLmEmpty == FALSE) || (StoredNtEmpty == FALSE))
8312 {
8313 /* Get fixed domain data */
8314 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8315 Status = SampGetObjectAttribute(UserObject->ParentObject,
8316 L"F",
8317 NULL,
8318 &DomainFixedData,
8319 &Length);
8320 if (!NT_SUCCESS(Status))
8321 {
8322 TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
8323 goto done;
8324 }
8325
8326 if (DomainFixedData.MinPasswordAge.QuadPart > 0)
8327 {
8328 if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
8329 {
8330 Status = STATUS_ACCOUNT_RESTRICTION;
8331 goto done;
8332 }
8333 }
8334 }
8335
8336 /* Decrypt the LM passwords, if present */
8337 if (LmPresent)
8338 {
8339 Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
8340 (const BYTE *)&StoredLmPassword,
8341 (LPBYTE)&NewLmPassword);
8342 if (!NT_SUCCESS(Status))
8343 {
8344 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8345 goto done;
8346 }
8347
8348 Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
8349 (const BYTE *)&NewLmPassword,
8350 (LPBYTE)&OldLmPassword);
8351 if (!NT_SUCCESS(Status))
8352 {
8353 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8354 goto done;
8355 }
8356 }
8357
8358 /* Decrypt the NT passwords, if present */
8359 if (NtPresent)
8360 {
8361 Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
8362 (const BYTE *)&StoredNtPassword,
8363 (LPBYTE)&NewNtPassword);
8364 if (!NT_SUCCESS(Status))
8365 {
8366 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8367 goto done;
8368 }
8369
8370 Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
8371 (const BYTE *)&NewNtPassword,
8372 (LPBYTE)&OldNtPassword);
8373 if (!NT_SUCCESS(Status))
8374 {
8375 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8376 goto done;
8377 }
8378 }
8379
8380 /* Check if the old passwords match the stored ones */
8381 if (NtPresent)
8382 {
8383 if (LmPresent)
8384 {
8385 if (!RtlEqualMemory(&StoredLmPassword,
8386 &OldLmPassword,
8387 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8388 {
8389 TRACE("Old LM Password does not match!\n");
8390 Status = STATUS_WRONG_PASSWORD;
8391 }
8392 else
8393 {
8394 if (!RtlEqualMemory(&StoredNtPassword,
8395 &OldNtPassword,
8396 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8397 {
8398 TRACE("Old NT Password does not match!\n");
8399 Status = STATUS_WRONG_PASSWORD;
8400 }
8401 }
8402 }
8403 else
8404 {
8405 if (!RtlEqualMemory(&StoredNtPassword,
8406 &OldNtPassword,
8407 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8408 {
8409 TRACE("Old NT Password does not match!\n");
8410 Status = STATUS_WRONG_PASSWORD;
8411 }
8412 }
8413 }
8414 else
8415 {
8416 if (LmPresent)
8417 {
8418 if (!RtlEqualMemory(&StoredLmPassword,
8419 &OldLmPassword,
8420 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8421 {
8422 TRACE("Old LM Password does not match!\n");
8423 Status = STATUS_WRONG_PASSWORD;
8424 }
8425 }
8426 else
8427 {
8428 Status = STATUS_INVALID_PARAMETER;
8429 }
8430 }
8431
8432 /* Store the new password hashes */
8433 if (NT_SUCCESS(Status))
8434 {
8435 Status = SampSetUserPassword(UserObject,
8436 &NewNtPassword,
8437 NtPresent,
8438 &NewLmPassword,
8439 LmPresent);
8440 if (NT_SUCCESS(Status))
8441 {
8442 /* Update PasswordLastSet */
8443 UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
8444
8445 /* Set the fixed size user data */
8446 Length = sizeof(SAM_USER_FIXED_DATA);
8447 Status = SampSetObjectAttribute(UserObject,
8448 L"F",
8449 REG_BINARY,
8450 &UserFixedData,
8451 Length);
8452 }
8453 }
8454
8455 if (Status == STATUS_WRONG_PASSWORD)
8456 {
8457 /* Update BadPasswordCount and LastBadPasswordTime */
8458 UserFixedData.BadPasswordCount++;
8459 UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
8460
8461 /* Set the fixed size user data */
8462 Length = sizeof(SAM_USER_FIXED_DATA);
8463 Status = SampSetObjectAttribute(UserObject,
8464 L"F",
8465 REG_BINARY,
8466 &UserFixedData,
8467 Length);
8468 }
8469
8470 done:
8471 RtlReleaseResource(&SampResource);
8472
8473 return Status;
8474 }
8475
8476
8477 /* Function 39 */
8478 NTSTATUS
8479 NTAPI
8480 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
8481 OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
8482 {
8483 PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
8484 PSAM_DB_OBJECT UserObject;
8485 ULONG Length = 0;
8486 NTSTATUS Status;
8487
8488 TRACE("SamrGetGroupsForUser(%p %p)\n",
8489 UserHandle, Groups);
8490
8491 RtlAcquireResourceShared(&SampResource,
8492 TRUE);
8493
8494 /* Validate the user handle */
8495 Status = SampValidateDbObject(UserHandle,
8496 SamDbUserObject,
8497 USER_LIST_GROUPS,
8498 &UserObject);
8499 if (!NT_SUCCESS(Status))
8500 {
8501 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8502 goto done;
8503 }
8504
8505 /* Allocate the groups buffer */
8506 GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
8507 if (GroupsBuffer == NULL)
8508 {
8509 Status = STATUS_INSUFFICIENT_RESOURCES;
8510 goto done;
8511 }
8512
8513 /*
8514 * Get the size of the Groups attribute.
8515 * Do not check the status code because in case of an error
8516 * Length will be 0. And that is all we need.
8517 */
8518 SampGetObjectAttribute(UserObject,
8519 L"Groups",
8520 NULL,
8521 NULL,
8522 &Length);
8523
8524 /* If there is no Groups attribute, return a groups buffer without an array */
8525 if (Length == 0)
8526 {
8527 GroupsBuffer->MembershipCount = 0;
8528 GroupsBuffer->Groups = NULL;
8529
8530 *Groups = GroupsBuffer;
8531
8532 Status = STATUS_SUCCESS;
8533 goto done;
8534 }
8535
8536 /* Allocate a buffer for the Groups attribute */
8537 GroupsBuffer->Groups = midl_user_allocate(Length);
8538 if (GroupsBuffer->Groups == NULL)
8539 {
8540 Status = STATUS_INSUFFICIENT_RESOURCES;
8541 goto done;
8542 }
8543
8544 /* Retrieve the Grous attribute */
8545 Status = SampGetObjectAttribute(UserObject,
8546 L"Groups",
8547 NULL,
8548 GroupsBuffer->Groups,
8549 &Length);
8550 if (!NT_SUCCESS(Status))
8551 {
8552 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8553 goto done;
8554 }
8555
8556 /* Calculate the membership count */
8557 GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8558
8559 /* Return the groups buffer to the caller */
8560 *Groups = GroupsBuffer;
8561
8562 done:
8563 if (!NT_SUCCESS(Status))
8564 {
8565 if (GroupsBuffer != NULL)
8566 {
8567 if (GroupsBuffer->Groups != NULL)
8568 midl_user_free(GroupsBuffer->Groups);
8569
8570 midl_user_free(GroupsBuffer);
8571 }
8572 }
8573
8574 RtlReleaseResource(&SampResource);
8575
8576 return Status;
8577 }
8578
8579
8580 /* Function 40 */
8581 NTSTATUS
8582 NTAPI
8583 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8584 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8585 IN unsigned long Index,
8586 IN unsigned long EntryCount,
8587 IN unsigned long PreferredMaximumLength,
8588 OUT unsigned long *TotalAvailable,
8589 OUT unsigned long *TotalReturned,
8590 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8591 {
8592 UNIMPLEMENTED;
8593 return STATUS_NOT_IMPLEMENTED;
8594 }
8595
8596 /* Function 41 */
8597 NTSTATUS
8598 NTAPI
8599 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8600 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8601 IN PRPC_UNICODE_STRING Prefix,
8602 OUT unsigned long *Index)
8603 {
8604 UNIMPLEMENTED;
8605 return STATUS_NOT_IMPLEMENTED;
8606 }
8607
8608 /* Function 42 */
8609 NTSTATUS
8610 NTAPI
8611 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8612 {
8613 UNIMPLEMENTED;
8614 return STATUS_NOT_IMPLEMENTED;
8615 }
8616
8617 /* Function 43 */
8618 NTSTATUS
8619 NTAPI
8620 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8621 {
8622 UNIMPLEMENTED;
8623 return STATUS_NOT_IMPLEMENTED;
8624 }
8625
8626
8627 /* Function 44 */
8628 NTSTATUS
8629 NTAPI
8630 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8631 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8632 {
8633 SAM_DOMAIN_FIXED_DATA DomainFixedData;
8634 SAM_USER_FIXED_DATA UserFixedData;
8635 PSAM_DB_OBJECT DomainObject;
8636 PSAM_DB_OBJECT UserObject;
8637 ULONG Length = 0;
8638 NTSTATUS Status;
8639
8640 TRACE("(%p %p)\n",
8641 UserHandle, PasswordInformation);
8642
8643 RtlAcquireResourceShared(&SampResource,
8644 TRUE);
8645
8646 /* Validate the user handle */
8647 Status = SampValidateDbObject(UserHandle,
8648 SamDbUserObject,
8649 0,
8650 &UserObject);
8651 if (!NT_SUCCESS(Status))
8652 {
8653 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8654 goto done;
8655 }
8656
8657 /* Validate the domain object */
8658 Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8659 SamDbDomainObject,
8660 DOMAIN_READ_PASSWORD_PARAMETERS,
8661 &DomainObject);
8662 if (!NT_SUCCESS(Status))
8663 {
8664 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8665 goto done;
8666 }
8667
8668 /* Get fixed user data */
8669 Length = sizeof(SAM_USER_FIXED_DATA);
8670 Status = SampGetObjectAttribute(UserObject,
8671 L"F",
8672 NULL,
8673 (PVOID)&UserFixedData,
8674 &Length);
8675 if (!NT_SUCCESS(Status))
8676 {
8677 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8678 goto done;
8679 }
8680
8681 if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8682 (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8683 USER_WORKSTATION_TRUST_ACCOUNT |
8684 USER_SERVER_TRUST_ACCOUNT)))
8685 {
8686 PasswordInformation->MinPasswordLength = 0;
8687 PasswordInformation->PasswordProperties = 0;
8688 }
8689 else
8690 {
8691 /* Get fixed domain data */
8692 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8693 Status = SampGetObjectAttribute(DomainObject,
8694 L"F",
8695 NULL,
8696 (PVOID)&DomainFixedData,
8697 &Length);
8698 if (!NT_SUCCESS(Status))
8699 {
8700 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8701 goto done;
8702 }
8703
8704 PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8705 PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8706 }
8707
8708 done:
8709 RtlReleaseResource(&SampResource);
8710
8711 return STATUS_SUCCESS;
8712 }
8713
8714
8715 /* Function 45 */
8716 NTSTATUS
8717 NTAPI
8718 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8719 IN PRPC_SID MemberSid)
8720 {
8721 PSAM_DB_OBJECT DomainObject;
8722 ULONG Rid = 0;
8723 NTSTATUS Status;
8724
8725 TRACE("(%p %p)\n",
8726 DomainHandle, MemberSid);
8727
8728 RtlAcquireResourceExclusive(&SampResource,
8729 TRUE);
8730
8731 /* Validate the domain object */
8732 Status = SampValidateDbObject(DomainHandle,
8733 SamDbDomainObject,
8734 DOMAIN_LOOKUP,
8735 &DomainObject);
8736 if (!NT_SUCCESS(Status))
8737 {
8738 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8739 goto done;
8740 }
8741
8742 /* Retrieve the RID from the MemberSID */
8743 Status = SampGetRidFromSid((PSID)MemberSid,
8744 &Rid);
8745 if (!NT_SUCCESS(Status))
8746 {
8747 TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8748 goto done;
8749 }
8750
8751 /* Fail, if the RID represents a special account */
8752 if (Rid < 1000)
8753 {
8754 TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8755 Status = STATUS_SPECIAL_ACCOUNT;
8756 goto done;
8757 }
8758
8759 /* Remove the member from all aliases in the domain */
8760 Status = SampRemoveMemberFromAllAliases(DomainObject,
8761 MemberSid);
8762 if (!NT_SUCCESS(Status))
8763 {
8764 TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8765 }
8766
8767 done:
8768 RtlReleaseResource(&SampResource);
8769
8770 return Status;
8771 }
8772
8773
8774 /* Function 46 */
8775 NTSTATUS
8776 NTAPI
8777 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8778 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8779 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8780 {
8781 TRACE("(%p %lu %p)\n", DomainHandle, DomainInformationClass, Buffer);
8782
8783 return SamrQueryInformationDomain(DomainHandle,
8784 DomainInformationClass,
8785 Buffer);
8786 }
8787
8788
8789 /* Function 47 */
8790 NTSTATUS
8791 NTAPI
8792 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8793 IN USER_INFORMATION_CLASS UserInformationClass,
8794 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8795 {
8796 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
8797
8798 return SamrQueryInformationUser(UserHandle,
8799 UserInformationClass,
8800 Buffer);
8801 }
8802
8803
8804 /* Function 48 */
8805 NTSTATUS
8806 NTAPI
8807 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8808 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8809 IN unsigned long Index,
8810 IN unsigned long EntryCount,
8811 IN unsigned long PreferredMaximumLength,
8812 OUT unsigned long *TotalAvailable,
8813 OUT unsigned long *TotalReturned,
8814 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8815 {
8816 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
8817 DomainHandle, DisplayInformationClass, Index,
8818 EntryCount, PreferredMaximumLength, TotalAvailable,
8819 TotalReturned, Buffer);
8820
8821 return SamrQueryDisplayInformation(DomainHandle,
8822 DisplayInformationClass,
8823 Index,
8824 EntryCount,
8825 PreferredMaximumLength,
8826 TotalAvailable,
8827 TotalReturned,
8828 Buffer);
8829 }
8830
8831
8832 /* Function 49 */
8833 NTSTATUS
8834 NTAPI
8835 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8836 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8837 IN PRPC_UNICODE_STRING Prefix,
8838 OUT unsigned long *Index)
8839 {
8840 TRACE("(%p %lu %p %p)\n",
8841 DomainHandle, DisplayInformationClass, Prefix, Index);
8842
8843 return SamrGetDisplayEnumerationIndex(DomainHandle,
8844 DisplayInformationClass,
8845 Prefix,
8846 Index);
8847 }
8848
8849
8850 /* Function 50 */
8851 NTSTATUS
8852 NTAPI
8853 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8854 IN PRPC_UNICODE_STRING Name,
8855 IN unsigned long AccountType,
8856 IN ACCESS_MASK DesiredAccess,
8857 OUT SAMPR_HANDLE *UserHandle,
8858 OUT unsigned long *GrantedAccess,
8859 OUT unsigned long *RelativeId)
8860 {
8861 SAM_DOMAIN_FIXED_DATA FixedDomainData;
8862 SAM_USER_FIXED_DATA FixedUserData;
8863 PSAM_DB_OBJECT DomainObject;
8864 PSAM_DB_OBJECT UserObject;
8865 GROUP_MEMBERSHIP GroupMembership;
8866 UCHAR LogonHours[23];
8867 ULONG ulSize;
8868 ULONG ulRid;
8869 WCHAR szRid[9];
8870 PSECURITY_DESCRIPTOR Sd = NULL;
8871 ULONG SdSize = 0;
8872 PSID UserSid = NULL;
8873 NTSTATUS Status;
8874
8875 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
8876 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
8877
8878 if (Name == NULL ||
8879 Name->Length == 0 ||
8880 Name->Buffer == NULL ||
8881 UserHandle == NULL ||
8882 RelativeId == NULL)
8883 return STATUS_INVALID_PARAMETER;
8884
8885 /* Check for valid account type */
8886 if (AccountType != USER_NORMAL_ACCOUNT &&
8887 AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
8888 AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
8889 AccountType != USER_SERVER_TRUST_ACCOUNT &&
8890 AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
8891 return STATUS_INVALID_PARAMETER;
8892
8893 /* Map generic access rights */
8894 RtlMapGenericMask(&DesiredAccess,
8895 &UserMapping);
8896
8897 RtlAcquireResourceExclusive(&SampResource,
8898 TRUE);
8899
8900 /* Validate the domain handle */
8901 Status = SampValidateDbObject(DomainHandle,
8902 SamDbDomainObject,
8903 DOMAIN_CREATE_USER,
8904 &DomainObject);
8905 if (!NT_SUCCESS(Status))
8906 {
8907 TRACE("failed with status 0x%08lx\n", Status);
8908 goto done;
8909 }
8910
8911 /* Check the user account name */
8912 Status = SampCheckAccountName(Name, 20);
8913 if (!NT_SUCCESS(Status))
8914 {
8915 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
8916 goto done;
8917 }
8918
8919 /* Check if the user name already exists in the domain */
8920 Status = SampCheckAccountNameInDomain(DomainObject,
8921 Name->Buffer);
8922 if (!NT_SUCCESS(Status))
8923 {
8924 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
8925 Name->Buffer, Status);
8926 goto done;
8927 }
8928
8929 /* Get the fixed domain attributes */
8930 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
8931 Status = SampGetObjectAttribute(DomainObject,
8932 L"F",
8933 NULL,
8934 (PVOID)&FixedDomainData,
8935 &ulSize);
8936 if (!NT_SUCCESS(Status))
8937 {
8938 TRACE("failed with status 0x%08lx\n", Status);
8939 goto done;
8940 }
8941
8942 /* Increment the NextRid attribute */
8943 ulRid = FixedDomainData.NextRid;
8944 FixedDomainData.NextRid++;
8945
8946 TRACE("RID: %lx\n", ulRid);
8947
8948 /* Create the user SID */
8949 Status = SampCreateAccountSid(DomainObject,
8950 ulRid,
8951 &UserSid);
8952 if (!NT_SUCCESS(Status))
8953 {
8954 TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
8955 goto done;
8956 }
8957
8958 /* Create the security descriptor */
8959 Status = SampCreateUserSD(UserSid,
8960 &Sd,
8961 &SdSize);
8962 if (!NT_SUCCESS(Status))
8963 {
8964 TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
8965 goto done;
8966 }
8967
8968 /* Store the fixed domain attributes */
8969 Status = SampSetObjectAttribute(DomainObject,
8970 L"F",
8971 REG_BINARY,
8972 &FixedDomainData,
8973 ulSize);
8974 if (!NT_SUCCESS(Status))
8975 {
8976 TRACE("failed with status 0x%08lx\n", Status);
8977 goto done;
8978 }
8979
8980 /* Convert the RID into a string (hex) */
8981 swprintf(szRid, L"%08lX", ulRid);
8982
8983 /* Create the user object */
8984 Status = SampCreateDbObject(DomainObject,
8985 L"Users",
8986 szRid,
8987 ulRid,
8988 SamDbUserObject,
8989 DesiredAccess,
8990 &UserObject);
8991 if (!NT_SUCCESS(Status))
8992 {
8993 TRACE("failed with status 0x%08lx\n", Status);
8994 goto done;
8995 }
8996
8997 /* Add the account name for the user object */
8998 Status = SampSetAccountNameInDomain(DomainObject,
8999 L"Users",
9000 Name->Buffer,
9001 ulRid);
9002 if (!NT_SUCCESS(Status))
9003 {
9004 TRACE("failed with status 0x%08lx\n", Status);
9005 goto done;
9006 }
9007
9008 /* Initialize fixed user data */
9009 FixedUserData.Version = 1;
9010 FixedUserData.Reserved = 0;
9011 FixedUserData.LastLogon.QuadPart = 0;
9012 FixedUserData.LastLogoff.QuadPart = 0;
9013 FixedUserData.PasswordLastSet.QuadPart = 0;
9014 FixedUserData.AccountExpires.LowPart = MAXULONG;
9015 FixedUserData.AccountExpires.HighPart = MAXLONG;
9016 FixedUserData.LastBadPasswordTime.QuadPart = 0;
9017 FixedUserData.UserId = ulRid;
9018 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
9019 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
9020 USER_PASSWORD_NOT_REQUIRED |
9021 AccountType;
9022 FixedUserData.CountryCode = 0;
9023 FixedUserData.CodePage = 0;
9024 FixedUserData.BadPasswordCount = 0;
9025 FixedUserData.LogonCount = 0;
9026 FixedUserData.AdminCount = 0;
9027 FixedUserData.OperatorCount = 0;
9028
9029 /* Set fixed user data attribute */
9030 Status = SampSetObjectAttribute(UserObject,
9031 L"F",
9032 REG_BINARY,
9033 (LPVOID)&FixedUserData,
9034 sizeof(SAM_USER_FIXED_DATA));
9035 if (!NT_SUCCESS(Status))
9036 {
9037 TRACE("failed with status 0x%08lx\n", Status);
9038 goto done;
9039 }
9040
9041 /* Set the Name attribute */
9042 Status = SampSetObjectAttributeString(UserObject,
9043 L"Name",
9044 Name);
9045 if (!NT_SUCCESS(Status))
9046 {
9047 TRACE("failed with status 0x%08lx\n", Status);
9048 goto done;
9049 }
9050
9051 /* Set the FullName attribute */
9052 Status = SampSetObjectAttributeString(UserObject,
9053 L"FullName",
9054 NULL);
9055 if (!NT_SUCCESS(Status))
9056 {
9057 TRACE("failed with status 0x%08lx\n", Status);
9058 goto done;
9059 }
9060
9061 /* Set the HomeDirectory attribute */
9062 Status = SampSetObjectAttributeString(UserObject,
9063 L"HomeDirectory",
9064 NULL);
9065 if (!NT_SUCCESS(Status))
9066 {
9067 TRACE("failed with status 0x%08lx\n", Status);
9068 goto done;
9069 }
9070
9071 /* Set the HomeDirectoryDrive attribute */
9072 Status = SampSetObjectAttributeString(UserObject,
9073 L"HomeDirectoryDrive",
9074 NULL);
9075 if (!NT_SUCCESS(Status))
9076 {
9077 TRACE("failed with status 0x%08lx\n", Status);
9078 goto done;
9079 }
9080
9081 /* Set the ScriptPath attribute */
9082 Status = SampSetObjectAttributeString(UserObject,
9083 L"ScriptPath",
9084 NULL);
9085 if (!NT_SUCCESS(Status))
9086 {
9087 TRACE("failed with status 0x%08lx\n", Status);
9088 goto done;
9089 }
9090
9091 /* Set the ProfilePath attribute */
9092 Status = SampSetObjectAttributeString(UserObject,
9093 L"ProfilePath",
9094 NULL);
9095 if (!NT_SUCCESS(Status))
9096 {
9097 TRACE("failed with status 0x%08lx\n", Status);
9098 goto done;
9099 }
9100
9101 /* Set the AdminComment attribute */
9102 Status = SampSetObjectAttributeString(UserObject,
9103 L"AdminComment",
9104 NULL);
9105 if (!NT_SUCCESS(Status))
9106 {
9107 TRACE("failed with status 0x%08lx\n", Status);
9108 goto done;
9109 }
9110
9111 /* Set the UserComment attribute */
9112 Status = SampSetObjectAttributeString(UserObject,
9113 L"UserComment",
9114 NULL);
9115 if (!NT_SUCCESS(Status))
9116 {
9117 TRACE("failed with status 0x%08lx\n", Status);
9118 goto done;
9119 }
9120
9121 /* Set the WorkStations attribute */
9122 Status = SampSetObjectAttributeString(UserObject,
9123 L"WorkStations",
9124 NULL);
9125 if (!NT_SUCCESS(Status))
9126 {
9127 TRACE("failed with status 0x%08lx\n", Status);
9128 goto done;
9129 }
9130
9131 /* Set the Parameters attribute */
9132 Status = SampSetObjectAttributeString(UserObject,
9133 L"Parameters",
9134 NULL);
9135 if (!NT_SUCCESS(Status))
9136 {
9137 TRACE("failed with status 0x%08lx\n", Status);
9138 goto done;
9139 }
9140
9141 /* Set LogonHours attribute*/
9142 *((PUSHORT)LogonHours) = 168;
9143 memset(&(LogonHours[2]), 0xff, 21);
9144
9145 Status = SampSetObjectAttribute(UserObject,
9146 L"LogonHours",
9147 REG_BINARY,
9148 &LogonHours,
9149 sizeof(LogonHours));
9150 if (!NT_SUCCESS(Status))
9151 {
9152 TRACE("failed with status 0x%08lx\n", Status);
9153 goto done;
9154 }
9155
9156 /* Set Groups attribute*/
9157 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
9158 GroupMembership.Attributes = SE_GROUP_MANDATORY |
9159 SE_GROUP_ENABLED |
9160 SE_GROUP_ENABLED_BY_DEFAULT;
9161
9162 Status = SampSetObjectAttribute(UserObject,
9163 L"Groups",
9164 REG_BINARY,
9165 &GroupMembership,
9166 sizeof(GROUP_MEMBERSHIP));
9167 if (!NT_SUCCESS(Status))
9168 {
9169 TRACE("failed with status 0x%08lx\n", Status);
9170 goto done;
9171 }
9172
9173 /* Set LMPwd attribute*/
9174 Status = SampSetObjectAttribute(UserObject,
9175 L"LMPwd",
9176 REG_BINARY,
9177 NULL,
9178 0);
9179 if (!NT_SUCCESS(Status))
9180 {
9181 TRACE("failed with status 0x%08lx\n", Status);
9182 goto done;
9183 }
9184
9185 /* Set NTPwd attribute*/
9186 Status = SampSetObjectAttribute(UserObject,
9187 L"NTPwd",
9188 REG_BINARY,
9189 NULL,
9190 0);
9191 if (!NT_SUCCESS(Status))
9192 {
9193 TRACE("failed with status 0x%08lx\n", Status);
9194 goto done;
9195 }
9196
9197 /* Set LMPwdHistory attribute*/
9198 Status = SampSetObjectAttribute(UserObject,
9199 L"LMPwdHistory",
9200 REG_BINARY,
9201 NULL,
9202 0);
9203 if (!NT_SUCCESS(Status))
9204 {
9205 TRACE("failed with status 0x%08lx\n", Status);
9206 goto done;
9207 }
9208
9209 /* Set NTPwdHistory attribute*/
9210 Status = SampSetObjectAttribute(UserObject,
9211 L"NTPwdHistory",
9212 REG_BINARY,
9213 NULL,
9214 0);
9215 if (!NT_SUCCESS(Status))
9216 {
9217 TRACE("failed with status 0x%08lx\n", Status);
9218 goto done;
9219 }
9220
9221 /* Set the PrivateData attribute */
9222 Status = SampSetObjectAttributeString(UserObject,
9223 L"PrivateData",
9224 NULL);
9225 if (!NT_SUCCESS(Status))
9226 {
9227 TRACE("failed with status 0x%08lx\n", Status);
9228 goto done;
9229 }
9230
9231 /* Set the SecDesc attribute*/
9232 Status = SampSetObjectAttribute(UserObject,
9233 L"SecDesc",
9234 REG_BINARY,
9235 Sd,
9236 SdSize);
9237 if (!NT_SUCCESS(Status))
9238 {
9239 TRACE("failed with status 0x%08lx\n", Status);
9240 goto done;
9241 }
9242
9243 if (NT_SUCCESS(Status))
9244 {
9245 *UserHandle = (SAMPR_HANDLE)UserObject;
9246 *RelativeId = ulRid;
9247 *GrantedAccess = UserObject->Access;
9248 }
9249
9250 done:
9251 if (Sd != NULL)
9252 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
9253
9254 if (UserSid != NULL)
9255 RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
9256
9257 RtlReleaseResource(&SampResource);
9258
9259 TRACE("returns with status 0x%08lx\n", Status);
9260
9261 return Status;
9262 }
9263
9264
9265 /* Function 51 */
9266 NTSTATUS
9267 NTAPI
9268 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
9269 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
9270 IN unsigned long Index,
9271 IN unsigned long EntryCount,
9272 IN unsigned long PreferredMaximumLength,
9273 OUT unsigned long *TotalAvailable,
9274 OUT unsigned long *TotalReturned,
9275 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
9276 {
9277 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
9278 DomainHandle, DisplayInformationClass, Index,
9279 EntryCount, PreferredMaximumLength, TotalAvailable,
9280 TotalReturned, Buffer);
9281
9282 return SamrQueryDisplayInformation(DomainHandle,
9283 DisplayInformationClass,
9284 Index,
9285 EntryCount,
9286 PreferredMaximumLength,
9287 TotalAvailable,
9288 TotalReturned,
9289 Buffer);
9290 }
9291
9292
9293 /* Function 52 */
9294 NTSTATUS
9295 NTAPI
9296 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
9297 IN PSAMPR_PSID_ARRAY MembersBuffer)
9298 {
9299 ULONG i;
9300 NTSTATUS Status = STATUS_SUCCESS;
9301
9302 TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
9303 AliasHandle, MembersBuffer);
9304
9305 for (i = 0; i < MembersBuffer->Count; i++)
9306 {
9307 Status = SamrAddMemberToAlias(AliasHandle,
9308 ((PSID *)MembersBuffer->Sids)[i]);
9309
9310 if (Status == STATUS_MEMBER_IN_ALIAS)
9311 Status = STATUS_SUCCESS;
9312
9313 if (!NT_SUCCESS(Status))
9314 break;
9315 }
9316
9317 return Status;
9318 }
9319
9320
9321 /* Function 53 */
9322 NTSTATUS
9323 NTAPI
9324 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
9325 IN PSAMPR_PSID_ARRAY MembersBuffer)
9326 {
9327 ULONG i;
9328 NTSTATUS Status = STATUS_SUCCESS;
9329
9330 TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
9331 AliasHandle, MembersBuffer);
9332
9333 for (i = 0; i < MembersBuffer->Count; i++)
9334 {
9335 Status = SamrRemoveMemberFromAlias(AliasHandle,
9336 ((PSID *)MembersBuffer->Sids)[i]);
9337
9338 if (Status == STATUS_MEMBER_IN_ALIAS)
9339 Status = STATUS_SUCCESS;
9340
9341 if (!NT_SUCCESS(Status))
9342 break;
9343 }
9344
9345 return Status;
9346 }
9347
9348
9349 /* Function 54 */
9350 NTSTATUS
9351 NTAPI
9352 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
9353 IN PRPC_STRING ServerName,
9354 IN PRPC_STRING UserName,
9355 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9356 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
9357 {
9358 UNIMPLEMENTED;
9359 return STATUS_NOT_IMPLEMENTED;
9360 }
9361
9362 /* Function 55 */
9363 NTSTATUS
9364 NTAPI
9365 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
9366 IN PRPC_UNICODE_STRING ServerName,
9367 IN PRPC_UNICODE_STRING UserName,
9368 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
9369 IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
9370 IN unsigned char LmPresent,
9371 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9372 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
9373 {
9374 UNIMPLEMENTED;
9375 return STATUS_NOT_IMPLEMENTED;
9376 }
9377
9378
9379 /* Function 56 */
9380 NTSTATUS
9381 NTAPI
9382 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
9383 IN PRPC_UNICODE_STRING Unused,
9384 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
9385 {
9386 SAMPR_HANDLE ServerHandle = NULL;
9387 PSAM_DB_OBJECT DomainObject = NULL;
9388 SAM_DOMAIN_FIXED_DATA FixedData;
9389 ULONG Length;
9390 NTSTATUS Status;
9391
9392 TRACE("(%p %p %p)\n", BindingHandle, Unused, PasswordInformation);
9393
9394 Status = SamrConnect(NULL,
9395 &ServerHandle,
9396 SAM_SERVER_LOOKUP_DOMAIN);
9397 if (!NT_SUCCESS(Status))
9398 {
9399 TRACE("SamrConnect() failed (Status 0x%08lx)\n", Status);
9400 goto done;
9401 }
9402
9403 Status = SampOpenDbObject((PSAM_DB_OBJECT)ServerHandle,
9404 L"Domains",
9405 L"Account",
9406 0,
9407 SamDbDomainObject,
9408 DOMAIN_READ_PASSWORD_PARAMETERS,
9409 &DomainObject);
9410 if (!NT_SUCCESS(Status))
9411 {
9412 TRACE("SampOpenDbObject() failed (Status 0x%08lx)\n", Status);
9413 goto done;
9414 }
9415
9416 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
9417 Status = SampGetObjectAttribute(DomainObject,
9418 L"F",
9419 NULL,
9420 &FixedData,
9421 &Length);
9422 if (!NT_SUCCESS(Status))
9423 {
9424 TRACE("SampGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
9425 goto done;
9426 }
9427
9428 PasswordInformation->MinPasswordLength = FixedData.MinPasswordLength;
9429 PasswordInformation->PasswordProperties = FixedData.PasswordProperties;
9430
9431 done:
9432 if (DomainObject != NULL)
9433 SampCloseDbObject(DomainObject);
9434
9435 if (ServerHandle != NULL)
9436 SamrCloseHandle(ServerHandle);
9437
9438 return Status;
9439 }
9440
9441
9442 /* Function 57 */
9443 NTSTATUS
9444 NTAPI
9445 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
9446 OUT SAMPR_HANDLE *ServerHandle,
9447 IN ACCESS_MASK DesiredAccess)
9448 {
9449 TRACE("(%p %p %lx)\n", ServerName, ServerHandle, DesiredAccess);
9450
9451 return SamrConnect(ServerName,
9452 ServerHandle,
9453 DesiredAccess);
9454 }
9455
9456
9457 /* Function 58 */
9458 NTSTATUS
9459 NTAPI
9460 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
9461 IN USER_INFORMATION_CLASS UserInformationClass,
9462 IN PSAMPR_USER_INFO_BUFFER Buffer)
9463 {
9464 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
9465
9466 return SamrSetInformationUser(UserHandle,
9467 UserInformationClass,
9468 Buffer);
9469 }
9470
9471
9472 /* Function 59 */
9473 NTSTATUS
9474 NTAPI
9475 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9476 {
9477 UNIMPLEMENTED;
9478 return STATUS_NOT_IMPLEMENTED;
9479 }
9480
9481 /* Function 60 */
9482 NTSTATUS
9483 NTAPI
9484 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9485 {
9486 UNIMPLEMENTED;
9487 return STATUS_NOT_IMPLEMENTED;
9488 }
9489
9490 /* Function 61 */
9491 NTSTATUS
9492 NTAPI
9493 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
9494 {
9495 UNIMPLEMENTED;
9496 return STATUS_NOT_IMPLEMENTED;
9497 }
9498
9499 /* Function 62 */
9500 NTSTATUS
9501 NTAPI
9502 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
9503 OUT SAMPR_HANDLE *ServerHandle,
9504 IN unsigned long ClientRevision,
9505 IN ACCESS_MASK DesiredAccess)
9506 {
9507 UNIMPLEMENTED;
9508 return STATUS_NOT_IMPLEMENTED;
9509 }
9510
9511 /* Function 63 */
9512 NTSTATUS
9513 NTAPI
9514 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
9515 {
9516 UNIMPLEMENTED;
9517 return STATUS_NOT_IMPLEMENTED;
9518 }
9519
9520 /* Function 64 */
9521 NTSTATUS
9522 NTAPI
9523 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
9524 IN ACCESS_MASK DesiredAccess,
9525 IN unsigned long InVersion,
9526 IN SAMPR_REVISION_INFO *InRevisionInfo,
9527 OUT unsigned long *OutVersion,
9528 OUT SAMPR_REVISION_INFO *OutRevisionInfo,
9529 OUT SAMPR_HANDLE *ServerHandle)
9530 {
9531 UNIMPLEMENTED;
9532 return STATUS_NOT_IMPLEMENTED;
9533 }
9534
9535 /* Function 65 */
9536 NTSTATUS
9537 NTAPI
9538 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
9539 IN unsigned long Rid,
9540 OUT PRPC_SID *Sid)
9541 {
9542 UNIMPLEMENTED;
9543 return STATUS_NOT_IMPLEMENTED;
9544 }
9545
9546 /* Function 66 */
9547 NTSTATUS
9548 NTAPI
9549 SamrSetDSRMPassword(IN handle_t BindingHandle,
9550 IN PRPC_UNICODE_STRING Unused,
9551 IN unsigned long UserId,
9552 IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
9553 {
9554 UNIMPLEMENTED;
9555 return STATUS_NOT_IMPLEMENTED;
9556 }
9557
9558 /* Function 67 */
9559 NTSTATUS
9560 NTAPI
9561 SamrValidatePassword(IN handle_t Handle,
9562 IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
9563 IN PSAM_VALIDATE_INPUT_ARG InputArg,
9564 OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
9565 {
9566 UNIMPLEMENTED;
9567 return STATUS_NOT_IMPLEMENTED;
9568 }
9569
9570 /* EOF */