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