[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 SampSetGroupName(PSAM_DB_OBJECT GroupObject,
3967 PSAMPR_GROUP_INFO_BUFFER Buffer)
3968 {
3969 UNICODE_STRING OldGroupName = {0, 0, NULL};
3970 UNICODE_STRING NewGroupName;
3971 NTSTATUS Status;
3972
3973 Status = SampGetObjectAttributeString(GroupObject,
3974 L"Name",
3975 (PRPC_UNICODE_STRING)&OldGroupName);
3976 if (!NT_SUCCESS(Status))
3977 {
3978 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
3979 goto done;
3980 }
3981
3982 NewGroupName.Length = Buffer->Name.Name.Length;
3983 NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
3984 NewGroupName.Buffer = Buffer->Name.Name.Buffer;
3985
3986 if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
3987 {
3988 Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
3989 NewGroupName.Buffer);
3990 if (!NT_SUCCESS(Status))
3991 {
3992 TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
3993 NewGroupName.Buffer, Status);
3994 goto done;
3995 }
3996 }
3997
3998 Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
3999 L"Groups",
4000 NewGroupName.Buffer,
4001 GroupObject->RelativeId);
4002 if (!NT_SUCCESS(Status))
4003 {
4004 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4005 goto done;
4006 }
4007
4008 Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
4009 L"Groups",
4010 OldGroupName.Buffer);
4011 if (!NT_SUCCESS(Status))
4012 {
4013 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4014 goto done;
4015 }
4016
4017 Status = SampSetObjectAttribute(GroupObject,
4018 L"Name",
4019 REG_SZ,
4020 NewGroupName.Buffer,
4021 NewGroupName.Length + sizeof(WCHAR));
4022 if (!NT_SUCCESS(Status))
4023 {
4024 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4025 }
4026
4027 done:
4028 if (OldGroupName.Buffer != NULL)
4029 midl_user_free(OldGroupName.Buffer);
4030
4031 return Status;
4032 }
4033
4034
4035 static NTSTATUS
4036 SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
4037 PSAMPR_GROUP_INFO_BUFFER Buffer)
4038 {
4039 SAM_GROUP_FIXED_DATA FixedData;
4040 ULONG Length = 0;
4041 NTSTATUS Status;
4042
4043 Length = sizeof(SAM_GROUP_FIXED_DATA);
4044 Status = SampGetObjectAttribute(GroupObject,
4045 L"F",
4046 NULL,
4047 (PVOID)&FixedData,
4048 &Length);
4049 if (!NT_SUCCESS(Status))
4050 goto done;
4051
4052 FixedData.Attributes = Buffer->Attribute.Attributes;
4053
4054 Status = SampSetObjectAttribute(GroupObject,
4055 L"F",
4056 REG_BINARY,
4057 &FixedData,
4058 Length);
4059
4060 done:
4061 return Status;
4062 }
4063
4064
4065 /* Function 21 */
4066 NTSTATUS
4067 NTAPI
4068 SamrSetInformationGroup(IN SAMPR_HANDLE GroupHandle,
4069 IN GROUP_INFORMATION_CLASS GroupInformationClass,
4070 IN PSAMPR_GROUP_INFO_BUFFER Buffer)
4071 {
4072 PSAM_DB_OBJECT GroupObject;
4073 NTSTATUS Status;
4074
4075 TRACE("SamrSetInformationGroup(%p %lu %p)\n",
4076 GroupHandle, GroupInformationClass, Buffer);
4077
4078 /* Validate the group handle */
4079 Status = SampValidateDbObject(GroupHandle,
4080 SamDbGroupObject,
4081 GROUP_WRITE_ACCOUNT,
4082 &GroupObject);
4083 if (!NT_SUCCESS(Status))
4084 return Status;
4085
4086 switch (GroupInformationClass)
4087 {
4088 case GroupNameInformation:
4089 Status = SampSetGroupName(GroupObject,
4090 Buffer);
4091 break;
4092
4093 case GroupAttributeInformation:
4094 Status = SampSetGroupAttribute(GroupObject,
4095 Buffer);
4096 break;
4097
4098 case GroupAdminCommentInformation:
4099 Status = SampSetObjectAttribute(GroupObject,
4100 L"Description",
4101 REG_SZ,
4102 Buffer->AdminComment.AdminComment.Buffer,
4103 Buffer->AdminComment.AdminComment.Length + sizeof(WCHAR));
4104 break;
4105
4106 default:
4107 Status = STATUS_INVALID_INFO_CLASS;
4108 break;
4109 }
4110
4111 return Status;
4112 }
4113
4114
4115 /* Function 22 */
4116 NTSTATUS
4117 NTAPI
4118 SamrAddMemberToGroup(IN SAMPR_HANDLE GroupHandle,
4119 IN unsigned long MemberId,
4120 IN unsigned long Attributes)
4121 {
4122 PSAM_DB_OBJECT GroupObject;
4123 PSAM_DB_OBJECT UserObject = NULL;
4124 NTSTATUS Status;
4125
4126 TRACE("(%p %lu %lx)\n",
4127 GroupHandle, MemberId, Attributes);
4128
4129 /* Validate the group handle */
4130 Status = SampValidateDbObject(GroupHandle,
4131 SamDbGroupObject,
4132 GROUP_ADD_MEMBER,
4133 &GroupObject);
4134 if (!NT_SUCCESS(Status))
4135 return Status;
4136
4137 /* Open the user object in the same domain */
4138 Status = SampOpenUserObject(GroupObject->ParentObject,
4139 MemberId,
4140 0,
4141 &UserObject);
4142 if (!NT_SUCCESS(Status))
4143 {
4144 TRACE("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4145 goto done;
4146 }
4147
4148 /* Add group membership to the user object */
4149 Status = SampAddGroupMembershipToUser(UserObject,
4150 GroupObject->RelativeId,
4151 Attributes);
4152 if (!NT_SUCCESS(Status))
4153 {
4154 TRACE("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4155 goto done;
4156 }
4157
4158 /* Add the member to the group object */
4159 Status = SampAddMemberToGroup(GroupObject,
4160 MemberId);
4161 if (!NT_SUCCESS(Status))
4162 {
4163 TRACE("SampAddMemberToGroup() failed (Status 0x%08lx)\n", Status);
4164 }
4165
4166 done:
4167 if (UserObject)
4168 SampCloseDbObject(UserObject);
4169
4170 return Status;
4171 }
4172
4173
4174 /* Function 21 */
4175 NTSTATUS
4176 NTAPI
4177 SamrDeleteGroup(IN OUT SAMPR_HANDLE *GroupHandle)
4178 {
4179 PSAM_DB_OBJECT GroupObject;
4180 ULONG Length = 0;
4181 NTSTATUS Status;
4182
4183 TRACE("(%p)\n", GroupHandle);
4184
4185 /* Validate the group handle */
4186 Status = SampValidateDbObject(*GroupHandle,
4187 SamDbGroupObject,
4188 DELETE,
4189 &GroupObject);
4190 if (!NT_SUCCESS(Status))
4191 {
4192 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
4193 return Status;
4194 }
4195
4196 /* Fail, if the group is built-in */
4197 if (GroupObject->RelativeId < 1000)
4198 {
4199 TRACE("You can not delete a special account!\n");
4200 return STATUS_SPECIAL_ACCOUNT;
4201 }
4202
4203 /* Get the length of the Members attribute */
4204 SampGetObjectAttribute(GroupObject,
4205 L"Members",
4206 NULL,
4207 NULL,
4208 &Length);
4209
4210 /* Fail, if the group has members */
4211 if (Length != 0)
4212 {
4213 TRACE("There are still members in the group!\n");
4214 return STATUS_MEMBER_IN_GROUP;
4215 }
4216
4217 /* FIXME: Remove the group from all aliases */
4218
4219 /* Delete the group from the database */
4220 Status = SampDeleteAccountDbObject(GroupObject);
4221 if (!NT_SUCCESS(Status))
4222 {
4223 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4224 return Status;
4225 }
4226
4227 /* Invalidate the handle */
4228 *GroupHandle = NULL;
4229
4230 return STATUS_SUCCESS;
4231 }
4232
4233
4234 /* Function 24 */
4235 NTSTATUS
4236 NTAPI
4237 SamrRemoveMemberFromGroup(IN SAMPR_HANDLE GroupHandle,
4238 IN unsigned long MemberId)
4239 {
4240 PSAM_DB_OBJECT GroupObject;
4241 PSAM_DB_OBJECT UserObject = NULL;
4242 NTSTATUS Status;
4243
4244 TRACE("(%p %lu)\n",
4245 GroupHandle, MemberId);
4246
4247 /* Validate the group handle */
4248 Status = SampValidateDbObject(GroupHandle,
4249 SamDbGroupObject,
4250 GROUP_REMOVE_MEMBER,
4251 &GroupObject);
4252 if (!NT_SUCCESS(Status))
4253 return Status;
4254
4255 /* Open the user object in the same domain */
4256 Status = SampOpenUserObject(GroupObject->ParentObject,
4257 MemberId,
4258 0,
4259 &UserObject);
4260 if (!NT_SUCCESS(Status))
4261 {
4262 ERR("SampOpenUserObject() failed (Status 0x%08lx)\n", Status);
4263 goto done;
4264 }
4265
4266 /* Remove group membership from the user object */
4267 Status = SampRemoveGroupMembershipFromUser(UserObject,
4268 GroupObject->RelativeId);
4269 if (!NT_SUCCESS(Status))
4270 {
4271 ERR("SampAddGroupMembershipToUser() failed (Status 0x%08lx)\n", Status);
4272 goto done;
4273 }
4274
4275 /* Remove the member from the group object */
4276 Status = SampRemoveMemberFromGroup(GroupObject,
4277 MemberId);
4278 if (!NT_SUCCESS(Status))
4279 {
4280 ERR("SampRemoveMemberFromGroup() failed (Status 0x%08lx)\n", Status);
4281 }
4282
4283 done:
4284 if (UserObject)
4285 SampCloseDbObject(UserObject);
4286
4287 return Status;
4288 }
4289
4290
4291 /* Function 25 */
4292 NTSTATUS
4293 NTAPI
4294 SamrGetMembersInGroup(IN SAMPR_HANDLE GroupHandle,
4295 OUT PSAMPR_GET_MEMBERS_BUFFER *Members)
4296 {
4297 PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
4298 PSAM_DB_OBJECT GroupObject;
4299 ULONG Length = 0;
4300 ULONG i;
4301 NTSTATUS Status;
4302
4303 /* Validate the group handle */
4304 Status = SampValidateDbObject(GroupHandle,
4305 SamDbGroupObject,
4306 GROUP_LIST_MEMBERS,
4307 &GroupObject);
4308 if (!NT_SUCCESS(Status))
4309 return Status;
4310
4311 MembersBuffer = midl_user_allocate(sizeof(SAMPR_GET_MEMBERS_BUFFER));
4312 if (MembersBuffer == NULL)
4313 return STATUS_INSUFFICIENT_RESOURCES;
4314
4315 SampGetObjectAttribute(GroupObject,
4316 L"Members",
4317 NULL,
4318 NULL,
4319 &Length);
4320
4321 if (Length == 0)
4322 {
4323 MembersBuffer->MemberCount = 0;
4324 MembersBuffer->Members = NULL;
4325 MembersBuffer->Attributes = NULL;
4326
4327 *Members = MembersBuffer;
4328
4329 return STATUS_SUCCESS;
4330 }
4331
4332 MembersBuffer->Members = midl_user_allocate(Length);
4333 if (MembersBuffer->Members == NULL)
4334 {
4335 Status = STATUS_INSUFFICIENT_RESOURCES;
4336 goto done;
4337 }
4338
4339 MembersBuffer->Attributes = midl_user_allocate(Length);
4340 if (MembersBuffer->Attributes == NULL)
4341 {
4342 Status = STATUS_INSUFFICIENT_RESOURCES;
4343 goto done;
4344 }
4345
4346 Status = SampGetObjectAttribute(GroupObject,
4347 L"Members",
4348 NULL,
4349 MembersBuffer->Members,
4350 &Length);
4351 if (!NT_SUCCESS(Status))
4352 {
4353 TRACE("SampGetObjectAttributes() failed (Status 0x%08lx)\n", Status);
4354 goto done;
4355 }
4356
4357 MembersBuffer->MemberCount = Length / sizeof(ULONG);
4358
4359 for (i = 0; i < MembersBuffer->MemberCount; i++)
4360 {
4361 Status = SampGetUserGroupAttributes(GroupObject->ParentObject,
4362 MembersBuffer->Members[i],
4363 GroupObject->RelativeId,
4364 &(MembersBuffer->Attributes[i]));
4365 if (!NT_SUCCESS(Status))
4366 {
4367 TRACE("SampGetUserGroupAttributes() failed (Status 0x%08lx)\n", Status);
4368 goto done;
4369 }
4370 }
4371
4372 *Members = MembersBuffer;
4373
4374 done:
4375 if (!NT_SUCCESS(Status))
4376 {
4377 if (MembersBuffer != NULL)
4378 {
4379 if (MembersBuffer->Members != NULL)
4380 midl_user_free(MembersBuffer->Members);
4381
4382 if (MembersBuffer->Attributes != NULL)
4383 midl_user_free(MembersBuffer->Attributes);
4384
4385 midl_user_free(MembersBuffer);
4386 }
4387 }
4388
4389 return Status;
4390 }
4391
4392
4393 /* Function 26 */
4394 NTSTATUS
4395 NTAPI
4396 SamrSetMemberAttributesOfGroup(IN SAMPR_HANDLE GroupHandle,
4397 IN unsigned long MemberId,
4398 IN unsigned long Attributes)
4399 {
4400 PSAM_DB_OBJECT GroupObject;
4401 NTSTATUS Status;
4402
4403 /* Validate the group handle */
4404 Status = SampValidateDbObject(GroupHandle,
4405 SamDbGroupObject,
4406 GROUP_ADD_MEMBER,
4407 &GroupObject);
4408 if (!NT_SUCCESS(Status))
4409 {
4410 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
4411 return Status;
4412 }
4413
4414 Status = SampSetUserGroupAttributes(GroupObject->ParentObject,
4415 MemberId,
4416 GroupObject->RelativeId,
4417 Attributes);
4418 if (!NT_SUCCESS(Status))
4419 {
4420 TRACE("SampSetUserGroupAttributes failed with status 0x%08lx\n", Status);
4421 }
4422
4423 return Status;
4424 }
4425
4426
4427 /* Function 27 */
4428 NTSTATUS
4429 NTAPI
4430 SamrOpenAlias(IN SAMPR_HANDLE DomainHandle,
4431 IN ACCESS_MASK DesiredAccess,
4432 IN ULONG AliasId,
4433 OUT SAMPR_HANDLE *AliasHandle)
4434 {
4435 PSAM_DB_OBJECT DomainObject;
4436 PSAM_DB_OBJECT AliasObject;
4437 WCHAR szRid[9];
4438 NTSTATUS Status;
4439
4440 TRACE("SamrOpenAlias(%p %lx %lx %p)\n",
4441 DomainHandle, DesiredAccess, AliasId, AliasHandle);
4442
4443 /* Map generic access rights */
4444 RtlMapGenericMask(&DesiredAccess,
4445 &AliasMapping);
4446
4447 /* Validate the domain handle */
4448 Status = SampValidateDbObject(DomainHandle,
4449 SamDbDomainObject,
4450 DOMAIN_LOOKUP,
4451 &DomainObject);
4452 if (!NT_SUCCESS(Status))
4453 {
4454 TRACE("failed with status 0x%08lx\n", Status);
4455 return Status;
4456 }
4457
4458 /* Convert the RID into a string (hex) */
4459 swprintf(szRid, L"%08lX", AliasId);
4460
4461 /* Create the alias object */
4462 Status = SampOpenDbObject(DomainObject,
4463 L"Aliases",
4464 szRid,
4465 AliasId,
4466 SamDbAliasObject,
4467 DesiredAccess,
4468 &AliasObject);
4469 if (!NT_SUCCESS(Status))
4470 {
4471 TRACE("failed with status 0x%08lx\n", Status);
4472 return Status;
4473 }
4474
4475 *AliasHandle = (SAMPR_HANDLE)AliasObject;
4476
4477 return STATUS_SUCCESS;
4478 }
4479
4480
4481 static NTSTATUS
4482 SampQueryAliasGeneral(PSAM_DB_OBJECT AliasObject,
4483 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4484 {
4485 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4486 HANDLE MembersKeyHandle = NULL;
4487 NTSTATUS Status;
4488
4489 *Buffer = NULL;
4490
4491 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4492 if (InfoBuffer == NULL)
4493 return STATUS_INSUFFICIENT_RESOURCES;
4494
4495 Status = SampGetObjectAttributeString(AliasObject,
4496 L"Name",
4497 &InfoBuffer->General.Name);
4498 if (!NT_SUCCESS(Status))
4499 {
4500 TRACE("Status 0x%08lx\n", Status);
4501 goto done;
4502 }
4503
4504 Status = SampGetObjectAttributeString(AliasObject,
4505 L"Description",
4506 &InfoBuffer->General.AdminComment);
4507 if (!NT_SUCCESS(Status))
4508 {
4509 TRACE("Status 0x%08lx\n", Status);
4510 goto done;
4511 }
4512
4513 /* Open the Members subkey */
4514 Status = SampRegOpenKey(AliasObject->KeyHandle,
4515 L"Members",
4516 KEY_READ,
4517 &MembersKeyHandle);
4518 if (NT_SUCCESS(Status))
4519 {
4520 /* Retrieve the number of members of the alias */
4521 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4522 NULL,
4523 &InfoBuffer->General.MemberCount);
4524 if (!NT_SUCCESS(Status))
4525 {
4526 TRACE("Status 0x%08lx\n", Status);
4527 goto done;
4528 }
4529 }
4530 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4531 {
4532 InfoBuffer->General.MemberCount = 0;
4533 Status = STATUS_SUCCESS;
4534 }
4535 else
4536 {
4537 TRACE("Status 0x%08lx\n", Status);
4538 goto done;
4539 }
4540
4541 *Buffer = InfoBuffer;
4542
4543 done:
4544 if (MembersKeyHandle != NULL)
4545 SampRegCloseKey(MembersKeyHandle);
4546
4547 if (!NT_SUCCESS(Status))
4548 {
4549 if (InfoBuffer != NULL)
4550 {
4551 if (InfoBuffer->General.Name.Buffer != NULL)
4552 midl_user_free(InfoBuffer->General.Name.Buffer);
4553
4554 if (InfoBuffer->General.AdminComment.Buffer != NULL)
4555 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
4556
4557 midl_user_free(InfoBuffer);
4558 }
4559 }
4560
4561 return Status;
4562 }
4563
4564
4565 static NTSTATUS
4566 SampQueryAliasName(PSAM_DB_OBJECT AliasObject,
4567 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4568 {
4569 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4570 NTSTATUS Status;
4571
4572 *Buffer = NULL;
4573
4574 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4575 if (InfoBuffer == NULL)
4576 return STATUS_INSUFFICIENT_RESOURCES;
4577
4578 Status = SampGetObjectAttributeString(AliasObject,
4579 L"Name",
4580 &InfoBuffer->Name.Name);
4581 if (!NT_SUCCESS(Status))
4582 {
4583 TRACE("Status 0x%08lx\n", Status);
4584 goto done;
4585 }
4586
4587 *Buffer = InfoBuffer;
4588
4589 done:
4590 if (!NT_SUCCESS(Status))
4591 {
4592 if (InfoBuffer != NULL)
4593 {
4594 if (InfoBuffer->Name.Name.Buffer != NULL)
4595 midl_user_free(InfoBuffer->Name.Name.Buffer);
4596
4597 midl_user_free(InfoBuffer);
4598 }
4599 }
4600
4601 return Status;
4602 }
4603
4604
4605 static NTSTATUS
4606 SampQueryAliasAdminComment(PSAM_DB_OBJECT AliasObject,
4607 PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4608 {
4609 PSAMPR_ALIAS_INFO_BUFFER InfoBuffer = NULL;
4610 NTSTATUS Status;
4611
4612 *Buffer = NULL;
4613
4614 InfoBuffer = midl_user_allocate(sizeof(SAMPR_ALIAS_INFO_BUFFER));
4615 if (InfoBuffer == NULL)
4616 return STATUS_INSUFFICIENT_RESOURCES;
4617
4618 Status = SampGetObjectAttributeString(AliasObject,
4619 L"Description",
4620 &InfoBuffer->AdminComment.AdminComment);
4621 if (!NT_SUCCESS(Status))
4622 {
4623 TRACE("Status 0x%08lx\n", Status);
4624 goto done;
4625 }
4626
4627 *Buffer = InfoBuffer;
4628
4629 done:
4630 if (!NT_SUCCESS(Status))
4631 {
4632 if (InfoBuffer != NULL)
4633 {
4634 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
4635 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
4636
4637 midl_user_free(InfoBuffer);
4638 }
4639 }
4640
4641 return Status;
4642 }
4643
4644
4645 /* Function 28 */
4646 NTSTATUS
4647 NTAPI
4648 SamrQueryInformationAlias(IN SAMPR_HANDLE AliasHandle,
4649 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4650 OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer)
4651 {
4652 PSAM_DB_OBJECT AliasObject;
4653 NTSTATUS Status;
4654
4655 TRACE("SamrQueryInformationAlias(%p %lu %p)\n",
4656 AliasHandle, AliasInformationClass, Buffer);
4657
4658 /* Validate the alias handle */
4659 Status = SampValidateDbObject(AliasHandle,
4660 SamDbAliasObject,
4661 ALIAS_READ_INFORMATION,
4662 &AliasObject);
4663 if (!NT_SUCCESS(Status))
4664 return Status;
4665
4666 switch (AliasInformationClass)
4667 {
4668 case AliasGeneralInformation:
4669 Status = SampQueryAliasGeneral(AliasObject,
4670 Buffer);
4671 break;
4672
4673 case AliasNameInformation:
4674 Status = SampQueryAliasName(AliasObject,
4675 Buffer);
4676 break;
4677
4678 case AliasAdminCommentInformation:
4679 Status = SampQueryAliasAdminComment(AliasObject,
4680 Buffer);
4681 break;
4682
4683 default:
4684 Status = STATUS_INVALID_INFO_CLASS;
4685 break;
4686 }
4687
4688 return Status;
4689 }
4690
4691
4692 static NTSTATUS
4693 SampSetAliasName(PSAM_DB_OBJECT AliasObject,
4694 PSAMPR_ALIAS_INFO_BUFFER Buffer)
4695 {
4696 UNICODE_STRING OldAliasName = {0, 0, NULL};
4697 UNICODE_STRING NewAliasName;
4698 NTSTATUS Status;
4699
4700 Status = SampGetObjectAttributeString(AliasObject,
4701 L"Name",
4702 (PRPC_UNICODE_STRING)&OldAliasName);
4703 if (!NT_SUCCESS(Status))
4704 {
4705 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
4706 goto done;
4707 }
4708
4709 NewAliasName.Length = Buffer->Name.Name.Length;
4710 NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
4711 NewAliasName.Buffer = Buffer->Name.Name.Buffer;
4712
4713 if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
4714 {
4715 Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
4716 NewAliasName.Buffer);
4717 if (!NT_SUCCESS(Status))
4718 {
4719 TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
4720 NewAliasName.Buffer, Status);
4721 goto done;
4722 }
4723 }
4724
4725 Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
4726 L"Aliases",
4727 NewAliasName.Buffer,
4728 AliasObject->RelativeId);
4729 if (!NT_SUCCESS(Status))
4730 {
4731 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
4732 goto done;
4733 }
4734
4735 Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
4736 L"Aliases",
4737 OldAliasName.Buffer);
4738 if (!NT_SUCCESS(Status))
4739 {
4740 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
4741 goto done;
4742 }
4743
4744 Status = SampSetObjectAttribute(AliasObject,
4745 L"Name",
4746 REG_SZ,
4747 NewAliasName.Buffer,
4748 NewAliasName.Length + sizeof(WCHAR));
4749 if (!NT_SUCCESS(Status))
4750 {
4751 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
4752 }
4753
4754 done:
4755 if (OldAliasName.Buffer != NULL)
4756 midl_user_free(OldAliasName.Buffer);
4757
4758 return Status;
4759 }
4760
4761
4762 /* Function 29 */
4763 NTSTATUS
4764 NTAPI
4765 SamrSetInformationAlias(IN SAMPR_HANDLE AliasHandle,
4766 IN ALIAS_INFORMATION_CLASS AliasInformationClass,
4767 IN PSAMPR_ALIAS_INFO_BUFFER Buffer)
4768 {
4769 PSAM_DB_OBJECT AliasObject;
4770 NTSTATUS Status;
4771
4772 TRACE("SamrSetInformationAlias(%p %lu %p)\n",
4773 AliasHandle, AliasInformationClass, Buffer);
4774
4775 /* Validate the alias handle */
4776 Status = SampValidateDbObject(AliasHandle,
4777 SamDbAliasObject,
4778 ALIAS_WRITE_ACCOUNT,
4779 &AliasObject);
4780 if (!NT_SUCCESS(Status))
4781 return Status;
4782
4783 switch (AliasInformationClass)
4784 {
4785 case AliasNameInformation:
4786 Status = SampSetAliasName(AliasObject,
4787 Buffer);
4788 break;
4789
4790 case AliasAdminCommentInformation:
4791 Status = SampSetObjectAttribute(AliasObject,
4792 L"Description",
4793 REG_SZ,
4794 Buffer->AdminComment.AdminComment.Buffer,
4795 Buffer->AdminComment.AdminComment.Length + sizeof(WCHAR));
4796 break;
4797
4798 default:
4799 Status = STATUS_INVALID_INFO_CLASS;
4800 break;
4801 }
4802
4803 return Status;
4804 }
4805
4806
4807 /* Function 30 */
4808 NTSTATUS
4809 NTAPI
4810 SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
4811 {
4812 PSAM_DB_OBJECT AliasObject;
4813 NTSTATUS Status;
4814
4815 /* Validate the alias handle */
4816 Status = SampValidateDbObject(*AliasHandle,
4817 SamDbAliasObject,
4818 DELETE,
4819 &AliasObject);
4820 if (!NT_SUCCESS(Status))
4821 {
4822 TRACE("SampValidateDbObject failed (Status 0x%08lx)\n", Status);
4823 return Status;
4824 }
4825
4826 /* Fail, if the alias is built-in */
4827 if (AliasObject->RelativeId < 1000)
4828 {
4829 TRACE("You can not delete a special account!\n");
4830 return STATUS_SPECIAL_ACCOUNT;
4831 }
4832
4833 /* FIXME: Remove all members from the alias */
4834
4835 /* Delete the alias from the database */
4836 Status = SampDeleteAccountDbObject(AliasObject);
4837 if (!NT_SUCCESS(Status))
4838 {
4839 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
4840 return Status;
4841 }
4842
4843 /* Invalidate the handle */
4844 *AliasHandle = NULL;
4845
4846 return Status;
4847 }
4848
4849
4850 /* Function 31 */
4851 NTSTATUS
4852 NTAPI
4853 SamrAddMemberToAlias(IN SAMPR_HANDLE AliasHandle,
4854 IN PRPC_SID MemberId)
4855 {
4856 PSAM_DB_OBJECT AliasObject;
4857 NTSTATUS Status;
4858
4859 TRACE("(%p %p)\n", AliasHandle, MemberId);
4860
4861 /* Validate the alias handle */
4862 Status = SampValidateDbObject(AliasHandle,
4863 SamDbAliasObject,
4864 ALIAS_ADD_MEMBER,
4865 &AliasObject);
4866 if (!NT_SUCCESS(Status))
4867 {
4868 TRACE("failed with status 0x%08lx\n", Status);
4869 return Status;
4870 }
4871
4872 Status = SampAddMemberToAlias(AliasObject,
4873 MemberId);
4874 if (!NT_SUCCESS(Status))
4875 {
4876 TRACE("failed with status 0x%08lx\n", Status);
4877 }
4878
4879 return Status;
4880 }
4881
4882
4883 /* Function 32 */
4884 NTSTATUS
4885 NTAPI
4886 SamrRemoveMemberFromAlias(IN SAMPR_HANDLE AliasHandle,
4887 IN PRPC_SID MemberId)
4888 {
4889 PSAM_DB_OBJECT AliasObject;
4890 NTSTATUS Status;
4891
4892 TRACE("(%p %p)\n", AliasHandle, MemberId);
4893
4894 /* Validate the alias handle */
4895 Status = SampValidateDbObject(AliasHandle,
4896 SamDbAliasObject,
4897 ALIAS_REMOVE_MEMBER,
4898 &AliasObject);
4899 if (!NT_SUCCESS(Status))
4900 {
4901 TRACE("failed with status 0x%08lx\n", Status);
4902 return Status;
4903 }
4904
4905 Status = SampRemoveMemberFromAlias(AliasObject,
4906 MemberId);
4907 if (!NT_SUCCESS(Status))
4908 {
4909 TRACE("failed with status 0x%08lx\n", Status);
4910 }
4911
4912 return Status;
4913 }
4914
4915
4916 /* Function 33 */
4917 NTSTATUS
4918 NTAPI
4919 SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
4920 OUT PSAMPR_PSID_ARRAY_OUT Members)
4921 {
4922 PSAM_DB_OBJECT AliasObject;
4923 HANDLE MembersKeyHandle = NULL;
4924 PSAMPR_SID_INFORMATION MemberArray = NULL;
4925 ULONG ValueCount = 0;
4926 ULONG DataLength;
4927 ULONG Index;
4928 NTSTATUS Status;
4929
4930 TRACE("SamrGetMembersInAlias(%p %p %p)\n",
4931 AliasHandle, Members);
4932
4933 /* Validate the alias handle */
4934 Status = SampValidateDbObject(AliasHandle,
4935 SamDbAliasObject,
4936 ALIAS_LIST_MEMBERS,
4937 &AliasObject);
4938 if (!NT_SUCCESS(Status))
4939 {
4940 ERR("failed with status 0x%08lx\n", Status);
4941 return Status;
4942 }
4943
4944 /* Open the members key of the alias objct */
4945 Status = SampRegOpenKey(AliasObject->KeyHandle,
4946 L"Members",
4947 KEY_READ,
4948 &MembersKeyHandle);
4949 if (!NT_SUCCESS(Status))
4950 {
4951 ERR("SampRegOpenKey failed with status 0x%08lx\n", Status);
4952 return Status;
4953 }
4954
4955 /* Get the number of members */
4956 Status = SampRegQueryKeyInfo(MembersKeyHandle,
4957 NULL,
4958 &ValueCount);
4959 if (!NT_SUCCESS(Status))
4960 {
4961 ERR("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
4962 goto done;
4963 }
4964
4965 /* Allocate the member array */
4966 MemberArray = midl_user_allocate(ValueCount * sizeof(SAMPR_SID_INFORMATION));
4967 if (MemberArray == NULL)
4968 {
4969 Status = STATUS_INSUFFICIENT_RESOURCES;
4970 goto done;
4971 }
4972
4973 /* Enumerate the members */
4974 Index = 0;
4975 while (TRUE)
4976 {
4977 /* Get the size of the next SID */
4978 DataLength = 0;
4979 Status = SampRegEnumerateValue(MembersKeyHandle,
4980 Index,
4981 NULL,
4982 NULL,
4983 NULL,
4984 NULL,
4985 &DataLength);
4986 if (!NT_SUCCESS(Status))
4987 {
4988 if (Status == STATUS_NO_MORE_ENTRIES)
4989 Status = STATUS_SUCCESS;
4990 break;
4991 }
4992
4993 /* Allocate a buffer for the SID */
4994 MemberArray[Index].SidPointer = midl_user_allocate(DataLength);
4995 if (MemberArray[Index].SidPointer == NULL)
4996 {
4997 Status = STATUS_INSUFFICIENT_RESOURCES;
4998 goto done;
4999 }
5000
5001 /* Read the SID into the buffer */
5002 Status = SampRegEnumerateValue(MembersKeyHandle,
5003 Index,
5004 NULL,
5005 NULL,
5006 NULL,
5007 (PVOID)MemberArray[Index].SidPointer,
5008 &DataLength);
5009 if (!NT_SUCCESS(Status))
5010 {
5011 goto done;
5012 }
5013
5014 Index++;
5015 }
5016
5017 /* Return the number of members and the member array */
5018 if (NT_SUCCESS(Status))
5019 {
5020 Members->Count = ValueCount;
5021 Members->Sids = MemberArray;
5022 }
5023
5024 done:
5025 /* Clean up the members array and the SID buffers if something failed */
5026 if (!NT_SUCCESS(Status))
5027 {
5028 if (MemberArray != NULL)
5029 {
5030 for (Index = 0; Index < ValueCount; Index++)
5031 {
5032 if (MemberArray[Index].SidPointer != NULL)
5033 midl_user_free(MemberArray[Index].SidPointer);
5034 }
5035
5036 midl_user_free(MemberArray);
5037 }
5038 }
5039
5040 /* Close the members key */
5041 if (MembersKeyHandle != NULL)
5042 SampRegCloseKey(MembersKeyHandle);
5043
5044 return Status;
5045 }
5046
5047
5048 /* Function 34 */
5049 NTSTATUS
5050 NTAPI
5051 SamrOpenUser(IN SAMPR_HANDLE DomainHandle,
5052 IN ACCESS_MASK DesiredAccess,
5053 IN unsigned long UserId,
5054 OUT SAMPR_HANDLE *UserHandle)
5055 {
5056 PSAM_DB_OBJECT DomainObject;
5057 PSAM_DB_OBJECT UserObject;
5058 WCHAR szRid[9];
5059 NTSTATUS Status;
5060
5061 TRACE("SamrOpenUser(%p %lx %lx %p)\n",
5062 DomainHandle, DesiredAccess, UserId, UserHandle);
5063
5064 /* Map generic access rights */
5065 RtlMapGenericMask(&DesiredAccess,
5066 &UserMapping);
5067
5068 /* Validate the domain handle */
5069 Status = SampValidateDbObject(DomainHandle,
5070 SamDbDomainObject,
5071 DOMAIN_LOOKUP,
5072 &DomainObject);
5073 if (!NT_SUCCESS(Status))
5074 {
5075 TRACE("failed with status 0x%08lx\n", Status);
5076 return Status;
5077 }
5078
5079 /* Convert the RID into a string (hex) */
5080 swprintf(szRid, L"%08lX", UserId);
5081
5082 /* Create the user object */
5083 Status = SampOpenDbObject(DomainObject,
5084 L"Users",
5085 szRid,
5086 UserId,
5087 SamDbUserObject,
5088 DesiredAccess,
5089 &UserObject);
5090 if (!NT_SUCCESS(Status))
5091 {
5092 TRACE("failed with status 0x%08lx\n", Status);
5093 return Status;
5094 }
5095
5096 *UserHandle = (SAMPR_HANDLE)UserObject;
5097
5098 return STATUS_SUCCESS;
5099 }
5100
5101
5102 /* Function 35 */
5103 NTSTATUS
5104 NTAPI
5105 SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
5106 {
5107 PSAM_DB_OBJECT UserObject;
5108 NTSTATUS Status;
5109
5110 TRACE("(%p)\n", UserHandle);
5111
5112 /* Validate the user handle */
5113 Status = SampValidateDbObject(*UserHandle,
5114 SamDbUserObject,
5115 DELETE,
5116 &UserObject);
5117 if (!NT_SUCCESS(Status))
5118 {
5119 TRACE("SampValidateDbObject() failed (Status 0x%08lx)\n", Status);
5120 return Status;
5121 }
5122
5123 /* Fail, if the user is built-in */
5124 if (UserObject->RelativeId < 1000)
5125 {
5126 TRACE("You can not delete a special account!\n");
5127 return STATUS_SPECIAL_ACCOUNT;
5128 }
5129
5130 /* FIXME: Remove the user from all groups */
5131
5132 /* FIXME: Remove the user from all aliases */
5133
5134 /* Delete the user from the database */
5135 Status = SampDeleteAccountDbObject(UserObject);
5136 if (!NT_SUCCESS(Status))
5137 {
5138 TRACE("SampDeleteAccountDbObject() failed (Status 0x%08lx)\n", Status);
5139 return Status;
5140 }
5141
5142 /* Invalidate the handle */
5143 *UserHandle = NULL;
5144
5145 return STATUS_SUCCESS;
5146 }
5147
5148
5149 static
5150 NTSTATUS
5151 SampQueryUserGeneral(PSAM_DB_OBJECT UserObject,
5152 PSAMPR_USER_INFO_BUFFER *Buffer)
5153 {
5154 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5155 SAM_USER_FIXED_DATA FixedData;
5156 ULONG Length = 0;
5157 NTSTATUS Status;
5158
5159 *Buffer = NULL;
5160
5161 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5162 if (InfoBuffer == NULL)
5163 return STATUS_INSUFFICIENT_RESOURCES;
5164
5165 Length = sizeof(SAM_USER_FIXED_DATA);
5166 Status = SampGetObjectAttribute(UserObject,
5167 L"F",
5168 NULL,
5169 (PVOID)&FixedData,
5170 &Length);
5171 if (!NT_SUCCESS(Status))
5172 goto done;
5173
5174 InfoBuffer->General.PrimaryGroupId = FixedData.PrimaryGroupId;
5175
5176 /* Get the Name string */
5177 Status = SampGetObjectAttributeString(UserObject,
5178 L"Name",
5179 &InfoBuffer->General.UserName);
5180 if (!NT_SUCCESS(Status))
5181 {
5182 TRACE("Status 0x%08lx\n", Status);
5183 goto done;
5184 }
5185
5186 /* Get the FullName string */
5187 Status = SampGetObjectAttributeString(UserObject,
5188 L"FullName",
5189 &InfoBuffer->General.FullName);
5190 if (!NT_SUCCESS(Status))
5191 {
5192 TRACE("Status 0x%08lx\n", Status);
5193 goto done;
5194 }
5195
5196 /* Get the AdminComment string */
5197 Status = SampGetObjectAttributeString(UserObject,
5198 L"AdminComment",
5199 &InfoBuffer->General.AdminComment);
5200 if (!NT_SUCCESS(Status))
5201 {
5202 TRACE("Status 0x%08lx\n", Status);
5203 goto done;
5204 }
5205
5206 /* Get the UserComment string */
5207 Status = SampGetObjectAttributeString(UserObject,
5208 L"UserComment",
5209 &InfoBuffer->General.UserComment);
5210 if (!NT_SUCCESS(Status))
5211 {
5212 TRACE("Status 0x%08lx\n", Status);
5213 goto done;
5214 }
5215
5216 *Buffer = InfoBuffer;
5217
5218 done:
5219 if (!NT_SUCCESS(Status))
5220 {
5221 if (InfoBuffer != NULL)
5222 {
5223 if (InfoBuffer->General.UserName.Buffer != NULL)
5224 midl_user_free(InfoBuffer->General.UserName.Buffer);
5225
5226 if (InfoBuffer->General.FullName.Buffer != NULL)
5227 midl_user_free(InfoBuffer->General.FullName.Buffer);
5228
5229 if (InfoBuffer->General.AdminComment.Buffer != NULL)
5230 midl_user_free(InfoBuffer->General.AdminComment.Buffer);
5231
5232 if (InfoBuffer->General.UserComment.Buffer != NULL)
5233 midl_user_free(InfoBuffer->General.UserComment.Buffer);
5234
5235 midl_user_free(InfoBuffer);
5236 }
5237 }
5238
5239 return Status;
5240 }
5241
5242
5243 static
5244 NTSTATUS
5245 SampQueryUserPreferences(PSAM_DB_OBJECT UserObject,
5246 PSAMPR_USER_INFO_BUFFER *Buffer)
5247 {
5248 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5249 SAM_USER_FIXED_DATA FixedData;
5250 ULONG Length = 0;
5251 NTSTATUS Status;
5252
5253 *Buffer = NULL;
5254
5255 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5256 if (InfoBuffer == NULL)
5257 return STATUS_INSUFFICIENT_RESOURCES;
5258
5259 Length = sizeof(SAM_USER_FIXED_DATA);
5260 Status = SampGetObjectAttribute(UserObject,
5261 L"F",
5262 NULL,
5263 (PVOID)&FixedData,
5264 &Length);
5265 if (!NT_SUCCESS(Status))
5266 goto done;
5267
5268 InfoBuffer->Preferences.CountryCode = FixedData.CountryCode;
5269 InfoBuffer->Preferences.CodePage = FixedData.CodePage;
5270
5271 /* Get the UserComment string */
5272 Status = SampGetObjectAttributeString(UserObject,
5273 L"UserComment",
5274 &InfoBuffer->Preferences.UserComment);
5275 if (!NT_SUCCESS(Status))
5276 {
5277 TRACE("Status 0x%08lx\n", Status);
5278 goto done;
5279 }
5280
5281 *Buffer = InfoBuffer;
5282
5283 done:
5284 if (!NT_SUCCESS(Status))
5285 {
5286 if (InfoBuffer != NULL)
5287 {
5288 if (InfoBuffer->Preferences.UserComment.Buffer != NULL)
5289 midl_user_free(InfoBuffer->Preferences.UserComment.Buffer);
5290
5291 midl_user_free(InfoBuffer);
5292 }
5293 }
5294
5295 return Status;
5296 }
5297
5298
5299 static
5300 NTSTATUS
5301 SampQueryUserLogon(PSAM_DB_OBJECT UserObject,
5302 PSAMPR_USER_INFO_BUFFER *Buffer)
5303 {
5304 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5305 SAM_DOMAIN_FIXED_DATA DomainFixedData;
5306 SAM_USER_FIXED_DATA FixedData;
5307 LARGE_INTEGER PasswordCanChange;
5308 LARGE_INTEGER PasswordMustChange;
5309 ULONG Length = 0;
5310 NTSTATUS Status;
5311
5312 *Buffer = NULL;
5313
5314 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5315 if (InfoBuffer == NULL)
5316 return STATUS_INSUFFICIENT_RESOURCES;
5317
5318 /* Get the fixed size domain data */
5319 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
5320 Status = SampGetObjectAttribute(UserObject->ParentObject,
5321 L"F",
5322 NULL,
5323 (PVOID)&DomainFixedData,
5324 &Length);
5325 if (!NT_SUCCESS(Status))
5326 goto done;
5327
5328 /* Get the fixed size user data */
5329 Length = sizeof(SAM_USER_FIXED_DATA);
5330 Status = SampGetObjectAttribute(UserObject,
5331 L"F",
5332 NULL,
5333 (PVOID)&FixedData,
5334 &Length);
5335 if (!NT_SUCCESS(Status))
5336 goto done;
5337
5338 InfoBuffer->Logon.UserId = FixedData.UserId;
5339 InfoBuffer->Logon.PrimaryGroupId = FixedData.PrimaryGroupId;
5340 InfoBuffer->Logon.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5341 InfoBuffer->Logon.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5342 InfoBuffer->Logon.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5343 InfoBuffer->Logon.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5344 InfoBuffer->Logon.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5345 InfoBuffer->Logon.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5346 InfoBuffer->Logon.BadPasswordCount = FixedData.BadPasswordCount;
5347 InfoBuffer->Logon.LogonCount = FixedData.LogonCount;
5348 InfoBuffer->Logon.UserAccountControl = FixedData.UserAccountControl;
5349
5350 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5351 DomainFixedData.MinPasswordAge);
5352 InfoBuffer->Logon.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
5353 InfoBuffer->Logon.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
5354
5355 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
5356 DomainFixedData.MaxPasswordAge);
5357 InfoBuffer->Logon.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
5358 InfoBuffer->Logon.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
5359
5360 /* Get the Name string */
5361 Status = SampGetObjectAttributeString(UserObject,
5362 L"Name",
5363 &InfoBuffer->Logon.UserName);
5364 if (!NT_SUCCESS(Status))
5365 {
5366 TRACE("Status 0x%08lx\n", Status);
5367 goto done;
5368 }
5369
5370 /* Get the FullName string */
5371 Status = SampGetObjectAttributeString(UserObject,
5372 L"FullName",
5373 &InfoBuffer->Logon.FullName);
5374 if (!NT_SUCCESS(Status))
5375 {
5376 TRACE("Status 0x%08lx\n", Status);
5377 goto done;
5378 }
5379
5380 /* Get the HomeDirectory string */
5381 Status = SampGetObjectAttributeString(UserObject,
5382 L"HomeDirectory",
5383 &InfoBuffer->Logon.HomeDirectory);
5384 if (!NT_SUCCESS(Status))
5385 {
5386 TRACE("Status 0x%08lx\n", Status);
5387 goto done;
5388 }
5389
5390 /* Get the HomeDirectoryDrive string */
5391 Status = SampGetObjectAttributeString(UserObject,
5392 L"HomeDirectoryDrive",
5393 &InfoBuffer->Logon.HomeDirectoryDrive);
5394 if (!NT_SUCCESS(Status))
5395 {
5396 TRACE("Status 0x%08lx\n", Status);
5397 goto done;
5398 }
5399
5400 /* Get the ScriptPath string */
5401 Status = SampGetObjectAttributeString(UserObject,
5402 L"ScriptPath",
5403 &InfoBuffer->Logon.ScriptPath);
5404 if (!NT_SUCCESS(Status))
5405 {
5406 TRACE("Status 0x%08lx\n", Status);
5407 goto done;
5408 }
5409
5410 /* Get the ProfilePath string */
5411 Status = SampGetObjectAttributeString(UserObject,
5412 L"ProfilePath",
5413 &InfoBuffer->Logon.ProfilePath);
5414 if (!NT_SUCCESS(Status))
5415 {
5416 TRACE("Status 0x%08lx\n", Status);
5417 goto done;
5418 }
5419
5420 /* Get the WorkStations string */
5421 Status = SampGetObjectAttributeString(UserObject,
5422 L"WorkStations",
5423 &InfoBuffer->Logon.WorkStations);
5424 if (!NT_SUCCESS(Status))
5425 {
5426 TRACE("Status 0x%08lx\n", Status);
5427 goto done;
5428 }
5429
5430 /* Get the LogonHours attribute */
5431 Status = SampGetLogonHoursAttrbute(UserObject,
5432 &InfoBuffer->Logon.LogonHours);
5433 if (!NT_SUCCESS(Status))
5434 {
5435 TRACE("Status 0x%08lx\n", Status);
5436 goto done;
5437 }
5438
5439 *Buffer = InfoBuffer;
5440
5441 done:
5442 if (!NT_SUCCESS(Status))
5443 {
5444 if (InfoBuffer != NULL)
5445 {
5446 if (InfoBuffer->Logon.UserName.Buffer != NULL)
5447 midl_user_free(InfoBuffer->Logon.UserName.Buffer);
5448
5449 if (InfoBuffer->Logon.FullName.Buffer != NULL)
5450 midl_user_free(InfoBuffer->Logon.FullName.Buffer);
5451
5452 if (InfoBuffer->Logon.HomeDirectory.Buffer != NULL)
5453 midl_user_free(InfoBuffer->Logon.HomeDirectory.Buffer);
5454
5455 if (InfoBuffer->Logon.HomeDirectoryDrive.Buffer != NULL)
5456 midl_user_free(InfoBuffer->Logon.HomeDirectoryDrive.Buffer);
5457
5458 if (InfoBuffer->Logon.ScriptPath.Buffer != NULL)
5459 midl_user_free(InfoBuffer->Logon.ScriptPath.Buffer);
5460
5461 if (InfoBuffer->Logon.ProfilePath.Buffer != NULL)
5462 midl_user_free(InfoBuffer->Logon.ProfilePath.Buffer);
5463
5464 if (InfoBuffer->Logon.WorkStations.Buffer != NULL)
5465 midl_user_free(InfoBuffer->Logon.WorkStations.Buffer);
5466
5467 if (InfoBuffer->Logon.LogonHours.LogonHours != NULL)
5468 midl_user_free(InfoBuffer->Logon.LogonHours.LogonHours);
5469
5470 midl_user_free(InfoBuffer);
5471 }
5472 }
5473
5474 return Status;
5475 }
5476
5477
5478 static
5479 NTSTATUS
5480 SampQueryUserAccount(PSAM_DB_OBJECT UserObject,
5481 PSAMPR_USER_INFO_BUFFER *Buffer)
5482 {
5483 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5484 SAM_USER_FIXED_DATA FixedData;
5485 ULONG Length = 0;
5486 NTSTATUS Status;
5487
5488 *Buffer = NULL;
5489
5490 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5491 if (InfoBuffer == NULL)
5492 return STATUS_INSUFFICIENT_RESOURCES;
5493
5494 Length = sizeof(SAM_USER_FIXED_DATA);
5495 Status = SampGetObjectAttribute(UserObject,
5496 L"F",
5497 NULL,
5498 (PVOID)&FixedData,
5499 &Length);
5500 if (!NT_SUCCESS(Status))
5501 goto done;
5502
5503 InfoBuffer->Account.UserId = FixedData.UserId;
5504 InfoBuffer->Account.PrimaryGroupId = FixedData.PrimaryGroupId;
5505 InfoBuffer->Account.LastLogon.LowPart = FixedData.LastLogon.LowPart;
5506 InfoBuffer->Account.LastLogon.HighPart = FixedData.LastLogon.HighPart;
5507 InfoBuffer->Account.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
5508 InfoBuffer->Account.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
5509 InfoBuffer->Account.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
5510 InfoBuffer->Account.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
5511 InfoBuffer->Account.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
5512 InfoBuffer->Account.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
5513 InfoBuffer->Account.BadPasswordCount = FixedData.BadPasswordCount;
5514 InfoBuffer->Account.LogonCount = FixedData.LogonCount;
5515 InfoBuffer->Account.UserAccountControl = FixedData.UserAccountControl;
5516
5517 /* Get the Name string */
5518 Status = SampGetObjectAttributeString(UserObject,
5519 L"Name",
5520 &InfoBuffer->Account.UserName);
5521 if (!NT_SUCCESS(Status))
5522 {
5523 TRACE("Status 0x%08lx\n", Status);
5524 goto done;
5525 }
5526
5527 /* Get the FullName string */
5528 Status = SampGetObjectAttributeString(UserObject,
5529 L"FullName",
5530 &InfoBuffer->Account.FullName);
5531 if (!NT_SUCCESS(Status))
5532 {
5533 TRACE("Status 0x%08lx\n", Status);
5534 goto done;
5535 }
5536
5537 /* Get the HomeDirectory string */
5538 Status = SampGetObjectAttributeString(UserObject,
5539 L"HomeDirectory",
5540 &InfoBuffer->Account.HomeDirectory);
5541 if (!NT_SUCCESS(Status))
5542 {
5543 TRACE("Status 0x%08lx\n", Status);
5544 goto done;
5545 }
5546
5547 /* Get the HomeDirectoryDrive string */
5548 Status = SampGetObjectAttributeString(UserObject,
5549 L"HomeDirectoryDrive",
5550 &InfoBuffer->Account.HomeDirectoryDrive);
5551 if (!NT_SUCCESS(Status))
5552 {
5553 TRACE("Status 0x%08lx\n", Status);
5554 goto done;
5555 }
5556
5557 /* Get the ScriptPath string */
5558 Status = SampGetObjectAttributeString(UserObject,
5559 L"ScriptPath",
5560 &InfoBuffer->Account.ScriptPath);
5561 if (!NT_SUCCESS(Status))
5562 {
5563 TRACE("Status 0x%08lx\n", Status);
5564 goto done;
5565 }
5566
5567 /* Get the ProfilePath string */
5568 Status = SampGetObjectAttributeString(UserObject,
5569 L"ProfilePath",
5570 &InfoBuffer->Account.ProfilePath);
5571 if (!NT_SUCCESS(Status))
5572 {
5573 TRACE("Status 0x%08lx\n", Status);
5574 goto done;
5575 }
5576
5577 /* Get the AdminComment string */
5578 Status = SampGetObjectAttributeString(UserObject,
5579 L"AdminComment",
5580 &InfoBuffer->Account.AdminComment);
5581 if (!NT_SUCCESS(Status))
5582 {
5583 TRACE("Status 0x%08lx\n", Status);
5584 goto done;
5585 }
5586
5587 /* Get the WorkStations string */
5588 Status = SampGetObjectAttributeString(UserObject,
5589 L"WorkStations",
5590 &InfoBuffer->Account.WorkStations);
5591 if (!NT_SUCCESS(Status))
5592 {
5593 TRACE("Status 0x%08lx\n", Status);
5594 goto done;
5595 }
5596
5597 /* Get the LogonHours attribute */
5598 Status = SampGetLogonHoursAttrbute(UserObject,
5599 &InfoBuffer->Account.LogonHours);
5600 if (!NT_SUCCESS(Status))
5601 {
5602 TRACE("Status 0x%08lx\n", Status);
5603 goto done;
5604 }
5605
5606 *Buffer = InfoBuffer;
5607
5608 done:
5609 if (!NT_SUCCESS(Status))
5610 {
5611 if (InfoBuffer != NULL)
5612 {
5613 if (InfoBuffer->Account.UserName.Buffer != NULL)
5614 midl_user_free(InfoBuffer->Account.UserName.Buffer);
5615
5616 if (InfoBuffer->Account.FullName.Buffer != NULL)
5617 midl_user_free(InfoBuffer->Account.FullName.Buffer);
5618
5619 if (InfoBuffer->Account.HomeDirectory.Buffer != NULL)
5620 midl_user_free(InfoBuffer->Account.HomeDirectory.Buffer);
5621
5622 if (InfoBuffer->Account.HomeDirectoryDrive.Buffer != NULL)
5623 midl_user_free(InfoBuffer->Account.HomeDirectoryDrive.Buffer);
5624
5625 if (InfoBuffer->Account.ScriptPath.Buffer != NULL)
5626 midl_user_free(InfoBuffer->Account.ScriptPath.Buffer);
5627
5628 if (InfoBuffer->Account.ProfilePath.Buffer != NULL)
5629 midl_user_free(InfoBuffer->Account.ProfilePath.Buffer);
5630
5631 if (InfoBuffer->Account.AdminComment.Buffer != NULL)
5632 midl_user_free(InfoBuffer->Account.AdminComment.Buffer);
5633
5634 if (InfoBuffer->Account.WorkStations.Buffer != NULL)
5635 midl_user_free(InfoBuffer->Account.WorkStations.Buffer);
5636
5637 if (InfoBuffer->Account.LogonHours.LogonHours != NULL)
5638 midl_user_free(InfoBuffer->Account.LogonHours.LogonHours);
5639
5640 midl_user_free(InfoBuffer);
5641 }
5642 }
5643
5644 return Status;
5645 }
5646
5647
5648 static
5649 NTSTATUS
5650 SampQueryUserLogonHours(PSAM_DB_OBJECT UserObject,
5651 PSAMPR_USER_INFO_BUFFER *Buffer)
5652 {
5653 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5654 NTSTATUS Status;
5655
5656 TRACE("(%p %p)\n", UserObject, Buffer);
5657
5658 *Buffer = NULL;
5659
5660 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5661 if (InfoBuffer == NULL)
5662 {
5663 TRACE("Failed to allocate InfoBuffer!\n");
5664 return STATUS_INSUFFICIENT_RESOURCES;
5665 }
5666
5667 Status = SampGetLogonHoursAttrbute(UserObject,
5668 &InfoBuffer->LogonHours.LogonHours);
5669 if (!NT_SUCCESS(Status))
5670 {
5671 TRACE("SampGetLogonHoursAttrbute failed (Status 0x%08lx)\n", Status);
5672 goto done;
5673 }
5674
5675 *Buffer = InfoBuffer;
5676
5677 done:
5678 if (!NT_SUCCESS(Status))
5679 {
5680 if (InfoBuffer != NULL)
5681 {
5682 if (InfoBuffer->LogonHours.LogonHours.LogonHours != NULL)
5683 midl_user_free(InfoBuffer->LogonHours.LogonHours.LogonHours);
5684
5685 midl_user_free(InfoBuffer);
5686 }
5687 }
5688
5689 return Status;
5690 }
5691
5692
5693 static
5694 NTSTATUS
5695 SampQueryUserName(PSAM_DB_OBJECT UserObject,
5696 PSAMPR_USER_INFO_BUFFER *Buffer)
5697 {
5698 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5699 NTSTATUS Status;
5700
5701 *Buffer = NULL;
5702
5703 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5704 if (InfoBuffer == NULL)
5705 return STATUS_INSUFFICIENT_RESOURCES;
5706
5707 /* Get the Name string */
5708 Status = SampGetObjectAttributeString(UserObject,
5709 L"Name",
5710 &InfoBuffer->Name.UserName);
5711 if (!NT_SUCCESS(Status))
5712 {
5713 TRACE("Status 0x%08lx\n", Status);
5714 goto done;
5715 }
5716
5717 /* Get the FullName string */
5718 Status = SampGetObjectAttributeString(UserObject,
5719 L"FullName",
5720 &InfoBuffer->Name.FullName);
5721 if (!NT_SUCCESS(Status))
5722 {
5723 TRACE("Status 0x%08lx\n", Status);
5724 goto done;
5725 }
5726
5727 *Buffer = InfoBuffer;
5728
5729 done:
5730 if (!NT_SUCCESS(Status))
5731 {
5732 if (InfoBuffer != NULL)
5733 {
5734 if (InfoBuffer->Name.UserName.Buffer != NULL)
5735 midl_user_free(InfoBuffer->Name.UserName.Buffer);
5736
5737 if (InfoBuffer->Name.FullName.Buffer != NULL)
5738 midl_user_free(InfoBuffer->Name.FullName.Buffer);
5739
5740 midl_user_free(InfoBuffer);
5741 }
5742 }
5743
5744 return Status;
5745 }
5746
5747
5748 static NTSTATUS
5749 SampQueryUserAccountName(PSAM_DB_OBJECT UserObject,
5750 PSAMPR_USER_INFO_BUFFER *Buffer)
5751 {
5752 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5753 NTSTATUS Status;
5754
5755 *Buffer = NULL;
5756
5757 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5758 if (InfoBuffer == NULL)
5759 return STATUS_INSUFFICIENT_RESOURCES;
5760
5761 /* Get the Name string */
5762 Status = SampGetObjectAttributeString(UserObject,
5763 L"Name",
5764 &InfoBuffer->AccountName.UserName);
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->AccountName.UserName.Buffer != NULL)
5779 midl_user_free(InfoBuffer->AccountName.UserName.Buffer);
5780
5781 midl_user_free(InfoBuffer);
5782 }
5783 }
5784
5785 return Status;
5786 }
5787
5788
5789 static NTSTATUS
5790 SampQueryUserFullName(PSAM_DB_OBJECT UserObject,
5791 PSAMPR_USER_INFO_BUFFER *Buffer)
5792 {
5793 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5794 NTSTATUS Status;
5795
5796 *Buffer = NULL;
5797
5798 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5799 if (InfoBuffer == NULL)
5800 return STATUS_INSUFFICIENT_RESOURCES;
5801
5802 /* Get the FullName string */
5803 Status = SampGetObjectAttributeString(UserObject,
5804 L"FullName",
5805 &InfoBuffer->FullName.FullName);
5806 if (!NT_SUCCESS(Status))
5807 {
5808 TRACE("Status 0x%08lx\n", Status);
5809 goto done;
5810 }
5811
5812 *Buffer = InfoBuffer;
5813
5814 done:
5815 if (!NT_SUCCESS(Status))
5816 {
5817 if (InfoBuffer != NULL)
5818 {
5819 if (InfoBuffer->FullName.FullName.Buffer != NULL)
5820 midl_user_free(InfoBuffer->FullName.FullName.Buffer);
5821
5822 midl_user_free(InfoBuffer);
5823 }
5824 }
5825
5826 return Status;
5827 }
5828
5829
5830 static
5831 NTSTATUS
5832 SampQueryUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
5833 PSAMPR_USER_INFO_BUFFER *Buffer)
5834 {
5835 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5836 SAM_USER_FIXED_DATA FixedData;
5837 ULONG Length = 0;
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 Length = sizeof(SAM_USER_FIXED_DATA);
5847 Status = SampGetObjectAttribute(UserObject,
5848 L"F",
5849 NULL,
5850 (PVOID)&FixedData,
5851 &Length);
5852 if (!NT_SUCCESS(Status))
5853 goto done;
5854
5855 InfoBuffer->PrimaryGroup.PrimaryGroupId = FixedData.PrimaryGroupId;
5856
5857 *Buffer = InfoBuffer;
5858
5859 done:
5860 if (!NT_SUCCESS(Status))
5861 {
5862 if (InfoBuffer != NULL)
5863 {
5864 midl_user_free(InfoBuffer);
5865 }
5866 }
5867
5868 return Status;
5869 }
5870
5871
5872 static NTSTATUS
5873 SampQueryUserHome(PSAM_DB_OBJECT UserObject,
5874 PSAMPR_USER_INFO_BUFFER *Buffer)
5875 {
5876 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5877 NTSTATUS Status;
5878
5879 *Buffer = NULL;
5880
5881 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5882 if (InfoBuffer == NULL)
5883 return STATUS_INSUFFICIENT_RESOURCES;
5884
5885 /* Get the HomeDirectory string */
5886 Status = SampGetObjectAttributeString(UserObject,
5887 L"HomeDirectory",
5888 &InfoBuffer->Home.HomeDirectory);
5889 if (!NT_SUCCESS(Status))
5890 {
5891 TRACE("Status 0x%08lx\n", Status);
5892 goto done;
5893 }
5894
5895 /* Get the HomeDirectoryDrive string */
5896 Status = SampGetObjectAttributeString(UserObject,
5897 L"HomeDirectoryDrive",
5898 &InfoBuffer->Home.HomeDirectoryDrive);
5899 if (!NT_SUCCESS(Status))
5900 {
5901 TRACE("Status 0x%08lx\n", Status);
5902 goto done;
5903 }
5904
5905 *Buffer = InfoBuffer;
5906
5907 done:
5908 if (!NT_SUCCESS(Status))
5909 {
5910 if (InfoBuffer != NULL)
5911 {
5912 if (InfoBuffer->Home.HomeDirectory.Buffer != NULL)
5913 midl_user_free(InfoBuffer->Home.HomeDirectory.Buffer);
5914
5915 if (InfoBuffer->Home.HomeDirectoryDrive.Buffer != NULL)
5916 midl_user_free(InfoBuffer->Home.HomeDirectoryDrive.Buffer);
5917
5918 midl_user_free(InfoBuffer);
5919 }
5920 }
5921
5922 return Status;
5923 }
5924
5925
5926 static NTSTATUS
5927 SampQueryUserScript(PSAM_DB_OBJECT UserObject,
5928 PSAMPR_USER_INFO_BUFFER *Buffer)
5929 {
5930 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5931 NTSTATUS Status;
5932
5933 *Buffer = NULL;
5934
5935 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5936 if (InfoBuffer == NULL)
5937 return STATUS_INSUFFICIENT_RESOURCES;
5938
5939 /* Get the ScriptPath string */
5940 Status = SampGetObjectAttributeString(UserObject,
5941 L"ScriptPath",
5942 &InfoBuffer->Script.ScriptPath);
5943 if (!NT_SUCCESS(Status))
5944 {
5945 TRACE("Status 0x%08lx\n", Status);
5946 goto done;
5947 }
5948
5949 *Buffer = InfoBuffer;
5950
5951 done:
5952 if (!NT_SUCCESS(Status))
5953 {
5954 if (InfoBuffer != NULL)
5955 {
5956 if (InfoBuffer->Script.ScriptPath.Buffer != NULL)
5957 midl_user_free(InfoBuffer->Script.ScriptPath.Buffer);
5958
5959 midl_user_free(InfoBuffer);
5960 }
5961 }
5962
5963 return Status;
5964 }
5965
5966
5967 static NTSTATUS
5968 SampQueryUserProfile(PSAM_DB_OBJECT UserObject,
5969 PSAMPR_USER_INFO_BUFFER *Buffer)
5970 {
5971 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
5972 NTSTATUS Status;
5973
5974 *Buffer = NULL;
5975
5976 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
5977 if (InfoBuffer == NULL)
5978 return STATUS_INSUFFICIENT_RESOURCES;
5979
5980 /* Get the ProfilePath string */
5981 Status = SampGetObjectAttributeString(UserObject,
5982 L"ProfilePath",
5983 &InfoBuffer->Profile.ProfilePath);
5984 if (!NT_SUCCESS(Status))
5985 {
5986 TRACE("Status 0x%08lx\n", Status);
5987 goto done;
5988 }
5989
5990 *Buffer = InfoBuffer;
5991
5992 done:
5993 if (!NT_SUCCESS(Status))
5994 {
5995 if (InfoBuffer != NULL)
5996 {
5997 if (InfoBuffer->Profile.ProfilePath.Buffer != NULL)
5998 midl_user_free(InfoBuffer->Profile.ProfilePath.Buffer);
5999
6000 midl_user_free(InfoBuffer);
6001 }
6002 }
6003
6004 return Status;
6005 }
6006
6007
6008 static NTSTATUS
6009 SampQueryUserAdminComment(PSAM_DB_OBJECT UserObject,
6010 PSAMPR_USER_INFO_BUFFER *Buffer)
6011 {
6012 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6013 NTSTATUS Status;
6014
6015 *Buffer = NULL;
6016
6017 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6018 if (InfoBuffer == NULL)
6019 return STATUS_INSUFFICIENT_RESOURCES;
6020
6021 /* Get the AdminComment string */
6022 Status = SampGetObjectAttributeString(UserObject,
6023 L"AdminComment",
6024 &InfoBuffer->AdminComment.AdminComment);
6025 if (!NT_SUCCESS(Status))
6026 {
6027 TRACE("Status 0x%08lx\n", Status);
6028 goto done;
6029 }
6030
6031 *Buffer = InfoBuffer;
6032
6033 done:
6034 if (!NT_SUCCESS(Status))
6035 {
6036 if (InfoBuffer != NULL)
6037 {
6038 if (InfoBuffer->AdminComment.AdminComment.Buffer != NULL)
6039 midl_user_free(InfoBuffer->AdminComment.AdminComment.Buffer);
6040
6041 midl_user_free(InfoBuffer);
6042 }
6043 }
6044
6045 return Status;
6046 }
6047
6048
6049 static NTSTATUS
6050 SampQueryUserWorkStations(PSAM_DB_OBJECT UserObject,
6051 PSAMPR_USER_INFO_BUFFER *Buffer)
6052 {
6053 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6054 NTSTATUS Status;
6055
6056 *Buffer = NULL;
6057
6058 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6059 if (InfoBuffer == NULL)
6060 return STATUS_INSUFFICIENT_RESOURCES;
6061
6062 /* Get the WorkStations string */
6063 Status = SampGetObjectAttributeString(UserObject,
6064 L"WorkStations",
6065 &InfoBuffer->WorkStations.WorkStations);
6066 if (!NT_SUCCESS(Status))
6067 {
6068 TRACE("Status 0x%08lx\n", Status);
6069 goto done;
6070 }
6071
6072 *Buffer = InfoBuffer;
6073
6074 done:
6075 if (!NT_SUCCESS(Status))
6076 {
6077 if (InfoBuffer != NULL)
6078 {
6079 if (InfoBuffer->WorkStations.WorkStations.Buffer != NULL)
6080 midl_user_free(InfoBuffer->WorkStations.WorkStations.Buffer);
6081
6082 midl_user_free(InfoBuffer);
6083 }
6084 }
6085
6086 return Status;
6087 }
6088
6089
6090 static
6091 NTSTATUS
6092 SampQueryUserControl(PSAM_DB_OBJECT UserObject,
6093 PSAMPR_USER_INFO_BUFFER *Buffer)
6094 {
6095 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6096 SAM_USER_FIXED_DATA FixedData;
6097 ULONG Length = 0;
6098 NTSTATUS Status;
6099
6100 *Buffer = NULL;
6101
6102 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6103 if (InfoBuffer == NULL)
6104 return STATUS_INSUFFICIENT_RESOURCES;
6105
6106 Length = sizeof(SAM_USER_FIXED_DATA);
6107 Status = SampGetObjectAttribute(UserObject,
6108 L"F",
6109 NULL,
6110 (PVOID)&FixedData,
6111 &Length);
6112 if (!NT_SUCCESS(Status))
6113 goto done;
6114
6115 InfoBuffer->Control.UserAccountControl = FixedData.UserAccountControl;
6116
6117 *Buffer = InfoBuffer;
6118
6119 done:
6120 if (!NT_SUCCESS(Status))
6121 {
6122 if (InfoBuffer != NULL)
6123 {
6124 midl_user_free(InfoBuffer);
6125 }
6126 }
6127
6128 return Status;
6129 }
6130
6131
6132 static
6133 NTSTATUS
6134 SampQueryUserExpires(PSAM_DB_OBJECT UserObject,
6135 PSAMPR_USER_INFO_BUFFER *Buffer)
6136 {
6137 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6138 SAM_USER_FIXED_DATA FixedData;
6139 ULONG Length = 0;
6140 NTSTATUS Status;
6141
6142 *Buffer = NULL;
6143
6144 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6145 if (InfoBuffer == NULL)
6146 return STATUS_INSUFFICIENT_RESOURCES;
6147
6148 Length = sizeof(SAM_USER_FIXED_DATA);
6149 Status = SampGetObjectAttribute(UserObject,
6150 L"F",
6151 NULL,
6152 (PVOID)&FixedData,
6153 &Length);
6154 if (!NT_SUCCESS(Status))
6155 goto done;
6156
6157 InfoBuffer->Expires.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6158 InfoBuffer->Expires.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6159
6160 *Buffer = InfoBuffer;
6161
6162 done:
6163 if (!NT_SUCCESS(Status))
6164 {
6165 if (InfoBuffer != NULL)
6166 {
6167 midl_user_free(InfoBuffer);
6168 }
6169 }
6170
6171 return Status;
6172 }
6173
6174
6175 static
6176 NTSTATUS
6177 SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
6178 PSAMPR_USER_INFO_BUFFER *Buffer)
6179 {
6180 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6181 ULONG Length = 0;
6182 NTSTATUS Status = STATUS_SUCCESS;
6183
6184 /* Fail, if the caller is not a trusted caller */
6185 if (UserObject->Trusted == FALSE)
6186 return STATUS_INVALID_INFO_CLASS;
6187
6188 *Buffer = NULL;
6189
6190 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6191 if (InfoBuffer == NULL)
6192 return STATUS_INSUFFICIENT_RESOURCES;
6193
6194 /* Get the NT password */
6195 Length = 0;
6196 SampGetObjectAttribute(UserObject,
6197 L"NTPwd",
6198 NULL,
6199 NULL,
6200 &Length);
6201
6202 if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
6203 {
6204 Status = SampGetObjectAttribute(UserObject,
6205 L"NTPwd",
6206 NULL,
6207 (PVOID)&InfoBuffer->Internal1.EncryptedNtOwfPassword,
6208 &Length);
6209 if (!NT_SUCCESS(Status))
6210 goto done;
6211 }
6212
6213 InfoBuffer->Internal1.NtPasswordPresent = (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD));
6214
6215 /* Get the LM password */
6216 Length = 0;
6217 SampGetObjectAttribute(UserObject,
6218 L"LMPwd",
6219 NULL,
6220 NULL,
6221 &Length);
6222
6223 if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
6224 {
6225 Status = SampGetObjectAttribute(UserObject,
6226 L"LMPwd",
6227 NULL,
6228 (PVOID)&InfoBuffer->Internal1.EncryptedLmOwfPassword,
6229 &Length);
6230 if (!NT_SUCCESS(Status))
6231 goto done;
6232 }
6233
6234 InfoBuffer->Internal1.LmPasswordPresent = (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD));
6235
6236 InfoBuffer->Internal1.PasswordExpired = FALSE;
6237
6238 *Buffer = InfoBuffer;
6239
6240 done:
6241 if (!NT_SUCCESS(Status))
6242 {
6243 if (InfoBuffer != NULL)
6244 {
6245 midl_user_free(InfoBuffer);
6246 }
6247 }
6248
6249 return Status;
6250 }
6251
6252
6253 static NTSTATUS
6254 SampQueryUserParameters(PSAM_DB_OBJECT UserObject,
6255 PSAMPR_USER_INFO_BUFFER *Buffer)
6256 {
6257 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6258 NTSTATUS Status;
6259
6260 *Buffer = NULL;
6261
6262 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6263 if (InfoBuffer == NULL)
6264 return STATUS_INSUFFICIENT_RESOURCES;
6265
6266 /* Get the Parameters string */
6267 Status = SampGetObjectAttributeString(UserObject,
6268 L"Parameters",
6269 &InfoBuffer->Parameters.Parameters);
6270 if (!NT_SUCCESS(Status))
6271 {
6272 TRACE("Status 0x%08lx\n", Status);
6273 goto done;
6274 }
6275
6276 *Buffer = InfoBuffer;
6277
6278 done:
6279 if (!NT_SUCCESS(Status))
6280 {
6281 if (InfoBuffer != NULL)
6282 {
6283 if (InfoBuffer->Parameters.Parameters.Buffer != NULL)
6284 midl_user_free(InfoBuffer->Parameters.Parameters.Buffer);
6285
6286 midl_user_free(InfoBuffer);
6287 }
6288 }
6289
6290 return Status;
6291 }
6292
6293
6294 static NTSTATUS
6295 SampQueryUserAll(PSAM_DB_OBJECT UserObject,
6296 PSAMPR_USER_INFO_BUFFER *Buffer)
6297 {
6298 PSAMPR_USER_INFO_BUFFER InfoBuffer = NULL;
6299 SAM_DOMAIN_FIXED_DATA DomainFixedData;
6300 SAM_USER_FIXED_DATA FixedData;
6301 LARGE_INTEGER PasswordCanChange;
6302 LARGE_INTEGER PasswordMustChange;
6303 ULONG Length = 0;
6304 NTSTATUS Status;
6305
6306 *Buffer = NULL;
6307
6308 InfoBuffer = midl_user_allocate(sizeof(SAMPR_USER_INFO_BUFFER));
6309 if (InfoBuffer == NULL)
6310 return STATUS_INSUFFICIENT_RESOURCES;
6311
6312 /* Get the fixed size domain data */
6313 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
6314 Status = SampGetObjectAttribute(UserObject->ParentObject,
6315 L"F",
6316 NULL,
6317 (PVOID)&DomainFixedData,
6318 &Length);
6319 if (!NT_SUCCESS(Status))
6320 goto done;
6321
6322 /* Get the fixed size user data */
6323 Length = sizeof(SAM_USER_FIXED_DATA);
6324 Status = SampGetObjectAttribute(UserObject,
6325 L"F",
6326 NULL,
6327 (PVOID)&FixedData,
6328 &Length);
6329 if (!NT_SUCCESS(Status))
6330 goto done;
6331
6332 if (UserObject->Access & USER_READ_GENERAL)
6333 {
6334 /* Get the Name string */
6335 Status = SampGetObjectAttributeString(UserObject,
6336 L"Name",
6337 &InfoBuffer->All.UserName);
6338 if (!NT_SUCCESS(Status))
6339 {
6340 TRACE("Status 0x%08lx\n", Status);
6341 goto done;
6342 }
6343
6344 /* Get the FullName string */
6345 Status = SampGetObjectAttributeString(UserObject,
6346 L"FullName",
6347 &InfoBuffer->All.FullName);
6348 if (!NT_SUCCESS(Status))
6349 {
6350 TRACE("Status 0x%08lx\n", Status);
6351 goto done;
6352 }
6353
6354 /* Get the user ID*/
6355 InfoBuffer->All.UserId = FixedData.UserId;
6356
6357 /* Get the primary group ID */
6358 InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
6359
6360 /* Get the AdminComment string */
6361 Status = SampGetObjectAttributeString(UserObject,
6362 L"AdminComment",
6363 &InfoBuffer->All.AdminComment);
6364 if (!NT_SUCCESS(Status))
6365 {
6366 TRACE("Status 0x%08lx\n", Status);
6367 goto done;
6368 }
6369
6370 /* Get the UserComment string */
6371 Status = SampGetObjectAttributeString(UserObject,
6372 L"UserComment",
6373 &InfoBuffer->All.UserComment);
6374 if (!NT_SUCCESS(Status))
6375 {
6376 TRACE("Status 0x%08lx\n", Status);
6377 goto done;
6378 }
6379
6380 InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
6381 // USER_ALL_USERNAME |
6382 // USER_ALL_FULLNAME |
6383 // USER_ALL_USERID |
6384 // USER_ALL_PRIMARYGROUPID |
6385 // USER_ALL_ADMINCOMMENT |
6386 // USER_ALL_USERCOMMENT;
6387 }
6388
6389 if (UserObject->Access & USER_READ_LOGON)
6390 {
6391 /* Get the HomeDirectory string */
6392 Status = SampGetObjectAttributeString(UserObject,
6393 L"HomeDirectory",
6394 &InfoBuffer->All.HomeDirectory);
6395 if (!NT_SUCCESS(Status))
6396 {
6397 TRACE("Status 0x%08lx\n", Status);
6398 goto done;
6399 }
6400
6401 /* Get the HomeDirectoryDrive string */
6402 Status = SampGetObjectAttributeString(UserObject,
6403 L"HomeDirectoryDrive",
6404 &InfoBuffer->Home.HomeDirectoryDrive);
6405 if (!NT_SUCCESS(Status))
6406 {
6407 TRACE("Status 0x%08lx\n", Status);
6408 goto done;
6409 }
6410
6411 /* Get the ScriptPath string */
6412 Status = SampGetObjectAttributeString(UserObject,
6413 L"ScriptPath",
6414 &InfoBuffer->All.ScriptPath);
6415 if (!NT_SUCCESS(Status))
6416 {
6417 TRACE("Status 0x%08lx\n", Status);
6418 goto done;
6419 }
6420
6421 /* Get the ProfilePath string */
6422 Status = SampGetObjectAttributeString(UserObject,
6423 L"ProfilePath",
6424 &InfoBuffer->All.ProfilePath);
6425 if (!NT_SUCCESS(Status))
6426 {
6427 TRACE("Status 0x%08lx\n", Status);
6428 goto done;
6429 }
6430
6431 /* Get the WorkStations string */
6432 Status = SampGetObjectAttributeString(UserObject,
6433 L"WorkStations",
6434 &InfoBuffer->All.WorkStations);
6435 if (!NT_SUCCESS(Status))
6436 {
6437 TRACE("Status 0x%08lx\n", Status);
6438 goto done;
6439 }
6440
6441 /* Get the LogonHours attribute */
6442 Status = SampGetLogonHoursAttrbute(UserObject,
6443 &InfoBuffer->All.LogonHours);
6444 if (!NT_SUCCESS(Status))
6445 {
6446 TRACE("Status 0x%08lx\n", Status);
6447 goto done;
6448 }
6449
6450 InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
6451 InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
6452
6453 InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
6454 InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
6455
6456 InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
6457
6458 InfoBuffer->All.LogonCount = FixedData.LogonCount;
6459
6460 PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
6461 DomainFixedData.MinPasswordAge);
6462 InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
6463 InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
6464
6465 PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
6466 DomainFixedData.MaxPasswordAge);
6467 InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
6468 InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
6469
6470 InfoBuffer->All. WhichFields |= USER_ALL_READ_LOGON_MASK;
6471 /*
6472 USER_ALL_HOMEDIRECTORY |
6473 USER_ALL_HOMEDIRECTORYDRIVE |
6474 USER_ALL_SCRIPTPATH |
6475 USER_ALL_PROFILEPATH |
6476 USER_ALL_WORKSTATIONS |
6477 USER_ALL_LASTLOGON |
6478 USER_ALL_LASTLOGOFF |
6479 USER_ALL_LOGONHOURS |
6480 USER_ALL_BADPASSWORDCOUNT |
6481 USER_ALL_LOGONCOUNT;
6482 USER_ALL_PASSWORDCANCHANGE |
6483 USER_ALL_PASSWORDMUSTCHANGE;
6484 */
6485 }
6486
6487 if (UserObject->Access & USER_READ_ACCOUNT)
6488 {
6489 InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
6490 InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
6491
6492 InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
6493 InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
6494
6495 InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
6496
6497 /* Get the Parameters string */
6498 Status = SampGetObjectAttributeString(UserObject,
6499 L"Parameters",
6500 &InfoBuffer->All.Parameters);
6501 if (!NT_SUCCESS(Status))
6502 {
6503 TRACE("Status 0x%08lx\n", Status);
6504 goto done;
6505 }
6506
6507 InfoBuffer->All. WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
6508 // USER_ALL_PASSWORDLASTSET |
6509 // USER_ALL_ACCOUNTEXPIRES |
6510 // USER_ALL_USERACCOUNTCONTROL |
6511 // USER_ALL_PARAMETERS;
6512 }
6513
6514 if (UserObject->Access & USER_READ_PREFERENCES)
6515 {
6516 InfoBuffer->All.CountryCode = FixedData.CountryCode;
6517
6518 InfoBuffer->All.CodePage = FixedData.CodePage;
6519
6520 InfoBuffer->All. WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
6521 // USER_ALL_COUNTRYCODE |
6522 // USER_ALL_CODEPAGE;
6523 }
6524
6525 *Buffer = InfoBuffer;
6526
6527 done:
6528 if (!NT_SUCCESS(Status))
6529 {
6530 if (InfoBuffer != NULL)
6531 {
6532 if (InfoBuffer->All.UserName.Buffer != NULL)
6533 midl_user_free(InfoBuffer->All.UserName.Buffer);
6534
6535 if (InfoBuffer->All.FullName.Buffer != NULL)
6536 midl_user_free(InfoBuffer->All.FullName.Buffer);
6537
6538 if (InfoBuffer->All.AdminComment.Buffer != NULL)
6539 midl_user_free(InfoBuffer->All.AdminComment.Buffer);
6540
6541 if (InfoBuffer->All.UserComment.Buffer != NULL)
6542 midl_user_free(InfoBuffer->All.UserComment.Buffer);
6543
6544 if (InfoBuffer->All.HomeDirectory.Buffer != NULL)
6545 midl_user_free(InfoBuffer->All.HomeDirectory.Buffer);
6546
6547 if (InfoBuffer->All.HomeDirectoryDrive.Buffer != NULL)
6548 midl_user_free(InfoBuffer->All.HomeDirectoryDrive.Buffer);
6549
6550 if (InfoBuffer->All.ScriptPath.Buffer != NULL)
6551 midl_user_free(InfoBuffer->All.ScriptPath.Buffer);
6552
6553 if (InfoBuffer->All.ProfilePath.Buffer != NULL)
6554 midl_user_free(InfoBuffer->All.ProfilePath.Buffer);
6555
6556 if (InfoBuffer->All.WorkStations.Buffer != NULL)
6557 midl_user_free(InfoBuffer->All.WorkStations.Buffer);
6558
6559 if (InfoBuffer->All.LogonHours.LogonHours != NULL)
6560 midl_user_free(InfoBuffer->All.LogonHours.LogonHours);
6561
6562 if (InfoBuffer->All.Parameters.Buffer != NULL)
6563 midl_user_free(InfoBuffer->All.Parameters.Buffer);
6564
6565 midl_user_free(InfoBuffer);
6566 }
6567 }
6568
6569 return Status;
6570 }
6571
6572
6573 /* Function 36 */
6574 NTSTATUS
6575 NTAPI
6576 SamrQueryInformationUser(IN SAMPR_HANDLE UserHandle,
6577 IN USER_INFORMATION_CLASS UserInformationClass,
6578 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
6579 {
6580 PSAM_DB_OBJECT UserObject;
6581 ACCESS_MASK DesiredAccess;
6582 NTSTATUS Status;
6583
6584 TRACE("SamrQueryInformationUser(%p %lu %p)\n",
6585 UserHandle, UserInformationClass, Buffer);
6586
6587 switch (UserInformationClass)
6588 {
6589 case UserGeneralInformation:
6590 case UserNameInformation:
6591 case UserAccountNameInformation:
6592 case UserFullNameInformation:
6593 case UserPrimaryGroupInformation:
6594 case UserAdminCommentInformation:
6595 DesiredAccess = USER_READ_GENERAL;
6596 break;
6597
6598 case UserLogonHoursInformation:
6599 case UserHomeInformation:
6600 case UserScriptInformation:
6601 case UserProfileInformation:
6602 case UserWorkStationsInformation:
6603 DesiredAccess = USER_READ_LOGON;
6604 break;
6605
6606 case UserControlInformation:
6607 case UserExpiresInformation:
6608 case UserParametersInformation:
6609 DesiredAccess = USER_READ_ACCOUNT;
6610 break;
6611
6612 case UserPreferencesInformation:
6613 DesiredAccess = USER_READ_GENERAL |
6614 USER_READ_PREFERENCES;
6615 break;
6616
6617 case UserLogonInformation:
6618 case UserAccountInformation:
6619 DesiredAccess = USER_READ_GENERAL |
6620 USER_READ_PREFERENCES |
6621 USER_READ_LOGON |
6622 USER_READ_ACCOUNT;
6623 break;
6624
6625 case UserInternal1Information:
6626 case UserAllInformation:
6627 DesiredAccess = 0;
6628 break;
6629
6630 default:
6631 return STATUS_INVALID_INFO_CLASS;
6632 }
6633
6634 /* Validate the domain handle */
6635 Status = SampValidateDbObject(UserHandle,
6636 SamDbUserObject,
6637 DesiredAccess,
6638 &UserObject);
6639 if (!NT_SUCCESS(Status))
6640 {
6641 TRACE("failed with status 0x%08lx\n", Status);
6642 return Status;
6643 }
6644
6645 switch (UserInformationClass)
6646 {
6647 case UserGeneralInformation:
6648 Status = SampQueryUserGeneral(UserObject,
6649 Buffer);
6650 break;
6651
6652 case UserPreferencesInformation:
6653 Status = SampQueryUserPreferences(UserObject,
6654 Buffer);
6655 break;
6656
6657 case UserLogonInformation:
6658 Status = SampQueryUserLogon(UserObject,
6659 Buffer);
6660 break;
6661
6662 case UserLogonHoursInformation:
6663 Status = SampQueryUserLogonHours(UserObject,
6664 Buffer);
6665 break;
6666
6667 case UserAccountInformation:
6668 Status = SampQueryUserAccount(UserObject,
6669 Buffer);
6670 break;
6671
6672 case UserNameInformation:
6673 Status = SampQueryUserName(UserObject,
6674 Buffer);
6675 break;
6676
6677 case UserAccountNameInformation:
6678 Status = SampQueryUserAccountName(UserObject,
6679 Buffer);
6680 break;
6681
6682 case UserFullNameInformation:
6683 Status = SampQueryUserFullName(UserObject,
6684 Buffer);
6685 break;
6686
6687 case UserPrimaryGroupInformation:
6688 Status = SampQueryUserPrimaryGroup(UserObject,
6689 Buffer);
6690 break;
6691
6692 case UserHomeInformation:
6693 Status = SampQueryUserHome(UserObject,
6694 Buffer);
6695
6696 case UserScriptInformation:
6697 Status = SampQueryUserScript(UserObject,
6698 Buffer);
6699 break;
6700
6701 case UserProfileInformation:
6702 Status = SampQueryUserProfile(UserObject,
6703 Buffer);
6704 break;
6705
6706 case UserAdminCommentInformation:
6707 Status = SampQueryUserAdminComment(UserObject,
6708 Buffer);
6709 break;
6710
6711 case UserWorkStationsInformation:
6712 Status = SampQueryUserWorkStations(UserObject,
6713 Buffer);
6714 break;
6715
6716 case UserControlInformation:
6717 Status = SampQueryUserControl(UserObject,
6718 Buffer);
6719 break;
6720
6721 case UserExpiresInformation:
6722 Status = SampQueryUserExpires(UserObject,
6723 Buffer);
6724 break;
6725
6726 case UserInternal1Information:
6727 Status = SampQueryUserInternal1(UserObject,
6728 Buffer);
6729 break;
6730
6731 case UserParametersInformation:
6732 Status = SampQueryUserParameters(UserObject,
6733 Buffer);
6734 break;
6735
6736 case UserAllInformation:
6737 Status = SampQueryUserAll(UserObject,
6738 Buffer);
6739 break;
6740
6741 // case UserInternal4Information:
6742 // case UserInternal5Information:
6743 // case UserInternal4InformationNew:
6744 // case UserInternal5InformationNew:
6745
6746 default:
6747 Status = STATUS_INVALID_INFO_CLASS;
6748 }
6749
6750 return Status;
6751 }
6752
6753
6754 static NTSTATUS
6755 SampSetUserName(PSAM_DB_OBJECT UserObject,
6756 PRPC_UNICODE_STRING NewUserName)
6757 {
6758 UNICODE_STRING OldUserName = {0, 0, NULL};
6759 NTSTATUS Status;
6760
6761 Status = SampGetObjectAttributeString(UserObject,
6762 L"Name",
6763 (PRPC_UNICODE_STRING)&OldUserName);
6764 if (!NT_SUCCESS(Status))
6765 {
6766 TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
6767 goto done;
6768 }
6769
6770 if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
6771 {
6772 Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
6773 NewUserName->Buffer);
6774 if (!NT_SUCCESS(Status))
6775 {
6776 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
6777 NewUserName->Buffer, Status);
6778 goto done;
6779 }
6780 }
6781
6782 Status = SampSetAccountNameInDomain(UserObject->ParentObject,
6783 L"Users",
6784 NewUserName->Buffer,
6785 UserObject->RelativeId);
6786 if (!NT_SUCCESS(Status))
6787 {
6788 TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
6789 goto done;
6790 }
6791
6792 Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
6793 L"Users",
6794 OldUserName.Buffer);
6795 if (!NT_SUCCESS(Status))
6796 {
6797 TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
6798 goto done;
6799 }
6800
6801 Status = SampSetObjectAttribute(UserObject,
6802 L"Name",
6803 REG_SZ,
6804 NewUserName->Buffer,
6805 NewUserName->Length + sizeof(WCHAR));
6806 if (!NT_SUCCESS(Status))
6807 {
6808 TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
6809 }
6810
6811 done:
6812 if (OldUserName.Buffer != NULL)
6813 midl_user_free(OldUserName.Buffer);
6814
6815 return Status;
6816 }
6817
6818
6819 static NTSTATUS
6820 SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
6821 PSAMPR_USER_INFO_BUFFER Buffer)
6822 {
6823 SAM_USER_FIXED_DATA FixedData;
6824 ULONG Length = 0;
6825 NTSTATUS Status;
6826
6827 Length = sizeof(SAM_USER_FIXED_DATA);
6828 Status = SampGetObjectAttribute(UserObject,
6829 L"F",
6830 NULL,
6831 (PVOID)&FixedData,
6832 &Length);
6833 if (!NT_SUCCESS(Status))
6834 goto done;
6835
6836 FixedData.PrimaryGroupId = Buffer->General.PrimaryGroupId;
6837
6838 Status = SampSetObjectAttribute(UserObject,
6839 L"F",
6840 REG_BINARY,
6841 &FixedData,
6842 Length);
6843 if (!NT_SUCCESS(Status))
6844 goto done;
6845
6846 Status = SampSetUserName(UserObject,
6847 &Buffer->General.UserName);
6848 if (!NT_SUCCESS(Status))
6849 goto done;
6850
6851 Status = SampSetObjectAttribute(UserObject,
6852 L"FullName",
6853 REG_SZ,
6854 Buffer->General.FullName.Buffer,
6855 Buffer->General.FullName.MaximumLength);
6856 if (!NT_SUCCESS(Status))
6857 goto done;
6858
6859 Status = SampSetObjectAttribute(UserObject,
6860 L"AdminComment",
6861 REG_SZ,
6862 Buffer->General.AdminComment.Buffer,
6863 Buffer->General.AdminComment.MaximumLength);
6864 if (!NT_SUCCESS(Status))
6865 goto done;
6866
6867 Status = SampSetObjectAttribute(UserObject,
6868 L"UserComment",
6869 REG_SZ,
6870 Buffer->General.UserComment.Buffer,
6871 Buffer->General.UserComment.MaximumLength);
6872
6873 done:
6874 return Status;
6875 }
6876
6877
6878 static NTSTATUS
6879 SampSetUserPreferences(PSAM_DB_OBJECT UserObject,
6880 PSAMPR_USER_INFO_BUFFER Buffer)
6881 {
6882 SAM_USER_FIXED_DATA FixedData;
6883 ULONG Length = 0;
6884 NTSTATUS Status;
6885
6886 Length = sizeof(SAM_USER_FIXED_DATA);
6887 Status = SampGetObjectAttribute(UserObject,
6888 L"F",
6889 NULL,
6890 (PVOID)&FixedData,
6891 &Length);
6892 if (!NT_SUCCESS(Status))
6893 goto done;
6894
6895 FixedData.CountryCode = Buffer->Preferences.CountryCode;
6896 FixedData.CodePage = Buffer->Preferences.CodePage;
6897
6898 Status = SampSetObjectAttribute(UserObject,
6899 L"F",
6900 REG_BINARY,
6901 &FixedData,
6902 Length);
6903 if (!NT_SUCCESS(Status))
6904 goto done;
6905
6906 Status = SampSetObjectAttribute(UserObject,
6907 L"UserComment",
6908 REG_SZ,
6909 Buffer->Preferences.UserComment.Buffer,
6910 Buffer->Preferences.UserComment.MaximumLength);
6911
6912 done:
6913 return Status;
6914 }
6915
6916
6917 static NTSTATUS
6918 SampSetUserPrimaryGroup(PSAM_DB_OBJECT UserObject,
6919 PSAMPR_USER_INFO_BUFFER Buffer)
6920 {
6921 SAM_USER_FIXED_DATA FixedData;
6922 ULONG Length = 0;
6923 NTSTATUS Status;
6924
6925 Length = sizeof(SAM_USER_FIXED_DATA);
6926 Status = SampGetObjectAttribute(UserObject,
6927 L"F",
6928 NULL,
6929 (PVOID)&FixedData,
6930 &Length);
6931 if (!NT_SUCCESS(Status))
6932 goto done;
6933
6934 FixedData.PrimaryGroupId = Buffer->PrimaryGroup.PrimaryGroupId;
6935
6936 Status = SampSetObjectAttribute(UserObject,
6937 L"F",
6938 REG_BINARY,
6939 &FixedData,
6940 Length);
6941
6942 done:
6943 return Status;
6944 }
6945
6946
6947 static NTSTATUS
6948 SampSetUserControl(PSAM_DB_OBJECT UserObject,
6949 PSAMPR_USER_INFO_BUFFER Buffer)
6950 {
6951 SAM_USER_FIXED_DATA FixedData;
6952 ULONG Length = 0;
6953 NTSTATUS Status;
6954
6955 Length = sizeof(SAM_USER_FIXED_DATA);
6956 Status = SampGetObjectAttribute(UserObject,
6957 L"F",
6958 NULL,
6959 (PVOID)&FixedData,
6960 &Length);
6961 if (!NT_SUCCESS(Status))
6962 goto done;
6963
6964 FixedData.UserAccountControl = Buffer->Control.UserAccountControl;
6965
6966 Status = SampSetObjectAttribute(UserObject,
6967 L"F",
6968 REG_BINARY,
6969 &FixedData,
6970 Length);
6971
6972 done:
6973 return Status;
6974 }
6975
6976
6977 static NTSTATUS
6978 SampSetUserExpires(PSAM_DB_OBJECT UserObject,
6979 PSAMPR_USER_INFO_BUFFER Buffer)
6980 {
6981 SAM_USER_FIXED_DATA FixedData;
6982 ULONG Length = 0;
6983 NTSTATUS Status;
6984
6985 Length = sizeof(SAM_USER_FIXED_DATA);
6986 Status = SampGetObjectAttribute(UserObject,
6987 L"F",
6988 NULL,
6989 (PVOID)&FixedData,
6990 &Length);
6991 if (!NT_SUCCESS(Status))
6992 goto done;
6993
6994 FixedData.AccountExpires.LowPart = Buffer->Expires.AccountExpires.LowPart;
6995 FixedData.AccountExpires.HighPart = Buffer->Expires.AccountExpires.HighPart;
6996
6997 Status = SampSetObjectAttribute(UserObject,
6998 L"F",
6999 REG_BINARY,
7000 &FixedData,
7001 Length);
7002
7003 done:
7004 return Status;
7005 }
7006
7007
7008 static NTSTATUS
7009 SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
7010 PSAMPR_USER_INFO_BUFFER Buffer)
7011 {
7012 SAM_USER_FIXED_DATA FixedData;
7013 ULONG Length = 0;
7014 NTSTATUS Status = STATUS_SUCCESS;
7015
7016 /* FIXME: Decrypt NT password */
7017 /* FIXME: Decrypt LM password */
7018
7019 Status = SampSetUserPassword(UserObject,
7020 &Buffer->Internal1.EncryptedNtOwfPassword,
7021 Buffer->Internal1.NtPasswordPresent,
7022 &Buffer->Internal1.EncryptedLmOwfPassword,
7023 Buffer->Internal1.LmPasswordPresent);
7024 if (!NT_SUCCESS(Status))
7025 goto done;
7026
7027 /* Get the fixed user attributes */
7028 Length = sizeof(SAM_USER_FIXED_DATA);
7029 Status = SampGetObjectAttribute(UserObject,
7030 L"F",
7031 NULL,
7032 (PVOID)&FixedData,
7033 &Length);
7034 if (!NT_SUCCESS(Status))
7035 goto done;
7036
7037 if (Buffer->Internal1.PasswordExpired)
7038 {
7039 /* The pasword was last set ages ago */
7040 FixedData.PasswordLastSet.LowPart = 0;
7041 FixedData.PasswordLastSet.HighPart = 0;
7042 }
7043 else
7044 {
7045 /* The pasword was last set right now */
7046 Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
7047 if (!NT_SUCCESS(Status))
7048 goto done;
7049 }
7050
7051 /* Set the fixed user attributes */
7052 Status = SampSetObjectAttribute(UserObject,
7053 L"F",
7054 REG_BINARY,
7055 &FixedData,
7056 Length);
7057
7058 done:
7059 return Status;
7060 }
7061
7062
7063 static NTSTATUS
7064 SampSetUserAll(PSAM_DB_OBJECT UserObject,
7065 PSAMPR_USER_INFO_BUFFER Buffer)
7066 {
7067 SAM_USER_FIXED_DATA FixedData;
7068 ULONG Length = 0;
7069 ULONG WhichFields;
7070 NTSTATUS Status = STATUS_SUCCESS;
7071
7072 WhichFields = Buffer->All.WhichFields;
7073
7074 if (WhichFields & USER_ALL_USERNAME)
7075 {
7076 Status = SampSetUserName(UserObject,
7077 &Buffer->All.UserName);
7078 if (!NT_SUCCESS(Status))
7079 goto done;
7080 }
7081
7082 if (WhichFields & USER_ALL_FULLNAME)
7083 {
7084 Status = SampSetObjectAttribute(UserObject,
7085 L"FullName",
7086 REG_SZ,
7087 Buffer->All.FullName.Buffer,
7088 Buffer->All.FullName.MaximumLength);
7089 if (!NT_SUCCESS(Status))
7090 goto done;
7091 }
7092
7093 if (WhichFields & USER_ALL_ADMINCOMMENT)
7094 {
7095 Status = SampSetObjectAttribute(UserObject,
7096 L"AdminComment",
7097 REG_SZ,
7098 Buffer->All.AdminComment.Buffer,
7099 Buffer->All.AdminComment.MaximumLength);
7100 if (!NT_SUCCESS(Status))
7101 goto done;
7102 }
7103
7104 if (WhichFields & USER_ALL_USERCOMMENT)
7105 {
7106 Status = SampSetObjectAttribute(UserObject,
7107 L"UserComment",
7108 REG_SZ,
7109 Buffer->All.UserComment.Buffer,
7110 Buffer->All.UserComment.MaximumLength);
7111 if (!NT_SUCCESS(Status))
7112 goto done;
7113 }
7114
7115 if (WhichFields & USER_ALL_HOMEDIRECTORY)
7116 {
7117 Status = SampSetObjectAttribute(UserObject,
7118 L"HomeDirectory",
7119 REG_SZ,
7120 Buffer->All.HomeDirectory.Buffer,
7121 Buffer->All.HomeDirectory.MaximumLength);
7122 if (!NT_SUCCESS(Status))
7123 goto done;
7124 }
7125
7126 if (WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
7127 {
7128 Status = SampSetObjectAttribute(UserObject,
7129 L"HomeDirectoryDrive",
7130 REG_SZ,
7131 Buffer->All.HomeDirectoryDrive.Buffer,
7132 Buffer->All.HomeDirectoryDrive.MaximumLength);
7133 if (!NT_SUCCESS(Status))
7134 goto done;
7135 }
7136
7137 if (WhichFields & USER_ALL_SCRIPTPATH)
7138 {
7139 Status = SampSetObjectAttribute(UserObject,
7140 L"ScriptPath",
7141 REG_SZ,
7142 Buffer->All.ScriptPath.Buffer,
7143 Buffer->All.ScriptPath.MaximumLength);
7144 if (!NT_SUCCESS(Status))
7145 goto done;
7146 }
7147
7148 if (WhichFields & USER_ALL_PROFILEPATH)
7149 {
7150 Status = SampSetObjectAttribute(UserObject,
7151 L"ProfilePath",
7152 REG_SZ,
7153 Buffer->All.ProfilePath.Buffer,
7154 Buffer->All.ProfilePath.MaximumLength);
7155 if (!NT_SUCCESS(Status))
7156 goto done;
7157 }
7158
7159 if (WhichFields & USER_ALL_WORKSTATIONS)
7160 {
7161 Status = SampSetObjectAttribute(UserObject,
7162 L"WorkStations",
7163 REG_SZ,
7164 Buffer->All.WorkStations.Buffer,
7165 Buffer->All.WorkStations.MaximumLength);
7166 if (!NT_SUCCESS(Status))
7167 goto done;
7168 }
7169
7170 if (WhichFields & USER_ALL_PARAMETERS)
7171 {
7172 Status = SampSetObjectAttribute(UserObject,
7173 L"Parameters",
7174 REG_SZ,
7175 Buffer->All.Parameters.Buffer,
7176 Buffer->All.Parameters.MaximumLength);
7177 if (!NT_SUCCESS(Status))
7178 goto done;
7179 }
7180
7181 if (WhichFields & USER_ALL_LOGONHOURS)
7182 {
7183 Status = SampSetLogonHoursAttrbute(UserObject,
7184 &Buffer->All.LogonHours);
7185 if (!NT_SUCCESS(Status))
7186 goto done;
7187 }
7188
7189 if (WhichFields & (USER_ALL_PRIMARYGROUPID |
7190 USER_ALL_ACCOUNTEXPIRES |
7191 USER_ALL_USERACCOUNTCONTROL |
7192 USER_ALL_COUNTRYCODE |
7193 USER_ALL_CODEPAGE))
7194 {
7195 Length = sizeof(SAM_USER_FIXED_DATA);
7196 Status = SampGetObjectAttribute(UserObject,
7197 L"F",
7198 NULL,
7199 (PVOID)&FixedData,
7200 &Length);
7201 if (!NT_SUCCESS(Status))
7202 goto done;
7203
7204 if (WhichFields & USER_ALL_PRIMARYGROUPID)
7205 FixedData.PrimaryGroupId = Buffer->All.PrimaryGroupId;
7206
7207 if (WhichFields & USER_ALL_ACCOUNTEXPIRES)
7208 {
7209 FixedData.AccountExpires.LowPart = Buffer->All.AccountExpires.LowPart;
7210 FixedData.AccountExpires.HighPart = Buffer->All.AccountExpires.HighPart;
7211 }
7212
7213 if (WhichFields & USER_ALL_USERACCOUNTCONTROL)
7214 FixedData.UserAccountControl = Buffer->All.UserAccountControl;
7215
7216 if (WhichFields & USER_ALL_COUNTRYCODE)
7217 FixedData.CountryCode = Buffer->Preferences.CountryCode;
7218
7219 if (WhichFields & USER_ALL_CODEPAGE)
7220 FixedData.CodePage = Buffer->Preferences.CodePage;
7221
7222 Status = SampSetObjectAttribute(UserObject,
7223 L"F",
7224 REG_BINARY,
7225 &FixedData,
7226 Length);
7227 if (!NT_SUCCESS(Status))
7228 goto done;
7229 }
7230
7231 /*
7232 FIXME:
7233 USER_ALL_NTPASSWORDPRESENT
7234 USER_ALL_LMPASSWORDPRESENT
7235 USER_ALL_PASSWORDEXPIRED
7236 */
7237
7238 done:
7239
7240 return Status;
7241 }
7242
7243
7244 /* Function 37 */
7245 NTSTATUS
7246 NTAPI
7247 SamrSetInformationUser(IN SAMPR_HANDLE UserHandle,
7248 IN USER_INFORMATION_CLASS UserInformationClass,
7249 IN PSAMPR_USER_INFO_BUFFER Buffer)
7250 {
7251 PSAM_DB_OBJECT UserObject;
7252 ACCESS_MASK DesiredAccess;
7253 NTSTATUS Status;
7254
7255 TRACE("SamrSetInformationUser(%p %lu %p)\n",
7256 UserHandle, UserInformationClass, Buffer);
7257
7258 switch (UserInformationClass)
7259 {
7260 case UserLogonHoursInformation:
7261 case UserNameInformation:
7262 case UserAccountNameInformation:
7263 case UserFullNameInformation:
7264 case UserPrimaryGroupInformation:
7265 case UserHomeInformation:
7266 case UserScriptInformation:
7267 case UserProfileInformation:
7268 case UserAdminCommentInformation:
7269 case UserWorkStationsInformation:
7270 case UserControlInformation:
7271 case UserExpiresInformation:
7272 case UserParametersInformation:
7273 DesiredAccess = USER_WRITE_ACCOUNT;
7274 break;
7275
7276 case UserGeneralInformation:
7277 DesiredAccess = USER_WRITE_ACCOUNT |
7278 USER_WRITE_PREFERENCES;
7279 break;
7280
7281 case UserPreferencesInformation:
7282 DesiredAccess = USER_WRITE_PREFERENCES;
7283 break;
7284
7285 case UserSetPasswordInformation:
7286 case UserInternal1Information:
7287 DesiredAccess = USER_FORCE_PASSWORD_CHANGE;
7288 break;
7289
7290 case UserAllInformation:
7291 DesiredAccess = 0; /* FIXME */
7292 break;
7293
7294 default:
7295 return STATUS_INVALID_INFO_CLASS;
7296 }
7297
7298 /* Validate the domain handle */
7299 Status = SampValidateDbObject(UserHandle,
7300 SamDbUserObject,
7301 DesiredAccess,
7302 &UserObject);
7303 if (!NT_SUCCESS(Status))
7304 {
7305 TRACE("failed with status 0x%08lx\n", Status);
7306 return Status;
7307 }
7308
7309 switch (UserInformationClass)
7310 {
7311 case UserGeneralInformation:
7312 Status = SampSetUserGeneral(UserObject,
7313 Buffer);
7314 break;
7315
7316 case UserPreferencesInformation:
7317 Status = SampSetUserPreferences(UserObject,
7318 Buffer);
7319 break;
7320
7321 case UserLogonHoursInformation:
7322 Status = SampSetLogonHoursAttrbute(UserObject,
7323 &Buffer->LogonHours.LogonHours);
7324 break;
7325
7326 case UserNameInformation:
7327 Status = SampSetUserName(UserObject,
7328 &Buffer->Name.UserName);
7329 if (!NT_SUCCESS(Status))
7330 break;
7331
7332 Status = SampSetObjectAttribute(UserObject,
7333 L"FullName",
7334 REG_SZ,
7335 Buffer->Name.FullName.Buffer,
7336 Buffer->Name.FullName.MaximumLength);
7337 break;
7338
7339 case UserAccountNameInformation:
7340 Status = SampSetUserName(UserObject,
7341 &Buffer->AccountName.UserName);
7342 break;
7343
7344 case UserFullNameInformation:
7345 Status = SampSetObjectAttribute(UserObject,
7346 L"FullName",
7347 REG_SZ,
7348 Buffer->FullName.FullName.Buffer,
7349 Buffer->FullName.FullName.MaximumLength);
7350 break;
7351
7352 case UserPrimaryGroupInformation:
7353 Status = SampSetUserPrimaryGroup(UserObject,
7354 Buffer);
7355 break;
7356
7357 case UserHomeInformation:
7358 Status = SampSetObjectAttribute(UserObject,
7359 L"HomeDirectory",
7360 REG_SZ,
7361 Buffer->Home.HomeDirectory.Buffer,
7362 Buffer->Home.HomeDirectory.MaximumLength);
7363 if (!NT_SUCCESS(Status))
7364 break;
7365
7366 Status = SampSetObjectAttribute(UserObject,
7367 L"HomeDirectoryDrive",
7368 REG_SZ,
7369 Buffer->Home.HomeDirectoryDrive.Buffer,
7370 Buffer->Home.HomeDirectoryDrive.MaximumLength);
7371 break;
7372
7373 case UserScriptInformation:
7374 Status = SampSetObjectAttribute(UserObject,
7375 L"ScriptPath",
7376 REG_SZ,
7377 Buffer->Script.ScriptPath.Buffer,
7378 Buffer->Script.ScriptPath.MaximumLength);
7379 break;
7380
7381 case UserProfileInformation:
7382 Status = SampSetObjectAttribute(UserObject,
7383 L"ProfilePath",
7384 REG_SZ,
7385 Buffer->Profile.ProfilePath.Buffer,
7386 Buffer->Profile.ProfilePath.MaximumLength);
7387 break;
7388
7389 case UserAdminCommentInformation:
7390 Status = SampSetObjectAttribute(UserObject,
7391 L"AdminComment",
7392 REG_SZ,
7393 Buffer->AdminComment.AdminComment.Buffer,
7394 Buffer->AdminComment.AdminComment.MaximumLength);
7395 break;
7396
7397 case UserWorkStationsInformation:
7398 Status = SampSetObjectAttribute(UserObject,
7399 L"WorkStations",
7400 REG_SZ,
7401 Buffer->WorkStations.WorkStations.Buffer,
7402 Buffer->WorkStations.WorkStations.MaximumLength);
7403 break;
7404
7405 case UserSetPasswordInformation:
7406 TRACE("Password: %S\n", Buffer->SetPassword.Password.Buffer);
7407 TRACE("PasswordExpired: %d\n", Buffer->SetPassword.PasswordExpired);
7408
7409 Status = SampSetObjectAttribute(UserObject,
7410 L"Password",
7411 REG_SZ,
7412 Buffer->SetPassword.Password.Buffer,
7413 Buffer->SetPassword.Password.MaximumLength);
7414 break;
7415
7416 case UserControlInformation:
7417 Status = SampSetUserControl(UserObject,
7418 Buffer);
7419 break;
7420
7421 case UserExpiresInformation:
7422 Status = SampSetUserExpires(UserObject,
7423 Buffer);
7424 break;
7425
7426 case UserInternal1Information:
7427 Status = SampSetUserInternal1(UserObject,
7428 Buffer);
7429 break;
7430
7431 case UserParametersInformation:
7432 Status = SampSetObjectAttribute(UserObject,
7433 L"Parameters",
7434 REG_SZ,
7435 Buffer->Parameters.Parameters.Buffer,
7436 Buffer->Parameters.Parameters.MaximumLength);
7437 break;
7438
7439 case UserAllInformation:
7440 Status = SampSetUserAll(UserObject,
7441 Buffer);
7442 break;
7443
7444 // case UserInternal4Information:
7445 // case UserInternal5Information:
7446 // case UserInternal4InformationNew:
7447 // case UserInternal5InformationNew:
7448
7449 default:
7450 Status = STATUS_INVALID_INFO_CLASS;
7451 }
7452
7453 return Status;
7454 }
7455
7456
7457 /* Function 38 */
7458 NTSTATUS
7459 NTAPI
7460 SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
7461 IN unsigned char LmPresent,
7462 IN PENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm,
7463 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm,
7464 IN unsigned char NtPresent,
7465 IN PENCRYPTED_NT_OWF_PASSWORD OldNtEncryptedWithNewNt,
7466 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithOldNt,
7467 IN unsigned char NtCrossEncryptionPresent,
7468 IN PENCRYPTED_NT_OWF_PASSWORD NewNtEncryptedWithNewLm,
7469 IN unsigned char LmCrossEncryptionPresent,
7470 IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
7471 {
7472 ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
7473 ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
7474 PENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
7475 PENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
7476 PENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
7477 PENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
7478 PSAM_DB_OBJECT UserObject;
7479 ULONG Length;
7480 NTSTATUS Status;
7481
7482 TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
7483 UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
7484 NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
7485 NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
7486
7487 /* Validate the user handle */
7488 Status = SampValidateDbObject(UserHandle,
7489 SamDbUserObject,
7490 USER_CHANGE_PASSWORD,
7491 &UserObject);
7492 if (!NT_SUCCESS(Status))
7493 {
7494 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7495 return Status;
7496 }
7497
7498 /* Retrieve the LM password */
7499 Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7500 Status = SampGetObjectAttribute(UserObject,
7501 L"LMPwd",
7502 NULL,
7503 &StoredLmPassword,
7504 &Length);
7505 if (!NT_SUCCESS(Status))
7506 {
7507
7508 }
7509
7510 /* Retrieve the NT password */
7511 Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7512 Status = SampGetObjectAttribute(UserObject,
7513 L"NTPwd",
7514 NULL,
7515 &StoredNtPassword,
7516 &Length);
7517 if (!NT_SUCCESS(Status))
7518 {
7519
7520 }
7521
7522 /* FIXME: Decrypt passwords */
7523 OldLmPassword = OldLmEncryptedWithNewLm;
7524 NewLmPassword = NewLmEncryptedWithOldLm;
7525 OldNtPassword = OldNtEncryptedWithNewNt;
7526 NewNtPassword = NewNtEncryptedWithOldNt;
7527
7528 /* Check if the old passwords match the stored ones */
7529 if (NtPresent)
7530 {
7531 if (LmPresent)
7532 {
7533 if (!RtlEqualMemory(&StoredLmPassword,
7534 OldLmPassword,
7535 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7536 {
7537 TRACE("Old LM Password does not match!\n");
7538 Status = STATUS_WRONG_PASSWORD;
7539 }
7540 else
7541 {
7542 if (!RtlEqualMemory(&StoredNtPassword,
7543 OldNtPassword,
7544 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7545 {
7546 TRACE("Old NT Password does not match!\n");
7547 Status = STATUS_WRONG_PASSWORD;
7548 }
7549 }
7550 }
7551 else
7552 {
7553 if (!RtlEqualMemory(&StoredNtPassword,
7554 OldNtPassword,
7555 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7556 {
7557 TRACE("Old NT Password does not match!\n");
7558 Status = STATUS_WRONG_PASSWORD;
7559 }
7560 }
7561 }
7562 else
7563 {
7564 if (LmPresent)
7565 {
7566 if (!RtlEqualMemory(&StoredLmPassword,
7567 OldLmPassword,
7568 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
7569 {
7570 TRACE("Old LM Password does not match!\n");
7571 Status = STATUS_WRONG_PASSWORD;
7572 }
7573 }
7574 else
7575 {
7576 Status = STATUS_INVALID_PARAMETER;
7577 }
7578 }
7579
7580 /* Store the new LM password */
7581 if (NT_SUCCESS(Status))
7582 {
7583 if (LmPresent)
7584 {
7585 Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
7586 Status = SampSetObjectAttribute(UserObject,
7587 L"LMPwd",
7588 REG_BINARY,
7589 NewLmPassword,
7590 Length);
7591 if (!NT_SUCCESS(Status))
7592 {
7593 goto done;
7594 }
7595 }
7596
7597 /* Store the new NT password */
7598 if (NtPresent)
7599 {
7600 Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
7601 Status = SampSetObjectAttribute(UserObject,
7602 L"NTPwd",
7603 REG_BINARY,
7604 NewNtPassword,
7605 Length);
7606 if (!NT_SUCCESS(Status))
7607 {
7608 goto done;
7609 }
7610 }
7611 }
7612
7613
7614 done:
7615 return Status;
7616 }
7617
7618
7619 /* Function 39 */
7620 NTSTATUS
7621 NTAPI
7622 SamrGetGroupsForUser(IN SAMPR_HANDLE UserHandle,
7623 OUT PSAMPR_GET_GROUPS_BUFFER *Groups)
7624 {
7625 PSAMPR_GET_GROUPS_BUFFER GroupsBuffer = NULL;
7626 PSAM_DB_OBJECT UserObject;
7627 ULONG Length = 0;
7628 NTSTATUS Status;
7629
7630 TRACE("SamrGetGroupsForUser(%p %p)\n",
7631 UserHandle, Groups);
7632
7633 /* Validate the user handle */
7634 Status = SampValidateDbObject(UserHandle,
7635 SamDbUserObject,
7636 USER_LIST_GROUPS,
7637 &UserObject);
7638 if (!NT_SUCCESS(Status))
7639 {
7640 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7641 return Status;
7642 }
7643
7644 /* Allocate the groups buffer */
7645 GroupsBuffer = midl_user_allocate(sizeof(SAMPR_GET_GROUPS_BUFFER));
7646 if (GroupsBuffer == NULL)
7647 return STATUS_INSUFFICIENT_RESOURCES;
7648
7649 /*
7650 * Get the size of the Groups attribute.
7651 * Do not check the status code because in case of an error
7652 * Length will be 0. And that is all we need.
7653 */
7654 SampGetObjectAttribute(UserObject,
7655 L"Groups",
7656 NULL,
7657 NULL,
7658 &Length);
7659
7660 /* If there is no Groups attribute, return a groups buffer without an array */
7661 if (Length == 0)
7662 {
7663 GroupsBuffer->MembershipCount = 0;
7664 GroupsBuffer->Groups = NULL;
7665
7666 *Groups = GroupsBuffer;
7667
7668 return STATUS_SUCCESS;
7669 }
7670
7671 /* Allocate a buffer for the Groups attribute */
7672 GroupsBuffer->Groups = midl_user_allocate(Length);
7673 if (GroupsBuffer->Groups == NULL)
7674 {
7675 Status = STATUS_INSUFFICIENT_RESOURCES;
7676 goto done;
7677 }
7678
7679 /* Retrieve the Grous attribute */
7680 Status = SampGetObjectAttribute(UserObject,
7681 L"Groups",
7682 NULL,
7683 GroupsBuffer->Groups,
7684 &Length);
7685 if (!NT_SUCCESS(Status))
7686 {
7687 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
7688 goto done;
7689 }
7690
7691 /* Calculate the membership count */
7692 GroupsBuffer->MembershipCount = Length / sizeof(GROUP_MEMBERSHIP);
7693
7694 /* Return the groups buffer to the caller */
7695 *Groups = GroupsBuffer;
7696
7697 done:
7698 if (!NT_SUCCESS(Status))
7699 {
7700 if (GroupsBuffer != NULL)
7701 {
7702 if (GroupsBuffer->Groups != NULL)
7703 midl_user_free(GroupsBuffer->Groups);
7704
7705 midl_user_free(GroupsBuffer);
7706 }
7707 }
7708
7709 return Status;
7710 }
7711
7712
7713 /* Function 40 */
7714 NTSTATUS
7715 NTAPI
7716 SamrQueryDisplayInformation(IN SAMPR_HANDLE DomainHandle,
7717 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7718 IN unsigned long Index,
7719 IN unsigned long EntryCount,
7720 IN unsigned long PreferredMaximumLength,
7721 OUT unsigned long *TotalAvailable,
7722 OUT unsigned long *TotalReturned,
7723 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
7724 {
7725 UNIMPLEMENTED;
7726 return STATUS_NOT_IMPLEMENTED;
7727 }
7728
7729 /* Function 41 */
7730 NTSTATUS
7731 NTAPI
7732 SamrGetDisplayEnumerationIndex(IN SAMPR_HANDLE DomainHandle,
7733 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7734 IN PRPC_UNICODE_STRING Prefix,
7735 OUT unsigned long *Index)
7736 {
7737 UNIMPLEMENTED;
7738 return STATUS_NOT_IMPLEMENTED;
7739 }
7740
7741 /* Function 42 */
7742 NTSTATUS
7743 NTAPI
7744 SamrTestPrivateFunctionsDomain(IN SAMPR_HANDLE DomainHandle)
7745 {
7746 UNIMPLEMENTED;
7747 return STATUS_NOT_IMPLEMENTED;
7748 }
7749
7750 /* Function 43 */
7751 NTSTATUS
7752 NTAPI
7753 SamrTestPrivateFunctionsUser(IN SAMPR_HANDLE UserHandle)
7754 {
7755 UNIMPLEMENTED;
7756 return STATUS_NOT_IMPLEMENTED;
7757 }
7758
7759
7760 /* Function 44 */
7761 NTSTATUS
7762 NTAPI
7763 SamrGetUserDomainPasswordInformation(IN SAMPR_HANDLE UserHandle,
7764 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
7765 {
7766 SAM_DOMAIN_FIXED_DATA DomainFixedData;
7767 SAM_USER_FIXED_DATA UserFixedData;
7768 PSAM_DB_OBJECT DomainObject;
7769 PSAM_DB_OBJECT UserObject;
7770 ULONG Length = 0;
7771 NTSTATUS Status;
7772
7773 TRACE("(%p %p)\n",
7774 UserHandle, PasswordInformation);
7775
7776 /* Validate the user handle */
7777 Status = SampValidateDbObject(UserHandle,
7778 SamDbUserObject,
7779 0,
7780 &UserObject);
7781 if (!NT_SUCCESS(Status))
7782 {
7783 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7784 return Status;
7785 }
7786
7787 /* Validate the domain object */
7788 Status = SampValidateDbObject((SAMPR_HANDLE)UserObject->ParentObject,
7789 SamDbDomainObject,
7790 DOMAIN_READ_PASSWORD_PARAMETERS,
7791 &DomainObject);
7792 if (!NT_SUCCESS(Status))
7793 {
7794 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7795 return Status;
7796 }
7797
7798 /* Get fixed user data */
7799 Length = sizeof(SAM_USER_FIXED_DATA);
7800 Status = SampGetObjectAttribute(UserObject,
7801 L"F",
7802 NULL,
7803 (PVOID)&UserFixedData,
7804 &Length);
7805 if (!NT_SUCCESS(Status))
7806 {
7807 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
7808 return Status;
7809 }
7810
7811 if ((UserObject->RelativeId == DOMAIN_USER_RID_KRBTGT) ||
7812 (UserFixedData.UserAccountControl & (USER_INTERDOMAIN_TRUST_ACCOUNT |
7813 USER_WORKSTATION_TRUST_ACCOUNT |
7814 USER_SERVER_TRUST_ACCOUNT)))
7815 {
7816 PasswordInformation->MinPasswordLength = 0;
7817 PasswordInformation->PasswordProperties = 0;
7818 }
7819 else
7820 {
7821 /* Get fixed domain data */
7822 Length = sizeof(SAM_DOMAIN_FIXED_DATA);
7823 Status = SampGetObjectAttribute(DomainObject,
7824 L"F",
7825 NULL,
7826 (PVOID)&DomainFixedData,
7827 &Length);
7828 if (!NT_SUCCESS(Status))
7829 {
7830 TRACE("SampGetObjectAttribute failed with status 0x%08lx\n", Status);
7831 return Status;
7832 }
7833
7834 PasswordInformation->MinPasswordLength = DomainFixedData.MinPasswordLength;
7835 PasswordInformation->PasswordProperties = DomainFixedData.PasswordProperties;
7836 }
7837
7838 return STATUS_SUCCESS;
7839 }
7840
7841
7842 /* Function 45 */
7843 NTSTATUS
7844 NTAPI
7845 SamrRemoveMemberFromForeignDomain(IN SAMPR_HANDLE DomainHandle,
7846 IN PRPC_SID MemberSid)
7847 {
7848 PSAM_DB_OBJECT DomainObject;
7849 ULONG Rid = 0;
7850 NTSTATUS Status;
7851
7852 TRACE("(%p %p)\n",
7853 DomainHandle, MemberSid);
7854
7855 /* Validate the domain object */
7856 Status = SampValidateDbObject(DomainHandle,
7857 SamDbDomainObject,
7858 DOMAIN_LOOKUP,
7859 &DomainObject);
7860 if (!NT_SUCCESS(Status))
7861 {
7862 TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
7863 return Status;
7864 }
7865
7866 /* Retrieve the RID from the MemberSID */
7867 Status = SampGetRidFromSid((PSID)MemberSid,
7868 &Rid);
7869 if (!NT_SUCCESS(Status))
7870 {
7871 TRACE("SampGetRidFromSid failed with status 0x%08lx\n", Status);
7872 return Status;
7873 }
7874
7875 /* Fail, if the RID represents a special account */
7876 if (Rid < 1000)
7877 {
7878 TRACE("Cannot remove a special account (RID: %lu)\n", Rid);
7879 return STATUS_SPECIAL_ACCOUNT;
7880 }
7881
7882 /* Remove the member from all aliases in the domain */
7883 Status = SampRemoveMemberFromAllAliases(DomainObject,
7884 MemberSid);
7885 if (!NT_SUCCESS(Status))
7886 {
7887 TRACE("SampRemoveMemberFromAllAliases failed with status 0x%08lx\n", Status);
7888 }
7889
7890 return Status;
7891 }
7892
7893
7894 /* Function 46 */
7895 NTSTATUS
7896 NTAPI
7897 SamrQueryInformationDomain2(IN SAMPR_HANDLE DomainHandle,
7898 IN DOMAIN_INFORMATION_CLASS DomainInformationClass,
7899 OUT PSAMPR_DOMAIN_INFO_BUFFER *Buffer)
7900 {
7901 TRACE("(%p %lu %p)\n", DomainHandle, DomainInformationClass, Buffer);
7902
7903 return SamrQueryInformationDomain(DomainHandle,
7904 DomainInformationClass,
7905 Buffer);
7906 }
7907
7908
7909 /* Function 47 */
7910 NTSTATUS
7911 NTAPI
7912 SamrQueryInformationUser2(IN SAMPR_HANDLE UserHandle,
7913 IN USER_INFORMATION_CLASS UserInformationClass,
7914 OUT PSAMPR_USER_INFO_BUFFER *Buffer)
7915 {
7916 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
7917
7918 return SamrQueryInformationUser(UserHandle,
7919 UserInformationClass,
7920 Buffer);
7921 }
7922
7923
7924 /* Function 48 */
7925 NTSTATUS
7926 NTAPI
7927 SamrQueryDisplayInformation2(IN SAMPR_HANDLE DomainHandle,
7928 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7929 IN unsigned long Index,
7930 IN unsigned long EntryCount,
7931 IN unsigned long PreferredMaximumLength,
7932 OUT unsigned long *TotalAvailable,
7933 OUT unsigned long *TotalReturned,
7934 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
7935 {
7936 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
7937 DomainHandle, DisplayInformationClass, Index,
7938 EntryCount, PreferredMaximumLength, TotalAvailable,
7939 TotalReturned, Buffer);
7940
7941 return SamrQueryDisplayInformation(DomainHandle,
7942 DisplayInformationClass,
7943 Index,
7944 EntryCount,
7945 PreferredMaximumLength,
7946 TotalAvailable,
7947 TotalReturned,
7948 Buffer);
7949 }
7950
7951
7952 /* Function 49 */
7953 NTSTATUS
7954 NTAPI
7955 SamrGetDisplayEnumerationIndex2(IN SAMPR_HANDLE DomainHandle,
7956 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
7957 IN PRPC_UNICODE_STRING Prefix,
7958 OUT unsigned long *Index)
7959 {
7960 TRACE("(%p %lu %p %p)\n",
7961 DomainHandle, DisplayInformationClass, Prefix, Index);
7962
7963 return SamrGetDisplayEnumerationIndex(DomainHandle,
7964 DisplayInformationClass,
7965 Prefix,
7966 Index);
7967 }
7968
7969
7970 /* Function 50 */
7971 NTSTATUS
7972 NTAPI
7973 SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
7974 IN PRPC_UNICODE_STRING Name,
7975 IN unsigned long AccountType,
7976 IN ACCESS_MASK DesiredAccess,
7977 OUT SAMPR_HANDLE *UserHandle,
7978 OUT unsigned long *GrantedAccess,
7979 OUT unsigned long *RelativeId)
7980 {
7981 UNICODE_STRING EmptyString = RTL_CONSTANT_STRING(L"");
7982 SAM_DOMAIN_FIXED_DATA FixedDomainData;
7983 SAM_USER_FIXED_DATA FixedUserData;
7984 PSAM_DB_OBJECT DomainObject;
7985 PSAM_DB_OBJECT UserObject;
7986 GROUP_MEMBERSHIP GroupMembership;
7987 UCHAR LogonHours[23];
7988 ULONG ulSize;
7989 ULONG ulRid;
7990 WCHAR szRid[9];
7991 NTSTATUS Status;
7992
7993 TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
7994 DomainHandle, Name, DesiredAccess, UserHandle, RelativeId);
7995
7996 if (Name == NULL ||
7997 Name->Length == 0 ||
7998 Name->Buffer == NULL ||
7999 UserHandle == NULL ||
8000 RelativeId == NULL)
8001 return STATUS_INVALID_PARAMETER;
8002
8003 /* Check for valid account type */
8004 if (AccountType != USER_NORMAL_ACCOUNT &&
8005 AccountType != USER_WORKSTATION_TRUST_ACCOUNT &&
8006 AccountType != USER_INTERDOMAIN_TRUST_ACCOUNT &&
8007 AccountType != USER_SERVER_TRUST_ACCOUNT &&
8008 AccountType != USER_TEMP_DUPLICATE_ACCOUNT)
8009 return STATUS_INVALID_PARAMETER;
8010
8011 /* Map generic access rights */
8012 RtlMapGenericMask(&DesiredAccess,
8013 &UserMapping);
8014
8015 /* Validate the domain handle */
8016 Status = SampValidateDbObject(DomainHandle,
8017 SamDbDomainObject,
8018 DOMAIN_CREATE_USER,
8019 &DomainObject);
8020 if (!NT_SUCCESS(Status))
8021 {
8022 TRACE("failed with status 0x%08lx\n", Status);
8023 return Status;
8024 }
8025
8026 /* Check if the user name already exists in the domain */
8027 Status = SampCheckAccountNameInDomain(DomainObject,
8028 Name->Buffer);
8029 if (!NT_SUCCESS(Status))
8030 {
8031 TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
8032 Name->Buffer, Status);
8033 return Status;
8034 }
8035
8036 /* Get the fixed domain attributes */
8037 ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
8038 Status = SampGetObjectAttribute(DomainObject,
8039 L"F",
8040 NULL,
8041 (PVOID)&FixedDomainData,
8042 &ulSize);
8043 if (!NT_SUCCESS(Status))
8044 {
8045 TRACE("failed with status 0x%08lx\n", Status);
8046 return Status;
8047 }
8048
8049 /* Increment the NextRid attribute */
8050 ulRid = FixedDomainData.NextRid;
8051 FixedDomainData.NextRid++;
8052
8053 /* Store the fixed domain attributes */
8054 Status = SampSetObjectAttribute(DomainObject,
8055 L"F",
8056 REG_BINARY,
8057 &FixedDomainData,
8058 ulSize);
8059 if (!NT_SUCCESS(Status))
8060 {
8061 TRACE("failed with status 0x%08lx\n", Status);
8062 return Status;
8063 }
8064
8065 TRACE("RID: %lx\n", ulRid);
8066
8067 /* Convert the RID into a string (hex) */
8068 swprintf(szRid, L"%08lX", ulRid);
8069
8070 /* Create the user object */
8071 Status = SampCreateDbObject(DomainObject,
8072 L"Users",
8073 szRid,
8074 ulRid,
8075 SamDbUserObject,
8076 DesiredAccess,
8077 &UserObject);
8078 if (!NT_SUCCESS(Status))
8079 {
8080 TRACE("failed with status 0x%08lx\n", Status);
8081 return Status;
8082 }
8083
8084 /* Add the account name for the user object */
8085 Status = SampSetAccountNameInDomain(DomainObject,
8086 L"Users",
8087 Name->Buffer,
8088 ulRid);
8089 if (!NT_SUCCESS(Status))
8090 {
8091 TRACE("failed with status 0x%08lx\n", Status);
8092 return Status;
8093 }
8094
8095 /* Initialize fixed user data */
8096 FixedUserData.Version = 1;
8097 FixedUserData.Reserved = 0;
8098 FixedUserData.LastLogon.QuadPart = 0;
8099 FixedUserData.LastLogoff.QuadPart = 0;
8100 FixedUserData.PasswordLastSet.QuadPart = 0;
8101 FixedUserData.AccountExpires.LowPart = MAXULONG;
8102 FixedUserData.AccountExpires.HighPart = MAXLONG;
8103 FixedUserData.LastBadPasswordTime.QuadPart = 0;
8104 FixedUserData.UserId = ulRid;
8105 FixedUserData.PrimaryGroupId = DOMAIN_GROUP_RID_USERS;
8106 FixedUserData.UserAccountControl = USER_ACCOUNT_DISABLED |
8107 USER_PASSWORD_NOT_REQUIRED |
8108 AccountType;
8109 FixedUserData.CountryCode = 0;
8110 FixedUserData.CodePage = 0;
8111 FixedUserData.BadPasswordCount = 0;
8112 FixedUserData.LogonCount = 0;
8113 FixedUserData.AdminCount = 0;
8114 FixedUserData.OperatorCount = 0;
8115
8116 /* Set fixed user data attribute */
8117 Status = SampSetObjectAttribute(UserObject,
8118 L"F",
8119 REG_BINARY,
8120 (LPVOID)&FixedUserData,
8121 sizeof(SAM_USER_FIXED_DATA));
8122 if (!NT_SUCCESS(Status))
8123 {
8124 TRACE("failed with status 0x%08lx\n", Status);
8125 return Status;
8126 }
8127
8128 /* Set the Name attribute */
8129 Status = SampSetObjectAttribute(UserObject,
8130 L"Name",
8131 REG_SZ,
8132 (LPVOID)Name->Buffer,
8133 Name->MaximumLength);
8134 if (!NT_SUCCESS(Status))
8135 {
8136 TRACE("failed with status 0x%08lx\n", Status);
8137 return Status;
8138 }
8139
8140 /* Set the FullName attribute */
8141 Status = SampSetObjectAttribute(UserObject,
8142 L"FullName",
8143 REG_SZ,
8144 EmptyString.Buffer,
8145 EmptyString.MaximumLength);
8146 if (!NT_SUCCESS(Status))
8147 {
8148 TRACE("failed with status 0x%08lx\n", Status);
8149 return Status;
8150 }
8151
8152 /* Set the HomeDirectory attribute */
8153 Status = SampSetObjectAttribute(UserObject,
8154 L"HomeDirectory",
8155 REG_SZ,
8156 EmptyString.Buffer,
8157 EmptyString.MaximumLength);
8158 if (!NT_SUCCESS(Status))
8159 {
8160 TRACE("failed with status 0x%08lx\n", Status);
8161 return Status;
8162 }
8163
8164 /* Set the HomeDirectoryDrive attribute */
8165 Status = SampSetObjectAttribute(UserObject,
8166 L"HomeDirectoryDrive",
8167 REG_SZ,
8168 EmptyString.Buffer,
8169 EmptyString.MaximumLength);
8170 if (!NT_SUCCESS(Status))
8171 {
8172 TRACE("failed with status 0x%08lx\n", Status);
8173 return Status;
8174 }
8175
8176 /* Set the ScriptPath attribute */
8177 Status = SampSetObjectAttribute(UserObject,
8178 L"ScriptPath",
8179 REG_SZ,
8180 EmptyString.Buffer,
8181 EmptyString.MaximumLength);
8182 if (!NT_SUCCESS(Status))
8183 {
8184 TRACE("failed with status 0x%08lx\n", Status);
8185 return Status;
8186 }
8187
8188 /* Set the ProfilePath attribute */
8189 Status = SampSetObjectAttribute(UserObject,
8190 L"ProfilePath",
8191 REG_SZ,
8192 EmptyString.Buffer,
8193 EmptyString.MaximumLength);
8194 if (!NT_SUCCESS(Status))
8195 {
8196 TRACE("failed with status 0x%08lx\n", Status);
8197 return Status;
8198 }
8199
8200 /* Set the AdminComment attribute */
8201 Status = SampSetObjectAttribute(UserObject,
8202 L"AdminComment",
8203 REG_SZ,
8204 EmptyString.Buffer,
8205 EmptyString.MaximumLength);
8206 if (!NT_SUCCESS(Status))
8207 {
8208 TRACE("failed with status 0x%08lx\n", Status);
8209 return Status;
8210 }
8211
8212 /* Set the UserComment attribute */
8213 Status = SampSetObjectAttribute(UserObject,
8214 L"UserComment",
8215 REG_SZ,
8216 EmptyString.Buffer,
8217 EmptyString.MaximumLength);
8218 if (!NT_SUCCESS(Status))
8219 {
8220 TRACE("failed with status 0x%08lx\n", Status);
8221 return Status;
8222 }
8223
8224 /* Set the WorkStations attribute */
8225 Status = SampSetObjectAttribute(UserObject,
8226 L"WorkStations",
8227 REG_SZ,
8228 EmptyString.Buffer,
8229 EmptyString.MaximumLength);
8230 if (!NT_SUCCESS(Status))
8231 {
8232 TRACE("failed with status 0x%08lx\n", Status);
8233 return Status;
8234 }
8235
8236 /* Set the Parameters attribute */
8237 Status = SampSetObjectAttribute(UserObject,
8238 L"Parameters",
8239 REG_SZ,
8240 EmptyString.Buffer,
8241 EmptyString.MaximumLength);
8242 if (!NT_SUCCESS(Status))
8243 {
8244 TRACE("failed with status 0x%08lx\n", Status);
8245 return Status;
8246 }
8247
8248 /* Set LogonHours attribute*/
8249 *((PUSHORT)LogonHours) = 168;
8250 memset(&(LogonHours[2]), 0xff, 21);
8251
8252 Status = SampSetObjectAttribute(UserObject,
8253 L"LogonHours",
8254 REG_BINARY,
8255 &LogonHours,
8256 sizeof(LogonHours));
8257 if (!NT_SUCCESS(Status))
8258 {
8259 TRACE("failed with status 0x%08lx\n", Status);
8260 return Status;
8261 }
8262
8263 /* Set Groups attribute*/
8264 GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
8265 GroupMembership.Attributes = SE_GROUP_MANDATORY |
8266 SE_GROUP_ENABLED |
8267 SE_GROUP_ENABLED_BY_DEFAULT;
8268
8269 Status = SampSetObjectAttribute(UserObject,
8270 L"Groups",
8271 REG_BINARY,
8272 &GroupMembership,
8273 sizeof(GROUP_MEMBERSHIP));
8274 if (!NT_SUCCESS(Status))
8275 {
8276 TRACE("failed with status 0x%08lx\n", Status);
8277 return Status;
8278 }
8279
8280 /* Set LMPwd attribute*/
8281 Status = SampSetObjectAttribute(UserObject,
8282 L"LMPwd",
8283 REG_BINARY,
8284 NULL,
8285 0);
8286 if (!NT_SUCCESS(Status))
8287 {
8288 TRACE("failed with status 0x%08lx\n", Status);
8289 return Status;
8290 }
8291
8292 /* Set NTPwd attribute*/
8293 Status = SampSetObjectAttribute(UserObject,
8294 L"NTPwd",
8295 REG_BINARY,
8296 NULL,
8297 0);
8298 if (!NT_SUCCESS(Status))
8299 {
8300 TRACE("failed with status 0x%08lx\n", Status);
8301 return Status;
8302 }
8303
8304 /* Set LMPwdHistory attribute*/
8305 Status = SampSetObjectAttribute(UserObject,
8306 L"LMPwdHistory",
8307 REG_BINARY,
8308 NULL,
8309 0);
8310 if (!NT_SUCCESS(Status))
8311 {
8312 TRACE("failed with status 0x%08lx\n", Status);
8313 return Status;
8314 }
8315
8316 /* Set NTPwdHistory attribute*/
8317 Status = SampSetObjectAttribute(UserObject,
8318 L"NTPwdHistory",
8319 REG_BINARY,
8320 NULL,
8321 0);
8322 if (!NT_SUCCESS(Status))
8323 {
8324 TRACE("failed with status 0x%08lx\n", Status);
8325 return Status;
8326 }
8327
8328 /* FIXME: Set SecDesc attribute*/
8329
8330 if (NT_SUCCESS(Status))
8331 {
8332 *UserHandle = (SAMPR_HANDLE)UserObject;
8333 *RelativeId = ulRid;
8334 *GrantedAccess = UserObject->Access;
8335 }
8336
8337 TRACE("returns with status 0x%08lx\n", Status);
8338
8339 return Status;
8340 }
8341
8342
8343 /* Function 51 */
8344 NTSTATUS
8345 NTAPI
8346 SamrQueryDisplayInformation3(IN SAMPR_HANDLE DomainHandle,
8347 IN DOMAIN_DISPLAY_INFORMATION DisplayInformationClass,
8348 IN unsigned long Index,
8349 IN unsigned long EntryCount,
8350 IN unsigned long PreferredMaximumLength,
8351 OUT unsigned long *TotalAvailable,
8352 OUT unsigned long *TotalReturned,
8353 OUT PSAMPR_DISPLAY_INFO_BUFFER Buffer)
8354 {
8355 TRACE("%p %lu %lu %lu %lu %p %p %p\n",
8356 DomainHandle, DisplayInformationClass, Index,
8357 EntryCount, PreferredMaximumLength, TotalAvailable,
8358 TotalReturned, Buffer);
8359
8360 return SamrQueryDisplayInformation(DomainHandle,
8361 DisplayInformationClass,
8362 Index,
8363 EntryCount,
8364 PreferredMaximumLength,
8365 TotalAvailable,
8366 TotalReturned,
8367 Buffer);
8368 }
8369
8370
8371 /* Function 52 */
8372 NTSTATUS
8373 NTAPI
8374 SamrAddMultipleMembersToAlias(IN SAMPR_HANDLE AliasHandle,
8375 IN PSAMPR_PSID_ARRAY MembersBuffer)
8376 {
8377 ULONG i;
8378 NTSTATUS Status = STATUS_SUCCESS;
8379
8380 TRACE("SamrAddMultipleMembersToAlias(%p %p)\n",
8381 AliasHandle, MembersBuffer);
8382
8383 for (i = 0; i < MembersBuffer->Count; i++)
8384 {
8385 Status = SamrAddMemberToAlias(AliasHandle,
8386 ((PSID *)MembersBuffer->Sids)[i]);
8387
8388 if (Status == STATUS_MEMBER_IN_ALIAS)
8389 Status = STATUS_SUCCESS;
8390
8391 if (!NT_SUCCESS(Status))
8392 break;
8393 }
8394
8395 return Status;
8396 }
8397
8398
8399 /* Function 53 */
8400 NTSTATUS
8401 NTAPI
8402 SamrRemoveMultipleMembersFromAlias(IN SAMPR_HANDLE AliasHandle,
8403 IN PSAMPR_PSID_ARRAY MembersBuffer)
8404 {
8405 ULONG i;
8406 NTSTATUS Status = STATUS_SUCCESS;
8407
8408 TRACE("SamrRemoveMultipleMembersFromAlias(%p %p)\n",
8409 AliasHandle, MembersBuffer);
8410
8411 for (i = 0; i < MembersBuffer->Count; i++)
8412 {
8413 Status = SamrRemoveMemberFromAlias(AliasHandle,
8414 ((PSID *)MembersBuffer->Sids)[i]);
8415
8416 if (Status == STATUS_MEMBER_IN_ALIAS)
8417 Status = STATUS_SUCCESS;
8418
8419 if (!NT_SUCCESS(Status))
8420 break;
8421 }
8422
8423 return Status;
8424 }
8425
8426
8427 /* Function 54 */
8428 NTSTATUS
8429 NTAPI
8430 SamrOemChangePasswordUser2(IN handle_t BindingHandle,
8431 IN PRPC_STRING ServerName,
8432 IN PRPC_STRING UserName,
8433 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
8434 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewLm)
8435 {
8436 UNIMPLEMENTED;
8437 return STATUS_NOT_IMPLEMENTED;
8438 }
8439
8440 /* Function 55 */
8441 NTSTATUS
8442 NTAPI
8443 SamrUnicodeChangePasswordUser2(IN handle_t BindingHandle,
8444 IN PRPC_UNICODE_STRING ServerName,
8445 IN PRPC_UNICODE_STRING UserName,
8446 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldNt,
8447 IN PENCRYPTED_NT_OWF_PASSWORD OldNtOwfPasswordEncryptedWithNewNt,
8448 IN unsigned char LmPresent,
8449 IN PSAMPR_ENCRYPTED_USER_PASSWORD NewPasswordEncryptedWithOldLm,
8450 IN PENCRYPTED_LM_OWF_PASSWORD OldLmOwfPasswordEncryptedWithNewNt)
8451 {
8452 UNIMPLEMENTED;
8453 return STATUS_NOT_IMPLEMENTED;
8454 }
8455
8456 /* Function 56 */
8457 NTSTATUS
8458 NTAPI
8459 SamrGetDomainPasswordInformation(IN handle_t BindingHandle,
8460 IN PRPC_UNICODE_STRING Unused,
8461 OUT PUSER_DOMAIN_PASSWORD_INFORMATION PasswordInformation)
8462 {
8463 UNIMPLEMENTED;
8464 return STATUS_NOT_IMPLEMENTED;
8465 }
8466
8467
8468 /* Function 57 */
8469 NTSTATUS
8470 NTAPI
8471 SamrConnect2(IN PSAMPR_SERVER_NAME ServerName,
8472 OUT SAMPR_HANDLE *ServerHandle,
8473 IN ACCESS_MASK DesiredAccess)
8474 {
8475 TRACE("(%p %p %lx)\n", ServerName, ServerHandle, DesiredAccess);
8476
8477 return SamrConnect(ServerName,
8478 ServerHandle,
8479 DesiredAccess);
8480 }
8481
8482
8483 /* Function 58 */
8484 NTSTATUS
8485 NTAPI
8486 SamrSetInformationUser2(IN SAMPR_HANDLE UserHandle,
8487 IN USER_INFORMATION_CLASS UserInformationClass,
8488 IN PSAMPR_USER_INFO_BUFFER Buffer)
8489 {
8490 TRACE("(%p %lu %p)\n", UserHandle, UserInformationClass, Buffer);
8491
8492 return SamrSetInformationUser(UserHandle,
8493 UserInformationClass,
8494 Buffer);
8495 }
8496
8497
8498 /* Function 59 */
8499 NTSTATUS
8500 NTAPI
8501 SamrSetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
8502 {
8503 UNIMPLEMENTED;
8504 return STATUS_NOT_IMPLEMENTED;
8505 }
8506
8507 /* Function 60 */
8508 NTSTATUS
8509 NTAPI
8510 SamrGetBootKeyInformation(IN handle_t BindingHandle) /* FIXME */
8511 {
8512 UNIMPLEMENTED;
8513 return STATUS_NOT_IMPLEMENTED;
8514 }
8515
8516 /* Function 61 */
8517 NTSTATUS
8518 NTAPI
8519 SamrConnect3(IN handle_t BindingHandle) /* FIXME */
8520 {
8521 UNIMPLEMENTED;
8522 return STATUS_NOT_IMPLEMENTED;
8523 }
8524
8525 /* Function 62 */
8526 NTSTATUS
8527 NTAPI
8528 SamrConnect4(IN PSAMPR_SERVER_NAME ServerName,
8529 OUT SAMPR_HANDLE *ServerHandle,
8530 IN unsigned long ClientRevision,
8531 IN ACCESS_MASK DesiredAccess)
8532 {
8533 UNIMPLEMENTED;
8534 return STATUS_NOT_IMPLEMENTED;
8535 }
8536
8537 /* Function 63 */
8538 NTSTATUS
8539 NTAPI
8540 SamrUnicodeChangePasswordUser3(IN handle_t BindingHandle) /* FIXME */
8541 {
8542 UNIMPLEMENTED;
8543 return STATUS_NOT_IMPLEMENTED;
8544 }
8545
8546 /* Function 64 */
8547 NTSTATUS
8548 NTAPI
8549 SamrConnect5(IN PSAMPR_SERVER_NAME ServerName,
8550 IN ACCESS_MASK DesiredAccess,
8551 IN unsigned long InVersion,
8552 IN SAMPR_REVISION_INFO *InRevisionInfo,
8553 OUT unsigned long *OutVersion,
8554 OUT SAMPR_REVISION_INFO *OutRevisionInfo,
8555 OUT SAMPR_HANDLE *ServerHandle)
8556 {
8557 UNIMPLEMENTED;
8558 return STATUS_NOT_IMPLEMENTED;
8559 }
8560
8561 /* Function 65 */
8562 NTSTATUS
8563 NTAPI
8564 SamrRidToSid(IN SAMPR_HANDLE ObjectHandle,
8565 IN unsigned long Rid,
8566 OUT PRPC_SID *Sid)
8567 {
8568 UNIMPLEMENTED;
8569 return STATUS_NOT_IMPLEMENTED;
8570 }
8571
8572 /* Function 66 */
8573 NTSTATUS
8574 NTAPI
8575 SamrSetDSRMPassword(IN handle_t BindingHandle,
8576 IN PRPC_UNICODE_STRING Unused,
8577 IN unsigned long UserId,
8578 IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword)
8579 {
8580 UNIMPLEMENTED;
8581 return STATUS_NOT_IMPLEMENTED;
8582 }
8583
8584 /* Function 67 */
8585 NTSTATUS
8586 NTAPI
8587 SamrValidatePassword(IN handle_t Handle,
8588 IN PASSWORD_POLICY_VALIDATION_TYPE ValidationType,
8589 IN PSAM_VALIDATE_INPUT_ARG InputArg,
8590 OUT PSAM_VALIDATE_OUTPUT_ARG *OutputArg)
8591 {
8592 UNIMPLEMENTED;
8593 return STATUS_NOT_IMPLEMENTED;
8594 }
8595
8596 /* EOF */