[SAMSRV] SamrChangePasswordUser: Check StoredLmEmpty and StoredNtEmpty instead of...
[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.LowPart = MAXULONG;
2561 FixedUserData.AccountExpires.HighPart = MAXLONG;
2562 FixedUserData.LastBadPasswordTime.QuadPart = 0;
2563 FixedUserData.UserId = ulRid;
2564 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
2565 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
2566 USER_PASSWORD_NOT_REQUIRED |
2567 USER_NORMAL_ACCOUNT;
2568 FixedUserData.CountryCode = 0;
2569 FixedUserData.CodePage = 0;
2570 FixedUserData.BadPasswordCount = 0;
2571 FixedUserData.LogonCount = 0;
2572 FixedUserData.AdminCount = 0;
2573 FixedUserData.OperatorCount = 0;
2574
2575 /* Set fixed user data attribute */
2576 Status = SampSetObjectAttribute(UserObject,
2577 L"F",
2578 REG_BINARY,
2579 (LPVOID)&FixedUserData,
2580 sizeof(SAM_USER_FIXED_DATA));
2581 if (!NT_SUCCESS(Status))
2582 {
2583 TRACE("failed with status 0x%08lx\n", Status);
2584 goto done;
2585 }
2586
2587 /* Set the Name attribute */
2588 Status = SampSetObjectAttributeString(UserObject,
2589 L"Name",
2590 Name);
2591 if (!NT_SUCCESS(Status))
2592 {
2593 TRACE("failed with status 0x%08lx\n", Status);
2594 goto done;
2595 }
2596
2597 /* Set the FullName attribute */
2598 Status = SampSetObjectAttributeString(UserObject,
2599 L"FullName",
2600 NULL);
2601 if (!NT_SUCCESS(Status))
2602 {
2603 TRACE("failed with status 0x%08lx\n", Status);
2604 goto done;
2605 }
2606
2607 /* Set the HomeDirectory attribute */
2608 Status = SampSetObjectAttributeString(UserObject,
2609 L"HomeDirectory",
2610 NULL);
2611 if (!NT_SUCCESS(Status))
2612 {
2613 TRACE("failed with status 0x%08lx\n", Status);
2614 goto done;
2615 }
2616
2617 /* Set the HomeDirectoryDrive attribute */
2618 Status = SampSetObjectAttributeString(UserObject,
2619 L"HomeDirectoryDrive",
2620 NULL);
2621 if (!NT_SUCCESS(Status))
2622 {
2623 TRACE("failed with status 0x%08lx\n", Status);
2624 goto done;
2625 }
2626
2627 /* Set the ScriptPath attribute */
2628 Status = SampSetObjectAttributeString(UserObject,
2629 L"ScriptPath",
2630 NULL);
2631 if (!NT_SUCCESS(Status))
2632 {
2633 TRACE("failed with status 0x%08lx\n", Status);
2634 goto done;
2635 }
2636
2637 /* Set the ProfilePath attribute */
2638 Status = SampSetObjectAttributeString(UserObject,
2639 L"ProfilePath",
2640 NULL);
2641 if (!NT_SUCCESS(Status))
2642 {
2643 TRACE("failed with status 0x%08lx\n", Status);
2644 goto done;
2645 }
2646
2647 /* Set the AdminComment attribute */
2648 Status = SampSetObjectAttributeString(UserObject,
2649 L"AdminComment",
2650 NULL);
2651 if (!NT_SUCCESS(Status))
2652 {
2653 TRACE("failed with status 0x%08lx\n", Status);
2654 goto done;
2655 }
2656
2657 /* Set the UserComment attribute */
2658 Status = SampSetObjectAttributeString(UserObject,
2659 L"UserComment",
2660 NULL);
2661 if (!NT_SUCCESS(Status))
2662 {
2663 TRACE("failed with status 0x%08lx\n", Status);
2664 goto done;
2665 }
2666
2667 /* Set the WorkStations attribute */
2668 Status = SampSetObjectAttributeString(UserObject,
2669 L"WorkStations",
2670 NULL);
2671 if (!NT_SUCCESS(Status))
2672 {
2673 TRACE("failed with status 0x%08lx\n", Status);
2674 goto done;
2675 }
2676
2677 /* Set the Parameters attribute */
2678 Status = SampSetObjectAttributeString(UserObject,
2679 L"Parameters",
2680 NULL);
2681 if (!NT_SUCCESS(Status))
2682 {
2683 TRACE("failed with status 0x%08lx\n", Status);
2684 goto done;
2685 }
2686
2687 /* Set LogonHours attribute*/
2688 *((PUSHORT)LogonHours) = 168;
2689 memset(&(LogonHours[2]), 0xff, 21);
2690
2691 Status = SampSetObjectAttribute(UserObject,
2692 L"LogonHours",
2693 REG_BINARY,
2694 &LogonHours,
2695 sizeof(LogonHours));
2696 if (!NT_SUCCESS(Status))
2697 {
2698 TRACE("failed with status 0x%08lx\n", Status);
2699 goto done;
2700 }
2701
2702 /* Set Groups attribute*/
2703 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
2704 GroupMembership.Attributes = SE_GROUP_MANDATORY |
2705 SE_GROUP_ENABLED |
2706 SE_GROUP_ENABLED_BY_DEFAULT;
2707
2708 Status = SampSetObjectAttribute(UserObject,
2709 L"Groups",
2710 REG_BINARY,
2711 &GroupMembership,
2712 sizeof(GROUP_MEMBERSHIP));
2713 if (!NT_SUCCESS(Status))
2714 {
2715 TRACE("failed with status 0x%08lx\n", Status);
2716 goto done;
2717 }
2718
2719 /* Set LMPwd attribute*/
2720 Status = SampSetObjectAttribute(UserObject,
2721 L"LMPwd",
2722 REG_BINARY,
2723 &EmptyLmHash,
2724 sizeof(ENCRYPTED_LM_OWF_PASSWORD));
2725 if (!NT_SUCCESS(Status))
2726 {
2727 TRACE("failed with status 0x%08lx\n", Status);
2728 goto done;
2729 }
2730
2731 /* Set NTPwd attribute*/
2732 Status = SampSetObjectAttribute(UserObject,
2733 L"NTPwd",
2734 REG_BINARY,
2735 &EmptyNtHash,
2736 sizeof(ENCRYPTED_NT_OWF_PASSWORD));
2737 if (!NT_SUCCESS(Status))
2738 {
2739 TRACE("failed with status 0x%08lx\n", Status);
2740 goto done;
2741 }
2742
2743 /* Set LMPwdHistory attribute*/
2744 Status = SampSetObjectAttribute(UserObject,
2745 L"LMPwdHistory",
2746 REG_BINARY,
2747 NULL,
2748 0);
2749 if (!NT_SUCCESS(Status))
2750 {
2751 TRACE("failed with status 0x%08lx\n", Status);
2752 goto done;
2753 }
2754
2755 /* Set NTPwdHistory attribute*/
2756 Status = SampSetObjectAttribute(UserObject,
2757 L"NTPwdHistory",
2758 REG_BINARY,
2759 NULL,
2760 0);
2761 if (!NT_SUCCESS(Status))
2762 {
2763 TRACE("failed with status 0x%08lx\n", Status);
2764 goto done;
2765 }
2766
2767 /* Set the PrivateData attribute */
2768 Status = SampSetObjectAttributeString(UserObject,
2769 L"PrivateData",
2770 NULL);
2771 if (!NT_SUCCESS(Status))
2772 {
2773 TRACE("failed with status 0x%08lx\n", Status);
2774 goto done;
2775 }
2776
2777 /* Set the SecDesc attribute*/
2778 Status = SampSetObjectAttribute(UserObject,
2779 L"SecDesc",
2780 REG_BINARY,
2781 Sd,
2782 SdSize);
2783 if (!NT_SUCCESS(Status))
2784 {
2785 TRACE("failed with status 0x%08lx\n", Status);
2786 goto done;
2787 }
2788
2789 if (NT_SUCCESS(Status))
2790 {
2791 *UserHandle = (SAMPR_HANDLE)UserObject;
2792 *RelativeId = ulRid;
2793 }
2794
2795 done:
2796 if (Sd != NULL)
2797 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
2798
2799 if (UserSid != NULL)
2800 RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
2801
2802 RtlReleaseResource(&SampResource);
2803
2804 TRACE("returns with status 0x%08lx\n", Status);
2805
2806 return Status;
2807 }
2808
2809
2810 /* Function 13 */
2811 NTSTATUS
2812 NTAPI
2813 SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
2814 IN OUT unsigned long *EnumerationContext,
2815 IN unsigned long UserAccountControl,
2816 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
2817 IN unsigned long PreferedMaximumLength,
2818 OUT unsigned long *CountReturned)
2819 {
2820 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
2821 PSAM_DB_OBJECT DomainObject;
2822 HANDLE UsersKeyHandle = NULL;
2823 HANDLE NamesKeyHandle = NULL;
2824 WCHAR UserName[64];
2825 ULONG EnumIndex;
2826 ULONG EnumCount = 0;
2827 ULONG RequiredLength = 0;
2828 ULONG NameLength;
2829 ULONG DataLength;
2830 ULONG Rid;
2831 ULONG i;
2832 BOOLEAN MoreEntries = FALSE;
2833 NTSTATUS Status;
2834
2835 TRACE("SamrEnumerateUsersInDomain(%p %p %lx %p %lu %p)\n",
2836 DomainHandle, EnumerationContext, UserAccountControl, Buffer,
2837 PreferedMaximumLength, CountReturned);
2838
2839 RtlAcquireResourceShared(&SampResource,
2840 TRUE);
2841
2842 /* Validate the domain handle */
2843 Status = SampValidateDbObject(DomainHandle,
2844 SamDbDomainObject,
2845 DOMAIN_LIST_ACCOUNTS,
2846 &DomainObject);
2847 if (!NT_SUCCESS(Status))
2848 goto done;
2849
2850 Status = SampRegOpenKey(DomainObject->KeyHandle,
2851 L"Users",
2852 KEY_READ,
2853 &UsersKeyHandle);
2854 if (!NT_SUCCESS(Status))
2855 goto done;
2856
2857 Status = SampRegOpenKey(UsersKeyHandle,
2858 L"Names",
2859 KEY_READ,
2860 &NamesKeyHandle);
2861 if (!NT_SUCCESS(Status))
2862 goto done;
2863
2864 TRACE("Part 1\n");
2865
2866 EnumIndex = *EnumerationContext;
2867
2868 while (TRUE)
2869 {
2870 NameLength = 64 * sizeof(WCHAR);
2871 Status = SampRegEnumerateValue(NamesKeyHandle,
2872 EnumIndex,
2873 UserName,
2874 &NameLength,
2875 NULL,
2876 NULL,
2877 NULL);
2878 if (!NT_SUCCESS(Status))
2879 {
2880 if (Status == STATUS_NO_MORE_ENTRIES)
2881 Status = STATUS_SUCCESS;
2882 break;
2883 }
2884
2885 TRACE("EnumIndex: %lu\n", EnumIndex);
2886 TRACE("User name: %S\n", UserName);
2887 TRACE("Name length: %lu\n", NameLength);
2888
2889 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
2890 {
2891 MoreEntries = TRUE;
2892 break;
2893 }
2894
2895 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
2896 EnumCount++;
2897
2898 EnumIndex++;
2899 }
2900
2901 TRACE("EnumCount: %lu\n", EnumCount);
2902 TRACE("RequiredLength: %lu\n", RequiredLength);
2903
2904 if (!NT_SUCCESS(Status))
2905 goto done;
2906
2907 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
2908 if (EnumBuffer == NULL)
2909 {
2910 Status = STATUS_INSUFFICIENT_RESOURCES;
2911 goto done;
2912 }
2913
2914 EnumBuffer->EntriesRead = EnumCount;
2915 if (EnumCount == 0)
2916 goto done;
2917
2918 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
2919 if (EnumBuffer->Buffer == NULL)
2920 {
2921 Status = STATUS_INSUFFICIENT_RESOURCES;
2922 goto done;
2923 }
2924
2925 TRACE("Part 2\n");
2926
2927 EnumIndex = *EnumerationContext;
2928 for (i = 0; i < EnumCount; i++, EnumIndex++)
2929 {
2930 NameLength = 64 * sizeof(WCHAR);
2931 DataLength = sizeof(ULONG);
2932 Status = SampRegEnumerateValue(NamesKeyHandle,
2933 EnumIndex,
2934 UserName,
2935 &NameLength,
2936 NULL,
2937 &Rid,
2938 &DataLength);
2939 if (!NT_SUCCESS(Status))
2940 {
2941 if (Status == STATUS_NO_MORE_ENTRIES)
2942 Status = STATUS_SUCCESS;
2943 break;
2944 }
2945
2946 TRACE("EnumIndex: %lu\n", EnumIndex);
2947 TRACE("User name: %S\n", UserName);
2948 TRACE("Name length: %lu\n", NameLength);
2949 TRACE("RID: %lu\n", Rid);
2950
2951 EnumBuffer->Buffer[i].RelativeId = Rid;
2952
2953 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
2954 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
2955
2956 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
2957 #if 0
2958 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
2959 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
2960 {
2961 Status = STATUS_INSUFFICIENT_RESOURCES;
2962 goto done;
2963 }
2964
2965 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
2966 UserName,
2967 EnumBuffer->Buffer[i].Name.Length);
2968 #endif
2969 }
2970
2971 done:
2972 if (NT_SUCCESS(Status))
2973 {
2974 *EnumerationContext += EnumCount;
2975 *Buffer = EnumBuffer;
2976 *CountReturned = EnumCount;
2977 }
2978 else
2979 {
2980 *EnumerationContext = 0;
2981 *Buffer = NULL;
2982 *CountReturned = 0;
2983
2984 if (EnumBuffer != NULL)
2985 {
2986 if (EnumBuffer->Buffer != NULL)
2987 {
2988 if (EnumBuffer->EntriesRead != 0)
2989 {
2990 for (i = 0; i < EnumBuffer->EntriesRead; i++)
2991 {
2992 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
2993 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
2994 }
2995 }
2996
2997 midl_user_free(EnumBuffer->Buffer);
2998 }
2999
3000 midl_user_free(EnumBuffer);
3001 }
3002 }
3003
3004 SampRegCloseKey(&NamesKeyHandle);
3005 SampRegCloseKey(&UsersKeyHandle);
3006
3007 if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3008 Status = STATUS_MORE_ENTRIES;
3009
3010 RtlReleaseResource(&SampResource);
3011
3012 return Status;
3013 }
3014
3015
3016 /* Function 14 */
3017 NTSTATUS
3018 NTAPI
3019 SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
3020 IN PRPC_UNICODE_STRING AccountName,
3021 IN ACCESS_MASK DesiredAccess,
3022 OUT SAMPR_HANDLE *AliasHandle,
3023 OUT unsigned long *RelativeId)
3024 {
3025 SAM_DOMAIN_FIXED_DATA FixedDomainData;
3026 PSAM_DB_OBJECT DomainObject;
3027 PSAM_DB_OBJECT AliasObject;
3028 PSECURITY_DESCRIPTOR Sd = NULL;
3029 ULONG SdSize = 0;
3030 ULONG ulSize;
3031 ULONG ulRid;
3032 WCHAR szRid[9];
3033 NTSTATUS Status;
3034
3035 TRACE("SamrCreateAliasInDomain(%p %p %lx %p %p)\n",
3036 DomainHandle, AccountName, DesiredAccess, AliasHandle, RelativeId);
3037
3038 /* Map generic access rights */
3039 RtlMapGenericMask(&DesiredAccess,
3040 &AliasMapping);
3041
3042 RtlAcquireResourceExclusive(&SampResource,
3043 TRUE);
3044
3045 /* Validate the domain handle */
3046 Status = SampValidateDbObject(DomainHandle,
3047 SamDbDomainObject,
3048 DOMAIN_CREATE_ALIAS,
3049 &DomainObject);
3050 if (!NT_SUCCESS(Status))
3051 {
3052 TRACE("failed with status 0x%08lx\n", Status);
3053 goto done;
3054 }
3055
3056 /* Check the alias account name */
3057 Status = SampCheckAccountName(AccountName, 256);
3058 if (!NT_SUCCESS(Status))
3059 {
3060 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
3061 goto done;
3062 }
3063
3064 /* Check if the alias name already exists in the domain */
3065 Status = SampCheckAccountNameInDomain(DomainObject,
3066 AccountName->Buffer);
3067 if (!NT_SUCCESS(Status))
3068 {
3069 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
3070 AccountName->Buffer, Status);
3071 goto done;
3072 }
3073
3074 /* Create the security descriptor */
3075 Status = SampCreateAliasSD(&Sd,
3076 &SdSize);
3077 if (!NT_SUCCESS(Status))
3078 {
3079 TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
3080 goto done;
3081 }
3082
3083 /* Get the fixed domain attributes */
3084 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
3085 Status = SampGetObjectAttribute(DomainObject,
3086 L"F",
3087 NULL,
3088 (PVOID)&FixedDomainData,
3089 &ulSize);
3090 if (!NT_SUCCESS(Status))
3091 {
3092 TRACE("failed with status 0x%08lx\n", Status);
3093 goto done;
3094 }
3095
3096 /* Increment the NextRid attribute */
3097 ulRid = FixedDomainData.NextRid;
3098 FixedDomainData.NextRid++;
3099
3100 /* Store the fixed domain attributes */
3101 Status = SampSetObjectAttribute(DomainObject,
3102 L"F",
3103 REG_BINARY,
3104 &FixedDomainData,
3105 ulSize);
3106 if (!NT_SUCCESS(Status))
3107 {
3108 TRACE("failed with status 0x%08lx\n", Status);
3109 goto done;
3110 }
3111
3112 TRACE("RID: %lx\n", ulRid);
3113
3114 /* Convert the RID into a string (hex) */
3115 swprintf(szRid, L"%08lX", ulRid);
3116
3117 /* Create the alias object */
3118 Status = SampCreateDbObject(DomainObject,
3119 L"Aliases",
3120 szRid,
3121 ulRid,
3122 SamDbAliasObject,
3123 DesiredAccess,
3124 &AliasObject);
3125 if (!NT_SUCCESS(Status))
3126 {
3127 TRACE("failed with status 0x%08lx\n", Status);
3128 goto done;
3129 }
3130
3131 /* Add the account name for the alias object */
3132 Status = SampSetAccountNameInDomain(DomainObject,
3133 L"Aliases",
3134 AccountName->Buffer,
3135 ulRid);
3136 if (!NT_SUCCESS(Status))
3137 {
3138 TRACE("failed with status 0x%08lx\n", Status);
3139 goto done;
3140 }
3141
3142 /* Set the Name attribute */
3143 Status = SampSetObjectAttributeString(AliasObject,
3144 L"Name",
3145 AccountName);
3146 if (!NT_SUCCESS(Status))
3147 {
3148 TRACE("failed with status 0x%08lx\n", Status);
3149 goto done;
3150 }
3151
3152 /* Set the Description attribute */
3153 Status = SampSetObjectAttributeString(AliasObject,
3154 L"Description",
3155 NULL);
3156 if (!NT_SUCCESS(Status))
3157 {
3158 TRACE("failed with status 0x%08lx\n", Status);
3159 goto done;
3160 }
3161
3162 /* Set the SecDesc attribute*/
3163 Status = SampSetObjectAttribute(AliasObject,
3164 L"SecDesc",
3165 REG_BINARY,
3166 Sd,
3167 SdSize);
3168 if (!NT_SUCCESS(Status))
3169 {
3170 TRACE("failed with status 0x%08lx\n", Status);
3171 goto done;
3172 }
3173
3174 if (NT_SUCCESS(Status))
3175 {
3176 *AliasHandle = (SAMPR_HANDLE)AliasObject;
3177 *RelativeId = ulRid;
3178 }
3179
3180 done:
3181 if (Sd != NULL)
3182 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
3183
3184 RtlReleaseResource(&SampResource);
3185
3186 TRACE("returns with status 0x%08lx\n", Status);
3187
3188 return Status;
3189 }
3190
3191
3192 /* Function 15 */
3193 NTSTATUS
3194 NTAPI
3195 SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
3196 IN OUT unsigned long *EnumerationContext,
3197 OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
3198 IN unsigned long PreferedMaximumLength,
3199 OUT unsigned long *CountReturned)
3200 {
3201 PSAMPR_ENUMERATION_BUFFER EnumBuffer = NULL;
3202 PSAM_DB_OBJECT DomainObject;
3203 HANDLE AliasesKeyHandle = NULL;
3204 HANDLE NamesKeyHandle = NULL;
3205 WCHAR AliasName[64];
3206 ULONG EnumIndex;
3207 ULONG EnumCount = 0;
3208 ULONG RequiredLength = 0;
3209 ULONG NameLength;
3210 ULONG DataLength;
3211 ULONG Rid;
3212 ULONG i;
3213 BOOLEAN MoreEntries = FALSE;
3214 NTSTATUS Status;
3215
3216 TRACE("SamrEnumerateAliasesInDomain(%p %p %p %lu %p)\n",
3217 DomainHandle, EnumerationContext, Buffer,
3218 PreferedMaximumLength, CountReturned);
3219
3220 RtlAcquireResourceShared(&SampResource,
3221 TRUE);
3222
3223 /* Validate the domain handle */
3224 Status = SampValidateDbObject(DomainHandle,
3225 SamDbDomainObject,
3226 DOMAIN_LIST_ACCOUNTS,
3227 &DomainObject);
3228 if (!NT_SUCCESS(Status))
3229 goto done;
3230
3231 Status = SampRegOpenKey(DomainObject->KeyHandle,
3232 L"Aliases",
3233 KEY_READ,
3234 &AliasesKeyHandle);
3235 if (!NT_SUCCESS(Status))
3236 goto done;
3237
3238 Status = SampRegOpenKey(AliasesKeyHandle,
3239 L"Names",
3240 KEY_READ,
3241 &NamesKeyHandle);
3242 if (!NT_SUCCESS(Status))
3243 goto done;
3244
3245 TRACE("Part 1\n");
3246
3247 EnumIndex = *EnumerationContext;
3248
3249 while (TRUE)
3250 {
3251 NameLength = 64 * sizeof(WCHAR);
3252 Status = SampRegEnumerateValue(NamesKeyHandle,
3253 EnumIndex,
3254 AliasName,
3255 &NameLength,
3256 NULL,
3257 NULL,
3258 NULL);
3259 if (!NT_SUCCESS(Status))
3260 {
3261 if (Status == STATUS_NO_MORE_ENTRIES)
3262 Status = STATUS_SUCCESS;
3263 break;
3264 }
3265
3266 TRACE("EnumIndex: %lu\n", EnumIndex);
3267 TRACE("Alias name: %S\n", AliasName);
3268 TRACE("Name length: %lu\n", NameLength);
3269
3270 if ((RequiredLength + NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION)) > PreferedMaximumLength)
3271 {
3272 MoreEntries = TRUE;
3273 break;
3274 }
3275
3276 RequiredLength += (NameLength + sizeof(UNICODE_NULL) + sizeof(SAMPR_RID_ENUMERATION));
3277 EnumCount++;
3278
3279 EnumIndex++;
3280 }
3281
3282 TRACE("EnumCount: %lu\n", EnumCount);
3283 TRACE("RequiredLength: %lu\n", RequiredLength);
3284
3285 if (!NT_SUCCESS(Status))
3286 goto done;
3287
3288 EnumBuffer = midl_user_allocate(sizeof(SAMPR_ENUMERATION_BUFFER));
3289 if (EnumBuffer == NULL)
3290 {
3291 Status = STATUS_INSUFFICIENT_RESOURCES;
3292 goto done;
3293 }
3294
3295 EnumBuffer->EntriesRead = EnumCount;
3296 if (EnumCount == 0)
3297 goto done;
3298
3299 EnumBuffer->Buffer = midl_user_allocate(EnumCount * sizeof(SAMPR_RID_ENUMERATION));
3300 if (EnumBuffer->Buffer == NULL)
3301 {
3302 Status = STATUS_INSUFFICIENT_RESOURCES;
3303 goto done;
3304 }
3305
3306 TRACE("Part 2\n");
3307
3308 EnumIndex = *EnumerationContext;
3309 for (i = 0; i < EnumCount; i++, EnumIndex++)
3310 {
3311 NameLength = 64 * sizeof(WCHAR);
3312 DataLength = sizeof(ULONG);
3313 Status = SampRegEnumerateValue(NamesKeyHandle,
3314 EnumIndex,
3315 AliasName,
3316 &NameLength,
3317 NULL,
3318 &Rid,
3319 &DataLength);
3320 if (!NT_SUCCESS(Status))
3321 {
3322 if (Status == STATUS_NO_MORE_ENTRIES)
3323 Status = STATUS_SUCCESS;
3324 break;
3325 }
3326
3327 TRACE("EnumIndex: %lu\n", EnumIndex);
3328 TRACE("Alias name: %S\n", AliasName);
3329 TRACE("Name length: %lu\n", NameLength);
3330 TRACE("RID: %lu\n", Rid);
3331
3332 EnumBuffer->Buffer[i].RelativeId = Rid;
3333
3334 EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
3335 EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
3336
3337 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
3338 #if 0
3339 EnumBuffer->Buffer[i].Name.Buffer = midl_user_allocate(EnumBuffer->Buffer[i].Name.MaximumLength);
3340 if (EnumBuffer->Buffer[i].Name.Buffer == NULL)
3341 {
3342 Status = STATUS_INSUFFICIENT_RESOURCES;
3343 goto done;
3344 }
3345
3346 memcpy(EnumBuffer->Buffer[i].Name.Buffer,
3347 AliasName,
3348 EnumBuffer->Buffer[i].Name.Length);
3349 #endif
3350 }
3351
3352 done:
3353 if (NT_SUCCESS(Status))
3354 {
3355 *EnumerationContext += EnumCount;
3356 *Buffer = EnumBuffer;
3357 *CountReturned = EnumCount;
3358 }
3359 else
3360 {
3361 *EnumerationContext = 0;
3362 *Buffer = NULL;
3363 *CountReturned = 0;
3364
3365 if (EnumBuffer != NULL)
3366 {
3367 if (EnumBuffer->Buffer != NULL)
3368 {
3369 if (EnumBuffer->EntriesRead != 0)
3370 {
3371 for (i = 0; i < EnumBuffer->EntriesRead; i++)
3372 {
3373 if (EnumBuffer->Buffer[i].Name.Buffer != NULL)
3374 midl_user_free(EnumBuffer->Buffer[i].Name.Buffer);
3375 }
3376 }
3377
3378 midl_user_free(EnumBuffer->Buffer);
3379 }
3380
3381 midl_user_free(EnumBuffer);
3382 }
3383 }
3384
3385 SampRegCloseKey(&NamesKeyHandle);
3386 SampRegCloseKey(&AliasesKeyHandle);
3387
3388 if ((Status == STATUS_SUCCESS) && (MoreEntries != FALSE))
3389 Status = STATUS_MORE_ENTRIES;
3390
3391 RtlReleaseResource(&SampResource);
3392
3393 return Status;
3394 }
3395
3396
3397 /* Function 16 */
3398 NTSTATUS
3399 NTAPI
3400 SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
3401 IN PSAMPR_PSID_ARRAY SidArray,
3402 OUT PSAMPR_ULONG_ARRAY Membership)
3403 {
3404 PSAM_DB_OBJECT DomainObject;
3405 HANDLE AliasesKeyHandle = NULL;
3406 HANDLE MembersKeyHandle = NULL;
3407 HANDLE MemberKeyHandle = NULL;
3408 LPWSTR MemberSidString = NULL;
3409 PULONG RidArray = NULL;
3410 ULONG MaxSidCount = 0;
3411 ULONG ValueCount;
3412 ULONG DataLength;
3413 ULONG i, j;
3414 ULONG RidIndex;
3415 NTSTATUS Status;
3416 WCHAR NameBuffer[9];
3417
3418 TRACE("SamrGetAliasMembership(%p %p %p)\n",
3419 DomainHandle, SidArray, Membership);
3420
3421 RtlAcquireResourceShared(&SampResource,
3422 TRUE);
3423
3424 /* Validate the domain handle */
3425 Status = SampValidateDbObject(DomainHandle,
3426 SamDbDomainObject,
3427 DOMAIN_GET_ALIAS_MEMBERSHIP,
3428 &DomainObject);
3429 if (!NT_SUCCESS(Status))
3430 goto done;
3431
3432 Status = SampRegOpenKey(DomainObject->KeyHandle,
3433 L"Aliases",
3434 KEY_READ,
3435 &AliasesKeyHandle);
3436 TRACE("SampRegOpenKey returned %08lX\n", Status);
3437 if (!NT_SUCCESS(Status))
3438 goto done;
3439
3440 Status = SampRegOpenKey(AliasesKeyHandle,
3441 L"Members",
3442 KEY_READ,
3443 &MembersKeyHandle);
3444 TRACE("SampRegOpenKey returned %08lX\n", Status);
3445
3446 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3447 {
3448 Status = STATUS_SUCCESS;
3449 goto done;
3450 }
3451
3452 if (!NT_SUCCESS(Status))
3453 goto done;
3454
3455 for (i = 0; i < SidArray->Count; i++)
3456 {
3457 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3458 TRACE("Open %S\n", MemberSidString);
3459
3460 Status = SampRegOpenKey(MembersKeyHandle,
3461 MemberSidString,
3462 KEY_READ,
3463 &MemberKeyHandle);
3464 TRACE("SampRegOpenKey returned %08lX\n", Status);
3465 if (NT_SUCCESS(Status))
3466 {
3467 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3468 NULL,
3469 &ValueCount);
3470 if (NT_SUCCESS(Status))
3471 {
3472 TRACE("Found %lu values\n", ValueCount);
3473 MaxSidCount += ValueCount;
3474 }
3475
3476 SampRegCloseKey(&MemberKeyHandle);
3477 }
3478
3479 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3480 Status = STATUS_SUCCESS;
3481
3482 LocalFree(MemberSidString);
3483 }
3484
3485 if (MaxSidCount == 0)
3486 {
3487 Status = STATUS_SUCCESS;
3488 goto done;
3489 }
3490
3491 TRACE("Maximum sid count: %lu\n", MaxSidCount);
3492 RidArray = midl_user_allocate(MaxSidCount * sizeof(ULONG));
3493 if (RidArray == NULL)
3494 {
3495 Status = STATUS_INSUFFICIENT_RESOURCES;
3496 goto done;
3497 }
3498
3499 RidIndex = 0;
3500 for (i = 0; i < SidArray->Count; i++)
3501 {
3502 ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
3503 TRACE("Open %S\n", MemberSidString);
3504
3505 Status = SampRegOpenKey(MembersKeyHandle,
3506 MemberSidString,
3507 KEY_READ,
3508 &MemberKeyHandle);
3509 TRACE("SampRegOpenKey returned %08lX\n", Status);
3510 if (NT_SUCCESS(Status))
3511 {
3512 Status = SampRegQueryKeyInfo(MemberKeyHandle,
3513 NULL,
3514 &ValueCount);
3515 if (NT_SUCCESS(Status))
3516 {
3517 TRACE("Found %lu values\n", ValueCount);
3518
3519 for (j = 0; j < ValueCount; j++)
3520 {
3521 DataLength = 9 * sizeof(WCHAR);
3522 Status = SampRegEnumerateValue(MemberKeyHandle,
3523 j,
3524 NameBuffer,
3525 &DataLength,
3526 NULL,
3527 NULL,
3528 NULL);
3529 if (NT_SUCCESS(Status))
3530 {
3531 /* FIXME: Do not return each RID more than once. */
3532 RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
3533 RidIndex++;
3534 }
3535 }
3536 }
3537
3538 SampRegCloseKey(&MemberKeyHandle);
3539 }
3540
3541 LocalFree(MemberSidString);
3542 }
3543
3544 done:
3545 SampRegCloseKey(&MembersKeyHandle);
3546 SampRegCloseKey(&AliasesKeyHandle);
3547
3548 if (NT_SUCCESS(Status))
3549 {
3550 Membership->Count = MaxSidCount;
3551 Membership->Element = RidArray;
3552 }
3553 else
3554 {
3555 if (RidArray != NULL)
3556 midl_user_free(RidArray);
3557 }
3558
3559 RtlReleaseResource(&SampResource);
3560
3561 return Status;
3562 }
3563
3564
3565 /* Function 17 */
3566 NTSTATUS
3567 NTAPI
3568 SamrLookupNamesInDomain(IN SAMPR_HANDLE DomainHandle,
3569 IN ULONG Count,
3570 IN RPC_UNICODE_STRING Names[],
3571 OUT PSAMPR_ULONG_ARRAY RelativeIds,
3572 OUT PSAMPR_ULONG_ARRAY Use)
3573 {
3574 PSAM_DB_OBJECT DomainObject;
3575 HANDLE AccountsKeyHandle = NULL;
3576 HANDLE NamesKeyHandle = NULL;
3577 ULONG MappedCount = 0;
3578 ULONG DataLength;
3579 ULONG i;
3580 ULONG RelativeId;
3581 NTSTATUS Status;
3582
3583 TRACE("SamrLookupNamesInDomain(%p %lu %p %p %p)\n",
3584 DomainHandle, Count, Names, RelativeIds, Use);
3585
3586 RtlAcquireResourceShared(&SampResource,
3587 TRUE);
3588
3589 /* Validate the domain handle */
3590 Status = SampValidateDbObject(DomainHandle,
3591 SamDbDomainObject,
3592 DOMAIN_LOOKUP,
3593 &DomainObject);
3594 if (!NT_SUCCESS(Status))
3595 {
3596 TRACE("failed with status 0x%08lx\n", Status);
3597 goto done;
3598 }
3599
3600 RelativeIds->Count = 0;
3601 Use->Count = 0;
3602
3603 if (Count == 0)
3604 {
3605 Status = STATUS_SUCCESS;
3606 goto done;
3607 }
3608
3609 /* Allocate the relative IDs array */
3610 RelativeIds->Element = midl_user_allocate(Count * sizeof(ULONG));
3611 if (RelativeIds->Element == NULL)
3612 {
3613 Status = STATUS_INSUFFICIENT_RESOURCES;
3614 goto done;
3615 }
3616
3617 /* Allocate the use array */
3618 Use->Element = midl_user_allocate(Count * sizeof(ULONG));
3619 if (Use->Element == NULL)
3620 {
3621 Status = STATUS_INSUFFICIENT_RESOURCES;
3622 goto done;
3623 }
3624
3625 RelativeIds->Count = Count;
3626 Use->Count = Count;
3627
3628 for (i = 0; i < Count; i++)
3629 {
3630 TRACE("Name: %S\n", Names[i].Buffer);
3631
3632 RelativeId = 0;
3633
3634 /* Lookup aliases */
3635 Status = SampRegOpenKey(DomainObject->KeyHandle,
3636 L"Aliases",
3637 KEY_READ,
3638 &AccountsKeyHandle);
3639 if (NT_SUCCESS(Status))
3640 {
3641 Status = SampRegOpenKey(AccountsKeyHandle,
3642 L"Names",
3643 KEY_READ,
3644 &NamesKeyHandle);
3645 if (NT_SUCCESS(Status))
3646 {
3647 DataLength = sizeof(ULONG);
3648 Status = SampRegQueryValue(NamesKeyHandle,
3649 Names[i].Buffer,
3650 NULL,
3651 &RelativeId,
3652 &DataLength);
3653
3654 SampRegCloseKey(&NamesKeyHandle);
3655 }
3656
3657 SampRegCloseKey(&AccountsKeyHandle);
3658 }
3659
3660 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3661 break;
3662
3663 /* Return alias account */
3664 if (NT_SUCCESS(Status) && RelativeId != 0)
3665 {
3666 TRACE("Rid: %lu\n", RelativeId);
3667 RelativeIds->Element[i] = RelativeId;
3668 Use->Element[i] = SidTypeAlias;
3669 MappedCount++;
3670 continue;
3671 }
3672
3673 /* Lookup groups */
3674 Status = SampRegOpenKey(DomainObject->KeyHandle,
3675 L"Groups",
3676 KEY_READ,
3677 &AccountsKeyHandle);
3678 if (NT_SUCCESS(Status))
3679 {
3680 Status = SampRegOpenKey(AccountsKeyHandle,
3681 L"Names",
3682 KEY_READ,
3683 &NamesKeyHandle);
3684 if (NT_SUCCESS(Status))
3685 {
3686 DataLength = sizeof(ULONG);
3687 Status = SampRegQueryValue(NamesKeyHandle,
3688 Names[i].Buffer,
3689 NULL,
3690 &RelativeId,
3691 &DataLength);
3692
3693 SampRegCloseKey(&NamesKeyHandle);
3694 }
3695
3696 SampRegCloseKey(&AccountsKeyHandle);
3697 }
3698
3699 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3700 break;
3701
3702 /* Return group account */
3703 if (NT_SUCCESS(Status) && RelativeId != 0)
3704 {
3705 TRACE("Rid: %lu\n", RelativeId);
3706 RelativeIds->Element[i] = RelativeId;
3707 Use->Element[i] = SidTypeGroup;
3708 MappedCount++;
3709 continue;
3710 }
3711
3712 /* Lookup users */
3713 Status = SampRegOpenKey(DomainObject->KeyHandle,
3714 L"Users",
3715 KEY_READ,
3716 &AccountsKeyHandle);
3717 if (NT_SUCCESS(Status))
3718 {
3719 Status = SampRegOpenKey(AccountsKeyHandle,
3720 L"Names",
3721 KEY_READ,
3722 &NamesKeyHandle);
3723 if (NT_SUCCESS(Status))
3724 {
3725 DataLength = sizeof(ULONG);
3726 Status = SampRegQueryValue(NamesKeyHandle,
3727 Names[i].Buffer,
3728 NULL,
3729 &RelativeId,
3730 &DataLength);
3731
3732 SampRegCloseKey(&NamesKeyHandle);
3733 }
3734
3735 SampRegCloseKey(&AccountsKeyHandle);
3736 }
3737
3738 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3739 break;
3740
3741 /* Return user account */
3742 if (NT_SUCCESS(Status) && RelativeId != 0)
3743 {
3744 TRACE("Rid: %lu\n", RelativeId);
3745 RelativeIds->Element[i] = RelativeId;
3746 Use->Element[i] = SidTypeUser;
3747 MappedCount++;
3748 continue;
3749 }
3750
3751 /* Return unknown account */
3752 RelativeIds->Element[i] = 0;
3753 Use->Element[i] = SidTypeUnknown;
3754 }
3755
3756 done:
3757 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3758 Status = STATUS_SUCCESS;
3759
3760 if (NT_SUCCESS(Status))
3761 {
3762 if (MappedCount == 0)
3763 Status = STATUS_NONE_MAPPED;
3764 else if (MappedCount < Count)
3765 Status = STATUS_SOME_NOT_MAPPED;
3766 }
3767 else
3768 {
3769 if (RelativeIds->Element != NULL)
3770 {
3771 midl_user_free(RelativeIds->Element);
3772 RelativeIds->Element = NULL;
3773 }
3774
3775 RelativeIds->Count = 0;
3776
3777 if (Use->Element != NULL)
3778 {
3779 midl_user_free(Use->Element);
3780 Use->Element = NULL;
3781 }
3782
3783 Use->Count = 0;
3784 }
3785
3786 RtlReleaseResource(&SampResource);
3787
3788 TRACE("Returned Status %lx\n", Status);
3789
3790 return Status;
3791 }
3792
3793
3794 /* Function 18 */
3795 NTSTATUS
3796 NTAPI
3797 SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
3798 IN ULONG Count,
3799 IN ULONG *RelativeIds,
3800 OUT PSAMPR_RETURNED_USTRING_ARRAY Names,
3801 OUT PSAMPR_ULONG_ARRAY Use)
3802 {
3803 PSAM_DB_OBJECT DomainObject;
3804 WCHAR RidString[9];
3805 HANDLE AccountsKeyHandle = NULL;
3806 HANDLE AccountKeyHandle = NULL;
3807 ULONG MappedCount = 0;
3808 ULONG DataLength;
3809 ULONG i;
3810 NTSTATUS Status;
3811
3812 TRACE("SamrLookupIdsInDomain(%p %lu %p %p %p)\n",
3813 DomainHandle, Count, RelativeIds, Names, Use);
3814
3815 RtlAcquireResourceShared(&SampResource,
3816 TRUE);
3817
3818 /* Validate the domain handle */
3819 Status = SampValidateDbObject(DomainHandle,
3820 SamDbDomainObject,
3821 DOMAIN_LOOKUP,
3822 &DomainObject);
3823 if (!NT_SUCCESS(Status))
3824 {
3825 TRACE("failed with status 0x%08lx\n", Status);
3826 goto done;
3827 }
3828
3829 Names->Count = 0;
3830 Use->Count = 0;
3831
3832 if (Count == 0)
3833 {
3834 Status = STATUS_SUCCESS;
3835 goto done;
3836 }
3837
3838 /* Allocate the names array */
3839 Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
3840 if (Names->Element == NULL)
3841 {
3842 Status = STATUS_INSUFFICIENT_RESOURCES;
3843 goto done;
3844 }
3845
3846 /* Allocate the use array */
3847 Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
3848 if (Use->Element == NULL)
3849 {
3850 Status = STATUS_INSUFFICIENT_RESOURCES;
3851 goto done;
3852 }
3853
3854 Names->Count = Count;
3855 Use->Count = Count;
3856
3857 for (i = 0; i < Count; i++)
3858 {
3859 TRACE("RID: %lu\n", RelativeIds[i]);
3860
3861 swprintf(RidString, L"%08lx", RelativeIds[i]);
3862
3863 /* Lookup aliases */
3864 Status = SampRegOpenKey(DomainObject->KeyHandle,
3865 L"Aliases",
3866 KEY_READ,
3867 &AccountsKeyHandle);
3868 if (NT_SUCCESS(Status))
3869 {
3870 Status = SampRegOpenKey(AccountsKeyHandle,
3871 RidString,
3872 KEY_READ,
3873 &AccountKeyHandle);
3874 if (NT_SUCCESS(Status))
3875 {
3876 DataLength = 0;
3877 Status = SampRegQueryValue(AccountKeyHandle,
3878 L"Name",
3879 NULL,
3880 NULL,
3881 &DataLength);
3882 if (NT_SUCCESS(Status))
3883 {
3884 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3885 if (Names->Element[i].Buffer == NULL)
3886 Status = STATUS_INSUFFICIENT_RESOURCES;
3887
3888 if (NT_SUCCESS(Status))
3889 {
3890 Names->Element[i].MaximumLength = (USHORT)DataLength;
3891 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3892
3893 Status = SampRegQueryValue(AccountKeyHandle,
3894 L"Name",
3895 NULL,
3896 Names->Element[i].Buffer,
3897 &DataLength);
3898 }
3899 }
3900
3901 SampRegCloseKey(&AccountKeyHandle);
3902 }
3903
3904 SampRegCloseKey(&AccountsKeyHandle);
3905 }
3906
3907 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3908 break;
3909
3910 /* Return alias account */
3911 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3912 {
3913 TRACE("Name: %S\n", Names->Element[i].Buffer);
3914 Use->Element[i] = SidTypeAlias;
3915 MappedCount++;
3916 continue;
3917 }
3918
3919 /* Lookup groups */
3920 Status = SampRegOpenKey(DomainObject->KeyHandle,
3921 L"Groups",
3922 KEY_READ,
3923 &AccountsKeyHandle);
3924 if (NT_SUCCESS(Status))
3925 {
3926 Status = SampRegOpenKey(AccountsKeyHandle,
3927 RidString,
3928 KEY_READ,
3929 &AccountKeyHandle);
3930 if (NT_SUCCESS(Status))
3931 {
3932 DataLength = 0;
3933 Status = SampRegQueryValue(AccountKeyHandle,
3934 L"Name",
3935 NULL,
3936 NULL,
3937 &DataLength);
3938 if (NT_SUCCESS(Status))
3939 {
3940 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3941 if (Names->Element[i].Buffer == NULL)
3942 Status = STATUS_INSUFFICIENT_RESOURCES;
3943
3944 if (NT_SUCCESS(Status))
3945 {
3946 Names->Element[i].MaximumLength = (USHORT)DataLength;
3947 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
3948
3949 Status = SampRegQueryValue(AccountKeyHandle,
3950 L"Name",
3951 NULL,
3952 Names->Element[i].Buffer,
3953 &DataLength);
3954 }
3955 }
3956
3957 SampRegCloseKey(&AccountKeyHandle);
3958 }
3959
3960 SampRegCloseKey(&AccountsKeyHandle);
3961 }
3962
3963 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
3964 break;
3965
3966 /* Return group account */
3967 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
3968 {
3969 TRACE("Name: %S\n", Names->Element[i].Buffer);
3970 Use->Element[i] = SidTypeGroup;
3971 MappedCount++;
3972 continue;
3973 }
3974
3975 /* Lookup users */
3976 Status = SampRegOpenKey(DomainObject->KeyHandle,
3977 L"Users",
3978 KEY_READ,
3979 &AccountsKeyHandle);
3980 if (NT_SUCCESS(Status))
3981 {
3982 Status = SampRegOpenKey(AccountsKeyHandle,
3983 RidString,
3984 KEY_READ,
3985 &AccountKeyHandle);
3986 if (NT_SUCCESS(Status))
3987 {
3988 DataLength = 0;
3989 Status = SampRegQueryValue(AccountKeyHandle,
3990 L"Name",
3991 NULL,
3992 NULL,
3993 &DataLength);
3994 if (NT_SUCCESS(Status))
3995 {
3996 TRACE("DataLength: %lu\n", DataLength);
3997
3998 Names->Element[i].Buffer = midl_user_allocate(DataLength);
3999 if (Names->Element[i].Buffer == NULL)
4000 Status = STATUS_INSUFFICIENT_RESOURCES;
4001
4002 if (NT_SUCCESS(Status))
4003 {
4004 Names->Element[i].MaximumLength = (USHORT)DataLength;
4005 Names->Element[i].Length = (USHORT)(DataLength - sizeof(WCHAR));
4006
4007 Status = SampRegQueryValue(AccountKeyHandle,
4008 L"Name",
4009 NULL,
4010 Names->Element[i].Buffer,
4011 &DataLength);
4012 }
4013 }
4014
4015 SampRegCloseKey(&AccountKeyHandle);
4016 }
4017
4018 SampRegCloseKey(&AccountsKeyHandle);
4019 }
4020
4021 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4022 break;
4023
4024 /* Return user account */
4025 if (NT_SUCCESS(Status) && Names->Element[i].Buffer != NULL)
4026 {
4027 TRACE("Name: %S\n", Names->Element[i].Buffer);
4028 Use->Element[i] = SidTypeUser;
4029 MappedCount++;
4030 continue;
4031 }
4032
4033 /* Return unknown account */
4034 Use->Element[i] = SidTypeUnknown;
4035 }
4036
4037 done:
4038 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4039 Status = STATUS_SUCCESS;
4040
4041 if (NT_SUCCESS(Status))
4042 {
4043 if (MappedCount == 0)
4044 Status = STATUS_NONE_MAPPED;
4045 else if (MappedCount < Count)
4046 Status = STATUS_SOME_NOT_MAPPED;
4047 }
4048 else
4049 {
4050 if (Names->Element != NULL)
4051 {
4052 for (i = 0; i < Count; i++)
4053 {
4054 if (Names->Element[i].Buffer != NULL)
4055 midl_user_free(Names->Element[i].Buffer);
4056 }
4057
4058 midl_user_free(Names->Element);
4059 Names->Element = NULL;
4060 }
4061
4062 Names->Count = 0;
4063
4064 if (Use->Element != NULL)
4065 {
4066 midl_user_free(Use->Element);
4067 Use->Element = NULL;
4068 }
4069
4070 Use->Count = 0;
4071 }
4072
4073 RtlReleaseResource(&SampResource);
4074
4075 return Status;
4076 }
4077
4078
4079 /* Function 19 */
4080 NTSTATUS
4081 NTAPI
4082 SamrOpenGroup(IN SAMPR_HANDLE DomainHandle,
4083 IN ACCESS_MASK DesiredAccess,
4084 IN unsigned long GroupId,
4085 OUT SAMPR_HANDLE *GroupHandle)
4086 {
4087 PSAM_DB_OBJECT DomainObject;
4088 PSAM_DB_OBJECT GroupObject;
4089 WCHAR szRid[9];
4090 NTSTATUS Status;
4091
4092 TRACE("SamrOpenGroup(%p %lx %lx %p)\n",
4093 DomainHandle, DesiredAccess, GroupId, GroupHandle);
4094
4095 /* Map generic access rights */
4096 RtlMapGenericMask(&DesiredAccess,
4097 &GroupMapping);
4098
4099 RtlAcquireResourceShared(&SampResource,
4100 TRUE);
4101
4102 /* Validate the domain handle */
4103 Status = SampValidateDbObject(DomainHandle,
4104 SamDbDomainObject,
4105 DOMAIN_LOOKUP,
4106 &DomainObject);
4107 if (!NT_SUCCESS(Status))
4108 {
4109 TRACE("failed with status 0x%08lx\n", Status);
4110 goto done;
4111 }
4112
4113 /* Convert the RID into a string (hex) */
4114 swprintf(szRid, L"%08lX", GroupId);
4115
4116 /* Create the group object */
4117 Status = SampOpenDbObject(DomainObject,
4118 L"Groups",
4119 szRid,
4120 GroupId,
4121 SamDbGroupObject,
4122 DesiredAccess,
4123 &GroupObject);
4124 if (!NT_SUCCESS(Status))
4125 {
4126 TRACE("failed with status 0x%08lx\n", Status);
4127 goto done;
4128 }
4129
4130 *GroupHandle = (SAMPR_HANDLE)GroupObject;
4131
4132 done:
4133 RtlReleaseResource(&SampResource);
4134
4135 return Status;
4136 }
4137
4138
4139 static NTSTATUS
4140 SampQueryGroupGeneral(PSAM_DB_OBJECT GroupObject,
4141 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4142 {
4143 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4144 SAM_GROUP_FIXED_DATA FixedData;
4145 ULONG MembersLength = 0;
4146 ULONG Length = 0;
4147 NTSTATUS Status;
4148
4149 *Buffer = NULL;
4150
4151 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4152 if (InfoBuffer == NULL)
4153 return STATUS_INSUFFICIENT_RESOURCES;
4154
4155 Status = SampGetObjectAttributeString(GroupObject,
4156 L"Name",
4157 &InfoBuffer->General.Name);
4158 if (!NT_SUCCESS(Status))
4159 {
4160 TRACE("Status 0x%08lx\n", Status);
4161 goto done;
4162 }
4163
4164 Status = SampGetObjectAttributeString(GroupObject,
4165 L"Description",
4166 &InfoBuffer->General.AdminComment);
4167 if (!NT_SUCCESS(Status))
4168 {
4169 TRACE("Status 0x%08lx\n", Status);
4170 goto done;
4171 }
4172
4173 Length = sizeof(SAM_GROUP_FIXED_DATA);
4174 Status = SampGetObjectAttribute(GroupObject,
4175 L"F",
4176 NULL,
4177 (PVOID)&FixedData,
4178 &Length);
4179 if (!NT_SUCCESS(Status))
4180 goto done;
4181
4182 InfoBuffer->General.Attributes = FixedData.Attributes;
4183
4184 Status = SampGetObjectAttribute(GroupObject,
4185 L"Members",
4186 NULL,
4187 NULL,
4188 &MembersLength);
4189 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
4190 goto done;
4191
4192 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4193 InfoBuffer->General.MemberCount = 0;
4194 else
4195 InfoBuffer->General.MemberCount = MembersLength / sizeof(ULONG);
4196
4197 *Buffer = InfoBuffer;
4198
4199 done:
4200 if (!NT_SUCCESS(Status))
4201 {
4202 if (InfoBuffer != NULL)
4203 {
4204 if (InfoBuffer->General.Name.Buffer != NULL)
4205 midl_user_free(InfoBuffer->General.Name.Buffer);
4206
4207 if (InfoBuffer->General.AdminComment.Buffer != NULL)
4208 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4209
4210 midl_user_free(InfoBuffer);
4211 }
4212 }
4213
4214 return Status;
4215 }
4216
4217
4218 static NTSTATUS
4219 SampQueryGroupName(PSAM_DB_OBJECT GroupObject,
4220 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4221 {
4222 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4223 NTSTATUS Status;
4224
4225 *Buffer = NULL;
4226
4227 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4228 if (InfoBuffer == NULL)
4229 return STATUS_INSUFFICIENT_RESOURCES;
4230
4231 Status = SampGetObjectAttributeString(GroupObject,
4232 L"Name",
4233 &InfoBuffer->Name.Name);
4234 if (!NT_SUCCESS(Status))
4235 {
4236 TRACE("Status 0x%08lx\n", Status);
4237 goto done;
4238 }
4239
4240 *Buffer = InfoBuffer;
4241
4242 done:
4243 if (!NT_SUCCESS(Status))
4244 {
4245 if (InfoBuffer != NULL)
4246 {
4247 if (InfoBuffer->Name.Name.Buffer != NULL)
4248 midl_user_free(InfoBuffer->Name.Name.Buffer);
4249
4250 midl_user_free(InfoBuffer);
4251 }
4252 }
4253
4254 return Status;
4255 }
4256
4257
4258 static NTSTATUS
4259 SampQueryGroupAttribute(PSAM_DB_OBJECT GroupObject,
4260 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4261 {
4262 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4263 SAM_GROUP_FIXED_DATA FixedData;
4264 ULONG Length = 0;
4265 NTSTATUS Status;
4266
4267 *Buffer = NULL;
4268
4269 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4270 if (InfoBuffer == NULL)
4271 return STATUS_INSUFFICIENT_RESOURCES;
4272
4273 Length = sizeof(SAM_GROUP_FIXED_DATA);
4274 Status = SampGetObjectAttribute(GroupObject,
4275 L"F",
4276 NULL,
4277 (PVOID)&FixedData,
4278 &Length);
4279 if (!NT_SUCCESS(Status))
4280 goto done;
4281
4282 InfoBuffer->Attribute.Attributes = FixedData.Attributes;
4283
4284 *Buffer = InfoBuffer;
4285
4286 done:
4287 if (!NT_SUCCESS(Status))
4288 {
4289 if (InfoBuffer != NULL)
4290 {
4291 midl_user_free(InfoBuffer);
4292 }
4293 }
4294
4295 return Status;
4296 }
4297
4298
4299 static NTSTATUS
4300 SampQueryGroupAdminComment(PSAM_DB_OBJECT GroupObject,
4301 PSAMPR_GROUP_INFO_BUFFER *Buffer)
4302 {
4303 PSAMPR_GROUP_INFO_BUFFER InfoBuffer = NULL;
4304 NTSTATUS Status;
4305
4306 *Buffer = NULL;
4307
4308 InfoBuffer = midl_user_allocate(sizeof(SAMPR_GROUP_INFO_BUFFER));
4309 if (InfoBuffer == NULL)
4310 return STATUS_INSUFFICIENT_RESOURCES;
4311
4312 Status = SampGetObjectAttributeString(GroupObject,
4313 L"Description",
4314 &InfoBuffer->AdminComment.AdminComment);
4315 if (!NT_SUCCESS(Status))
4316 {
4317 TRACE("Status 0x%08lx\n", Status);
4318 goto done;
4319 }
4320
4321 *Buffer = InfoBuffer;
4322
4323 done:
4324 if (!NT_SUCCESS(Status))
4325 {
4326 if (InfoBuffer != NULL)
4327 {
4328 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4329 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4330
4331 midl_user_free(InfoBuffer);
4332 }
4333 }
4334
4335 return Status;
4336 }
4337
4338
4339 /* Function 20 */
4340 NTSTATUS
4341 NTAPI
4342 SamrQueryInformationGroup(IN SAMPR_HANDLE GroupHandle,
4343 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4344 OUT PSAMPR_GROUP_INFO_BUFFER *Buffer)
4345 {
4346 PSAM_DB_OBJECT GroupObject;
4347 NTSTATUS Status;
4348
4349 TRACE("SamrQueryInformationGroup(%p %lu %p)\n",
4350 GroupHandle, GroupInformationClass, Buffer);
4351
4352 RtlAcquireResourceShared(&SampResource,
4353 TRUE);
4354
4355 /* Validate the group handle */
4356 Status = SampValidateDbObject(GroupHandle,
4357 SamDbGroupObject,
4358 GROUP_READ_INFORMATION,
4359 &GroupObject);
4360 if (!NT_SUCCESS(Status))
4361 goto done;
4362
4363 switch (GroupInformationClass)
4364 {
4365 case GroupGeneralInformation:
4366 Status = SampQueryGroupGeneral(GroupObject,
4367 Buffer);
4368 break;
4369
4370 case GroupNameInformation:
4371 Status = SampQueryGroupName(GroupObject,
4372 Buffer);
4373 break;
4374
4375 case GroupAttributeInformation:
4376 Status = SampQueryGroupAttribute(GroupObject,
4377 Buffer);
4378 break;
4379
4380 case GroupAdminCommentInformation:
4381 Status = SampQueryGroupAdminComment(GroupObject,
4382 Buffer);
4383 break;
4384
4385 default:
4386 Status = STATUS_INVALID_INFO_CLASS;
4387 break;
4388 }
4389
4390 done:
4391 RtlReleaseResource(&SampResource);
4392
4393 return Status;
4394 }
4395
4396
4397 static NTSTATUS
4398 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
4399 PSAMPR_GROUP_INFO_BUFFER Buffer)
4400 {
4401 UNICODE_STRING OldGroupName = {0, 0, NULL};
4402 UNICODE_STRING NewGroupName;
4403 NTSTATUS Status;
4404
4405 Status = SampGetObjectAttributeString(GroupObject,
4406 L"Name",
4407 (PRPC_UNICODE_STRING)&OldGroupName);
4408 if (!NT_SUCCESS(Status))
4409 {
4410 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4411 goto done;
4412 }
4413
4414 /* Check the new account name */
4415 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
4416 if (!NT_SUCCESS(Status))
4417 {
4418 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
4419 return Status;
4420 }
4421
4422 NewGroupName.Length = Buffer->Name.Name.Length;
4423 NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
4424 NewGroupName.Buffer = Buffer->Name.Name.Buffer;
4425
4426 if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
4427 {
4428 Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
4429 NewGroupName.Buffer);
4430 if (!NT_SUCCESS(Status))
4431 {
4432 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
4433 NewGroupName.Buffer, Status);
4434 goto done;
4435 }
4436 }
4437
4438 Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
4439 L"Groups",
4440 NewGroupName.Buffer,
4441 GroupObject->RelativeId);
4442 if (!NT_SUCCESS(Status))
4443 {
4444 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4445 goto done;
4446 }
4447
4448 Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4449 L"Groups",
4450 OldGroupName.Buffer);
4451 if (!NT_SUCCESS(Status))
4452 {
4453 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4454 goto done;
4455 }
4456
4457 Status = SampSetObjectAttributeString(GroupObject,
4458 L"Name",
4459 (PRPC_UNICODE_STRING)&NewGroupName);
4460 if (!NT_SUCCESS(Status))
4461 {
4462 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4463 }
4464
4465 done:
4466 if (OldGroupName.Buffer != NULL)
4467 midl_user_free(OldGroupName.Buffer);
4468
4469 return Status;
4470 }
4471
4472
4473 static NTSTATUS
4474 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4475 PSAMPR_GROUP_INFO_BUFFER Buffer)
4476 {
4477 SAM_GROUP_FIXED_DATA FixedData;
4478 ULONG Length = 0;
4479 NTSTATUS Status;
4480
4481 Length = sizeof(SAM_GROUP_FIXED_DATA);
4482 Status = SampGetObjectAttribute(GroupObject,
4483 L"F",
4484 NULL,
4485 (PVOID)&FixedData,
4486 &Length);
4487 if (!NT_SUCCESS(Status))
4488 goto done;
4489
4490 FixedData.Attributes = Buffer->Attribute.Attributes;
4491
4492 Status = SampSetObjectAttribute(GroupObject,
4493 L"F",
4494 REG_BINARY,
4495 &FixedData,
4496 Length);
4497
4498 done:
4499 return Status;
4500 }
4501
4502
4503 /* Function 21 */
4504 NTSTATUS
4505 NTAPI
4506 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4507 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4508 IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4509 {
4510 PSAM_DB_OBJECT GroupObject;
4511 NTSTATUS Status;
4512
4513 TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4514 GroupHandle, GroupInformationClass, Buffer);
4515
4516 RtlAcquireResourceExclusive(&SampResource,
4517 TRUE);
4518
4519 /* Validate the group handle */
4520 Status = SampValidateDbObject(GroupHandle,
4521 SamDbGroupObject,
4522 GROUP_WRITE_ACCOUNT,
4523 &GroupObject);
4524 if (!NT_SUCCESS(Status))
4525 goto done;
4526
4527 switch (GroupInformationClass)
4528 {
4529 case GroupNameInformation:
4530 Status = SampSetGroupName(GroupObject,
4531 Buffer);
4532 break;
4533
4534 case GroupAttributeInformation:
4535 Status = SampSetGroupAttribute(GroupObject,
4536 Buffer);
4537 break;
4538
4539 case GroupAdminCommentInformation:
4540 Status = SampSetObjectAttributeString(GroupObject,
4541 L"Description",
4542 &Buffer->AdminComment.AdminComment);
4543 break;
4544
4545 default:
4546 Status = STATUS_INVALID_INFO_CLASS;
4547 break;
4548 }
4549
4550 done:
4551 RtlReleaseResource(&SampResource);
4552
4553 return Status;
4554 }
4555
4556
4557 /* Function 22 */
4558 NTSTATUS
4559 NTAPI
4560 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4561 IN unsigned long MemberId,
4562 IN unsigned long Attributes)
4563 {
4564 PSAM_DB_OBJECT GroupObject;
4565 PSAM_DB_OBJECT UserObject = NULL;
4566 NTSTATUS Status;
4567
4568 TRACE("(%p %lu %lx)\n",
4569 GroupHandle, MemberId, Attributes);
4570
4571 RtlAcquireResourceExclusive(&SampResource,
4572 TRUE);
4573
4574 /* Validate the group handle */
4575 Status = SampValidateDbObject(GroupHandle,
4576 SamDbGroupObject,
4577 GROUP_ADD_MEMBER,
4578 &GroupObject);
4579 if (!NT_SUCCESS(Status))
4580 goto done;
4581
4582 /* Open the user object in the same domain */
4583 Status = SampOpenUserObject(GroupObject->ParentObject,
4584 MemberId,
4585 0,
4586 &UserObject);
4587 if (!NT_SUCCESS(Status))
4588 {
4589 TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4590 goto done;
4591 }
4592
4593 /* Add group membership to the user object */
4594 Status = SampAddGroupMembershipToUser(UserObject,
4595 GroupObject->RelativeId,
4596 Attributes);
4597 if (!NT_SUCCESS(Status))
4598 {
4599 TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4600 goto done;
4601 }
4602
4603 /* Add the member to the group object */
4604 Status = SampAddMemberToGroup(GroupObject,
4605 MemberId);
4606 if (!NT_SUCCESS(Status))
4607 {
4608 TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4609 }
4610
4611 done:
4612 if (UserObject)
4613 SampCloseDbObject(UserObject);
4614
4615 RtlReleaseResource(&SampResource);
4616
4617 return Status;
4618 }
4619
4620
4621 /* Function 23 */
4622 NTSTATUS
4623 NTAPI
4624 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4625 {
4626 PSAM_DB_OBJECT GroupObject;
4627 ULONG Length = 0;
4628 NTSTATUS Status;
4629
4630 TRACE("(%p)\n", GroupHandle);
4631
4632 RtlAcquireResourceExclusive(&SampResource,
4633 TRUE);
4634
4635 /* Validate the group handle */
4636 Status = SampValidateDbObject(*GroupHandle,
4637 SamDbGroupObject,
4638 DELETE,
4639 &GroupObject);
4640 if (!NT_SUCCESS(Status))
4641 {
4642 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4643 goto done;
4644 }
4645
4646 /* Fail, if the group is built-in */
4647 if (GroupObject->RelativeId < 1000)
4648 {
4649 TRACE("You can not delete a special account!\n");
4650 Status = STATUS_SPECIAL_ACCOUNT;
4651 goto done;
4652 }
4653
4654 /* Get the length of the Members attribute */
4655 SampGetObjectAttribute(GroupObject,
4656 L"Members",
4657 NULL,
4658 NULL,
4659 &Length);
4660
4661 /* Fail, if the group has members */
4662 if (Length != 0)
4663 {
4664 TRACE("There are still members in the group!\n");
4665 Status = STATUS_MEMBER_IN_GROUP;
4666 goto done;
4667 }
4668
4669 /* FIXME: Remove the group from all aliases */
4670
4671 /* Delete the group from the database */
4672 Status = SampDeleteAccountDbObject(GroupObject);
4673 if (!NT_SUCCESS(Status))
4674 {
4675 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4676 goto done;
4677 }
4678
4679 /* Invalidate the handle */
4680 *GroupHandle = NULL;
4681
4682 done:
4683 RtlReleaseResource(&SampResource);
4684
4685 return Status;
4686 }
4687
4688
4689 /* Function 24 */
4690 NTSTATUS
4691 NTAPI
4692 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4693 IN unsigned long MemberId)
4694 {
4695 PSAM_DB_OBJECT GroupObject;
4696 PSAM_DB_OBJECT UserObject = NULL;
4697 NTSTATUS Status;
4698
4699 TRACE("(%p %lu)\n",
4700 GroupHandle, MemberId);
4701
4702 RtlAcquireResourceExclusive(&SampResource,
4703 TRUE);
4704
4705 /* Validate the group handle */
4706 Status = SampValidateDbObject(GroupHandle,
4707 SamDbGroupObject,
4708 GROUP_REMOVE_MEMBER,
4709 &GroupObject);
4710 if (!NT_SUCCESS(Status))
4711 goto done;
4712
4713 /* Open the user object in the same domain */
4714 Status = SampOpenUserObject(GroupObject->ParentObject,
4715 MemberId,
4716 0,
4717 &UserObject);
4718 if (!NT_SUCCESS(Status))
4719 {
4720 ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4721 goto done;
4722 }
4723
4724 /* Remove group membership from the user object */
4725 Status = SampRemoveGroupMembershipFromUser(UserObject,
4726 GroupObject->RelativeId);
4727 if (!NT_SUCCESS(Status))
4728 {
4729 ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4730 goto done;
4731 }
4732
4733 /* Remove the member from the group object */
4734 Status = SampRemoveMemberFromGroup(GroupObject,
4735 MemberId);
4736 if (!NT_SUCCESS(Status))
4737 {
4738 ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4739 }
4740
4741 done:
4742 if (UserObject)
4743 SampCloseDbObject(UserObject);
4744
4745 RtlReleaseResource(&SampResource);
4746
4747 return Status;
4748 }
4749
4750
4751 /* Function 25 */
4752 NTSTATUS
4753 NTAPI
4754 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4755 OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4756 {
4757 PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4758 PSAM_DB_OBJECT GroupObject;
4759 ULONG Length = 0;
4760 ULONG i;
4761 NTSTATUS Status;
4762
4763 RtlAcquireResourceShared(&SampResource,
4764 TRUE);
4765
4766 /* Validate the group handle */
4767 Status = SampValidateDbObject(GroupHandle,
4768 SamDbGroupObject,
4769 GROUP_LIST_MEMBERS,
4770 &GroupObject);
4771 if (!NT_SUCCESS(Status))
4772 goto done;
4773
4774 MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4775 if (MembersBuffer == NULL)
4776 {
4777 Status = STATUS_INSUFFICIENT_RESOURCES;
4778 goto done;
4779 }
4780
4781 SampGetObjectAttribute(GroupObject,
4782 L"Members",
4783 NULL,
4784 NULL,
4785 &Length);
4786
4787 if (Length == 0)
4788 {
4789 MembersBuffer->MemberCount = 0;
4790 MembersBuffer->Members = NULL;
4791 MembersBuffer->Attributes = NULL;
4792
4793 *Members = MembersBuffer;
4794
4795 Status = STATUS_SUCCESS;
4796 goto done;
4797 }
4798
4799 MembersBuffer->Members = midl_user_allocate(Length);
4800 if (MembersBuffer->Members == NULL)
4801 {
4802 Status = STATUS_INSUFFICIENT_RESOURCES;
4803 goto done;
4804 }
4805
4806 MembersBuffer->Attributes = midl_user_allocate(Length);
4807 if (MembersBuffer->Attributes == NULL)
4808 {
4809 Status = STATUS_INSUFFICIENT_RESOURCES;
4810 goto done;
4811 }
4812
4813 Status = SampGetObjectAttribute(GroupObject,
4814 L"Members",
4815 NULL,
4816 MembersBuffer->Members,
4817 &Length);
4818 if (!NT_SUCCESS(Status))
4819 {
4820 TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4821 goto done;
4822 }
4823
4824 MembersBuffer->MemberCount = Length / sizeof(ULONG);
4825
4826 for (i = 0; i < MembersBuffer->MemberCount; i++)
4827 {
4828 Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4829 MembersBuffer->Members[i],
4830 GroupObject->RelativeId,
4831 &(MembersBuffer->Attributes[i]));
4832 if (!NT_SUCCESS(Status))
4833 {
4834 TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4835 goto done;
4836 }
4837 }
4838
4839 *Members = MembersBuffer;
4840
4841 done:
4842 if (!NT_SUCCESS(Status))
4843 {
4844 if (MembersBuffer != NULL)
4845 {
4846 if (MembersBuffer->Members != NULL)
4847 midl_user_free(MembersBuffer->Members);
4848
4849 if (MembersBuffer->Attributes != NULL)
4850 midl_user_free(MembersBuffer->Attributes);
4851
4852 midl_user_free(MembersBuffer);
4853 }
4854 }
4855
4856 RtlReleaseResource(&SampResource);
4857
4858 return Status;
4859 }
4860
4861
4862 /* Function 26 */
4863 NTSTATUS
4864 NTAPI
4865 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4866 IN unsigned long MemberId,
4867 IN unsigned long Attributes)
4868 {
4869 PSAM_DB_OBJECT GroupObject;
4870 NTSTATUS Status;
4871
4872 RtlAcquireResourceExclusive(&SampResource,
4873 TRUE);
4874
4875 /* Validate the group handle */
4876 Status = SampValidateDbObject(GroupHandle,
4877 SamDbGroupObject,
4878 GROUP_ADD_MEMBER,
4879 &GroupObject);
4880 if (!NT_SUCCESS(Status))
4881 {
4882 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4883 goto done;
4884 }
4885
4886 Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4887 MemberId,
4888 GroupObject->RelativeId,
4889 Attributes);
4890 if (!NT_SUCCESS(Status))
4891 {
4892 TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4893 }
4894
4895 done:
4896 RtlReleaseResource(&SampResource);
4897
4898 return Status;
4899 }
4900
4901
4902 /* Function 27 */
4903 NTSTATUS
4904 NTAPI
4905 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4906 IN ACCESS_MASK DesiredAccess,
4907 IN ULONG AliasId,
4908 OUT SAMPR_HANDLE *AliasHandle)
4909 {
4910 PSAM_DB_OBJECT DomainObject;
4911 PSAM_DB_OBJECT AliasObject;
4912 WCHAR szRid[9];
4913 NTSTATUS Status;
4914
4915 TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4916 DomainHandle, DesiredAccess, AliasId, AliasHandle);
4917
4918 /* Map generic access rights */
4919 RtlMapGenericMask(&DesiredAccess,
4920 &AliasMapping);
4921
4922 RtlAcquireResourceShared(&SampResource,
4923 TRUE);
4924
4925 /* Validate the domain handle */
4926 Status = SampValidateDbObject(DomainHandle,
4927 SamDbDomainObject,
4928 DOMAIN_LOOKUP,
4929 &DomainObject);
4930 if (!NT_SUCCESS(Status))
4931 {
4932 TRACE("failed with status 0x%08lx\n", Status);
4933 goto done;
4934 }
4935
4936 /* Convert the RID into a string (hex) */
4937 swprintf(szRid, L"%08lX", AliasId);
4938
4939 /* Create the alias object */
4940 Status = SampOpenDbObject(DomainObject,
4941 L"Aliases",
4942 szRid,
4943 AliasId,
4944 SamDbAliasObject,
4945 DesiredAccess,
4946 &AliasObject);
4947 if (!NT_SUCCESS(Status))
4948 {
4949 TRACE("failed with status 0x%08lx\n", Status);
4950 goto done;
4951 }
4952
4953 *AliasHandle = (SAMPR_HANDLE)AliasObject;
4954
4955 done:
4956 RtlReleaseResource(&SampResource);
4957
4958 return Status;
4959 }
4960
4961
4962 static NTSTATUS
4963 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4964 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4965 {
4966 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4967 HANDLE MembersKeyHandle = NULL;
4968 NTSTATUS Status;
4969
4970 *Buffer = NULL;
4971
4972 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4973 if (InfoBuffer == NULL)
4974 return STATUS_INSUFFICIENT_RESOURCES;
4975
4976 Status = SampGetObjectAttributeString(AliasObject,
4977 L"Name",
4978 &InfoBuffer->General.Name);
4979 if (!NT_SUCCESS(Status))
4980 {
4981 TRACE("Status 0x%08lx\n", Status);
4982 goto done;
4983 }
4984
4985 Status = SampGetObjectAttributeString(AliasObject,
4986 L"Description",
4987 &InfoBuffer->General.AdminComment);
4988 if (!NT_SUCCESS(Status))
4989 {
4990 TRACE("Status 0x%08lx\n", Status);
4991 goto done;
4992 }
4993
4994 /* Open the Members subkey */
4995 Status = SampRegOpenKey(AliasObject->KeyHandle,
4996 L"Members",
4997 KEY_READ,
4998 &MembersKeyHandle);
4999 if (NT_SUCCESS(Status))
5000 {
5001 /* Retrieve the number of members of the alias */
5002 Status = SampRegQueryKeyInfo(MembersKeyHandle,
5003 NULL,
5004 &InfoBuffer->General.MemberCount);
5005 if (!NT_SUCCESS(Status))
5006 {
5007 TRACE("Status 0x%08lx\n", Status);
5008 goto done;
5009 }
5010 }
5011 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
5012 {
5013 InfoBuffer->General.MemberCount = 0;
5014 Status = STATUS_SUCCESS;
5015 }
5016 else
5017 {
5018 TRACE("Status 0x%08lx\n", Status);
5019 goto done;
5020 }
5021
5022 *Buffer = InfoBuffer;
5023
5024 done:
5025 SampRegCloseKey(&MembersKeyHandle);
5026
5027 if (!NT_SUCCESS(Status))
5028 {
5029 if (InfoBuffer != NULL)
5030 {
5031 if (InfoBuffer->General.Name.Buffer != NULL)
5032 midl_user_free(InfoBuffer->General.Name.Buffer);
5033
5034 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5035 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5036
5037 midl_user_free(InfoBuffer);
5038 }
5039 }
5040
5041 return Status;
5042 }
5043
5044
5045 static NTSTATUS
5046 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
5047 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5048 {
5049 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5050 NTSTATUS Status;
5051
5052 *Buffer = NULL;
5053
5054 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5055 if (InfoBuffer == NULL)
5056 return STATUS_INSUFFICIENT_RESOURCES;
5057
5058 Status = SampGetObjectAttributeString(AliasObject,
5059 L"Name",
5060 &InfoBuffer->Name.Name);
5061 if (!NT_SUCCESS(Status))
5062 {
5063 TRACE("Status 0x%08lx\n", Status);
5064 goto done;
5065 }
5066
5067 *Buffer = InfoBuffer;
5068
5069 done:
5070 if (!NT_SUCCESS(Status))
5071 {
5072 if (InfoBuffer != NULL)
5073 {
5074 if (InfoBuffer->Name.Name.Buffer != NULL)
5075 midl_user_free(InfoBuffer->Name.Name.Buffer);
5076
5077 midl_user_free(InfoBuffer);
5078 }
5079 }
5080
5081 return Status;
5082 }
5083
5084
5085 static NTSTATUS
5086 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
5087 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5088 {
5089 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
5090 NTSTATUS Status;
5091
5092 *Buffer = NULL;
5093
5094 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
5095 if (InfoBuffer == NULL)
5096 return STATUS_INSUFFICIENT_RESOURCES;
5097
5098 Status = SampGetObjectAttributeString(AliasObject,
5099 L"Description",
5100 &InfoBuffer->AdminComment.AdminComment);
5101 if (!NT_SUCCESS(Status))
5102 {
5103 TRACE("Status 0x%08lx\n", Status);
5104 goto done;
5105 }
5106
5107 *Buffer = InfoBuffer;
5108
5109 done:
5110 if (!NT_SUCCESS(Status))
5111 {
5112 if (InfoBuffer != NULL)
5113 {
5114 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
5115 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
5116
5117 midl_user_free(InfoBuffer);
5118 }
5119 }
5120
5121 return Status;
5122 }
5123
5124
5125 /* Function 28 */
5126 NTSTATUS
5127 NTAPI
5128 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
5129 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5130 OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
5131 {
5132 PSAM_DB_OBJECT AliasObject;
5133 NTSTATUS Status;
5134
5135 TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
5136 AliasHandle, AliasInformationClass, Buffer);
5137
5138 RtlAcquireResourceShared(&SampResource,
5139 TRUE);
5140
5141 /* Validate the alias handle */
5142 Status = SampValidateDbObject(AliasHandle,
5143 SamDbAliasObject,
5144 ALIAS_READ_INFORMATION,
5145 &AliasObject);
5146 if (!NT_SUCCESS(Status))
5147 goto done;
5148
5149 switch (AliasInformationClass)
5150 {
5151 case AliasGeneralInformation:
5152 Status = SampQueryAliasGeneral(AliasObject,
5153 Buffer);
5154 break;
5155
5156 case AliasNameInformation:
5157 Status = SampQueryAliasName(AliasObject,
5158 Buffer);
5159 break;
5160
5161 case AliasAdminCommentInformation:
5162 Status = SampQueryAliasAdminComment(AliasObject,
5163 Buffer);
5164 break;
5165
5166 default:
5167 Status = STATUS_INVALID_INFO_CLASS;
5168 break;
5169 }
5170
5171 done:
5172 RtlReleaseResource(&SampResource);
5173
5174 return Status;
5175 }
5176
5177
5178 static NTSTATUS
5179 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
5180 PSAMPR_ALIAS_INFO_BUFFER Buffer)
5181 {
5182 UNICODE_STRING OldAliasName = {0, 0, NULL};
5183 UNICODE_STRING NewAliasName;
5184 NTSTATUS Status;
5185
5186 Status = SampGetObjectAttributeString(AliasObject,
5187 L"Name",
5188 (PRPC_UNICODE_STRING)&OldAliasName);
5189 if (!NT_SUCCESS(Status))
5190 {
5191 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
5192 goto done;
5193 }
5194
5195 /* Check the new account name */
5196 Status = SampCheckAccountName(&Buffer->Name.Name, 256);
5197 if (!NT_SUCCESS(Status))
5198 {
5199 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
5200 return Status;
5201 }
5202
5203 NewAliasName.Length = Buffer->Name.Name.Length;
5204 NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
5205 NewAliasName.Buffer = Buffer->Name.Name.Buffer;
5206
5207 if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
5208 {
5209 Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
5210 NewAliasName.Buffer);
5211 if (!NT_SUCCESS(Status))
5212 {
5213 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
5214 NewAliasName.Buffer, Status);
5215 goto done;
5216 }
5217 }
5218
5219 Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
5220 L"Aliases",
5221 NewAliasName.Buffer,
5222 AliasObject->RelativeId);
5223 if (!NT_SUCCESS(Status))
5224 {
5225 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
5226 goto done;
5227 }
5228
5229 Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
5230 L"Aliases",
5231 OldAliasName.Buffer);
5232 if (!NT_SUCCESS(Status))
5233 {
5234 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
5235 goto done;
5236 }
5237
5238 Status = SampSetObjectAttributeString(AliasObject,
5239 L"Name",
5240 (PRPC_UNICODE_STRING)&NewAliasName);
5241 if (!NT_SUCCESS(Status))
5242 {
5243 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
5244 }
5245
5246 done:
5247 if (OldAliasName.Buffer != NULL)
5248 midl_user_free(OldAliasName.Buffer);
5249
5250 return Status;
5251 }
5252
5253
5254 /* Function 29 */
5255 NTSTATUS
5256 NTAPI
5257 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
5258 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
5259 IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
5260 {
5261 PSAM_DB_OBJECT AliasObject;
5262 NTSTATUS Status;
5263
5264 TRACE("SamrSetInformationAlias(%p %lu %p)\n",
5265 AliasHandle, AliasInformationClass, Buffer);
5266
5267 RtlAcquireResourceExclusive(&SampResource,
5268 TRUE);
5269
5270 /* Validate the alias handle */
5271 Status = SampValidateDbObject(AliasHandle,
5272 SamDbAliasObject,
5273 ALIAS_WRITE_ACCOUNT,
5274 &AliasObject);
5275 if (!NT_SUCCESS(Status))
5276 goto done;
5277
5278 switch (AliasInformationClass)
5279 {
5280 case AliasNameInformation:
5281 Status = SampSetAliasName(AliasObject,
5282 Buffer);
5283 break;
5284
5285 case AliasAdminCommentInformation:
5286 Status = SampSetObjectAttributeString(AliasObject,
5287 L"Description",
5288 &Buffer->AdminComment.AdminComment);
5289 break;
5290
5291 default:
5292 Status = STATUS_INVALID_INFO_CLASS;
5293 break;
5294 }
5295
5296 done:
5297 RtlReleaseResource(&SampResource);
5298
5299 return Status;
5300 }
5301
5302
5303 /* Function 30 */
5304 NTSTATUS
5305 NTAPI
5306 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
5307 {
5308 PSAM_DB_OBJECT AliasObject;
5309 NTSTATUS Status;
5310
5311 RtlAcquireResourceExclusive(&SampResource,
5312 TRUE);
5313
5314 /* Validate the alias handle */
5315 Status = SampValidateDbObject(*AliasHandle,
5316 SamDbAliasObject,
5317 DELETE,
5318 &AliasObject);
5319 if (!NT_SUCCESS(Status))
5320 {
5321 TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
5322 goto done;
5323 }
5324
5325 /* Fail, if the alias is built-in */
5326 if (AliasObject->RelativeId < 1000)
5327 {
5328 TRACE("You can not delete a special account!\n");
5329 Status = STATUS_SPECIAL_ACCOUNT;
5330 goto done;
5331 }
5332
5333 /* Remove all members from the alias */
5334 Status = SampRemoveAllMembersFromAlias(AliasObject);
5335 if (!NT_SUCCESS(Status))
5336 {
5337 TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
5338 goto done;
5339 }
5340
5341 /* Delete the alias from the database */
5342 Status = SampDeleteAccountDbObject(AliasObject);
5343 if (!NT_SUCCESS(Status))
5344 {
5345 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5346 goto done;
5347 }
5348
5349 /* Invalidate the handle */
5350 *AliasHandle = NULL;
5351
5352 done:
5353 RtlReleaseResource(&SampResource);
5354
5355 return Status;
5356 }
5357
5358
5359 /* Function 31 */
5360 NTSTATUS
5361 NTAPI
5362 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
5363 IN PRPC_SID MemberId)
5364 {
5365 PSAM_DB_OBJECT AliasObject;
5366 NTSTATUS Status;
5367
5368 TRACE("(%p %p)\n", AliasHandle, MemberId);
5369
5370 RtlAcquireResourceExclusive(&SampResource,
5371 TRUE);
5372
5373 /* Validate the alias handle */
5374 Status = SampValidateDbObject(AliasHandle,
5375 SamDbAliasObject,
5376 ALIAS_ADD_MEMBER,
5377 &AliasObject);
5378 if (!NT_SUCCESS(Status))
5379 {
5380 TRACE("failed with status 0x%08lx\n", Status);
5381 goto done;
5382 }
5383
5384 Status = SampAddMemberToAlias(AliasObject,
5385 MemberId);
5386 if (!NT_SUCCESS(Status))
5387 {
5388 TRACE("failed with status 0x%08lx\n", Status);
5389 }
5390
5391 done:
5392 RtlReleaseResource(&SampResource);
5393
5394 return Status;
5395 }
5396
5397
5398 /* Function 32 */
5399 NTSTATUS
5400 NTAPI
5401 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
5402 IN PRPC_SID MemberId)
5403 {
5404 PSAM_DB_OBJECT AliasObject;
5405 NTSTATUS Status;
5406
5407 TRACE("(%p %p)\n", AliasHandle, MemberId);
5408
5409 RtlAcquireResourceExclusive(&SampResource,
5410 TRUE);
5411
5412 /* Validate the alias handle */
5413 Status = SampValidateDbObject(AliasHandle,
5414 SamDbAliasObject,
5415 ALIAS_REMOVE_MEMBER,
5416 &AliasObject);
5417 if (!NT_SUCCESS(Status))
5418 {
5419 TRACE("failed with status 0x%08lx\n", Status);
5420 goto done;
5421 }
5422
5423 Status = SampRemoveMemberFromAlias(AliasObject,
5424 MemberId);
5425 if (!NT_SUCCESS(Status))
5426 {
5427 TRACE("failed with status 0x%08lx\n", Status);
5428 }
5429
5430 done:
5431 RtlReleaseResource(&SampResource);
5432
5433 return Status;
5434 }
5435
5436
5437 /* Function 33 */
5438 NTSTATUS
5439 NTAPI
5440 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
5441 OUT PSAMPR_PSID_ARRAY_OUT Members)
5442 {
5443 PSAM_DB_OBJECT AliasObject;
5444 PSAMPR_SID_INFORMATION MemberArray = NULL;
5445 ULONG MemberCount = 0;
5446 ULONG Index;
5447 NTSTATUS Status;
5448
5449 TRACE("SamrGetMembersInAlias(%p %p %p)\n",
5450 AliasHandle, Members);
5451
5452 RtlAcquireResourceShared(&SampResource,
5453 TRUE);
5454
5455 /* Validate the alias handle */
5456 Status = SampValidateDbObject(AliasHandle,
5457 SamDbAliasObject,
5458 ALIAS_LIST_MEMBERS,
5459 &AliasObject);
5460 if (!NT_SUCCESS(Status))
5461 {
5462 ERR("failed with status 0x%08lx\n", Status);
5463 goto done;
5464 }
5465
5466 Status = SampGetMembersInAlias(AliasObject,
5467 &MemberCount,
5468 &MemberArray);
5469
5470 /* Return the number of members and the member array */
5471 if (NT_SUCCESS(Status))
5472 {
5473 Members->Count = MemberCount;
5474 Members->Sids = MemberArray;
5475 }
5476
5477 done:
5478 /* Clean up the members array and the SID buffers if something failed */
5479 if (!NT_SUCCESS(Status))
5480 {
5481 if (MemberArray != NULL)
5482 {
5483 for (Index = 0; Index < MemberCount; Index++)
5484 {
5485 if (MemberArray[Index].SidPointer != NULL)
5486 midl_user_free(MemberArray[Index].SidPointer);
5487 }
5488
5489 midl_user_free(MemberArray);
5490 }
5491 }
5492
5493 RtlReleaseResource(&SampResource);
5494
5495 return Status;
5496 }
5497
5498
5499 /* Function 34 */
5500 NTSTATUS
5501 NTAPI
5502 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5503 IN ACCESS_MASK DesiredAccess,
5504 IN unsigned long UserId,
5505 OUT SAMPR_HANDLE *UserHandle)
5506 {
5507 PSAM_DB_OBJECT DomainObject;
5508 PSAM_DB_OBJECT UserObject;
5509 WCHAR szRid[9];
5510 NTSTATUS Status;
5511
5512 TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5513 DomainHandle, DesiredAccess, UserId, UserHandle);
5514
5515 /* Map generic access rights */
5516 RtlMapGenericMask(&DesiredAccess,
5517 &UserMapping);
5518
5519 RtlAcquireResourceShared(&SampResource,
5520 TRUE);
5521
5522 /* Validate the domain handle */
5523 Status = SampValidateDbObject(DomainHandle,
5524 SamDbDomainObject,
5525 DOMAIN_LOOKUP,
5526 &DomainObject);
5527 if (!NT_SUCCESS(Status))
5528 {
5529 TRACE("failed with status 0x%08lx\n", Status);
5530 goto done;
5531 }
5532
5533 /* Convert the RID into a string (hex) */
5534 swprintf(szRid, L"%08lX", UserId);
5535
5536 /* Create the user object */
5537 Status = SampOpenDbObject(DomainObject,
5538 L"Users",
5539 szRid,
5540 UserId,
5541 SamDbUserObject,
5542 DesiredAccess,
5543 &UserObject);
5544 if (!NT_SUCCESS(Status))
5545 {
5546 TRACE("failed with status 0x%08lx\n", Status);
5547 goto done;
5548 }
5549
5550 *UserHandle = (SAMPR_HANDLE)UserObject;
5551
5552 done:
5553 RtlReleaseResource(&SampResource);
5554
5555 return Status;
5556 }
5557
5558
5559 /* Function 35 */
5560 NTSTATUS
5561 NTAPI
5562 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5563 {
5564 PSAM_DB_OBJECT UserObject;
5565 NTSTATUS Status;
5566
5567 TRACE("(%p)\n", UserHandle);
5568
5569 RtlAcquireResourceExclusive(&SampResource,
5570 TRUE);
5571
5572 /* Validate the user handle */
5573 Status = SampValidateDbObject(*UserHandle,
5574 SamDbUserObject,
5575 DELETE,
5576 &UserObject);
5577 if (!NT_SUCCESS(Status))
5578 {
5579 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5580 goto done;
5581 }
5582
5583 /* Fail, if the user is built-in */
5584 if (UserObject->RelativeId < 1000)
5585 {
5586 TRACE("You can not delete a special account!\n");
5587 Status = STATUS_SPECIAL_ACCOUNT;
5588 goto done;
5589 }
5590
5591 /* Remove the user from all groups */
5592 Status = SampRemoveUserFromAllGroups(UserObject);
5593 if (!NT_SUCCESS(Status))
5594 {
5595 TRACE("SampRemoveUserFromAllGroups() failed (Status 0x%08lx)\n", Status);
5596 goto done;
5597 }
5598
5599 /* Remove the user from all aliases */
5600 Status = SampRemoveUserFromAllAliases(UserObject);
5601 if (!NT_SUCCESS(Status))
5602 {
5603 TRACE("SampRemoveUserFromAllAliases() failed (Status 0x%08lx)\n", Status);
5604 goto done;
5605 }
5606
5607 /* Delete the user from the database */
5608 Status = SampDeleteAccountDbObject(UserObject);
5609 if (!NT_SUCCESS(Status))
5610 {
5611 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5612 goto done;
5613 }
5614
5615 /* Invalidate the handle */
5616 *UserHandle = NULL;
5617
5618 done:
5619 RtlReleaseResource(&SampResource);
5620
5621 return Status;
5622 }
5623
5624
5625 static
5626 NTSTATUS
5627 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5628 PSAMPR_USER_INFO_BUFFER *Buffer)
5629 {
5630 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5631 SAM_USER_FIXED_DATA FixedData;
5632 ULONG Length = 0;
5633 NTSTATUS Status;
5634
5635 *Buffer = NULL;
5636
5637 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5638 if (InfoBuffer == NULL)
5639 return STATUS_INSUFFICIENT_RESOURCES;
5640
5641 Length = sizeof(SAM_USER_FIXED_DATA);
5642 Status = SampGetObjectAttribute(UserObject,
5643 L"F",
5644 NULL,
5645 (PVOID)&FixedData,
5646 &Length);
5647 if (!NT_SUCCESS(Status))
5648 goto done;
5649
5650 InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5651
5652 /* Get the Name string */
5653 Status = SampGetObjectAttributeString(UserObject,
5654 L"Name",
5655 &InfoBuffer->General.UserName);
5656 if (!NT_SUCCESS(Status))
5657 {
5658 TRACE("Status 0x%08lx\n", Status);
5659 goto done;
5660 }
5661
5662 /* Get the FullName string */
5663 Status = SampGetObjectAttributeString(UserObject,
5664 L"FullName",
5665 &InfoBuffer->General.FullName);
5666 if (!NT_SUCCESS(Status))
5667 {
5668 TRACE("Status 0x%08lx\n", Status);
5669 goto done;
5670 }
5671
5672 /* Get the AdminComment string */
5673 Status = SampGetObjectAttributeString(UserObject,
5674 L"AdminComment",
5675 &InfoBuffer->General.AdminComment);
5676 if (!NT_SUCCESS(Status))
5677 {
5678 TRACE("Status 0x%08lx\n", Status);
5679 goto done;
5680 }
5681
5682 /* Get the UserComment string */
5683 Status = SampGetObjectAttributeString(UserObject,
5684 L"UserComment",
5685 &InfoBuffer->General.UserComment);
5686 if (!NT_SUCCESS(Status))
5687 {
5688 TRACE("Status 0x%08lx\n", Status);
5689 goto done;
5690 }
5691
5692 *Buffer = InfoBuffer;
5693
5694 done:
5695 if (!NT_SUCCESS(Status))
5696 {
5697 if (InfoBuffer != NULL)
5698 {
5699 if (InfoBuffer->General.UserName.Buffer != NULL)
5700 midl_user_free(InfoBuffer->General.UserName.Buffer);
5701
5702 if (InfoBuffer->General.FullName.Buffer != NULL)
5703 midl_user_free(InfoBuffer->General.FullName.Buffer);
5704
5705 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5706 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5707
5708 if (InfoBuffer->General.UserComment.Buffer != NULL)
5709 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5710
5711 midl_user_free(InfoBuffer);
5712 }
5713 }
5714
5715 return Status;
5716 }
5717
5718
5719 static
5720 NTSTATUS
5721 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5722 PSAMPR_USER_INFO_BUFFER *Buffer)
5723 {
5724 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5725 SAM_USER_FIXED_DATA FixedData;
5726 ULONG Length = 0;
5727 NTSTATUS Status;
5728
5729 *Buffer = NULL;
5730
5731 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5732 if (InfoBuffer == NULL)
5733 return STATUS_INSUFFICIENT_RESOURCES;
5734
5735 Length = sizeof(SAM_USER_FIXED_DATA);
5736 Status = SampGetObjectAttribute(UserObject,
5737 L"F",
5738 NULL,
5739 (PVOID)&FixedData,
5740 &Length);
5741 if (!NT_SUCCESS(Status))
5742 goto done;
5743
5744 InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5745 InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5746
5747 /* Get the UserComment string */
5748 Status = SampGetObjectAttributeString(UserObject,
5749 L"UserComment",
5750 &InfoBuffer->Preferences.UserComment);
5751 if (!NT_SUCCESS(Status))
5752 {
5753 TRACE("Status 0x%08lx\n", Status);
5754 goto done;
5755 }
5756
5757 *Buffer = InfoBuffer;
5758
5759 done:
5760 if (!NT_SUCCESS(Status))
5761 {
5762 if (InfoBuffer != NULL)
5763 {
5764 if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5765 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5766
5767 midl_user_free(InfoBuffer);
5768 }
5769 }
5770
5771 return Status;
5772 }
5773
5774
5775 static
5776 NTSTATUS
5777 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5778 PSAMPR_USER_INFO_BUFFER *Buffer)
5779 {
5780 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5781 SAM_DOMAIN_FIXED_DATA DomainFixedData;
5782 SAM_USER_FIXED_DATA FixedData;
5783 LARGE_INTEGER PasswordCanChange;
5784 LARGE_INTEGER PasswordMustChange;
5785 ULONG Length = 0;
5786 NTSTATUS Status;
5787
5788 *Buffer = NULL;
5789
5790 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5791 if (InfoBuffer == NULL)
5792 return STATUS_INSUFFICIENT_RESOURCES;
5793
5794 /* Get the fixed size domain data */
5795 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5796 Status = SampGetObjectAttribute(UserObject->ParentObject,
5797 L"F",
5798 NULL,
5799 (PVOID)&DomainFixedData,
5800 &Length);
5801 if (!NT_SUCCESS(Status))
5802 goto done;
5803
5804 /* Get the fixed size user data */
5805 Length = sizeof(SAM_USER_FIXED_DATA);
5806 Status = SampGetObjectAttribute(UserObject,
5807 L"F",
5808 NULL,
5809 (PVOID)&FixedData,
5810 &Length);
5811 if (!NT_SUCCESS(Status))
5812 goto done;
5813
5814 InfoBuffer->Logon.UserId = FixedData.UserId;
5815 InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5816 InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5817 InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5818 InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5819 InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5820 InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5821 InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5822 InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5823 InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5824 InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5825
5826 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5827 DomainFixedData.MinPasswordAge);
5828 InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5829 InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5830
5831 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5832 DomainFixedData.MaxPasswordAge);
5833 InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5834 InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5835
5836 /* Get the Name string */
5837 Status = SampGetObjectAttributeString(UserObject,
5838 L"Name",
5839 &InfoBuffer->Logon.UserName);
5840 if (!NT_SUCCESS(Status))
5841 {
5842 TRACE("Status 0x%08lx\n", Status);
5843 goto done;
5844 }
5845
5846 /* Get the FullName string */
5847 Status = SampGetObjectAttributeString(UserObject,
5848 L"FullName",
5849 &InfoBuffer->Logon.FullName);
5850 if (!NT_SUCCESS(Status))
5851 {
5852 TRACE("Status 0x%08lx\n", Status);
5853 goto done;
5854 }
5855
5856 /* Get the HomeDirectory string */
5857 Status = SampGetObjectAttributeString(UserObject,
5858 L"HomeDirectory",
5859 &InfoBuffer->Logon.HomeDirectory);
5860 if (!NT_SUCCESS(Status))
5861 {
5862 TRACE("Status 0x%08lx\n", Status);
5863 goto done;
5864 }
5865
5866 /* Get the HomeDirectoryDrive string */
5867 Status = SampGetObjectAttributeString(UserObject,
5868 L"HomeDirectoryDrive",
5869 &InfoBuffer->Logon.HomeDirectoryDrive);
5870 if (!NT_SUCCESS(Status))
5871 {
5872 TRACE("Status 0x%08lx\n", Status);
5873 goto done;
5874 }
5875
5876 /* Get the ScriptPath string */
5877 Status = SampGetObjectAttributeString(UserObject,
5878 L"ScriptPath",
5879 &InfoBuffer->Logon.ScriptPath);
5880 if (!NT_SUCCESS(Status))
5881 {
5882 TRACE("Status 0x%08lx\n", Status);
5883 goto done;
5884 }
5885
5886 /* Get the ProfilePath string */
5887 Status = SampGetObjectAttributeString(UserObject,
5888 L"ProfilePath",
5889 &InfoBuffer->Logon.ProfilePath);
5890 if (!NT_SUCCESS(Status))
5891 {
5892 TRACE("Status 0x%08lx\n", Status);
5893 goto done;
5894 }
5895
5896 /* Get the WorkStations string */
5897 Status = SampGetObjectAttributeString(UserObject,
5898 L"WorkStations",
5899 &InfoBuffer->Logon.WorkStations);
5900 if (!NT_SUCCESS(Status))
5901 {
5902 TRACE("Status 0x%08lx\n", Status);
5903 goto done;
5904 }
5905
5906 /* Get the LogonHours attribute */
5907 Status = SampGetLogonHoursAttribute(UserObject,
5908 &InfoBuffer->Logon.LogonHours);
5909 if (!NT_SUCCESS(Status))
5910 {
5911 TRACE("Status 0x%08lx\n", Status);
5912 goto done;
5913 }
5914
5915 *Buffer = InfoBuffer;
5916
5917 done:
5918 if (!NT_SUCCESS(Status))
5919 {
5920 if (InfoBuffer != NULL)
5921 {
5922 if (InfoBuffer->Logon.UserName.Buffer != NULL)
5923 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5924
5925 if (InfoBuffer->Logon.FullName.Buffer != NULL)
5926 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5927
5928 if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5929 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5930
5931 if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5932 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5933
5934 if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5935 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5936
5937 if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5938 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5939
5940 if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5941 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5942
5943 if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5944 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5945
5946 midl_user_free(InfoBuffer);
5947 }
5948 }
5949
5950 return Status;
5951 }
5952
5953
5954 static
5955 NTSTATUS
5956 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5957 PSAMPR_USER_INFO_BUFFER *Buffer)
5958 {
5959 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5960 SAM_USER_FIXED_DATA FixedData;
5961 ULONG Length = 0;
5962 NTSTATUS Status;
5963
5964 *Buffer = NULL;
5965
5966 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5967 if (InfoBuffer == NULL)
5968 return STATUS_INSUFFICIENT_RESOURCES;
5969
5970 Length = sizeof(SAM_USER_FIXED_DATA);
5971 Status = SampGetObjectAttribute(UserObject,
5972 L"F",
5973 NULL,
5974 (PVOID)&FixedData,
5975 &Length);
5976 if (!NT_SUCCESS(Status))
5977 goto done;
5978
5979 InfoBuffer->Account.UserId = FixedData.UserId;
5980 InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5981 InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5982 InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5983 InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5984 InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5985 InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5986 InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5987 InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5988 InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5989 InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
5990 InfoBuffer->Account.LogonCount = FixedData.LogonCount;
5991 InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
5992
5993 /* Get the Name string */
5994 Status = SampGetObjectAttributeString(UserObject,
5995 L"Name",
5996 &InfoBuffer->Account.UserName);
5997 if (!NT_SUCCESS(Status))
5998 {
5999 TRACE("Status 0x%08lx\n", Status);
6000 goto done;
6001 }
6002
6003 /* Get the FullName string */
6004 Status = SampGetObjectAttributeString(UserObject,
6005 L"FullName",
6006 &InfoBuffer->Account.FullName);
6007 if (!NT_SUCCESS(Status))
6008 {
6009 TRACE("Status 0x%08lx\n", Status);
6010 goto done;
6011 }
6012
6013 /* Get the HomeDirectory string */
6014 Status = SampGetObjectAttributeString(UserObject,
6015 L"HomeDirectory",
6016 &InfoBuffer->Account.HomeDirectory);
6017 if (!NT_SUCCESS(Status))
6018 {
6019 TRACE("Status 0x%08lx\n", Status);
6020 goto done;
6021 }
6022
6023 /* Get the HomeDirectoryDrive string */
6024 Status = SampGetObjectAttributeString(UserObject,
6025 L"HomeDirectoryDrive",
6026 &InfoBuffer->Account.HomeDirectoryDrive);
6027 if (!NT_SUCCESS(Status))
6028 {
6029 TRACE("Status 0x%08lx\n", Status);
6030 goto done;
6031 }
6032
6033 /* Get the ScriptPath string */
6034 Status = SampGetObjectAttributeString(UserObject,
6035 L"ScriptPath",
6036 &InfoBuffer->Account.ScriptPath);
6037 if (!NT_SUCCESS(Status))
6038 {
6039 TRACE("Status 0x%08lx\n", Status);
6040 goto done;
6041 }
6042
6043 /* Get the ProfilePath string */
6044 Status = SampGetObjectAttributeString(UserObject,
6045 L"ProfilePath",
6046 &InfoBuffer->Account.ProfilePath);
6047 if (!NT_SUCCESS(Status))
6048 {
6049 TRACE("Status 0x%08lx\n", Status);
6050 goto done;
6051 }
6052
6053 /* Get the AdminComment string */
6054 Status = SampGetObjectAttributeString(UserObject,
6055 L"AdminComment",
6056 &InfoBuffer->Account.AdminComment);
6057 if (!NT_SUCCESS(Status))
6058 {
6059 TRACE("Status 0x%08lx\n", Status);
6060 goto done;
6061 }
6062
6063 /* Get the WorkStations string */
6064 Status = SampGetObjectAttributeString(UserObject,
6065 L"WorkStations",
6066 &InfoBuffer->Account.WorkStations);
6067 if (!NT_SUCCESS(Status))
6068 {
6069 TRACE("Status 0x%08lx\n", Status);
6070 goto done;
6071 }
6072
6073 /* Get the LogonHours attribute */
6074 Status = SampGetLogonHoursAttribute(UserObject,
6075 &InfoBuffer->Account.LogonHours);
6076 if (!NT_SUCCESS(Status))
6077 {
6078 TRACE("Status 0x%08lx\n", Status);
6079 goto done;
6080 }
6081
6082 *Buffer = InfoBuffer;
6083
6084 done:
6085 if (!NT_SUCCESS(Status))
6086 {
6087 if (InfoBuffer != NULL)
6088 {
6089 if (InfoBuffer->Account.UserName.Buffer != NULL)
6090 midl_user_free(InfoBuffer->Account.UserName.Buffer);
6091
6092 if (InfoBuffer->Account.FullName.Buffer != NULL)
6093 midl_user_free(InfoBuffer->Account.FullName.Buffer);
6094
6095 if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
6096 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
6097
6098 if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
6099 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
6100
6101 if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
6102 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
6103
6104 if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
6105 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
6106
6107 if (InfoBuffer->Account.AdminComment.Buffer != NULL)
6108 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
6109
6110 if (InfoBuffer->Account.WorkStations.Buffer != NULL)
6111 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
6112
6113 if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
6114 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
6115
6116 midl_user_free(InfoBuffer);
6117 }
6118 }
6119
6120 return Status;
6121 }
6122
6123
6124 static
6125 NTSTATUS
6126 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
6127 PSAMPR_USER_INFO_BUFFER *Buffer)
6128 {
6129 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6130 NTSTATUS Status;
6131
6132 TRACE("(%p %p)\n", UserObject, Buffer);
6133
6134 *Buffer = NULL;
6135
6136 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6137 if (InfoBuffer == NULL)
6138 {
6139 TRACE("Failed to allocate InfoBuffer!\n");
6140 return STATUS_INSUFFICIENT_RESOURCES;
6141 }
6142
6143 Status = SampGetLogonHoursAttribute(UserObject,
6144 &InfoBuffer->LogonHours.LogonHours);
6145 if (!NT_SUCCESS(Status))
6146 {
6147 TRACE("SampGetLogonHoursAttribute failed (Status 0x%08lx)\n", Status);
6148 goto done;
6149 }
6150
6151 *Buffer = InfoBuffer;
6152
6153 done:
6154 if (!NT_SUCCESS(Status))
6155 {
6156 if (InfoBuffer != NULL)
6157 {
6158 if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
6159 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
6160
6161 midl_user_free(InfoBuffer);
6162 }
6163 }
6164
6165 return Status;
6166 }
6167
6168
6169 static
6170 NTSTATUS
6171 SampQueryUserName(PSAM_DB_OBJECT UserObject,
6172 PSAMPR_USER_INFO_BUFFER *Buffer)
6173 {
6174 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6175 NTSTATUS Status;
6176
6177 *Buffer = NULL;
6178
6179 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6180 if (InfoBuffer == NULL)
6181 return STATUS_INSUFFICIENT_RESOURCES;
6182
6183 /* Get the Name string */
6184 Status = SampGetObjectAttributeString(UserObject,
6185 L"Name",
6186 &InfoBuffer->Name.UserName);
6187 if (!NT_SUCCESS(Status))
6188 {
6189 TRACE("Status 0x%08lx\n", Status);
6190 goto done;
6191 }
6192
6193 /* Get the FullName string */
6194 Status = SampGetObjectAttributeString(UserObject,
6195 L"FullName",
6196 &InfoBuffer->Name.FullName);
6197 if (!NT_SUCCESS(Status))
6198 {
6199 TRACE("Status 0x%08lx\n", Status);
6200 goto done;
6201 }
6202
6203 *Buffer = InfoBuffer;
6204
6205 done:
6206 if (!NT_SUCCESS(Status))
6207 {
6208 if (InfoBuffer != NULL)
6209 {
6210 if (InfoBuffer->Name.UserName.Buffer != NULL)
6211 midl_user_free(InfoBuffer->Name.UserName.Buffer);
6212
6213 if (InfoBuffer->Name.FullName.Buffer != NULL)
6214 midl_user_free(InfoBuffer->Name.FullName.Buffer);
6215
6216 midl_user_free(InfoBuffer);
6217 }
6218 }
6219
6220 return Status;
6221 }
6222
6223
6224 static NTSTATUS
6225 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
6226 PSAMPR_USER_INFO_BUFFER *Buffer)
6227 {
6228 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6229 NTSTATUS Status;
6230
6231 *Buffer = NULL;
6232
6233 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6234 if (InfoBuffer == NULL)
6235 return STATUS_INSUFFICIENT_RESOURCES;
6236
6237 /* Get the Name string */
6238 Status = SampGetObjectAttributeString(UserObject,
6239 L"Name",
6240 &InfoBuffer->AccountName.UserName);
6241 if (!NT_SUCCESS(Status))
6242 {
6243 TRACE("Status 0x%08lx\n", Status);
6244 goto done;
6245 }
6246
6247 *Buffer = InfoBuffer;
6248
6249 done:
6250 if (!NT_SUCCESS(Status))
6251 {
6252 if (InfoBuffer != NULL)
6253 {
6254 if (InfoBuffer->AccountName.UserName.Buffer != NULL)
6255 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
6256
6257 midl_user_free(InfoBuffer);
6258 }
6259 }
6260
6261 return Status;
6262 }
6263
6264
6265 static NTSTATUS
6266 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
6267 PSAMPR_USER_INFO_BUFFER *Buffer)
6268 {
6269 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6270 NTSTATUS Status;
6271
6272 *Buffer = NULL;
6273
6274 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6275 if (InfoBuffer == NULL)
6276 return STATUS_INSUFFICIENT_RESOURCES;
6277
6278 /* Get the FullName string */
6279 Status = SampGetObjectAttributeString(UserObject,
6280 L"FullName",
6281 &InfoBuffer->FullName.FullName);
6282 if (!NT_SUCCESS(Status))
6283 {
6284 TRACE("Status 0x%08lx\n", Status);
6285 goto done;
6286 }
6287
6288 *Buffer = InfoBuffer;
6289
6290 done:
6291 if (!NT_SUCCESS(Status))
6292 {
6293 if (InfoBuffer != NULL)
6294 {
6295 if (InfoBuffer->FullName.FullName.Buffer != NULL)
6296 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
6297
6298 midl_user_free(InfoBuffer);
6299 }
6300 }
6301
6302 return Status;
6303 }
6304
6305
6306 static
6307 NTSTATUS
6308 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6309 PSAMPR_USER_INFO_BUFFER *Buffer)
6310 {
6311 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6312 SAM_USER_FIXED_DATA FixedData;
6313 ULONG Length = 0;
6314 NTSTATUS Status;
6315
6316 *Buffer = NULL;
6317
6318 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6319 if (InfoBuffer == NULL)
6320 return STATUS_INSUFFICIENT_RESOURCES;
6321
6322 Length = sizeof(SAM_USER_FIXED_DATA);
6323 Status = SampGetObjectAttribute(UserObject,
6324 L"F",
6325 NULL,
6326 (PVOID)&FixedData,
6327 &Length);
6328 if (!NT_SUCCESS(Status))
6329 goto done;
6330
6331 InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
6332
6333 *Buffer = InfoBuffer;
6334
6335 done:
6336 if (!NT_SUCCESS(Status))
6337 {
6338 if (InfoBuffer != NULL)
6339 {
6340 midl_user_free(InfoBuffer);
6341 }
6342 }
6343
6344 return Status;
6345 }
6346
6347
6348 static NTSTATUS
6349 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
6350 PSAMPR_USER_INFO_BUFFER *Buffer)
6351 {
6352 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6353 NTSTATUS Status;
6354
6355 *Buffer = NULL;
6356
6357 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6358 if (InfoBuffer == NULL)
6359 return STATUS_INSUFFICIENT_RESOURCES;
6360
6361 /* Get the HomeDirectory string */
6362 Status = SampGetObjectAttributeString(UserObject,
6363 L"HomeDirectory",
6364 &InfoBuffer->Home.HomeDirectory);
6365 if (!NT_SUCCESS(Status))
6366 {
6367 TRACE("Status 0x%08lx\n", Status);
6368 goto done;
6369 }
6370
6371 /* Get the HomeDirectoryDrive string */
6372 Status = SampGetObjectAttributeString(UserObject,
6373 L"HomeDirectoryDrive",
6374 &InfoBuffer->Home.HomeDirectoryDrive);
6375 if (!NT_SUCCESS(Status))
6376 {
6377 TRACE("Status 0x%08lx\n", Status);
6378 goto done;
6379 }
6380
6381 *Buffer = InfoBuffer;
6382
6383 done:
6384 if (!NT_SUCCESS(Status))
6385 {
6386 if (InfoBuffer != NULL)
6387 {
6388 if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
6389 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
6390
6391 if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
6392 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
6393
6394 midl_user_free(InfoBuffer);
6395 }
6396 }
6397
6398 return Status;
6399 }
6400
6401
6402 static NTSTATUS
6403 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
6404 PSAMPR_USER_INFO_BUFFER *Buffer)
6405 {
6406 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6407 NTSTATUS Status;
6408
6409 *Buffer = NULL;
6410
6411 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6412 if (InfoBuffer == NULL)
6413 return STATUS_INSUFFICIENT_RESOURCES;
6414
6415 /* Get the ScriptPath string */
6416 Status = SampGetObjectAttributeString(UserObject,
6417 L"ScriptPath",
6418 &InfoBuffer->Script.ScriptPath);
6419 if (!NT_SUCCESS(Status))
6420 {
6421 TRACE("Status 0x%08lx\n", Status);
6422 goto done;
6423 }
6424
6425 *Buffer = InfoBuffer;
6426
6427 done:
6428 if (!NT_SUCCESS(Status))
6429 {
6430 if (InfoBuffer != NULL)
6431 {
6432 if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
6433 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
6434
6435 midl_user_free(InfoBuffer);
6436 }
6437 }
6438
6439 return Status;
6440 }
6441
6442
6443 static NTSTATUS
6444 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
6445 PSAMPR_USER_INFO_BUFFER *Buffer)
6446 {
6447 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6448 NTSTATUS Status;
6449
6450 *Buffer = NULL;
6451
6452 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6453 if (InfoBuffer == NULL)
6454 return STATUS_INSUFFICIENT_RESOURCES;
6455
6456 /* Get the ProfilePath string */
6457 Status = SampGetObjectAttributeString(UserObject,
6458 L"ProfilePath",
6459 &InfoBuffer->Profile.ProfilePath);
6460 if (!NT_SUCCESS(Status))
6461 {
6462 TRACE("Status 0x%08lx\n", Status);
6463 goto done;
6464 }
6465
6466 *Buffer = InfoBuffer;
6467
6468 done:
6469 if (!NT_SUCCESS(Status))
6470 {
6471 if (InfoBuffer != NULL)
6472 {
6473 if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
6474 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
6475
6476 midl_user_free(InfoBuffer);
6477 }
6478 }
6479
6480 return Status;
6481 }
6482
6483
6484 static NTSTATUS
6485 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6486 PSAMPR_USER_INFO_BUFFER *Buffer)
6487 {
6488 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6489 NTSTATUS Status;
6490
6491 *Buffer = NULL;
6492
6493 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6494 if (InfoBuffer == NULL)
6495 return STATUS_INSUFFICIENT_RESOURCES;
6496
6497 /* Get the AdminComment string */
6498 Status = SampGetObjectAttributeString(UserObject,
6499 L"AdminComment",
6500 &InfoBuffer->AdminComment.AdminComment);
6501 if (!NT_SUCCESS(Status))
6502 {
6503 TRACE("Status 0x%08lx\n", Status);
6504 goto done;
6505 }
6506
6507 *Buffer = InfoBuffer;
6508
6509 done:
6510 if (!NT_SUCCESS(Status))
6511 {
6512 if (InfoBuffer != NULL)
6513 {
6514 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6515 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6516
6517 midl_user_free(InfoBuffer);
6518 }
6519 }
6520
6521 return Status;
6522 }
6523
6524
6525 static NTSTATUS
6526 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6527 PSAMPR_USER_INFO_BUFFER *Buffer)
6528 {
6529 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6530 NTSTATUS Status;
6531
6532 *Buffer = NULL;
6533
6534 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6535 if (InfoBuffer == NULL)
6536 return STATUS_INSUFFICIENT_RESOURCES;
6537
6538 /* Get the WorkStations string */
6539 Status = SampGetObjectAttributeString(UserObject,
6540 L"WorkStations",
6541 &InfoBuffer->WorkStations.WorkStations);
6542 if (!NT_SUCCESS(Status))
6543 {
6544 TRACE("Status 0x%08lx\n", Status);
6545 goto done;
6546 }
6547
6548 *Buffer = InfoBuffer;
6549
6550 done:
6551 if (!NT_SUCCESS(Status))
6552 {
6553 if (InfoBuffer != NULL)
6554 {
6555 if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6556 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6557
6558 midl_user_free(InfoBuffer);
6559 }
6560 }
6561
6562 return Status;
6563 }
6564
6565
6566 static
6567 NTSTATUS
6568 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6569 PSAMPR_USER_INFO_BUFFER *Buffer)
6570 {
6571 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6572 SAM_USER_FIXED_DATA FixedData;
6573 ULONG Length = 0;
6574 NTSTATUS Status;
6575
6576 *Buffer = NULL;
6577
6578 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6579 if (InfoBuffer == NULL)
6580 return STATUS_INSUFFICIENT_RESOURCES;
6581
6582 Length = sizeof(SAM_USER_FIXED_DATA);
6583 Status = SampGetObjectAttribute(UserObject,
6584 L"F",
6585 NULL,
6586 (PVOID)&FixedData,
6587 &Length);
6588 if (!NT_SUCCESS(Status))
6589 goto done;
6590
6591 InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6592
6593 *Buffer = InfoBuffer;
6594
6595 done:
6596 if (!NT_SUCCESS(Status))
6597 {
6598 if (InfoBuffer != NULL)
6599 {
6600 midl_user_free(InfoBuffer);
6601 }
6602 }
6603
6604 return Status;
6605 }
6606
6607
6608 static
6609 NTSTATUS
6610 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6611 PSAMPR_USER_INFO_BUFFER *Buffer)
6612 {
6613 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6614 SAM_USER_FIXED_DATA FixedData;
6615 ULONG Length = 0;
6616 NTSTATUS Status;
6617
6618 *Buffer = NULL;
6619
6620 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6621 if (InfoBuffer == NULL)
6622 return STATUS_INSUFFICIENT_RESOURCES;
6623
6624 Length = sizeof(SAM_USER_FIXED_DATA);
6625 Status = SampGetObjectAttribute(UserObject,
6626 L"F",
6627 NULL,
6628 (PVOID)&FixedData,
6629 &Length);
6630 if (!NT_SUCCESS(Status))
6631 goto done;
6632
6633 InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6634 InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6635
6636 *Buffer = InfoBuffer;
6637
6638 done:
6639 if (!NT_SUCCESS(Status))
6640 {
6641 if (InfoBuffer != NULL)
6642 {
6643 midl_user_free(InfoBuffer);
6644 }
6645 }
6646
6647 return Status;
6648 }
6649
6650
6651 static
6652 NTSTATUS
6653 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6654 PSAMPR_USER_INFO_BUFFER *Buffer)
6655 {
6656 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6657 ULONG Length = 0;
6658 NTSTATUS Status = STATUS_SUCCESS;
6659
6660 /* Fail, if the caller is not a trusted caller */
6661 if (UserObject->Trusted == FALSE)
6662 return STATUS_INVALID_INFO_CLASS;
6663
6664 *Buffer = NULL;
6665
6666 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6667 if (InfoBuffer == NULL)
6668 return STATUS_INSUFFICIENT_RESOURCES;
6669
6670 InfoBuffer->Internal1.LmPasswordPresent = FALSE;
6671 InfoBuffer->Internal1.NtPasswordPresent = FALSE;
6672
6673 /* Get the NT password */
6674 Length = 0;
6675 SampGetObjectAttribute(UserObject,
6676 L"NTPwd",
6677 NULL,
6678 NULL,
6679 &Length);
6680
6681 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6682 {
6683 Status = SampGetObjectAttribute(UserObject,
6684 L"NTPwd",
6685 NULL,
6686 (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6687 &Length);
6688 if (!NT_SUCCESS(Status))
6689 goto done;
6690
6691 if (memcmp(&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6692 &EmptyNtHash,
6693 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
6694 InfoBuffer->Internal1.NtPasswordPresent = TRUE;
6695 }
6696
6697
6698 /* Get the LM password */
6699 Length = 0;
6700 SampGetObjectAttribute(UserObject,
6701 L"LMPwd",
6702 NULL,
6703 NULL,
6704 &Length);
6705
6706 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6707 {
6708 Status = SampGetObjectAttribute(UserObject,
6709 L"LMPwd",
6710 NULL,
6711 (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6712 &Length);
6713 if (!NT_SUCCESS(Status))
6714 goto done;
6715
6716 if (memcmp(&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6717 &EmptyLmHash,
6718 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
6719 InfoBuffer->Internal1.LmPasswordPresent = TRUE;
6720 }
6721
6722 InfoBuffer->Internal1.PasswordExpired = FALSE;
6723
6724 *Buffer = InfoBuffer;
6725
6726 done:
6727 if (!NT_SUCCESS(Status))
6728 {
6729 if (InfoBuffer != NULL)
6730 {
6731 midl_user_free(InfoBuffer);
6732 }
6733 }
6734
6735 return Status;
6736 }
6737
6738
6739 static NTSTATUS
6740 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6741 PSAMPR_USER_INFO_BUFFER *Buffer)
6742 {
6743 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6744 NTSTATUS Status;
6745
6746 *Buffer = NULL;
6747
6748 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6749 if (InfoBuffer == NULL)
6750 return STATUS_INSUFFICIENT_RESOURCES;
6751
6752 /* Get the Parameters string */
6753 Status = SampGetObjectAttributeString(UserObject,
6754 L"Parameters",
6755 &InfoBuffer->Parameters.Parameters);
6756 if (!NT_SUCCESS(Status))
6757 {
6758 TRACE("Status 0x%08lx\n", Status);
6759 goto done;
6760 }
6761
6762 *Buffer = InfoBuffer;
6763
6764 done:
6765 if (!NT_SUCCESS(Status))
6766 {
6767 if (InfoBuffer != NULL)
6768 {
6769 if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6770 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6771
6772 midl_user_free(InfoBuffer);
6773 }
6774 }
6775
6776 return Status;
6777 }
6778
6779
6780 static NTSTATUS
6781 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6782 PSAMPR_USER_INFO_BUFFER *Buffer)
6783 {
6784 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6785 SAM_DOMAIN_FIXED_DATA DomainFixedData;
6786 SAM_USER_FIXED_DATA FixedData;
6787 LARGE_INTEGER PasswordCanChange;
6788 LARGE_INTEGER PasswordMustChange;
6789 ULONG Length = 0;
6790 NTSTATUS Status;
6791
6792 *Buffer = NULL;
6793
6794 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6795 if (InfoBuffer == NULL)
6796 return STATUS_INSUFFICIENT_RESOURCES;
6797
6798 /* Get the fixed size domain data */
6799 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6800 Status = SampGetObjectAttribute(UserObject->ParentObject,
6801 L"F",
6802 NULL,
6803 (PVOID)&DomainFixedData,
6804 &Length);
6805 if (!NT_SUCCESS(Status))
6806 goto done;
6807
6808 /* Get the fixed size user data */
6809 Length = sizeof(SAM_USER_FIXED_DATA);
6810 Status = SampGetObjectAttribute(UserObject,
6811 L"F",
6812 NULL,
6813 (PVOID)&FixedData,
6814 &Length);
6815 if (!NT_SUCCESS(Status))
6816 goto done;
6817
6818 /* Set the fields to be returned */
6819 if (UserObject->Trusted)
6820 {
6821 InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
6822 USER_ALL_READ_LOGON_MASK |
6823 USER_ALL_READ_ACCOUNT_MASK |
6824 USER_ALL_READ_PREFERENCES_MASK |
6825 USER_ALL_READ_TRUSTED_MASK;
6826 }
6827 else
6828 {
6829 InfoBuffer->All.WhichFields = 0;
6830
6831 if (UserObject->Access & USER_READ_GENERAL)
6832 InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6833
6834 if (UserObject->Access & USER_READ_LOGON)
6835 InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
6836
6837 if (UserObject->Access & USER_READ_ACCOUNT)
6838 InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6839
6840 if (UserObject->Access & USER_READ_PREFERENCES)
6841 InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6842 }
6843
6844 /* Fail, if no fields are to be returned */
6845 if (InfoBuffer->All.WhichFields == 0)
6846 {
6847 Status = STATUS_ACCESS_DENIED;
6848 goto done;
6849 }
6850
6851 /* Get the UserName attribute */
6852 if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
6853 {
6854 Status = SampGetObjectAttributeString(UserObject,
6855 L"Name",
6856 &InfoBuffer->All.UserName);
6857 if (!NT_SUCCESS(Status))
6858 {
6859 TRACE("Status 0x%08lx\n", Status);
6860 goto done;
6861 }
6862 }
6863
6864 /* Get the FullName attribute */
6865 if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
6866 {
6867 Status = SampGetObjectAttributeString(UserObject,
6868 L"FullName",
6869 &InfoBuffer->All.FullName);
6870 if (!NT_SUCCESS(Status))
6871 {
6872 TRACE("Status 0x%08lx\n", Status);
6873 goto done;
6874 }
6875 }
6876
6877 /* Get the UserId attribute */
6878 if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
6879 {
6880 InfoBuffer->All.UserId = FixedData.UserId;
6881 }
6882
6883 /* Get the PrimaryGroupId attribute */
6884 if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
6885 {
6886 InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6887 }
6888
6889 /* Get the AdminComment attribute */
6890 if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
6891 {
6892 Status = SampGetObjectAttributeString(UserObject,
6893 L"AdminComment",
6894 &InfoBuffer->All.AdminComment);
6895 if (!NT_SUCCESS(Status))
6896 {
6897 TRACE("Status 0x%08lx\n", Status);
6898 goto done;
6899 }
6900 }
6901
6902 /* Get the UserComment attribute */
6903 if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
6904 {
6905 Status = SampGetObjectAttributeString(UserObject,
6906 L"UserComment",
6907 &InfoBuffer->All.UserComment);
6908 if (!NT_SUCCESS(Status))
6909 {
6910 TRACE("Status 0x%08lx\n", Status);
6911 goto done;
6912 }
6913 }
6914
6915 /* Get the HomeDirectory attribute */
6916 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
6917 {
6918 Status = SampGetObjectAttributeString(UserObject,
6919 L"HomeDirectory",
6920 &InfoBuffer->All.HomeDirectory);
6921 if (!NT_SUCCESS(Status))
6922 {
6923 TRACE("Status 0x%08lx\n", Status);
6924 goto done;
6925 }
6926 }
6927
6928 /* Get the HomeDirectoryDrive attribute */
6929 if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
6930 {
6931 Status = SampGetObjectAttributeString(UserObject,
6932 L"HomeDirectoryDrive",
6933 &InfoBuffer->Home.HomeDirectoryDrive);
6934 if (!NT_SUCCESS(Status))
6935 {
6936 TRACE("Status 0x%08lx\n", Status);
6937 goto done;
6938 }
6939 }
6940
6941 /* Get the ScriptPath attribute */
6942 if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
6943 {
6944 Status = SampGetObjectAttributeString(UserObject,
6945 L"ScriptPath",
6946 &InfoBuffer->All.ScriptPath);
6947 if (!NT_SUCCESS(Status))
6948 {
6949 TRACE("Status 0x%08lx\n", Status);
6950 goto done;
6951 }
6952 }
6953
6954 /* Get the ProfilePath attribute */
6955 if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
6956 {
6957 Status = SampGetObjectAttributeString(UserObject,
6958 L"ProfilePath",
6959 &InfoBuffer->All.ProfilePath);
6960 if (!NT_SUCCESS(Status))
6961 {
6962 TRACE("Status 0x%08lx\n", Status);
6963 goto done;
6964 }
6965 }
6966
6967 /* Get the WorkStations attribute */
6968 if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
6969 {
6970 Status = SampGetObjectAttributeString(UserObject,
6971 L"WorkStations",
6972 &InfoBuffer->All.WorkStations);
6973 if (!NT_SUCCESS(Status))
6974 {
6975 TRACE("Status 0x%08lx\n", Status);
6976 goto done;
6977 }
6978 }
6979
6980 /* Get the LastLogon attribute */
6981 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
6982 {
6983 InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6984 InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6985 }
6986
6987 /* Get the LastLogoff attribute */
6988 if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
6989 {
6990 InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6991 InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6992 }
6993
6994 /* Get the LogonHours attribute */
6995 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
6996 {
6997 Status = SampGetLogonHoursAttribute(UserObject,
6998 &InfoBuffer->All.LogonHours);
6999 if (!NT_SUCCESS(Status))
7000 {
7001 TRACE("Status 0x%08lx\n", Status);
7002 goto done;
7003 }
7004 }
7005
7006 /* Get the BadPasswordCount attribute */
7007 if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
7008 {
7009 InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
7010 }
7011
7012 /* Get the LogonCount attribute */
7013 if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
7014 {
7015 InfoBuffer->All.LogonCount = FixedData.LogonCount;
7016 }
7017
7018 /* Get the PasswordCanChange attribute */
7019 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
7020 {
7021 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7022 DomainFixedData.MinPasswordAge);
7023 InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
7024 InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
7025 }
7026
7027 /* Get the PasswordMustChange attribute */
7028 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
7029 {
7030 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
7031 DomainFixedData.MaxPasswordAge);
7032 InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
7033 InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
7034 }
7035
7036 /* Get the PasswordLastSet attribute */
7037 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
7038 {
7039 InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
7040 InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
7041 }
7042
7043 /* Get the AccountExpires attribute */
7044 if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
7045 {
7046 InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
7047 InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
7048 }
7049
7050 /* Get the UserAccountControl attribute */
7051 if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
7052 {
7053 InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
7054 }
7055
7056 /* Get the Parameters attribute */
7057 if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
7058 {
7059 Status = SampGetObjectAttributeString(UserObject,
7060 L"Parameters",
7061 &InfoBuffer->All.Parameters);
7062 if (!NT_SUCCESS(Status))
7063 {
7064 TRACE("Status 0x%08lx\n", Status);
7065 goto done;
7066 }
7067 }
7068
7069 /* Get the CountryCode attribute */
7070 if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
7071 {
7072 InfoBuffer->All.CountryCode = FixedData.CountryCode;
7073 }
7074
7075 /* Get the CodePage attribute */
7076 if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
7077 {
7078 InfoBuffer->All.CodePage = FixedData.CodePage;
7079 }
7080
7081 /* Get the LmPassword and NtPassword attributes */
7082 if (InfoBuffer->All.WhichFields & (USER_ALL_NTPASSWORDPRESENT | USER_ALL_LMPASSWORDPRESENT))
7083 {
7084 InfoBuffer->All.LmPasswordPresent = FALSE;
7085 InfoBuffer->All.NtPasswordPresent = FALSE;
7086
7087 /* Get the NT password */
7088 Length = 0;
7089 SampGetObjectAttribute(UserObject,
7090 L"NTPwd",
7091 NULL,
7092 NULL,
7093 &Length);
7094
7095 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
7096 {
7097 InfoBuffer->All.NtOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_NT_OWF_PASSWORD));
7098 if (InfoBuffer->All.NtOwfPassword.Buffer == NULL)
7099 {
7100 Status = STATUS_INSUFFICIENT_RESOURCES;
7101 goto done;
7102 }
7103
7104 InfoBuffer->All.NtOwfPassword.Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7105 InfoBuffer->All.NtOwfPassword.MaximumLength = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7106
7107 Status = SampGetObjectAttribute(UserObject,
7108 L"NTPwd",
7109 NULL,
7110 (PVOID)InfoBuffer->All.NtOwfPassword.Buffer,
7111 &Length);
7112 if (!NT_SUCCESS(Status))
7113 goto done;
7114
7115 if (memcmp(InfoBuffer->All.NtOwfPassword.Buffer,
7116 &EmptyNtHash,
7117 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
7118 InfoBuffer->All.NtPasswordPresent = TRUE;
7119 }
7120
7121 /* Get the LM password */
7122 Length = 0;
7123 SampGetObjectAttribute(UserObject,
7124 L"LMPwd",
7125 NULL,
7126 NULL,
7127 &Length);
7128
7129 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
7130 {
7131 InfoBuffer->All.LmOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_LM_OWF_PASSWORD));
7132 if (InfoBuffer->All.LmOwfPassword.Buffer == NULL)
7133 {
7134 Status = STATUS_INSUFFICIENT_RESOURCES;
7135 goto done;
7136 }
7137
7138 InfoBuffer->All.LmOwfPassword.Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7139 InfoBuffer->All.LmOwfPassword.MaximumLength = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7140
7141 Status = SampGetObjectAttribute(UserObject,
7142 L"LMPwd",
7143 NULL,
7144 (PVOID)InfoBuffer->All.LmOwfPassword.Buffer,
7145 &Length);
7146 if (!NT_SUCCESS(Status))
7147 goto done;
7148
7149 if (memcmp(InfoBuffer->All.LmOwfPassword.Buffer,
7150 &EmptyLmHash,
7151 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7152 InfoBuffer->All.LmPasswordPresent = TRUE;
7153 }
7154 }
7155
7156 if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
7157 {
7158 Status = SampGetObjectAttributeString(UserObject,
7159 L"PrivateData",
7160 &InfoBuffer->All.PrivateData);
7161 if (!NT_SUCCESS(Status))
7162 {
7163 TRACE("Status 0x%08lx\n", Status);
7164 goto done;
7165 }
7166 }
7167
7168 if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
7169 {
7170 /* FIXME */
7171 }
7172
7173 if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7174 {
7175 Length = 0;
7176 SampGetObjectAttribute(UserObject,
7177 L"SecDesc",
7178 NULL,
7179 NULL,
7180 &Length);
7181
7182 if (Length > 0)
7183 {
7184 InfoBuffer->All.SecurityDescriptor.SecurityDescriptor = midl_user_allocate(Length);
7185 if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor == NULL)
7186 {
7187 Status = STATUS_INSUFFICIENT_RESOURCES;
7188 goto done;
7189 }
7190
7191 InfoBuffer->All.SecurityDescriptor.Length = Length;
7192
7193 Status = SampGetObjectAttribute(UserObject,
7194 L"SecDesc",
7195 NULL,
7196 (PVOID)InfoBuffer->All.SecurityDescriptor.SecurityDescriptor,
7197 &Length);
7198 if (!NT_SUCCESS(Status))
7199 goto done;
7200 }
7201 }
7202
7203 *Buffer = InfoBuffer;
7204
7205 done:
7206 if (!NT_SUCCESS(Status))
7207 {
7208 if (InfoBuffer != NULL)
7209 {
7210 if (InfoBuffer->All.UserName.Buffer != NULL)
7211 midl_user_free(InfoBuffer->All.UserName.Buffer);
7212
7213 if (InfoBuffer->All.FullName.Buffer != NULL)
7214 midl_user_free(InfoBuffer->All.FullName.Buffer);
7215
7216 if (InfoBuffer->All.AdminComment.Buffer != NULL)
7217 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
7218
7219 if (InfoBuffer->All.UserComment.Buffer != NULL)
7220 midl_user_free(InfoBuffer->All.UserComment.Buffer);
7221
7222 if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
7223 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
7224
7225 if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
7226 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
7227
7228 if (InfoBuffer->All.ScriptPath.Buffer != NULL)
7229 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
7230
7231 if (InfoBuffer->All.ProfilePath.Buffer != NULL)
7232 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
7233
7234 if (InfoBuffer->All.WorkStations.Buffer != NULL)
7235 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
7236
7237 if (InfoBuffer->All.LogonHours.LogonHours != NULL)
7238 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
7239
7240 if (InfoBuffer->All.Parameters.Buffer != NULL)
7241 midl_user_free(InfoBuffer->All.Parameters.Buffer);
7242
7243 if (InfoBuffer->All.LmOwfPassword.Buffer != NULL)
7244 midl_user_free(InfoBuffer->All.LmOwfPassword.Buffer);
7245
7246 if (InfoBuffer->All.NtOwfPassword.Buffer != NULL)
7247 midl_user_free(InfoBuffer->All.NtOwfPassword.Buffer);
7248
7249 if (InfoBuffer->All.PrivateData.Buffer != NULL)
7250 midl_user_free(InfoBuffer->All.PrivateData.Buffer);
7251
7252 if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor != NULL)
7253 midl_user_free(InfoBuffer->All.SecurityDescriptor.SecurityDescriptor);
7254
7255 midl_user_free(InfoBuffer);
7256 }
7257 }
7258
7259 return Status;
7260 }
7261
7262
7263 /* Function 36 */
7264 NTSTATUS
7265 NTAPI
7266 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
7267 IN USER_INFORMATION_CLASS UserInformationClass,
7268 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
7269 {
7270 PSAM_DB_OBJECT UserObject;
7271 ACCESS_MASK DesiredAccess;
7272 NTSTATUS Status;
7273
7274 TRACE("SamrQueryInformationUser(%p %lu %p)\n",
7275 UserHandle, UserInformationClass, Buffer);
7276
7277 switch (UserInformationClass)
7278 {
7279 case UserGeneralInformation:
7280 case UserNameInformation:
7281 case UserAccountNameInformation:
7282 case UserFullNameInformation:
7283 case UserPrimaryGroupInformation:
7284 case UserAdminCommentInformation:
7285 DesiredAccess = USER_READ_GENERAL;
7286 break;
7287
7288 case UserLogonHoursInformation:
7289 case UserHomeInformation:
7290 case UserScriptInformation:
7291 case UserProfileInformation:
7292 case UserWorkStationsInformation:
7293 DesiredAccess = USER_READ_LOGON;
7294 break;
7295
7296 case UserControlInformation:
7297 case UserExpiresInformation:
7298 case UserParametersInformation:
7299 DesiredAccess = USER_READ_ACCOUNT;
7300 break;
7301
7302 case UserPreferencesInformation:
7303 DesiredAccess = USER_READ_GENERAL |
7304 USER_READ_PREFERENCES;
7305 break;
7306
7307 case UserLogonInformation:
7308 case UserAccountInformation:
7309 DesiredAccess = USER_READ_GENERAL |
7310 USER_READ_PREFERENCES |
7311 USER_READ_LOGON |
7312 USER_READ_ACCOUNT;
7313 break;
7314
7315 case UserInternal1Information:
7316 case UserAllInformation:
7317 DesiredAccess = 0;
7318 break;
7319
7320 default:
7321 return STATUS_INVALID_INFO_CLASS;
7322 }
7323
7324 RtlAcquireResourceShared(&SampResource,
7325 TRUE);
7326
7327 /* Validate the domain handle */
7328 Status = SampValidateDbObject(UserHandle,
7329 SamDbUserObject,
7330 DesiredAccess,
7331 &UserObject);
7332 if (!NT_SUCCESS(Status))
7333 {
7334 TRACE("failed with status 0x%08lx\n", Status);
7335 goto done;
7336 }
7337
7338 switch (UserInformationClass)
7339 {
7340 case UserGeneralInformation:
7341 Status = SampQueryUserGeneral(UserObject,
7342 Buffer);
7343 break;
7344
7345 case UserPreferencesInformation:
7346 Status = SampQueryUserPreferences(UserObject,
7347 Buffer);
7348 break;
7349
7350 case UserLogonInformation:
7351 Status = SampQueryUserLogon(UserObject,
7352 Buffer);
7353 break;
7354
7355 case UserLogonHoursInformation:
7356 Status = SampQueryUserLogonHours(UserObject,
7357 Buffer);
7358 break;
7359
7360 case UserAccountInformation:
7361 Status = SampQueryUserAccount(UserObject,
7362 Buffer);
7363 break;
7364
7365 case UserNameInformation:
7366 Status = SampQueryUserName(UserObject,
7367 Buffer);
7368 break;
7369
7370 case UserAccountNameInformation:
7371 Status = SampQueryUserAccountName(UserObject,
7372 Buffer);
7373 break;
7374
7375 case UserFullNameInformation:
7376 Status = SampQueryUserFullName(UserObject,
7377 Buffer);
7378 break;
7379
7380 case UserPrimaryGroupInformation:
7381 Status = SampQueryUserPrimaryGroup(UserObject,
7382 Buffer);
7383 break;
7384
7385 case UserHomeInformation:
7386 Status = SampQueryUserHome(UserObject,
7387 Buffer);
7388
7389 case UserScriptInformation:
7390 Status = SampQueryUserScript(UserObject,
7391 Buffer);
7392 break;
7393
7394 case UserProfileInformation:
7395 Status = SampQueryUserProfile(UserObject,
7396 Buffer);
7397 break;
7398
7399 case UserAdminCommentInformation:
7400 Status = SampQueryUserAdminComment(UserObject,
7401 Buffer);
7402 break;
7403
7404 case UserWorkStationsInformation:
7405 Status = SampQueryUserWorkStations(UserObject,
7406 Buffer);
7407 break;
7408
7409 case UserControlInformation:
7410 Status = SampQueryUserControl(UserObject,
7411 Buffer);
7412 break;
7413
7414 case UserExpiresInformation:
7415 Status = SampQueryUserExpires(UserObject,
7416 Buffer);
7417 break;
7418
7419 case UserInternal1Information:
7420 Status = SampQueryUserInternal1(UserObject,
7421 Buffer);
7422 break;
7423
7424 case UserParametersInformation:
7425 Status = SampQueryUserParameters(UserObject,
7426 Buffer);
7427 break;
7428
7429 case UserAllInformation:
7430 Status = SampQueryUserAll(UserObject,
7431 Buffer);
7432 break;
7433
7434 // case UserInternal4Information:
7435 // case UserInternal5Information:
7436 // case UserInternal4InformationNew:
7437 // case UserInternal5InformationNew:
7438
7439 default:
7440 Status = STATUS_INVALID_INFO_CLASS;
7441 }
7442
7443 done:
7444 RtlReleaseResource(&SampResource);
7445
7446 return Status;
7447 }
7448
7449
7450 static NTSTATUS
7451 SampSetUserName(PSAM_DB_OBJECT UserObject,
7452 PRPC_UNICODE_STRING NewUserName)
7453 {
7454 UNICODE_STRING OldUserName = {0, 0, NULL};
7455 NTSTATUS Status;
7456
7457 /* Check the account name */
7458 Status = SampCheckAccountName(NewUserName, 20);
7459 if (!NT_SUCCESS(Status))
7460 {
7461 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
7462 return Status;
7463 }
7464
7465 Status = SampGetObjectAttributeString(UserObject,
7466 L"Name",
7467 (PRPC_UNICODE_STRING)&OldUserName);
7468 if (!NT_SUCCESS(Status))
7469 {
7470 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
7471 goto done;
7472 }
7473
7474 if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
7475 {
7476 Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
7477 NewUserName->Buffer);
7478 if (!NT_SUCCESS(Status))
7479 {
7480 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
7481 NewUserName->Buffer, Status);
7482 goto done;
7483 }
7484 }
7485
7486 Status = SampSetAccountNameInDomain(UserObject->ParentObject,
7487 L"Users",
7488 NewUserName->Buffer,
7489 UserObject->RelativeId);
7490 if (!NT_SUCCESS(Status))
7491 {
7492 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
7493 goto done;
7494 }
7495
7496 Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
7497 L"Users",
7498 OldUserName.Buffer);
7499 if (!NT_SUCCESS(Status))
7500 {
7501 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
7502 goto done;
7503 }
7504
7505 Status = SampSetObjectAttributeString(UserObject,
7506 L"Name",
7507 NewUserName);
7508 if (!NT_SUCCESS(Status))
7509 {
7510 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
7511 }
7512
7513 done:
7514 if (OldUserName.Buffer != NULL)
7515 midl_user_free(OldUserName.Buffer);
7516
7517 return Status;
7518 }
7519
7520
7521 static NTSTATUS
7522 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
7523 PSAMPR_USER_INFO_BUFFER Buffer)
7524 {
7525 SAM_USER_FIXED_DATA FixedData;
7526 ULONG Length = 0;
7527 NTSTATUS Status;
7528
7529 Length = sizeof(SAM_USER_FIXED_DATA);
7530 Status = SampGetObjectAttribute(UserObject,
7531 L"F",
7532 NULL,
7533 (PVOID)&FixedData,
7534 &Length);
7535 if (!NT_SUCCESS(Status))
7536 goto done;
7537
7538 FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
7539
7540 Status = SampSetObjectAttribute(UserObject,
7541 L"F",
7542 REG_BINARY,
7543 &FixedData,
7544 Length);
7545 if (!NT_SUCCESS(Status))
7546 goto done;
7547
7548 Status = SampSetUserName(UserObject,
7549 &Buffer->General.UserName);
7550 if (!NT_SUCCESS(Status))
7551 goto done;
7552
7553 Status = SampSetObjectAttributeString(UserObject,
7554 L"FullName",
7555 &Buffer->General.FullName);
7556 if (!NT_SUCCESS(Status))
7557 goto done;
7558
7559 Status = SampSetObjectAttributeString(UserObject,
7560 L"AdminComment",
7561 &Buffer->General.AdminComment);
7562 if (!NT_SUCCESS(Status))
7563 goto done;
7564
7565 Status = SampSetObjectAttributeString(UserObject,
7566 L"UserComment",
7567 &Buffer->General.UserComment);
7568
7569 done:
7570 return Status;
7571 }
7572
7573
7574 static NTSTATUS
7575 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
7576 PSAMPR_USER_INFO_BUFFER Buffer)
7577 {
7578 SAM_USER_FIXED_DATA FixedData;
7579 ULONG Length = 0;
7580 NTSTATUS Status;
7581
7582 Length = sizeof(SAM_USER_FIXED_DATA);
7583 Status = SampGetObjectAttribute(UserObject,
7584 L"F",
7585 NULL,
7586 (PVOID)&FixedData,
7587 &Length);
7588 if (!NT_SUCCESS(Status))
7589 goto done;
7590
7591 FixedData.CountryCode = Buffer->Preferences.CountryCode;
7592 FixedData.CodePage = Buffer->Preferences.CodePage;
7593
7594 Status = SampSetObjectAttribute(UserObject,
7595 L"F",
7596 REG_BINARY,
7597 &FixedData,
7598 Length);
7599 if (!NT_SUCCESS(Status))
7600 goto done;
7601
7602 Status = SampSetObjectAttributeString(UserObject,
7603 L"UserComment",
7604 &Buffer->Preferences.UserComment);
7605
7606 done:
7607 return Status;
7608 }
7609
7610
7611 static NTSTATUS
7612 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
7613 PSAMPR_USER_INFO_BUFFER Buffer)
7614 {
7615 SAM_USER_FIXED_DATA FixedData;
7616 ULONG Length = 0;
7617 NTSTATUS Status;
7618
7619 Length = sizeof(SAM_USER_FIXED_DATA);
7620 Status = SampGetObjectAttribute(UserObject,
7621 L"F",
7622 NULL,
7623 (PVOID)&FixedData,
7624 &Length);
7625 if (!NT_SUCCESS(Status))
7626 goto done;
7627
7628 FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
7629
7630 Status = SampSetObjectAttribute(UserObject,
7631 L"F",
7632 REG_BINARY,
7633 &FixedData,
7634 Length);
7635
7636 done:
7637 return Status;
7638 }
7639
7640
7641 static NTSTATUS
7642 SampSetUserControl(PSAM_DB_OBJECT UserObject,
7643 PSAMPR_USER_INFO_BUFFER Buffer)
7644 {
7645 SAM_USER_FIXED_DATA FixedData;
7646 ULONG Length = 0;
7647 NTSTATUS Status;
7648
7649 Length = sizeof(SAM_USER_FIXED_DATA);
7650 Status = SampGetObjectAttribute(UserObject,
7651 L"F",
7652 NULL,
7653 (PVOID)&FixedData,
7654 &Length);
7655 if (!NT_SUCCESS(Status))
7656 goto done;
7657
7658 FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
7659
7660 Status = SampSetObjectAttribute(UserObject,
7661 L"F",
7662 REG_BINARY,
7663 &FixedData,
7664 Length);
7665
7666 done:
7667 return Status;
7668 }
7669
7670
7671 static NTSTATUS
7672 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
7673 PSAMPR_USER_INFO_BUFFER Buffer)
7674 {
7675 SAM_USER_FIXED_DATA FixedData;
7676 ULONG Length = 0;
7677 NTSTATUS Status;
7678
7679 Length = sizeof(SAM_USER_FIXED_DATA);
7680 Status = SampGetObjectAttribute(UserObject,
7681 L"F",
7682 NULL,
7683 (PVOID)&FixedData,
7684 &Length);
7685 if (!NT_SUCCESS(Status))
7686 goto done;
7687
7688 FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
7689 FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
7690
7691 Status = SampSetObjectAttribute(UserObject,
7692 L"F",
7693 REG_BINARY,
7694 &FixedData,
7695 Length);
7696
7697 done:
7698 return Status;
7699 }
7700
7701
7702 static NTSTATUS
7703 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7704 PSAMPR_USER_INFO_BUFFER Buffer)
7705 {
7706 SAM_USER_FIXED_DATA FixedData;
7707 ULONG Length = 0;
7708 NTSTATUS Status = STATUS_SUCCESS;
7709
7710 /* FIXME: Decrypt NT password */
7711 /* FIXME: Decrypt LM password */
7712
7713 Status = SampSetUserPassword(UserObject,
7714 &Buffer->Internal1.EncryptedNtOwfPassword,
7715 Buffer->Internal1.NtPasswordPresent,
7716 &Buffer->Internal1.EncryptedLmOwfPassword,
7717 Buffer->Internal1.LmPasswordPresent);
7718 if (!NT_SUCCESS(Status))
7719 goto done;
7720
7721 /* Get the fixed user attributes */
7722 Length = sizeof(SAM_USER_FIXED_DATA);
7723 Status = SampGetObjectAttribute(UserObject,
7724 L"F",
7725 NULL,
7726 (PVOID)&FixedData,
7727 &Length);
7728 if (!NT_SUCCESS(Status))
7729 goto done;
7730
7731 if (Buffer->Internal1.PasswordExpired)
7732 {
7733 /* The password was last set ages ago */
7734 FixedData.PasswordLastSet.LowPart = 0;
7735 FixedData.PasswordLastSet.HighPart = 0;
7736 }
7737 else
7738 {
7739 /* The password was last set right now */
7740 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7741 if (!NT_SUCCESS(Status))
7742 goto done;
7743 }
7744
7745 /* Set the fixed user attributes */
7746 Status = SampSetObjectAttribute(UserObject,
7747 L"F",
7748 REG_BINARY,
7749 &FixedData,
7750 Length);
7751
7752 done:
7753 return Status;
7754 }
7755
7756
7757 static NTSTATUS
7758 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7759 PSAMPR_USER_INFO_BUFFER Buffer)
7760 {
7761 SAM_USER_FIXED_DATA FixedData;
7762 ULONG Length = 0;
7763 ULONG WhichFields;
7764 PENCRYPTED_NT_OWF_PASSWORD NtPassword = NULL;
7765 PENCRYPTED_LM_OWF_PASSWORD LmPassword = NULL;
7766 BOOLEAN NtPasswordPresent = FALSE;
7767 BOOLEAN LmPasswordPresent = FALSE;
7768 BOOLEAN WriteFixedData = FALSE;
7769 NTSTATUS Status = STATUS_SUCCESS;
7770
7771 WhichFields = Buffer->All.WhichFields;
7772
7773 /* Get the fixed size attributes */
7774 Length = sizeof(SAM_USER_FIXED_DATA);
7775 Status = SampGetObjectAttribute(UserObject,
7776 L"F",
7777 NULL,
7778 (PVOID)&FixedData,
7779 &Length);
7780 if (!NT_SUCCESS(Status))
7781 goto done;
7782
7783 if (WhichFields & USER_ALL_USERNAME)
7784 {
7785 Status = SampSetUserName(UserObject,
7786 &Buffer->All.UserName);
7787 if (!NT_SUCCESS(Status))
7788 goto done;
7789 }
7790
7791 if (WhichFields & USER_ALL_FULLNAME)
7792 {
7793 Status = SampSetObjectAttributeString(UserObject,
7794 L"FullName",
7795 &Buffer->All.FullName);
7796 if (!NT_SUCCESS(Status))
7797 goto done;
7798 }
7799
7800 if (WhichFields & USER_ALL_ADMINCOMMENT)
7801 {
7802 Status = SampSetObjectAttributeString(UserObject,
7803 L"AdminComment",
7804 &Buffer->All.AdminComment);
7805 if (!NT_SUCCESS(Status))
7806 goto done;
7807 }
7808
7809 if (WhichFields & USER_ALL_USERCOMMENT)
7810 {
7811 Status = SampSetObjectAttributeString(UserObject,
7812 L"UserComment",
7813 &Buffer->All.UserComment);
7814 if (!NT_SUCCESS(Status))
7815 goto done;
7816 }
7817
7818 if (WhichFields & USER_ALL_HOMEDIRECTORY)
7819 {
7820 Status = SampSetObjectAttributeString(UserObject,
7821 L"HomeDirectory",
7822 &Buffer->All.HomeDirectory);
7823 if (!NT_SUCCESS(Status))
7824 goto done;
7825 }
7826
7827 if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7828 {
7829 Status = SampSetObjectAttributeString(UserObject,
7830 L"HomeDirectoryDrive",
7831 &Buffer->All.HomeDirectoryDrive);
7832 if (!NT_SUCCESS(Status))
7833 goto done;
7834 }
7835
7836 if (WhichFields & USER_ALL_SCRIPTPATH)
7837 {
7838 Status = SampSetObjectAttributeString(UserObject,
7839 L"ScriptPath",
7840 &Buffer->All.ScriptPath);
7841 if (!NT_SUCCESS(Status))
7842 goto done;
7843 }
7844
7845 if (WhichFields & USER_ALL_PROFILEPATH)
7846 {
7847 Status = SampSetObjectAttributeString(UserObject,
7848 L"ProfilePath",
7849 &Buffer->All.ProfilePath);
7850 if (!NT_SUCCESS(Status))
7851 goto done;
7852 }
7853
7854 if (WhichFields & USER_ALL_WORKSTATIONS)
7855 {
7856 Status = SampSetObjectAttributeString(UserObject,
7857 L"WorkStations",
7858 &Buffer->All.WorkStations);
7859 if (!NT_SUCCESS(Status))
7860 goto done;
7861 }
7862
7863 if (WhichFields & USER_ALL_PARAMETERS)
7864 {
7865 Status = SampSetObjectAttributeString(UserObject,
7866 L"Parameters",
7867 &Buffer->All.Parameters);
7868 if (!NT_SUCCESS(Status))
7869 goto done;
7870 }
7871
7872 if (WhichFields & USER_ALL_LOGONHOURS)
7873 {
7874 Status = SampSetLogonHoursAttribute(UserObject,
7875 &Buffer->All.LogonHours);
7876 if (!NT_SUCCESS(Status))
7877 goto done;
7878 }
7879
7880 if (WhichFields & USER_ALL_PRIMARYGROUPID)
7881 {
7882 FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
7883 WriteFixedData = TRUE;
7884 }
7885
7886 if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
7887 {
7888 FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
7889 FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
7890 WriteFixedData = TRUE;
7891 }
7892
7893 if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
7894 {
7895 FixedData.UserAccountControl = Buffer->All.UserAccountControl;
7896 WriteFixedData = TRUE;
7897 }
7898
7899 if (WhichFields & USER_ALL_COUNTRYCODE)
7900 {
7901 FixedData.CountryCode = Buffer->All.CountryCode;
7902 WriteFixedData = TRUE;
7903 }
7904
7905 if (WhichFields & USER_ALL_CODEPAGE)
7906 {
7907 FixedData.CodePage = Buffer->All.CodePage;
7908 WriteFixedData = TRUE;
7909 }
7910
7911 if (WhichFields & (USER_ALL_NTPASSWORDPRESENT |
7912 USER_ALL_LMPASSWORDPRESENT))
7913 {
7914 if (WhichFields & USER_ALL_NTPASSWORDPRESENT)
7915 {
7916 NtPassword = (PENCRYPTED_NT_OWF_PASSWORD)Buffer->All.NtOwfPassword.Buffer;
7917 NtPasswordPresent = Buffer->All.NtPasswordPresent;
7918 }
7919
7920 if (WhichFields & USER_ALL_LMPASSWORDPRESENT)
7921 {
7922 LmPassword = (PENCRYPTED_LM_OWF_PASSWORD)Buffer->All.LmOwfPassword.Buffer;
7923 LmPasswordPresent = Buffer->All.LmPasswordPresent;
7924 }
7925
7926 Status = SampSetUserPassword(UserObject,
7927 NtPassword,
7928 NtPasswordPresent,
7929 LmPassword,
7930 LmPasswordPresent);
7931 if (!NT_SUCCESS(Status))
7932 goto done;
7933
7934 /* The password has just been set */
7935 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7936 if (!NT_SUCCESS(Status))
7937 goto done;
7938
7939 WriteFixedData = TRUE;
7940 }
7941
7942 if (WhichFields & USER_ALL_PRIVATEDATA)
7943 {
7944 Status = SampSetObjectAttributeString(UserObject,
7945 L"PrivateData",
7946 &Buffer->All.PrivateData);
7947 if (!NT_SUCCESS(Status))
7948 goto done;
7949 }
7950
7951 if (WhichFields & USER_ALL_PASSWORDEXPIRED)
7952 {
7953 if (Buffer->All.PasswordExpired)
7954 {
7955 /* The password was last set ages ago */
7956 FixedData.PasswordLastSet.LowPart = 0;
7957 FixedData.PasswordLastSet.HighPart = 0;
7958 }
7959 else
7960 {
7961 /* The password was last set right now */
7962 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7963 if (!NT_SUCCESS(Status))
7964 goto done;
7965 }
7966
7967 WriteFixedData = TRUE;
7968 }
7969
7970 if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
7971 {
7972 Status = SampSetObjectAttribute(UserObject,
7973 L"SecDesc",
7974 REG_BINARY,
7975 Buffer->All.SecurityDescriptor.SecurityDescriptor,
7976 Buffer->All.SecurityDescriptor.Length);
7977 }
7978
7979 if (WriteFixedData != FALSE)
7980 {
7981 Status = SampSetObjectAttribute(UserObject,
7982 L"F",
7983 REG_BINARY,
7984 &FixedData,
7985 Length);
7986 if (!NT_SUCCESS(Status))
7987 goto done;
7988 }
7989
7990 done:
7991 return Status;
7992 }
7993
7994
7995 /* Function 37 */
7996 NTSTATUS
7997 NTAPI
7998 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
7999 IN USER_INFORMATION_CLASS UserInformationClass,
8000 IN PSAMPR_USER_INFO_BUFFER Buffer)
8001 {
8002 PSAM_DB_OBJECT UserObject;
8003 ACCESS_MASK DesiredAccess;
8004 NTSTATUS Status;
8005
8006 TRACE("SamrSetInformationUser(%p %lu %p)\n",
8007 UserHandle, UserInformationClass, Buffer);
8008
8009 switch (UserInformationClass)
8010 {
8011 case UserLogonHoursInformation:
8012 case UserNameInformation:
8013 case UserAccountNameInformation:
8014 case UserFullNameInformation:
8015 case UserPrimaryGroupInformation:
8016 case UserHomeInformation:
8017 case UserScriptInformation:
8018 case UserProfileInformation:
8019 case UserAdminCommentInformation:
8020 case UserWorkStationsInformation:
8021 case UserControlInformation:
8022 case UserExpiresInformation:
8023 case UserParametersInformation:
8024 DesiredAccess = USER_WRITE_ACCOUNT;
8025 break;
8026
8027 case UserGeneralInformation:
8028 DesiredAccess = USER_WRITE_ACCOUNT |
8029 USER_WRITE_PREFERENCES;
8030 break;
8031
8032 case UserPreferencesInformation:
8033 DesiredAccess = USER_WRITE_PREFERENCES;
8034 break;
8035
8036 case UserSetPasswordInformation:
8037 case UserInternal1Information:
8038 DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
8039 break;
8040
8041 case UserAllInformation:
8042 DesiredAccess = 0; /* FIXME */
8043 break;
8044
8045 default:
8046 return STATUS_INVALID_INFO_CLASS;
8047 }
8048
8049 RtlAcquireResourceExclusive(&SampResource,
8050 TRUE);
8051
8052 /* Validate the domain handle */
8053 Status = SampValidateDbObject(UserHandle,
8054 SamDbUserObject,
8055 DesiredAccess,
8056 &UserObject);
8057 if (!NT_SUCCESS(Status))
8058 {
8059 TRACE("failed with status 0x%08lx\n", Status);
8060 goto done;
8061 }
8062
8063 switch (UserInformationClass)
8064 {
8065 case UserGeneralInformation:
8066 Status = SampSetUserGeneral(UserObject,
8067 Buffer);
8068 break;
8069
8070 case UserPreferencesInformation:
8071 Status = SampSetUserPreferences(UserObject,
8072 Buffer);
8073 break;
8074
8075 case UserLogonHoursInformation:
8076 Status = SampSetLogonHoursAttribute(UserObject,
8077 &Buffer->LogonHours.LogonHours);
8078 break;
8079
8080 case UserNameInformation:
8081 Status = SampSetUserName(UserObject,
8082 &Buffer->Name.UserName);
8083 if (!NT_SUCCESS(Status))
8084 break;
8085
8086 Status = SampSetObjectAttributeString(UserObject,
8087 L"FullName",
8088 &Buffer->Name.FullName);
8089 break;
8090
8091 case UserAccountNameInformation:
8092 Status = SampSetUserName(UserObject,
8093 &Buffer->AccountName.UserName);
8094 break;
8095
8096 case UserFullNameInformation:
8097 Status = SampSetObjectAttributeString(UserObject,
8098 L"FullName",
8099 &Buffer->FullName.FullName);
8100 break;
8101
8102 case UserPrimaryGroupInformation:
8103 Status = SampSetUserPrimaryGroup(UserObject,
8104 Buffer);
8105 break;
8106
8107 case UserHomeInformation:
8108 Status = SampSetObjectAttributeString(UserObject,
8109 L"HomeDirectory",
8110 &Buffer->Home.HomeDirectory);
8111 if (!NT_SUCCESS(Status))
8112 break;
8113
8114 Status = SampSetObjectAttributeString(UserObject,
8115 L"HomeDirectoryDrive",
8116 &Buffer->Home.HomeDirectoryDrive);
8117 break;
8118
8119 case UserScriptInformation:
8120 Status = SampSetObjectAttributeString(UserObject,
8121 L"ScriptPath",
8122 &Buffer->Script.ScriptPath);
8123 break;
8124
8125 case UserProfileInformation:
8126 Status = SampSetObjectAttributeString(UserObject,
8127 L"ProfilePath",
8128 &Buffer->Profile.ProfilePath);
8129 break;
8130
8131 case UserAdminCommentInformation:
8132 Status = SampSetObjectAttributeString(UserObject,
8133 L"AdminComment",
8134 &Buffer->AdminComment.AdminComment);
8135 break;
8136
8137 case UserWorkStationsInformation:
8138 Status = SampSetObjectAttributeString(UserObject,
8139 L"WorkStations",
8140 &Buffer->WorkStations.WorkStations);
8141 break;
8142
8143 case UserSetPasswordInformation:
8144 TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
8145 TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
8146
8147 Status = SampSetObjectAttributeString(UserObject,
8148 L"Password",
8149 &Buffer->SetPassword.Password);
8150 break;
8151
8152 case UserControlInformation:
8153 Status = SampSetUserControl(UserObject,
8154 Buffer);
8155 break;
8156
8157 case UserExpiresInformation:
8158 Status = SampSetUserExpires(UserObject,
8159 Buffer);
8160 break;
8161
8162 case UserInternal1Information:
8163 Status = SampSetUserInternal1(UserObject,
8164 Buffer);
8165 break;
8166
8167 case UserParametersInformation:
8168 Status = SampSetObjectAttributeString(UserObject,
8169 L"Parameters",
8170 &Buffer->Parameters.Parameters);
8171 break;
8172
8173 case UserAllInformation:
8174 Status = SampSetUserAll(UserObject,
8175 Buffer);
8176 break;
8177
8178 // case UserInternal4Information:
8179 // case UserInternal5Information:
8180 // case UserInternal4InformationNew:
8181 // case UserInternal5InformationNew:
8182
8183 default:
8184 Status = STATUS_INVALID_INFO_CLASS;
8185 }
8186
8187 done:
8188 RtlReleaseResource(&SampResource);
8189
8190 return Status;
8191 }
8192
8193
8194 /* Function 38 */
8195 NTSTATUS
8196 NTAPI
8197 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
8198 IN unsigned char LmPresent,
8199 IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
8200 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
8201 IN unsigned char NtPresent,
8202 IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
8203 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
8204 IN unsigned char NtCrossEncryptionPresent,
8205 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
8206 IN unsigned char LmCrossEncryptionPresent,
8207 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
8208 {
8209 ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
8210 ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
8211 LM_OWF_PASSWORD OldLmPassword;
8212 LM_OWF_PASSWORD NewLmPassword;
8213 NT_OWF_PASSWORD OldNtPassword;
8214 NT_OWF_PASSWORD NewNtPassword;
8215 BOOLEAN StoredLmPresent = FALSE;
8216 BOOLEAN StoredNtPresent = FALSE;
8217 BOOLEAN StoredLmEmpty = TRUE;
8218 BOOLEAN StoredNtEmpty = TRUE;
8219 PSAM_DB_OBJECT UserObject;
8220 ULONG Length;
8221 SAM_USER_FIXED_DATA UserFixedData;
8222 SAM_DOMAIN_FIXED_DATA DomainFixedData;
8223 LARGE_INTEGER SystemTime;
8224 NTSTATUS Status;
8225
8226 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
8227 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
8228 DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
8229
8230 TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
8231 UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
8232 NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
8233 NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
8234
8235 RtlAcquireResourceExclusive(&SampResource,
8236 TRUE);
8237
8238 /* Validate the user handle */
8239 Status = SampValidateDbObject(UserHandle,
8240 SamDbUserObject,
8241 USER_CHANGE_PASSWORD,
8242 &UserObject);
8243 if (!NT_SUCCESS(Status))
8244 {
8245 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8246 goto done;
8247 }
8248
8249 /* Get the current time */
8250 Status = NtQuerySystemTime(&SystemTime);
8251 if (!NT_SUCCESS(Status))
8252 {
8253 TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
8254 goto done;
8255 }
8256
8257 /* Retrieve the LM password */
8258 Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
8259 Status = SampGetObjectAttribute(UserObject,
8260 L"LMPwd",
8261 NULL,
8262 &StoredLmPassword,
8263 &Length);
8264 if (NT_SUCCESS(Status))
8265 {
8266 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
8267 {
8268 StoredLmPresent = TRUE;
8269 if (!RtlEqualMemory(&StoredLmPassword,
8270 &EmptyLmHash,
8271 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8272 StoredLmEmpty = FALSE;
8273 }
8274 }
8275
8276 /* Retrieve the NT password */
8277 Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
8278 Status = SampGetObjectAttribute(UserObject,
8279 L"NTPwd",
8280 NULL,
8281 &StoredNtPassword,
8282 &Length);
8283 if (NT_SUCCESS(Status))
8284 {
8285 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
8286 {
8287 StoredNtPresent = TRUE;
8288 if (!RtlEqualMemory(&StoredNtPassword,
8289 &EmptyNtHash,
8290 sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
8291 StoredNtEmpty = FALSE;
8292 }
8293 }
8294
8295 /* Retrieve the fixed size user data */
8296 Length = sizeof(SAM_USER_FIXED_DATA);
8297 Status = SampGetObjectAttribute(UserObject,
8298 L"F",
8299 NULL,
8300 &UserFixedData,
8301 &Length);
8302 if (!NT_SUCCESS(Status))
8303 {
8304 TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
8305 goto done;
8306 }
8307
8308 /* Check if we can change the password at this time */
8309 if ((StoredLmEmpty == FALSE) || (StoredNtEmpty == FALSE))
8310 {
8311 /* Get fixed domain data */
8312 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8313 Status = SampGetObjectAttribute(UserObject->ParentObject,
8314 L"F",
8315 NULL,
8316 &DomainFixedData,
8317 &Length);
8318 if (!NT_SUCCESS(Status))
8319 {
8320 TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
8321 goto done;
8322 }
8323
8324 if (DomainFixedData.MinPasswordAge.QuadPart > 0)
8325 {
8326 if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
8327 {
8328 Status = STATUS_ACCOUNT_RESTRICTION;
8329 goto done;
8330 }
8331 }
8332 }
8333
8334 /* Decrypt the LM passwords, if present */
8335 if (LmPresent)
8336 {
8337 Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
8338 (const BYTE *)&StoredLmPassword,
8339 (LPBYTE)&NewLmPassword);
8340 if (!NT_SUCCESS(Status))
8341 {
8342 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8343 goto done;
8344 }
8345
8346 Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
8347 (const BYTE *)&NewLmPassword,
8348 (LPBYTE)&OldLmPassword);
8349 if (!NT_SUCCESS(Status))
8350 {
8351 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8352 goto done;
8353 }
8354 }
8355
8356 /* Decrypt the NT passwords, if present */
8357 if (NtPresent)
8358 {
8359 Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
8360 (const BYTE *)&StoredNtPassword,
8361 (LPBYTE)&NewNtPassword);
8362 if (!NT_SUCCESS(Status))
8363 {
8364 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8365 goto done;
8366 }
8367
8368 Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
8369 (const BYTE *)&NewNtPassword,
8370 (LPBYTE)&OldNtPassword);
8371 if (!NT_SUCCESS(Status))
8372 {
8373 TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
8374 goto done;
8375 }
8376 }
8377
8378 /* Check if the old passwords match the stored ones */
8379 if (NtPresent)
8380 {
8381 if (LmPresent)
8382 {
8383 if (!RtlEqualMemory(&StoredLmPassword,
8384 &OldLmPassword,
8385 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8386 {
8387 TRACE("Old LM Password does not match!\n");
8388 Status = STATUS_WRONG_PASSWORD;
8389 }
8390 else
8391 {
8392 if (!RtlEqualMemory(&StoredNtPassword,
8393 &OldNtPassword,
8394 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8395 {
8396 TRACE("Old NT Password does not match!\n");
8397 Status = STATUS_WRONG_PASSWORD;
8398 }
8399 }
8400 }
8401 else
8402 {
8403 if (!RtlEqualMemory(&StoredNtPassword,
8404 &OldNtPassword,
8405 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8406 {
8407 TRACE("Old NT Password does not match!\n");
8408 Status = STATUS_WRONG_PASSWORD;
8409 }
8410 }
8411 }
8412 else
8413 {
8414 if (LmPresent)
8415 {
8416 if (!RtlEqualMemory(&StoredLmPassword,
8417 &OldLmPassword,
8418 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
8419 {
8420 TRACE("Old LM Password does not match!\n");
8421 Status = STATUS_WRONG_PASSWORD;
8422 }
8423 }
8424 else
8425 {
8426 Status = STATUS_INVALID_PARAMETER;
8427 }
8428 }
8429
8430 /* Store the new password hashes */
8431 if (NT_SUCCESS(Status))
8432 {
8433 Status = SampSetUserPassword(UserObject,
8434 &NewNtPassword,
8435 NtPresent,
8436 &NewLmPassword,
8437 LmPresent);
8438 if (NT_SUCCESS(Status))
8439 {
8440 /* Update PasswordLastSet */
8441 UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
8442
8443 /* Set the fixed size user data */
8444 Length = sizeof(SAM_USER_FIXED_DATA);
8445 Status = SampSetObjectAttribute(UserObject,
8446 L"F",
8447 REG_BINARY,
8448 &UserFixedData,
8449 Length);
8450 }
8451 }
8452
8453 if (Status == STATUS_WRONG_PASSWORD)
8454 {
8455 /* Update BadPasswordCount and LastBadPasswordTime */
8456 UserFixedData.BadPasswordCount++;
8457 UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
8458
8459 /* Set the fixed size user data */
8460 Length = sizeof(SAM_USER_FIXED_DATA);
8461 Status = SampSetObjectAttribute(UserObject,
8462 L"F",
8463 REG_BINARY,
8464 &UserFixedData,
8465 Length);
8466 }
8467
8468 done:
8469 RtlReleaseResource(&SampResource);
8470
8471 return Status;
8472 }
8473
8474
8475 /* Function 39 */
8476 NTSTATUS
8477 NTAPI
8478 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
8479 OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
8480 {
8481 PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
8482 PSAM_DB_OBJECT UserObject;
8483 ULONG Length = 0;
8484 NTSTATUS Status;
8485
8486 TRACE("SamrGetGroupsForUser(%p %p)\n",
8487 UserHandle, Groups);
8488
8489 RtlAcquireResourceShared(&SampResource,
8490 TRUE);
8491
8492 /* Validate the user handle */
8493 Status = SampValidateDbObject(UserHandle,
8494 SamDbUserObject,
8495 USER_LIST_GROUPS,
8496 &UserObject);
8497 if (!NT_SUCCESS(Status))
8498 {
8499 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8500 goto done;
8501 }
8502
8503 /* Allocate the groups buffer */
8504 GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
8505 if (GroupsBuffer == NULL)
8506 {
8507 Status = STATUS_INSUFFICIENT_RESOURCES;
8508 goto done;
8509 }
8510
8511 /*
8512 * Get the size of the Groups attribute.
8513 * Do not check the status code because in case of an error
8514 * Length will be 0. And that is all we need.
8515 */
8516 SampGetObjectAttribute(UserObject,
8517 L"Groups",
8518 NULL,
8519 NULL,
8520 &Length);
8521
8522 /* If there is no Groups attribute, return a groups buffer without an array */
8523 if (Length == 0)
8524 {
8525 GroupsBuffer->MembershipCount = 0;
8526 GroupsBuffer->Groups = NULL;
8527
8528 *Groups = GroupsBuffer;
8529
8530 Status = STATUS_SUCCESS;
8531 goto done;
8532 }
8533
8534 /* Allocate a buffer for the Groups attribute */
8535 GroupsBuffer->Groups = midl_user_allocate(Length);
8536 if (GroupsBuffer->Groups == NULL)
8537 {
8538 Status = STATUS_INSUFFICIENT_RESOURCES;
8539 goto done;
8540 }
8541
8542 /* Retrieve the Grous attribute */
8543 Status = SampGetObjectAttribute(UserObject,
8544 L"Groups",
8545 NULL,
8546 GroupsBuffer->Groups,
8547 &Length);
8548 if (!NT_SUCCESS(Status))
8549 {
8550 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8551 goto done;
8552 }
8553
8554 /* Calculate the membership count */
8555 GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
8556
8557 /* Return the groups buffer to the caller */
8558 *Groups = GroupsBuffer;
8559
8560 done:
8561 if (!NT_SUCCESS(Status))
8562 {
8563 if (GroupsBuffer != NULL)
8564 {
8565 if (GroupsBuffer->Groups != NULL)
8566 midl_user_free(GroupsBuffer->Groups);
8567
8568 midl_user_free(GroupsBuffer);
8569 }
8570 }
8571
8572 RtlReleaseResource(&SampResource);
8573
8574 return Status;
8575 }
8576
8577
8578 /* Function 40 */
8579 NTSTATUS
8580 NTAPI
8581 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
8582 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8583 IN unsigned long Index,
8584 IN unsigned long EntryCount,
8585 IN unsigned long PreferredMaximumLength,
8586 OUT unsigned long *TotalAvailable,
8587 OUT unsigned long *TotalReturned,
8588 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8589 {
8590 UNIMPLEMENTED;
8591 return STATUS_NOT_IMPLEMENTED;
8592 }
8593
8594 /* Function 41 */
8595 NTSTATUS
8596 NTAPI
8597 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
8598 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8599 IN PRPC_UNICODE_STRING Prefix,
8600 OUT unsigned long *Index)
8601 {
8602 UNIMPLEMENTED;
8603 return STATUS_NOT_IMPLEMENTED;
8604 }
8605
8606 /* Function 42 */
8607 NTSTATUS
8608 NTAPI
8609 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
8610 {
8611 UNIMPLEMENTED;
8612 return STATUS_NOT_IMPLEMENTED;
8613 }
8614
8615 /* Function 43 */
8616 NTSTATUS
8617 NTAPI
8618 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
8619 {
8620 UNIMPLEMENTED;
8621 return STATUS_NOT_IMPLEMENTED;
8622 }
8623
8624
8625 /* Function 44 */
8626 NTSTATUS
8627 NTAPI
8628 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
8629 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8630 {
8631 SAM_DOMAIN_FIXED_DATA DomainFixedData;
8632 SAM_USER_FIXED_DATA UserFixedData;
8633 PSAM_DB_OBJECT DomainObject;
8634 PSAM_DB_OBJECT UserObject;
8635 ULONG Length = 0;
8636 NTSTATUS Status;
8637
8638 TRACE("(%p %p)\n",
8639 UserHandle, PasswordInformation);
8640
8641 RtlAcquireResourceShared(&SampResource,
8642 TRUE);
8643
8644 /* Validate the user handle */
8645 Status = SampValidateDbObject(UserHandle,
8646 SamDbUserObject,
8647 0,
8648 &UserObject);
8649 if (!NT_SUCCESS(Status))
8650 {
8651 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8652 goto done;
8653 }
8654
8655 /* Validate the domain object */
8656 Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
8657 SamDbDomainObject,
8658 DOMAIN_READ_PASSWORD_PARAMETERS,
8659 &DomainObject);
8660 if (!NT_SUCCESS(Status))
8661 {
8662 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8663 goto done;
8664 }
8665
8666 /* Get fixed user data */
8667 Length = sizeof(SAM_USER_FIXED_DATA);
8668 Status = SampGetObjectAttribute(UserObject,
8669 L"F",
8670 NULL,
8671 (PVOID)&UserFixedData,
8672 &Length);
8673 if (!NT_SUCCESS(Status))
8674 {
8675 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8676 goto done;
8677 }
8678
8679 if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
8680 (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
8681 USER_WORKSTATION_TRUST_ACCOUNT |
8682 USER_SERVER_TRUST_ACCOUNT)))
8683 {
8684 PasswordInformation->MinPasswordLength = 0;
8685 PasswordInformation->PasswordProperties = 0;
8686 }
8687 else
8688 {
8689 /* Get fixed domain data */
8690 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
8691 Status = SampGetObjectAttribute(DomainObject,
8692 L"F",
8693 NULL,
8694 (PVOID)&DomainFixedData,
8695 &Length);
8696 if (!NT_SUCCESS(Status))
8697 {
8698 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
8699 goto done;
8700 }
8701
8702 PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
8703 PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
8704 }
8705
8706 done:
8707 RtlReleaseResource(&SampResource);
8708
8709 return STATUS_SUCCESS;
8710 }
8711
8712
8713 /* Function 45 */
8714 NTSTATUS
8715 NTAPI
8716 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
8717 IN PRPC_SID MemberSid)
8718 {
8719 PSAM_DB_OBJECT DomainObject;
8720 ULONG Rid = 0;
8721 NTSTATUS Status;
8722
8723 TRACE("(%p %p)\n",
8724 DomainHandle, MemberSid);
8725
8726 RtlAcquireResourceExclusive(&SampResource,
8727 TRUE);
8728
8729 /* Validate the domain object */
8730 Status = SampValidateDbObject(DomainHandle,
8731 SamDbDomainObject,
8732 DOMAIN_LOOKUP,
8733 &DomainObject);
8734 if (!NT_SUCCESS(Status))
8735 {
8736 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
8737 goto done;
8738 }
8739
8740 /* Retrieve the RID from the MemberSID */
8741 Status = SampGetRidFromSid((PSID)MemberSid,
8742 &Rid);
8743 if (!NT_SUCCESS(Status))
8744 {
8745 TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
8746 goto done;
8747 }
8748
8749 /* Fail, if the RID represents a special account */
8750 if (Rid < 1000)
8751 {
8752 TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
8753 Status = STATUS_SPECIAL_ACCOUNT;
8754 goto done;
8755 }
8756
8757 /* Remove the member from all aliases in the domain */
8758 Status = SampRemoveMemberFromAllAliases(DomainObject,
8759 MemberSid);
8760 if (!NT_SUCCESS(Status))
8761 {
8762 TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
8763 }
8764
8765 done:
8766 RtlReleaseResource(&SampResource);
8767
8768 return Status;
8769 }
8770
8771
8772 /* Function 46 */
8773 NTSTATUS
8774 NTAPI
8775 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
8776 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
8777 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
8778 {
8779 TRACE("(%p %lu %p)\n", DomainHandle, DomainInformationClass, Buffer);
8780
8781 return SamrQueryInformationDomain(DomainHandle,
8782 DomainInformationClass,
8783 Buffer);
8784 }
8785
8786
8787 /* Function 47 */
8788 NTSTATUS
8789 NTAPI
8790 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
8791 IN USER_INFORMATION_CLASS UserInformationClass,
8792 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
8793 {
8794 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
8795
8796 return SamrQueryInformationUser(UserHandle,
8797 UserInformationClass,
8798 Buffer);
8799 }
8800
8801
8802 /* Function 48 */
8803 NTSTATUS
8804 NTAPI
8805 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
8806 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8807 IN unsigned long Index,
8808 IN unsigned long EntryCount,
8809 IN unsigned long PreferredMaximumLength,
8810 OUT unsigned long *TotalAvailable,
8811 OUT unsigned long *TotalReturned,
8812 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8813 {
8814 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
8815 DomainHandle, DisplayInformationClass, Index,
8816 EntryCount, PreferredMaximumLength, TotalAvailable,
8817 TotalReturned, Buffer);
8818
8819 return SamrQueryDisplayInformation(DomainHandle,
8820 DisplayInformationClass,
8821 Index,
8822 EntryCount,
8823 PreferredMaximumLength,
8824 TotalAvailable,
8825 TotalReturned,
8826 Buffer);
8827 }
8828
8829
8830 /* Function 49 */
8831 NTSTATUS
8832 NTAPI
8833 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
8834 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8835 IN PRPC_UNICODE_STRING Prefix,
8836 OUT unsigned long *Index)
8837 {
8838 TRACE("(%p %lu %p %p)\n",
8839 DomainHandle, DisplayInformationClass, Prefix, Index);
8840
8841 return SamrGetDisplayEnumerationIndex(DomainHandle,
8842 DisplayInformationClass,
8843 Prefix,
8844 Index);
8845 }
8846
8847
8848 /* Function 50 */
8849 NTSTATUS
8850 NTAPI
8851 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
8852 IN PRPC_UNICODE_STRING Name,
8853 IN unsigned long AccountType,
8854 IN ACCESS_MASK DesiredAccess,
8855 OUT SAMPR_HANDLE *UserHandle,
8856 OUT unsigned long *GrantedAccess,
8857 OUT unsigned long *RelativeId)
8858 {
8859 SAM_DOMAIN_FIXED_DATA FixedDomainData;
8860 SAM_USER_FIXED_DATA FixedUserData;
8861 PSAM_DB_OBJECT DomainObject;
8862 PSAM_DB_OBJECT UserObject;
8863 GROUP_MEMBERSHIP GroupMembership;
8864 UCHAR LogonHours[23];
8865 ULONG ulSize;
8866 ULONG ulRid;
8867 WCHAR szRid[9];
8868 PSECURITY_DESCRIPTOR Sd = NULL;
8869 ULONG SdSize = 0;
8870 PSID UserSid = NULL;
8871 NTSTATUS Status;
8872
8873 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
8874 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
8875
8876 if (Name == NULL ||
8877 Name->Length == 0 ||
8878 Name->Buffer == NULL ||
8879 UserHandle == NULL ||
8880 RelativeId == NULL)
8881 return STATUS_INVALID_PARAMETER;
8882
8883 /* Check for valid account type */
8884 if (AccountType != USER_NORMAL_ACCOUNT &&
8885 AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
8886 AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
8887 AccountType != USER_SERVER_TRUST_ACCOUNT &&
8888 AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
8889 return STATUS_INVALID_PARAMETER;
8890
8891 /* Map generic access rights */
8892 RtlMapGenericMask(&DesiredAccess,
8893 &UserMapping);
8894
8895 RtlAcquireResourceExclusive(&SampResource,
8896 TRUE);
8897
8898 /* Validate the domain handle */
8899 Status = SampValidateDbObject(DomainHandle,
8900 SamDbDomainObject,
8901 DOMAIN_CREATE_USER,
8902 &DomainObject);
8903 if (!NT_SUCCESS(Status))
8904 {
8905 TRACE("failed with status 0x%08lx\n", Status);
8906 goto done;
8907 }
8908
8909 /* Check the user account name */
8910 Status = SampCheckAccountName(Name, 20);
8911 if (!NT_SUCCESS(Status))
8912 {
8913 TRACE("SampCheckAccountName failed (Status 0x%08lx)\n", Status);
8914 goto done;
8915 }
8916
8917 /* Check if the user name already exists in the domain */
8918 Status = SampCheckAccountNameInDomain(DomainObject,
8919 Name->Buffer);
8920 if (!NT_SUCCESS(Status))
8921 {
8922 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
8923 Name->Buffer, Status);
8924 goto done;
8925 }
8926
8927 /* Get the fixed domain attributes */
8928 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
8929 Status = SampGetObjectAttribute(DomainObject,
8930 L"F",
8931 NULL,
8932 (PVOID)&FixedDomainData,
8933 &ulSize);
8934 if (!NT_SUCCESS(Status))
8935 {
8936 TRACE("failed with status 0x%08lx\n", Status);
8937 goto done;
8938 }
8939
8940 /* Increment the NextRid attribute */
8941 ulRid = FixedDomainData.NextRid;
8942 FixedDomainData.NextRid++;
8943
8944 TRACE("RID: %lx\n", ulRid);
8945
8946 /* Create the user SID */
8947 Status = SampCreateAccountSid(DomainObject,
8948 ulRid,
8949 &UserSid);
8950 if (!NT_SUCCESS(Status))
8951 {
8952 TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
8953 goto done;
8954 }
8955
8956 /* Create the security descriptor */
8957 Status = SampCreateUserSD(UserSid,
8958 &Sd,
8959 &SdSize);
8960 if (!NT_SUCCESS(Status))
8961 {
8962 TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
8963 goto done;
8964 }
8965
8966 /* Store the fixed domain attributes */
8967 Status = SampSetObjectAttribute(DomainObject,
8968 L"F",
8969 REG_BINARY,
8970 &FixedDomainData,
8971 ulSize);
8972 if (!NT_SUCCESS(Status))
8973 {
8974 TRACE("failed with status 0x%08lx\n", Status);
8975 goto done;
8976 }
8977
8978 /* Convert the RID into a string (hex) */
8979 swprintf(szRid, L"%08lX", ulRid);
8980
8981 /* Create the user object */
8982 Status = SampCreateDbObject(DomainObject,
8983 L"Users",
8984 szRid,
8985 ulRid,
8986 SamDbUserObject,
8987 DesiredAccess,
8988 &UserObject);
8989 if (!NT_SUCCESS(Status))
8990 {
8991 TRACE("failed with status 0x%08lx\n", Status);
8992 goto done;
8993 }
8994
8995 /* Add the account name for the user object */
8996 Status = SampSetAccountNameInDomain(DomainObject,
8997 L"Users",
8998 Name->Buffer,
8999 ulRid);
9000 if (!NT_SUCCESS(Status))
9001 {
9002 TRACE("failed with status 0x%08lx\n", Status);
9003 goto done;
9004 }
9005
9006 /* Initialize fixed user data */
9007 FixedUserData.Version = 1;
9008 FixedUserData.Reserved = 0;
9009 FixedUserData.LastLogon.QuadPart = 0;
9010 FixedUserData.LastLogoff.QuadPart = 0;
9011 FixedUserData.PasswordLastSet.QuadPart = 0;
9012 FixedUserData.AccountExpires.LowPart = MAXULONG;
9013 FixedUserData.AccountExpires.HighPart = MAXLONG;
9014 FixedUserData.LastBadPasswordTime.QuadPart = 0;
9015 FixedUserData.UserId = ulRid;
9016 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
9017 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
9018 USER_PASSWORD_NOT_REQUIRED |
9019 AccountType;
9020 FixedUserData.CountryCode = 0;
9021 FixedUserData.CodePage = 0;
9022 FixedUserData.BadPasswordCount = 0;
9023 FixedUserData.LogonCount = 0;
9024 FixedUserData.AdminCount = 0;
9025 FixedUserData.OperatorCount = 0;
9026
9027 /* Set fixed user data attribute */
9028 Status = SampSetObjectAttribute(UserObject,
9029 L"F",
9030 REG_BINARY,
9031 (LPVOID)&FixedUserData,
9032 sizeof(SAM_USER_FIXED_DATA));
9033 if (!NT_SUCCESS(Status))
9034 {
9035 TRACE("failed with status 0x%08lx\n", Status);
9036 goto done;
9037 }
9038
9039 /* Set the Name attribute */
9040 Status = SampSetObjectAttributeString(UserObject,
9041 L"Name",
9042 Name);
9043 if (!NT_SUCCESS(Status))
9044 {
9045 TRACE("failed with status 0x%08lx\n", Status);
9046 goto done;
9047 }
9048
9049 /* Set the FullName attribute */
9050 Status = SampSetObjectAttributeString(UserObject,
9051 L"FullName",
9052 NULL);
9053 if (!NT_SUCCESS(Status))
9054 {
9055 TRACE("failed with status 0x%08lx\n", Status);
9056 goto done;
9057 }
9058
9059 /* Set the HomeDirectory attribute */
9060 Status = SampSetObjectAttributeString(UserObject,
9061 L"HomeDirectory",
9062 NULL);
9063 if (!NT_SUCCESS(Status))
9064 {
9065 TRACE("failed with status 0x%08lx\n", Status);
9066 goto done;
9067 }
9068
9069 /* Set the HomeDirectoryDrive attribute */
9070 Status = SampSetObjectAttributeString(UserObject,
9071 L"HomeDirectoryDrive",
9072 NULL);
9073 if (!NT_SUCCESS(Status))
9074 {
9075 TRACE("failed with status 0x%08lx\n", Status);
9076 goto done;
9077 }
9078
9079 /* Set the ScriptPath attribute */
9080 Status = SampSetObjectAttributeString(UserObject,
9081 L"ScriptPath",
9082 NULL);
9083 if (!NT_SUCCESS(Status))
9084 {
9085 TRACE("failed with status 0x%08lx\n", Status);
9086 goto done;
9087 }
9088
9089 /* Set the ProfilePath attribute */
9090 Status = SampSetObjectAttributeString(UserObject,
9091 L"ProfilePath",
9092 NULL);
9093 if (!NT_SUCCESS(Status))
9094 {
9095 TRACE("failed with status 0x%08lx\n", Status);
9096 goto done;
9097 }
9098
9099 /* Set the AdminComment attribute */
9100 Status = SampSetObjectAttributeString(UserObject,
9101 L"AdminComment",
9102 NULL);
9103 if (!NT_SUCCESS(Status))
9104 {
9105 TRACE("failed with status 0x%08lx\n", Status);
9106 goto done;
9107 }
9108
9109 /* Set the UserComment attribute */
9110 Status = SampSetObjectAttributeString(UserObject,
9111 L"UserComment",
9112 NULL);
9113 if (!NT_SUCCESS(Status))
9114 {
9115 TRACE("failed with status 0x%08lx\n", Status);
9116 goto done;
9117 }
9118
9119 /* Set the WorkStations attribute */
9120 Status = SampSetObjectAttributeString(UserObject,
9121 L"WorkStations",
9122 NULL);
9123 if (!NT_SUCCESS(Status))
9124 {
9125 TRACE("failed with status 0x%08lx\n", Status);
9126 goto done;
9127 }
9128
9129 /* Set the Parameters attribute */
9130 Status = SampSetObjectAttributeString(UserObject,
9131 L"Parameters",
9132 NULL);
9133 if (!NT_SUCCESS(Status))
9134 {
9135 TRACE("failed with status 0x%08lx\n", Status);
9136 goto done;
9137 }
9138
9139 /* Set LogonHours attribute*/
9140 *((PUSHORT)LogonHours) = 168;
9141 memset(&(LogonHours[2]), 0xff, 21);
9142
9143 Status = SampSetObjectAttribute(UserObject,
9144 L"LogonHours",
9145 REG_BINARY,
9146 &LogonHours,
9147 sizeof(LogonHours));
9148 if (!NT_SUCCESS(Status))
9149 {
9150 TRACE("failed with status 0x%08lx\n", Status);
9151 goto done;
9152 }
9153
9154 /* Set Groups attribute*/
9155 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
9156 GroupMembership.Attributes = SE_GROUP_MANDATORY |
9157 SE_GROUP_ENABLED |
9158 SE_GROUP_ENABLED_BY_DEFAULT;
9159
9160 Status = SampSetObjectAttribute(UserObject,
9161 L"Groups",
9162 REG_BINARY,
9163 &GroupMembership,
9164 sizeof(GROUP_MEMBERSHIP));
9165 if (!NT_SUCCESS(Status))
9166 {
9167 TRACE("failed with status 0x%08lx\n", Status);
9168 goto done;
9169 }
9170
9171 /* Set LMPwd attribute*/
9172 Status = SampSetObjectAttribute(UserObject,
9173 L"LMPwd",
9174 REG_BINARY,
9175 NULL,
9176 0);
9177 if (!NT_SUCCESS(Status))
9178 {
9179 TRACE("failed with status 0x%08lx\n", Status);
9180 goto done;
9181 }
9182
9183 /* Set NTPwd attribute*/
9184 Status = SampSetObjectAttribute(UserObject,
9185 L"NTPwd",
9186 REG_BINARY,
9187 NULL,
9188 0);
9189 if (!NT_SUCCESS(Status))
9190 {
9191 TRACE("failed with status 0x%08lx\n", Status);
9192 goto done;
9193 }
9194
9195 /* Set LMPwdHistory attribute*/
9196 Status = SampSetObjectAttribute(UserObject,
9197 L"LMPwdHistory",
9198 REG_BINARY,
9199 NULL,
9200 0);
9201 if (!NT_SUCCESS(Status))
9202 {
9203 TRACE("failed with status 0x%08lx\n", Status);
9204 goto done;
9205 }
9206
9207 /* Set NTPwdHistory attribute*/
9208 Status = SampSetObjectAttribute(UserObject,
9209 L"NTPwdHistory",
9210 REG_BINARY,
9211 NULL,
9212 0);
9213 if (!NT_SUCCESS(Status))
9214 {
9215 TRACE("failed with status 0x%08lx\n", Status);
9216 goto done;
9217 }
9218
9219 /* Set the PrivateData attribute */
9220 Status = SampSetObjectAttributeString(UserObject,
9221 L"PrivateData",
9222 NULL);
9223 if (!NT_SUCCESS(Status))
9224 {
9225 TRACE("failed with status 0x%08lx\n", Status);
9226 goto done;
9227 }
9228
9229 /* Set the SecDesc attribute*/
9230 Status = SampSetObjectAttribute(UserObject,
9231 L"SecDesc",
9232 REG_BINARY,
9233 Sd,
9234 SdSize);
9235 if (!NT_SUCCESS(Status))
9236 {
9237 TRACE("failed with status 0x%08lx\n", Status);
9238 goto done;
9239 }
9240
9241 if (NT_SUCCESS(Status))
9242 {
9243 *UserHandle = (SAMPR_HANDLE)UserObject;
9244 *RelativeId = ulRid;
9245 *GrantedAccess = UserObject->Access;
9246 }
9247
9248 done:
9249 if (Sd != NULL)
9250 RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
9251
9252 if (UserSid != NULL)
9253 RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
9254
9255 RtlReleaseResource(&SampResource);
9256
9257 TRACE("returns with status 0x%08lx\n", Status);
9258
9259 return Status;
9260 }
9261
9262
9263 /* Function 51 */
9264 NTSTATUS
9265 NTAPI
9266 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
9267 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
9268 IN unsigned long Index,
9269 IN unsigned long EntryCount,
9270 IN unsigned long PreferredMaximumLength,
9271 OUT unsigned long *TotalAvailable,
9272 OUT unsigned long *TotalReturned,
9273 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
9274 {
9275 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
9276 DomainHandle, DisplayInformationClass, Index,
9277 EntryCount, PreferredMaximumLength, TotalAvailable,
9278 TotalReturned, Buffer);
9279
9280 return SamrQueryDisplayInformation(DomainHandle,
9281 DisplayInformationClass,
9282 Index,
9283 EntryCount,
9284 PreferredMaximumLength,
9285 TotalAvailable,
9286 TotalReturned,
9287 Buffer);
9288 }
9289
9290
9291 /* Function 52 */
9292 NTSTATUS
9293 NTAPI
9294 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
9295 IN PSAMPR_PSID_ARRAY MembersBuffer)
9296 {
9297 ULONG i;
9298 NTSTATUS Status = STATUS_SUCCESS;
9299
9300 TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
9301 AliasHandle, MembersBuffer);
9302
9303 for (i = 0; i < MembersBuffer->Count; i++)
9304 {
9305 Status = SamrAddMemberToAlias(AliasHandle,
9306 ((PSID *)MembersBuffer->Sids)[i]);
9307
9308 if (Status == STATUS_MEMBER_IN_ALIAS)
9309 Status = STATUS_SUCCESS;
9310
9311 if (!NT_SUCCESS(Status))
9312 break;
9313 }
9314
9315 return Status;
9316 }
9317
9318
9319 /* Function 53 */
9320 NTSTATUS
9321 NTAPI
9322 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
9323 IN PSAMPR_PSID_ARRAY MembersBuffer)
9324 {
9325 ULONG i;
9326 NTSTATUS Status = STATUS_SUCCESS;
9327
9328 TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
9329 AliasHandle, MembersBuffer);
9330
9331 for (i = 0; i < MembersBuffer->Count; i++)
9332 {
9333 Status = SamrRemoveMemberFromAlias(AliasHandle,
9334 ((PSID *)MembersBuffer->Sids)[i]);
9335
9336 if (Status == STATUS_MEMBER_IN_ALIAS)
9337 Status = STATUS_SUCCESS;
9338
9339 if (!NT_SUCCESS(Status))
9340 break;
9341 }
9342
9343 return Status;
9344 }
9345
9346
9347 /* Function 54 */
9348 NTSTATUS
9349 NTAPI
9350 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
9351 IN PRPC_STRING ServerName,
9352 IN PRPC_STRING UserName,
9353 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9354 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
9355 {
9356 UNIMPLEMENTED;
9357 return STATUS_NOT_IMPLEMENTED;
9358 }
9359
9360 /* Function 55 */
9361 NTSTATUS
9362 NTAPI
9363 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
9364 IN PRPC_UNICODE_STRING ServerName,
9365 IN PRPC_UNICODE_STRING UserName,
9366 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
9367 IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
9368 IN unsigned char LmPresent,
9369 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
9370 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
9371 {
9372 UNIMPLEMENTED;
9373 return STATUS_NOT_IMPLEMENTED;
9374 }
9375
9376
9377 /* Function 56 */
9378 NTSTATUS
9379 NTAPI
9380 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
9381 IN PRPC_UNICODE_STRING Unused,
9382 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
9383 {
9384 SAMPR_HANDLE ServerHandle = NULL;
9385 PSAM_DB_OBJECT DomainObject = NULL;
9386 SAM_DOMAIN_FIXED_DATA FixedData;
9387 ULONG Length;
9388 NTSTATUS Status;
9389
9390 TRACE("(%p %p %p)\n", BindingHandle, Unused, PasswordInformation);
9391
9392 Status = SamrConnect(NULL,
9393 &ServerHandle,
9394 SAM_SERVER_LOOKUP_DOMAIN);
9395 if (!NT_SUCCESS(Status))
9396 {
9397 TRACE("SamrConnect() failed (Status 0x%08lx)\n", Status);
9398 goto done;
9399 }
9400
9401 Status = SampOpenDbObject((PSAM_DB_OBJECT)ServerHandle,
9402 L"Domains",
9403 L"Account",
9404 0,
9405 SamDbDomainObject,
9406 DOMAIN_READ_PASSWORD_PARAMETERS,
9407 &DomainObject);
9408 if (!NT_SUCCESS(Status))
9409 {
9410 TRACE("SampOpenDbObject() failed (Status 0x%08lx)\n", Status);
9411 goto done;
9412 }
9413
9414 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
9415 Status = SampGetObjectAttribute(DomainObject,
9416 L"F",
9417 NULL,
9418 &FixedData,
9419 &Length);
9420 if (!NT_SUCCESS(Status))
9421 {
9422 TRACE("SampGetObjectAttribute() failed (Status 0x%08lx)\n", Status);
9423 goto done;
9424 }
9425
9426 PasswordInformation->MinPasswordLength = FixedData.MinPasswordLength;
9427 PasswordInformation->PasswordProperties = FixedData.PasswordProperties;
9428
9429 done:
9430 if (DomainObject != NULL)
9431 SampCloseDbObject(DomainObject);
9432
9433 if (ServerHandle != NULL)
9434 SamrCloseHandle(ServerHandle);
9435
9436 return Status;
9437 }
9438
9439
9440 /* Function 57 */
9441 NTSTATUS
9442 NTAPI
9443 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
9444 OUT SAMPR_HANDLE *ServerHandle,
9445 IN ACCESS_MASK DesiredAccess)
9446 {
9447 TRACE("(%p %p %lx)\n", ServerName, ServerHandle, DesiredAccess);
9448
9449 return SamrConnect(ServerName,
9450 ServerHandle,
9451 DesiredAccess);
9452 }
9453
9454
9455 /* Function 58 */
9456 NTSTATUS
9457 NTAPI
9458 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
9459 IN USER_INFORMATION_CLASS UserInformationClass,
9460 IN PSAMPR_USER_INFO_BUFFER Buffer)
9461 {
9462 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
9463
9464 return SamrSetInformationUser(UserHandle,
9465 UserInformationClass,
9466 Buffer);
9467 }
9468
9469
9470 /* Function 59 */
9471 NTSTATUS
9472 NTAPI
9473 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9474 {
9475 UNIMPLEMENTED;
9476 return STATUS_NOT_IMPLEMENTED;
9477 }
9478
9479 /* Function 60 */
9480 NTSTATUS
9481 NTAPI
9482 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
9483 {
9484 UNIMPLEMENTED;
9485 return STATUS_NOT_IMPLEMENTED;
9486 }
9487
9488 /* Function 61 */
9489 NTSTATUS
9490 NTAPI
9491 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
9492 {
9493 UNIMPLEMENTED;
9494 return STATUS_NOT_IMPLEMENTED;
9495 }
9496
9497 /* Function 62 */
9498 NTSTATUS
9499 NTAPI
9500 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
9501 OUT SAMPR_HANDLE *ServerHandle,
9502 IN unsigned long ClientRevision,
9503 IN ACCESS_MASK DesiredAccess)
9504 {
9505 UNIMPLEMENTED;
9506 return STATUS_NOT_IMPLEMENTED;
9507 }
9508
9509 /* Function 63 */
9510 NTSTATUS
9511 NTAPI
9512 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
9513 {
9514 UNIMPLEMENTED;
9515 return STATUS_NOT_IMPLEMENTED;
9516 }
9517
9518 /* Function 64 */
9519 NTSTATUS
9520 NTAPI
9521 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
9522 IN ACCESS_MASK DesiredAccess,
9523 IN unsigned long InVersion,
9524 IN SAMPR_REVISION_INFO *InRevisionInfo,
9525 OUT unsigned long *OutVersion,
9526 OUT SAMPR_REVISION_INFO *OutRevisionInfo,
9527 OUT SAMPR_HANDLE *ServerHandle)
9528 {
9529 UNIMPLEMENTED;
9530 return STATUS_NOT_IMPLEMENTED;
9531 }
9532
9533 /* Function 65 */
9534 NTSTATUS
9535 NTAPI
9536 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
9537 IN unsigned long Rid,
9538 OUT PRPC_SID *Sid)
9539 {
9540 UNIMPLEMENTED;
9541 return STATUS_NOT_IMPLEMENTED;
9542 }
9543
9544 /* Function 66 */
9545 NTSTATUS
9546 NTAPI
9547 SamrSetDSRMPassword(IN handle_t BindingHandle,
9548 IN PRPC_UNICODE_STRING Unused,
9549 IN unsigned long UserId,
9550 IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
9551 {
9552 UNIMPLEMENTED;
9553 return STATUS_NOT_IMPLEMENTED;
9554 }
9555
9556 /* Function 67 */
9557 NTSTATUS
9558 NTAPI
9559 SamrValidatePassword(IN handle_t Handle,
9560 IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
9561 IN PSAM_VALIDATE_INPUT_ARG InputArg,
9562 OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
9563 {
9564 UNIMPLEMENTED;
9565 return STATUS_NOT_IMPLEMENTED;
9566 }
9567
9568 /* EOF */