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