4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Security Accounts Manager RPC (SAMR) client-side interface.
30 * The SAM is a hierarchical database:
31 * - If you want to talk to the SAM you need a SAM handle.
32 * - If you want to work with a domain, use the SAM handle.
33 * to obtain a domain handle.
34 * - Use domain handles to obtain user handles etc.
36 * Be careful about returning null handles to the application. Use of a
37 * null handle may crash the domain controller if you attempt to use it.
45 #include <sys/param.h>
47 #include <smbsrv/libsmb.h>
48 #include <smbsrv/libmlrpc.h>
49 #include <smbsrv/libmlsvc.h>
50 #include <smbsrv/smbinfo.h>
51 #include <smbsrv/ntaccess.h>
52 #include <smbsrv/smb_sid.h>
55 static DWORD
samr_connect2(char *, char *, char *, DWORD
, mlsvc_handle_t
*);
56 static DWORD
samr_connect4(char *, char *, char *, DWORD
, mlsvc_handle_t
*);
57 static DWORD
samr_connect5(char *, char *, char *, DWORD
, mlsvc_handle_t
*);
59 typedef DWORD (*samr_connop_t
)(char *, char *, char *, DWORD
,
62 static int samr_setup_user_info(WORD
, struct samr_QueryUserInfo
*,
63 union samr_user_info
*);
68 * Wrapper round samr_connect to ensure that we connect using the server
69 * and domain. We default to the resource domain if the caller doesn't
70 * supply a server name and a domain name.
72 * If username argument is NULL, an anonymous connection will be established.
73 * Otherwise, an authenticated connection will be established.
75 * On success 0 is returned. Otherwise a -ve error code.
78 samr_open(char *server
, char *domain
, char *username
, DWORD access_mask
,
79 mlsvc_handle_t
*samr_handle
)
84 if (server
== NULL
|| domain
== NULL
) {
85 if (!smb_domain_getinfo(&di
))
86 return (NT_STATUS_INTERNAL_ERROR
);
87 server
= di
.d_dci
.dc_name
;
88 domain
= di
.d_primary
.di_nbname
;
92 username
= MLSVC_ANON_USER
;
94 status
= samr_connect(server
, domain
, username
, access_mask
,
104 * Connect to the SAMR service on the specified server (domain controller).
105 * New SAM connect calls have been added to Windows over time:
107 * Windows NT3.x: SamrConnect
108 * Windows NT4.0: SamrConnect2
109 * Windows 2000: SamrConnect4
110 * Windows XP: SamrConnect5
112 * Try the calls from most recent to oldest until the server responds with
113 * something other than an RPC protocol error. We don't use the original
114 * connect call because all supported servers should support SamrConnect2.
117 samr_connect(char *server
, char *domain
, char *username
, DWORD access_mask
,
118 mlsvc_handle_t
*samr_handle
)
120 static samr_connop_t samr_connop
[] = {
126 int n_op
= (sizeof (samr_connop
) / sizeof (samr_connop
[0]));
130 status
= ndr_rpc_bind(samr_handle
, server
, domain
, username
, "SAMR");
134 for (i
= 0; i
< n_op
; ++i
) {
135 status
= (*samr_connop
[i
])(server
, domain
, username
,
136 access_mask
, samr_handle
);
138 if (status
== NT_STATUS_SUCCESS
)
142 ndr_rpc_unbind(samr_handle
);
149 * Connect to the SAM on a Windows NT 4.0 server (domain controller).
150 * We need the domain controller name and, if everything works, we
151 * return a handle. This function adds the double backslash prefx to
152 * make it easy for applications.
154 * Returns 0 on success. Otherwise returns a -ve error code.
158 samr_connect2(char *server
, char *domain
, char *username
, DWORD access_mask
,
159 mlsvc_handle_t
*samr_handle
)
161 struct samr_Connect2 arg
;
166 bzero(&arg
, sizeof (struct samr_Connect2
));
167 opnum
= SAMR_OPNUM_Connect2
;
168 status
= NT_STATUS_SUCCESS
;
170 len
= strlen(server
) + 4;
171 arg
.servername
= ndr_rpc_malloc(samr_handle
, len
);
172 (void) snprintf((char *)arg
.servername
, len
, "\\\\%s", server
);
173 arg
.access_mask
= access_mask
;
175 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) != 0) {
176 status
= NT_STATUS_UNSUCCESSFUL
;
177 } else if (arg
.status
!= 0) {
178 status
= NT_SC_VALUE(arg
.status
);
180 (void) memcpy(&samr_handle
->handle
, &arg
.handle
,
181 sizeof (ndr_hdid_t
));
183 if (ndr_is_null_handle(samr_handle
))
184 status
= NT_STATUS_INVALID_HANDLE
;
187 ndr_rpc_release(samr_handle
);
194 * Connect to the SAM on a Windows 2000 domain controller.
198 samr_connect4(char *server
, char *domain
, char *username
, DWORD access_mask
,
199 mlsvc_handle_t
*samr_handle
)
201 struct samr_Connect4 arg
;
206 bzero(&arg
, sizeof (struct samr_Connect4
));
207 opnum
= SAMR_OPNUM_Connect4
;
208 status
= NT_STATUS_SUCCESS
;
210 len
= strlen(server
) + 4;
211 arg
.servername
= ndr_rpc_malloc(samr_handle
, len
);
212 (void) snprintf((char *)arg
.servername
, len
, "\\\\%s", server
);
213 arg
.revision
= SAMR_REVISION_2
;
214 arg
.access_mask
= access_mask
;
216 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) != 0) {
217 status
= NT_STATUS_UNSUCCESSFUL
;
218 } else if (arg
.status
!= 0) {
219 status
= NT_SC_VALUE(arg
.status
);
221 (void) memcpy(&samr_handle
->handle
, &arg
.handle
,
222 sizeof (ndr_hdid_t
));
224 if (ndr_is_null_handle(samr_handle
))
225 status
= NT_STATUS_INVALID_HANDLE
;
228 ndr_rpc_release(samr_handle
);
235 * Connect to the SAM on a Windows XP domain controller. On Windows
236 * XP, the server should be the fully qualified DNS domain name with
237 * a double backslash prefix. At this point, it is assumed that we
238 * need to add the prefix and the DNS domain name here.
240 * If this call succeeds, a SAMR handle is placed in samr_handle and
241 * zero is returned. Otherwise, a -ve error code is returned.
245 samr_connect5(char *server
, char *domain
, char *username
, DWORD access_mask
,
246 mlsvc_handle_t
*samr_handle
)
248 struct samr_Connect5 arg
;
253 bzero(&arg
, sizeof (struct samr_Connect5
));
254 opnum
= SAMR_OPNUM_Connect5
;
255 status
= NT_STATUS_SUCCESS
;
257 len
= strlen(server
) + 4;
258 arg
.servername
= ndr_rpc_malloc(samr_handle
, len
);
259 (void) snprintf((char *)arg
.servername
, len
, "\\\\%s", server
);
261 arg
.access_mask
= SAM_ENUM_LOCAL_DOMAIN
;
262 arg
.unknown2_00000001
= 0x00000001;
263 arg
.unknown3_00000001
= 0x00000001;
264 arg
.unknown4_00000003
= 0x00000003;
265 arg
.unknown5_00000000
= 0x00000000;
267 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) != 0) {
268 status
= NT_STATUS_UNSUCCESSFUL
;
269 } else if (arg
.status
!= 0) {
270 status
= NT_SC_VALUE(arg
.status
);
273 (void) memcpy(&samr_handle
->handle
, &arg
.handle
,
274 sizeof (ndr_hdid_t
));
276 if (ndr_is_null_handle(samr_handle
))
277 status
= NT_STATUS_INVALID_HANDLE
;
280 ndr_rpc_release(samr_handle
);
288 * This is function closes any valid handle, i.e. sam, domain, user etc.
289 * If the handle being closed is the top level connect handle, we unbind.
290 * Then we zero out the handle to invalidate it.
293 samr_close_handle(mlsvc_handle_t
*samr_handle
)
295 struct samr_CloseHandle arg
;
298 if (ndr_is_null_handle(samr_handle
))
301 opnum
= SAMR_OPNUM_CloseHandle
;
302 bzero(&arg
, sizeof (struct samr_CloseHandle
));
303 (void) memcpy(&arg
.handle
, &samr_handle
->handle
, sizeof (ndr_hdid_t
));
305 (void) ndr_rpc_call(samr_handle
, opnum
, &arg
);
306 ndr_rpc_release(samr_handle
);
308 if (ndr_is_bind_handle(samr_handle
))
309 ndr_rpc_unbind(samr_handle
);
311 bzero(samr_handle
, sizeof (mlsvc_handle_t
));
317 * We use a SAM handle to obtain a handle for a domain, specified by
318 * the SID. The SID can be obtain via the LSA interface. A handle for
319 * the domain is returned in domain_handle.
322 samr_open_domain(mlsvc_handle_t
*samr_handle
, DWORD access_mask
,
323 struct samr_sid
*sid
, mlsvc_handle_t
*domain_handle
)
325 struct samr_OpenDomain arg
;
329 if (ndr_is_null_handle(samr_handle
) ||
330 sid
== NULL
|| domain_handle
== NULL
) {
331 return (NT_STATUS_INVALID_PARAMETER
);
334 opnum
= SAMR_OPNUM_OpenDomain
;
335 bzero(&arg
, sizeof (struct samr_OpenDomain
));
336 (void) memcpy(&arg
.handle
, &samr_handle
->handle
, sizeof (ndr_hdid_t
));
338 arg
.access_mask
= access_mask
;
341 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) != 0) {
342 status
= NT_STATUS_UNSUCCESSFUL
;
343 } else if (arg
.status
!= 0) {
346 status
= NT_STATUS_SUCCESS
;
347 ndr_inherit_handle(domain_handle
, samr_handle
);
349 (void) memcpy(&domain_handle
->handle
, &arg
.domain_handle
,
350 sizeof (ndr_hdid_t
));
352 if (ndr_is_null_handle(domain_handle
))
353 status
= NT_STATUS_INVALID_HANDLE
;
356 if (status
!= NT_STATUS_SUCCESS
)
357 ndr_rpc_status(samr_handle
, opnum
, status
);
359 ndr_rpc_release(samr_handle
);
366 * Use a domain handle to obtain a handle for a user, specified by the
367 * user RID. A user RID (effectively a uid) can be obtained via the
368 * LSA interface. A handle for the user is returned in user_handle.
369 * Once you have a user handle it should be possible to query the SAM
370 * for information on that user.
373 samr_open_user(mlsvc_handle_t
*domain_handle
, DWORD access_mask
, DWORD rid
,
374 mlsvc_handle_t
*user_handle
)
376 struct samr_OpenUser arg
;
378 DWORD status
= NT_STATUS_SUCCESS
;
380 if (ndr_is_null_handle(domain_handle
) || user_handle
== NULL
)
381 return (NT_STATUS_INVALID_PARAMETER
);
383 opnum
= SAMR_OPNUM_OpenUser
;
384 bzero(&arg
, sizeof (struct samr_OpenUser
));
385 (void) memcpy(&arg
.handle
, &domain_handle
->handle
,
386 sizeof (ndr_hdid_t
));
387 arg
.access_mask
= access_mask
;
390 if (ndr_rpc_call(domain_handle
, opnum
, &arg
) != 0) {
391 status
= NT_STATUS_UNSUCCESSFUL
;
392 } else if (arg
.status
!= 0) {
393 ndr_rpc_status(domain_handle
, opnum
, arg
.status
);
394 status
= NT_SC_VALUE(arg
.status
);
396 ndr_inherit_handle(user_handle
, domain_handle
);
398 (void) memcpy(&user_handle
->handle
, &arg
.user_handle
,
399 sizeof (ndr_hdid_t
));
401 if (ndr_is_null_handle(user_handle
))
402 status
= NT_STATUS_INVALID_HANDLE
;
405 ndr_rpc_release(domain_handle
);
412 * Delete the user specified by the user_handle.
415 samr_delete_user(mlsvc_handle_t
*user_handle
)
417 struct samr_DeleteUser arg
;
421 if (ndr_is_null_handle(user_handle
))
422 return (NT_STATUS_INVALID_PARAMETER
);
424 opnum
= SAMR_OPNUM_DeleteUser
;
425 bzero(&arg
, sizeof (struct samr_DeleteUser
));
426 (void) memcpy(&arg
.user_handle
, &user_handle
->handle
,
427 sizeof (ndr_hdid_t
));
429 if (ndr_rpc_call(user_handle
, opnum
, &arg
) != 0) {
430 status
= NT_STATUS_INVALID_PARAMETER
;
431 } else if (arg
.status
!= 0) {
432 ndr_rpc_status(user_handle
, opnum
, arg
.status
);
433 status
= NT_SC_VALUE(arg
.status
);
438 ndr_rpc_release(user_handle
);
445 * Use a domain handle to obtain a handle for a group, specified by the
446 * group RID. A group RID (effectively a gid) can be obtained via the
447 * LSA interface. A handle for the group is returned in group_handle.
448 * Once you have a group handle it should be possible to query the SAM
449 * for information on that group.
453 mlsvc_handle_t
*domain_handle
,
455 mlsvc_handle_t
*group_handle
)
457 struct samr_OpenGroup arg
;
461 if (ndr_is_null_handle(domain_handle
) || group_handle
== NULL
)
464 opnum
= SAMR_OPNUM_OpenGroup
;
465 bzero(&arg
, sizeof (struct samr_OpenUser
));
466 (void) memcpy(&arg
.handle
, &domain_handle
->handle
,
467 sizeof (ndr_hdid_t
));
468 arg
.access_mask
= SAM_LOOKUP_INFORMATION
| SAM_ACCESS_USER_READ
;
471 if ((rc
= ndr_rpc_call(domain_handle
, opnum
, &arg
)) != 0)
474 if (arg
.status
!= 0) {
475 ndr_rpc_status(domain_handle
, opnum
, arg
.status
);
478 ndr_inherit_handle(group_handle
, domain_handle
);
480 (void) memcpy(&group_handle
->handle
, &arg
.group_handle
,
481 sizeof (ndr_hdid_t
));
483 if (ndr_is_null_handle(group_handle
))
487 ndr_rpc_release(domain_handle
);
494 * Create a user in the domain specified by the domain handle. If this
495 * call is successful, the server will return the RID for the user and
496 * a user handle, which may be used to set or query the SAM.
498 * Observed status codes:
499 * NT_STATUS_INVALID_PARAMETER
500 * NT_STATUS_INVALID_ACCOUNT_NAME
501 * NT_STATUS_ACCESS_DENIED
502 * NT_STATUS_USER_EXISTS
504 * Returns 0 on success. Otherwise returns an NT status code.
507 samr_create_user(mlsvc_handle_t
*domain_handle
, char *username
,
508 DWORD account_flags
, DWORD
*rid
, mlsvc_handle_t
*user_handle
)
510 struct samr_CreateUser arg
;
516 if (ndr_is_null_handle(domain_handle
) ||
517 username
== NULL
|| rid
== NULL
) {
518 return (NT_STATUS_INVALID_PARAMETER
);
521 opnum
= SAMR_OPNUM_CreateUser
;
523 bzero(&arg
, sizeof (struct samr_CreateUser
));
524 (void) memcpy(&arg
.handle
, &domain_handle
->handle
,
525 sizeof (ndr_hdid_t
));
527 heap
= ndr_rpc_get_heap(domain_handle
);
528 ndr_heap_mkvcs(heap
, username
, (ndr_vcstr_t
*)&arg
.username
);
530 arg
.account_flags
= account_flags
;
531 arg
.desired_access
= 0xE00500B0;
533 rc
= ndr_rpc_call(domain_handle
, opnum
, &arg
);
535 status
= NT_STATUS_INVALID_PARAMETER
;
536 } else if (arg
.status
!= 0) {
537 status
= NT_SC_VALUE(arg
.status
);
539 if (status
!= NT_STATUS_USER_EXISTS
) {
540 smb_tracef("SamrCreateUser[%s]: %s",
541 username
, xlate_nt_status(status
));
544 ndr_inherit_handle(user_handle
, domain_handle
);
546 (void) memcpy(&user_handle
->handle
, &arg
.user_handle
,
547 sizeof (ndr_hdid_t
));
551 if (ndr_is_null_handle(user_handle
))
552 status
= NT_STATUS_INVALID_HANDLE
;
557 ndr_rpc_release(domain_handle
);
564 * Lookup up the domain SID for the specified domain name. The handle
565 * should be one returned from samr_connect. The allocated memory for
566 * the returned SID must be freed by caller.
569 samr_lookup_domain(mlsvc_handle_t
*samr_handle
, char *domain_name
)
571 struct samr_LookupDomain arg
;
572 smb_sid_t
*domsid
= NULL
;
576 if (ndr_is_null_handle(samr_handle
) || domain_name
== NULL
)
579 opnum
= SAMR_OPNUM_LookupDomain
;
580 bzero(&arg
, sizeof (struct samr_LookupDomain
));
582 (void) memcpy(&arg
.handle
, &samr_handle
->handle
,
583 sizeof (samr_handle_t
));
585 length
= smb_wcequiv_strlen(domain_name
);
586 length
+= sizeof (smb_wchar_t
);
588 arg
.domain_name
.length
= length
;
589 arg
.domain_name
.allosize
= length
;
590 arg
.domain_name
.str
= (unsigned char *)domain_name
;
592 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) == 0)
593 domsid
= smb_sid_dup((smb_sid_t
*)arg
.sid
);
595 ndr_rpc_release(samr_handle
);
600 * samr_enum_local_domains
602 * Get the list of local domains supported by a server.
604 * Returns NT status codes.
607 samr_enum_local_domains(mlsvc_handle_t
*samr_handle
)
609 struct samr_EnumLocalDomain arg
;
613 if (ndr_is_null_handle(samr_handle
))
614 return (NT_STATUS_INVALID_PARAMETER
);
616 opnum
= SAMR_OPNUM_EnumLocalDomains
;
617 bzero(&arg
, sizeof (struct samr_EnumLocalDomain
));
619 (void) memcpy(&arg
.handle
, &samr_handle
->handle
,
620 sizeof (samr_handle_t
));
621 arg
.enum_context
= 0;
622 arg
.max_length
= 0x00002000; /* Value used by NT */
624 if (ndr_rpc_call(samr_handle
, opnum
, &arg
) != 0) {
625 status
= NT_STATUS_INVALID_PARAMETER
;
627 status
= NT_SC_VALUE(arg
.status
);
630 * Handle none-mapped status quietly.
632 if (status
!= NT_STATUS_NONE_MAPPED
)
633 ndr_rpc_status(samr_handle
, opnum
, arg
.status
);
636 ndr_rpc_release(samr_handle
);
641 * samr_lookup_domain_names
643 * Lookup up the given name in the domain specified by domain_handle.
644 * Upon a successful lookup the information is returned in the account
645 * arg and caller must free allocated memories by calling smb_account_free().
647 * Returns NT status codes.
650 samr_lookup_domain_names(mlsvc_handle_t
*domain_handle
, char *name
,
651 smb_account_t
*account
)
653 struct samr_LookupNames arg
;
658 if (ndr_is_null_handle(domain_handle
) ||
659 name
== NULL
|| account
== NULL
) {
660 return (NT_STATUS_INVALID_PARAMETER
);
663 bzero(account
, sizeof (smb_account_t
));
664 opnum
= SAMR_OPNUM_LookupNames
;
665 bzero(&arg
, sizeof (struct samr_LookupNames
));
667 (void) memcpy(&arg
.handle
, &domain_handle
->handle
,
668 sizeof (samr_handle_t
));
670 arg
.max_n_entry
= 1000;
674 length
= smb_wcequiv_strlen(name
);
675 length
+= sizeof (smb_wchar_t
);
677 arg
.name
.length
= length
;
678 arg
.name
.allosize
= length
;
679 arg
.name
.str
= (unsigned char *)name
;
681 if (ndr_rpc_call(domain_handle
, opnum
, &arg
) != 0) {
682 status
= NT_STATUS_INVALID_PARAMETER
;
683 } else if (arg
.status
!= NT_STATUS_SUCCESS
) {
684 status
= NT_SC_VALUE(arg
.status
);
687 * Handle none-mapped status quietly.
689 if (status
!= NT_STATUS_NONE_MAPPED
)
690 ndr_rpc_status(domain_handle
, opnum
, arg
.status
);
692 account
->a_type
= arg
.rid_types
.rid_type
[0];
693 account
->a_rid
= arg
.rids
.rid
[0];
694 status
= NT_STATUS_SUCCESS
;
697 ndr_rpc_release(domain_handle
);
702 * samr_query_user_info
704 * Query information on a specific user. The handle must be a valid
705 * user handle obtained via samr_open_user.
707 * Returns 0 on success, otherwise returns NT status code.
710 samr_query_user_info(mlsvc_handle_t
*user_handle
, WORD switch_value
,
711 union samr_user_info
*user_info
)
713 struct samr_QueryUserInfo arg
;
716 if (ndr_is_null_handle(user_handle
) || user_info
== 0)
717 return (NT_STATUS_INTERNAL_ERROR
);
719 opnum
= SAMR_OPNUM_QueryUserInfo
;
720 bzero(&arg
, sizeof (struct samr_QueryUserInfo
));
722 (void) memcpy(&arg
.user_handle
, &user_handle
->handle
,
723 sizeof (samr_handle_t
));
724 arg
.switch_value
= switch_value
;
726 if (ndr_rpc_call(user_handle
, opnum
, &arg
) != 0)
727 arg
.status
= RPC_NT_CALL_FAILED
;
730 (void) samr_setup_user_info(switch_value
, &arg
, user_info
);
736 * samr_setup_user_info
738 * Private function to set up the samr_user_info data. Dependent on
739 * the switch value this function may use strdup which will malloc
740 * memory. The caller is responsible for deallocating this memory.
742 * Returns 0 on success, otherwise returns -1.
745 samr_setup_user_info(WORD switch_value
,
746 struct samr_QueryUserInfo
*arg
, union samr_user_info
*user_info
)
748 struct samr_QueryUserInfo1
*info1
;
749 struct samr_QueryUserInfo6
*info6
;
751 switch (switch_value
) {
753 info1
= &arg
->ru
.info1
;
754 user_info
->info1
.username
= strdup(
755 (char const *)info1
->username
.str
);
756 user_info
->info1
.fullname
= strdup(
757 (char const *)info1
->fullname
.str
);
758 user_info
->info1
.description
= strdup(
759 (char const *)info1
->description
.str
);
760 user_info
->info1
.unknown
= 0;
761 user_info
->info1
.group_rid
= info1
->group_rid
;
765 info6
= &arg
->ru
.info6
;
766 user_info
->info6
.username
= strdup(
767 (char const *)info6
->username
.str
);
768 user_info
->info6
.fullname
= strdup(
769 (char const *)info6
->fullname
.str
);
773 user_info
->info7
.username
= strdup(
774 (char const *)arg
->ru
.info7
.username
.str
);
778 user_info
->info8
.fullname
= strdup(
779 (char const *)arg
->ru
.info8
.fullname
.str
);
783 user_info
->info9
.group_rid
= arg
->ru
.info9
.group_rid
;
787 user_info
->info16
.acct_ctrl
=
788 arg
->ru
.info16
.UserAccountControl
;
799 * samr_query_user_groups
801 * Query the groups for a specific user. The handle must be a valid
802 * user handle obtained via samr_open_user. The list of groups is
803 * returned in group_info. Note that group_info->groups is allocated
804 * using malloc. The caller is responsible for deallocating this
805 * memory when it is no longer required. If group_info->n_entry is 0
806 * then no memory was allocated.
808 * Returns 0 on success, otherwise returns -1.
811 samr_query_user_groups(mlsvc_handle_t
*user_handle
, int *n_groups
,
812 struct samr_UserGroups
**groups
)
814 struct samr_QueryUserGroups arg
;
819 if (ndr_is_null_handle(user_handle
))
822 opnum
= SAMR_OPNUM_QueryUserGroups
;
823 bzero(&arg
, sizeof (struct samr_QueryUserGroups
));
825 (void) memcpy(&arg
.user_handle
, &user_handle
->handle
,
826 sizeof (samr_handle_t
));
828 rc
= ndr_rpc_call(user_handle
, opnum
, &arg
);
833 nbytes
= arg
.info
->n_entry
*
834 sizeof (struct samr_UserGroups
);
836 if ((*groups
= malloc(nbytes
)) == NULL
) {
840 *n_groups
= arg
.info
->n_entry
;
841 bcopy(arg
.info
->groups
, *groups
, nbytes
);
846 ndr_rpc_release(user_handle
);
851 * samr_get_user_pwinfo
853 * Get some user password info. I'm not sure what this is yet but it is
854 * part of the create user sequence. The handle must be a valid user
855 * handle. Since I don't know what this is returning, I haven't provided
856 * any return data yet.
858 * Returns 0 on success. Otherwise returns an NT status code.
861 samr_get_user_pwinfo(mlsvc_handle_t
*user_handle
)
863 struct samr_GetUserPwInfo arg
;
867 if (ndr_is_null_handle(user_handle
))
868 return (NT_STATUS_INVALID_PARAMETER
);
870 opnum
= SAMR_OPNUM_GetUserPwInfo
;
871 bzero(&arg
, sizeof (struct samr_GetUserPwInfo
));
872 (void) memcpy(&arg
.user_handle
, &user_handle
->handle
,
873 sizeof (samr_handle_t
));
875 if (ndr_rpc_call(user_handle
, opnum
, &arg
) != 0) {
876 status
= NT_STATUS_INVALID_PARAMETER
;
877 } else if (arg
.status
!= 0) {
878 ndr_rpc_status(user_handle
, opnum
, arg
.status
);
879 status
= NT_SC_VALUE(arg
.status
);
884 ndr_rpc_release(user_handle
);
888 DECL_FIXUP_STRUCT(samr_SetUserInfo_u
);
889 DECL_FIXUP_STRUCT(samr_SetUserInfo_s
);
890 DECL_FIXUP_STRUCT(samr_SetUserInfo
);
895 * Returns 0 on success. Otherwise returns an NT status code.
896 * NT status codes observed so far:
897 * NT_STATUS_WRONG_PASSWORD
901 mlsvc_handle_t
*user_handle
,
905 struct samr_SetUserInfo arg
;
906 uint16_t usize
, tsize
;
909 if (ndr_is_null_handle(user_handle
))
910 return (NT_STATUS_INTERNAL_ERROR
);
913 * Only support a few levels
914 * MS-SAMR: UserInternal4Information
916 switch (info_level
) {
917 case 16: /* samr_SetUserInfo16 */
918 usize
= sizeof (struct samr_SetUserInfo16
);
920 case 21: /* samr_SetUserInfo21 */
921 usize
= sizeof (struct samr_SetUserInfo21
);
923 case 23: /* samr_SetUserInfo23 */
924 usize
= sizeof (struct samr_SetUserInfo23
);
926 case 24: /* samr_SetUserInfo24 */
927 usize
= sizeof (struct samr_SetUserInfo24
);
930 return (NT_STATUS_INVALID_LEVEL
);
934 * OK, now this gets really ugly, because
935 * ndrgen doesn't do unions correctly.
937 FIXUP_PDU_SIZE(samr_SetUserInfo_u
, usize
);
938 tsize
= usize
+ (2 * sizeof (WORD
));
939 FIXUP_PDU_SIZE(samr_SetUserInfo_s
, tsize
);
940 tsize
+= sizeof (ndr_request_hdr_t
) + sizeof (DWORD
);
941 FIXUP_PDU_SIZE(samr_SetUserInfo
, tsize
);
943 opnum
= SAMR_OPNUM_SetUserInfo
;
944 bzero(&arg
, sizeof (arg
));
945 (void) memcpy(&arg
.user_handle
, &user_handle
->handle
,
946 sizeof (samr_handle_t
));
947 arg
.info
.info_level
= info_level
;
948 arg
.info
.switch_value
= info_level
;
949 (void) memcpy(&arg
.info
.ru
, info_buf
, usize
);
951 if (ndr_rpc_call(user_handle
, opnum
, &arg
) != 0)
952 arg
.status
= RPC_NT_CALL_FAILED
;
953 else if (arg
.status
!= 0)
954 ndr_rpc_status(user_handle
, opnum
, arg
.status
);
956 ndr_rpc_release(user_handle
);
961 * Client side wrapper for SamrUnicodeChangePasswordUser2
962 * [MS-SAMR 3.1.5.10.3]
966 samr_change_password(
967 mlsvc_handle_t
*handle
,
970 struct samr_encr_passwd
*newpw
,
971 struct samr_encr_hash
*oldpw
)
973 static struct samr_encr_passwd zero_newpw
;
974 static struct samr_encr_hash zero_oldpw
;
975 struct samr_ChangePasswordUser2 arg
;
976 int opnum
= SAMR_OPNUM_ChangePasswordUser2
;
980 (void) memset(&arg
, 0, sizeof (arg
));
982 /* Need server name with slashes */
983 len
= 2 + strlen(server
) + 1;
984 slashserver
= ndr_rpc_malloc(handle
, len
);
985 if (slashserver
== NULL
)
986 return (NT_STATUS_NO_MEMORY
);
987 (void) snprintf(slashserver
, len
, "\\\\%s", server
);
989 arg
.servername
= ndr_rpc_malloc(handle
, sizeof (samr_string_t
));
990 if (arg
.servername
== NULL
)
991 return (NT_STATUS_NO_MEMORY
);
992 len
= smb_wcequiv_strlen(slashserver
);
994 return (NT_STATUS_INVALID_PARAMETER
);
995 len
+= 2; /* the WC null */
996 arg
.servername
->length
= len
;
997 arg
.servername
->allosize
= len
;
998 arg
.servername
->str
= (uint8_t *)slashserver
;
1000 arg
.username
= ndr_rpc_malloc(handle
, sizeof (samr_string_t
));
1001 if (arg
.username
== NULL
)
1002 return (NT_STATUS_NO_MEMORY
);
1003 len
= smb_wcequiv_strlen(account
);
1005 return (NT_STATUS_INVALID_PARAMETER
);
1006 len
+= 2; /* the WC null */
1007 arg
.username
->length
= len
;
1008 arg
.username
->allosize
= len
;
1009 arg
.username
->str
= (uint8_t *)account
;
1011 arg
.nt_newpw
= newpw
;
1012 arg
.nt_oldpw
= oldpw
;
1014 arg
.lm_newpw
= &zero_newpw
;
1015 arg
.lm_oldpw
= &zero_oldpw
;
1017 if (ndr_rpc_call(handle
, opnum
, &arg
) != 0)
1018 arg
.status
= RPC_NT_CALL_FAILED
;
1019 else if (arg
.status
!= 0)
1020 ndr_rpc_status(handle
, opnum
, arg
.status
);
1022 ndr_rpc_release(handle
);
1023 return (arg
.status
);