1fe1c642dSBill Krier /*
2fe1c642dSBill Krier  * CDDL HEADER START
3fe1c642dSBill Krier  *
4fe1c642dSBill Krier  * The contents of this file are subject to the terms of the
5fe1c642dSBill Krier  * Common Development and Distribution License (the "License").
6fe1c642dSBill Krier  * You may not use this file except in compliance with the License.
7fe1c642dSBill Krier  *
8fe1c642dSBill Krier  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fe1c642dSBill Krier  * or http://www.opensolaris.org/os/licensing.
10fe1c642dSBill Krier  * See the License for the specific language governing permissions
11fe1c642dSBill Krier  * and limitations under the License.
12fe1c642dSBill Krier  *
13fe1c642dSBill Krier  * When distributing Covered Code, include this CDDL HEADER in each
14fe1c642dSBill Krier  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fe1c642dSBill Krier  * If applicable, add the following below this CDDL HEADER, with the
16fe1c642dSBill Krier  * fields enclosed by brackets "[]" replaced with your own identifying
17fe1c642dSBill Krier  * information: Portions Copyright [yyyy] [name of copyright owner]
18fe1c642dSBill Krier  *
19fe1c642dSBill Krier  * CDDL HEADER END
20fe1c642dSBill Krier  */
21148c5f43SAlan Wright 
22fe1c642dSBill Krier /*
23148c5f43SAlan Wright  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24*adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
25fe1c642dSBill Krier  */
26fe1c642dSBill Krier 
27fe1c642dSBill Krier /*
28fe1c642dSBill Krier  * Security Accounts Manager RPC (SAMR) client-side interface.
29fe1c642dSBill Krier  *
30fe1c642dSBill Krier  * The SAM is a hierarchical database:
31fe1c642dSBill Krier  * - If you want to talk to the SAM you need a SAM handle.
32fe1c642dSBill Krier  * - If you want to work with a domain, use the SAM handle.
33fe1c642dSBill Krier  *   to obtain a domain handle.
34fe1c642dSBill Krier  * - Use domain handles to obtain user handles etc.
35fe1c642dSBill Krier  *
36fe1c642dSBill Krier  * Be careful about returning null handles to the application.  Use of a
37fe1c642dSBill Krier  * null handle may crash the domain controller if you attempt to use it.
38fe1c642dSBill Krier  */
39fe1c642dSBill Krier 
40fe1c642dSBill Krier #include <stdio.h>
41fe1c642dSBill Krier #include <strings.h>
42fe1c642dSBill Krier #include <stdlib.h>
43fe1c642dSBill Krier #include <unistd.h>
44fe1c642dSBill Krier #include <netdb.h>
45fe1c642dSBill Krier #include <sys/param.h>
46fe1c642dSBill Krier 
473299f39fSGordon Ross #include <libmlrpc/libmlrpc.h>
48fe1c642dSBill Krier #include <smbsrv/libsmb.h>
49fe1c642dSBill Krier #include <smbsrv/libmlsvc.h>
50fe1c642dSBill Krier #include <smbsrv/smbinfo.h>
51*adee6784SGordon Ross #include <smb/ntaccess.h>
52fe1c642dSBill Krier #include <smbsrv/smb_sid.h>
53fe1c642dSBill Krier #include <samlib.h>
54fe1c642dSBill Krier 
55fe1c642dSBill Krier static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
56fe1c642dSBill Krier static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
57cb174861Sjoyce mcintosh static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *);
58fe1c642dSBill Krier 
59fe1c642dSBill Krier typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD,
60fe1c642dSBill Krier     mlsvc_handle_t *);
61fe1c642dSBill Krier 
62fe1c642dSBill Krier static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
63fe1c642dSBill Krier     union samr_user_info *);
64fe1c642dSBill Krier 
65fe1c642dSBill Krier /*
66fe1c642dSBill Krier  * samr_open
67fe1c642dSBill Krier  *
68fe1c642dSBill Krier  * Wrapper round samr_connect to ensure that we connect using the server
69fe1c642dSBill Krier  * and domain.  We default to the resource domain if the caller doesn't
70fe1c642dSBill Krier  * supply a server name and a domain name.
71fe1c642dSBill Krier  *
72fe1c642dSBill Krier  * If username argument is NULL, an anonymous connection will be established.
73fe1c642dSBill Krier  * Otherwise, an authenticated connection will be established.
74fe1c642dSBill Krier  *
75fe1c642dSBill Krier  * On success 0 is returned. Otherwise a -ve error code.
76fe1c642dSBill Krier  */
771ed6b69aSGordon Ross DWORD
samr_open(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)78fe1c642dSBill Krier samr_open(char *server, char *domain, char *username, DWORD access_mask,
79fe1c642dSBill Krier     mlsvc_handle_t *samr_handle)
80fe1c642dSBill Krier {
81fe1c642dSBill Krier 	smb_domainex_t di;
821ed6b69aSGordon Ross 	DWORD status;
83fe1c642dSBill Krier 
84fe1c642dSBill Krier 	if (server == NULL || domain == NULL) {
85fe1c642dSBill Krier 		if (!smb_domain_getinfo(&di))
861ed6b69aSGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
87b3700b07SGordon Ross 		server = di.d_dci.dc_name;
88fe1c642dSBill Krier 		domain = di.d_primary.di_nbname;
89fe1c642dSBill Krier 	}
90fe1c642dSBill Krier 
91fe1c642dSBill Krier 	if (username == NULL)
92fe1c642dSBill Krier 		username = MLSVC_ANON_USER;
93fe1c642dSBill Krier 
941ed6b69aSGordon Ross 	status = samr_connect(server, domain, username, access_mask,
951ed6b69aSGordon Ross 	    samr_handle);
961ed6b69aSGordon Ross 
971ed6b69aSGordon Ross 	return (status);
98fe1c642dSBill Krier }
99fe1c642dSBill Krier 
100fe1c642dSBill Krier 
101fe1c642dSBill Krier /*
102fe1c642dSBill Krier  * samr_connect
103fe1c642dSBill Krier  *
104fe1c642dSBill Krier  * Connect to the SAMR service on the specified server (domain controller).
105fe1c642dSBill Krier  * New SAM connect calls have been added to Windows over time:
106fe1c642dSBill Krier  *
107fe1c642dSBill Krier  *	Windows NT3.x:	SamrConnect
108fe1c642dSBill Krier  *	Windows NT4.0:	SamrConnect2
109cb174861Sjoyce mcintosh  *	Windows 2000:	SamrConnect4
110cb174861Sjoyce mcintosh  *	Windows XP:	SamrConnect5
111fe1c642dSBill Krier  *
112fe1c642dSBill Krier  * Try the calls from most recent to oldest until the server responds with
113fe1c642dSBill Krier  * something other than an RPC protocol error.  We don't use the original
114fe1c642dSBill Krier  * connect call because all supported servers should support SamrConnect2.
115fe1c642dSBill Krier  */
1161ed6b69aSGordon Ross DWORD
samr_connect(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)117fe1c642dSBill Krier samr_connect(char *server, char *domain, char *username, DWORD access_mask,
118fe1c642dSBill Krier     mlsvc_handle_t *samr_handle)
119fe1c642dSBill Krier {
120fe1c642dSBill Krier 	static samr_connop_t samr_connop[] = {
121cb174861Sjoyce mcintosh 		samr_connect5,
122fe1c642dSBill Krier 		samr_connect4,
123fe1c642dSBill Krier 		samr_connect2
124fe1c642dSBill Krier 	};
125fe1c642dSBill Krier 
126fe1c642dSBill Krier 	int	n_op = (sizeof (samr_connop) / sizeof (samr_connop[0]));
127fe1c642dSBill Krier 	DWORD	status;
128fe1c642dSBill Krier 	int	i;
129fe1c642dSBill Krier 
1301ed6b69aSGordon Ross 	status = ndr_rpc_bind(samr_handle, server, domain, username, "SAMR");
1311ed6b69aSGordon Ross 	if (status)
1321ed6b69aSGordon Ross 		return (status);
133fe1c642dSBill Krier 
134fe1c642dSBill Krier 	for (i = 0; i < n_op; ++i) {
135fe1c642dSBill Krier 		status = (*samr_connop[i])(server, domain, username,
136fe1c642dSBill Krier 		    access_mask, samr_handle);
137fe1c642dSBill Krier 
138cb174861Sjoyce mcintosh 		if (status == NT_STATUS_SUCCESS)
1391ed6b69aSGordon Ross 			return (status);
140fe1c642dSBill Krier 	}
141fe1c642dSBill Krier 
142fe1c642dSBill Krier 	ndr_rpc_unbind(samr_handle);
143fe1c642dSBill Krier 	return (status);
144fe1c642dSBill Krier }
145fe1c642dSBill Krier 
146fe1c642dSBill Krier /*
147fe1c642dSBill Krier  * samr_connect2
148fe1c642dSBill Krier  *
149fe1c642dSBill Krier  * Connect to the SAM on a Windows NT 4.0 server (domain controller).
150fe1c642dSBill Krier  * We need the domain controller name and, if everything works, we
151fe1c642dSBill Krier  * return a handle.  This function adds the double backslash prefx to
152fe1c642dSBill Krier  * make it easy for applications.
153fe1c642dSBill Krier  *
154fe1c642dSBill Krier  * Returns 0 on success. Otherwise returns a -ve error code.
155fe1c642dSBill Krier  */
156fe1c642dSBill Krier /*ARGSUSED*/
157fe1c642dSBill Krier static DWORD
samr_connect2(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)158fe1c642dSBill Krier samr_connect2(char *server, char *domain, char *username, DWORD access_mask,
159fe1c642dSBill Krier     mlsvc_handle_t *samr_handle)
160fe1c642dSBill Krier {
161cb174861Sjoyce mcintosh 	struct samr_Connect2 arg;
162fe1c642dSBill Krier 	int opnum;
163fe1c642dSBill Krier 	DWORD status;
164fe1c642dSBill Krier 	int len;
165fe1c642dSBill Krier 
166cb174861Sjoyce mcintosh 	bzero(&arg, sizeof (struct samr_Connect2));
167cb174861Sjoyce mcintosh 	opnum = SAMR_OPNUM_Connect2;
168fe1c642dSBill Krier 	status = NT_STATUS_SUCCESS;
169fe1c642dSBill Krier 
170fe1c642dSBill Krier 	len = strlen(server) + 4;
171fe1c642dSBill Krier 	arg.servername = ndr_rpc_malloc(samr_handle, len);
172fe1c642dSBill Krier 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
173fe1c642dSBill Krier 	arg.access_mask = access_mask;
174fe1c642dSBill Krier 
175fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
176fe1c642dSBill Krier 		status = NT_STATUS_UNSUCCESSFUL;
177fe1c642dSBill Krier 	} else if (arg.status != 0) {
178fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
179fe1c642dSBill Krier 	} else {
180fe1c642dSBill Krier 		(void) memcpy(&samr_handle->handle, &arg.handle,
181fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
182fe1c642dSBill Krier 
183fe1c642dSBill Krier 		if (ndr_is_null_handle(samr_handle))
184fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
185fe1c642dSBill Krier 	}
186fe1c642dSBill Krier 
187fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
188fe1c642dSBill Krier 	return (status);
189fe1c642dSBill Krier }
190fe1c642dSBill Krier 
191fe1c642dSBill Krier /*
192cb174861Sjoyce mcintosh  * samr_connect4
193fe1c642dSBill Krier  *
194fe1c642dSBill Krier  * Connect to the SAM on a Windows 2000 domain controller.
195fe1c642dSBill Krier  */
196fe1c642dSBill Krier /*ARGSUSED*/
197fe1c642dSBill Krier static DWORD
samr_connect4(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)198cb174861Sjoyce mcintosh samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
199fe1c642dSBill Krier     mlsvc_handle_t *samr_handle)
200fe1c642dSBill Krier {
201cb174861Sjoyce mcintosh 	struct samr_Connect4 arg;
202fe1c642dSBill Krier 	int opnum;
203fe1c642dSBill Krier 	DWORD status;
204fe1c642dSBill Krier 	int len;
205fe1c642dSBill Krier 
206cb174861Sjoyce mcintosh 	bzero(&arg, sizeof (struct samr_Connect4));
207cb174861Sjoyce mcintosh 	opnum = SAMR_OPNUM_Connect4;
208fe1c642dSBill Krier 	status = NT_STATUS_SUCCESS;
209fe1c642dSBill Krier 
210fe1c642dSBill Krier 	len = strlen(server) + 4;
211fe1c642dSBill Krier 	arg.servername = ndr_rpc_malloc(samr_handle, len);
212fe1c642dSBill Krier 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
213fe1c642dSBill Krier 	arg.revision = SAMR_REVISION_2;
214fe1c642dSBill Krier 	arg.access_mask = access_mask;
215fe1c642dSBill Krier 
216fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
217fe1c642dSBill Krier 		status = NT_STATUS_UNSUCCESSFUL;
218fe1c642dSBill Krier 	} else if (arg.status != 0) {
219fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
220fe1c642dSBill Krier 	} else {
221fe1c642dSBill Krier 		(void) memcpy(&samr_handle->handle, &arg.handle,
222fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
223fe1c642dSBill Krier 
224fe1c642dSBill Krier 		if (ndr_is_null_handle(samr_handle))
225fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
226fe1c642dSBill Krier 	}
227fe1c642dSBill Krier 
228fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
229fe1c642dSBill Krier 	return (status);
230fe1c642dSBill Krier }
231fe1c642dSBill Krier 
232fe1c642dSBill Krier /*
233cb174861Sjoyce mcintosh  * samr_connect5
234fe1c642dSBill Krier  *
235fe1c642dSBill Krier  * Connect to the SAM on a Windows XP domain controller.  On Windows
236fe1c642dSBill Krier  * XP, the server should be the fully qualified DNS domain name with
237fe1c642dSBill Krier  * a double backslash prefix.  At this point, it is assumed that we
238fe1c642dSBill Krier  * need to add the prefix and the DNS domain name here.
239fe1c642dSBill Krier  *
240fe1c642dSBill Krier  * If this call succeeds, a SAMR handle is placed in samr_handle and
241fe1c642dSBill Krier  * zero is returned. Otherwise, a -ve error code is returned.
242fe1c642dSBill Krier  */
243fe1c642dSBill Krier /*ARGSUSED*/
244fe1c642dSBill Krier static DWORD
samr_connect5(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)245cb174861Sjoyce mcintosh samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
246fe1c642dSBill Krier     mlsvc_handle_t *samr_handle)
247fe1c642dSBill Krier {
248cb174861Sjoyce mcintosh 	struct samr_Connect5 arg;
249fe1c642dSBill Krier 	int len;
250fe1c642dSBill Krier 	int opnum;
251fe1c642dSBill Krier 	DWORD status;
252fe1c642dSBill Krier 
253cb174861Sjoyce mcintosh 	bzero(&arg, sizeof (struct samr_Connect5));
254cb174861Sjoyce mcintosh 	opnum = SAMR_OPNUM_Connect5;
255fe1c642dSBill Krier 	status = NT_STATUS_SUCCESS;
256fe1c642dSBill Krier 
2571ed6b69aSGordon Ross 	len = strlen(server) + 4;
258fe1c642dSBill Krier 	arg.servername = ndr_rpc_malloc(samr_handle, len);
259fe1c642dSBill Krier 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
260fe1c642dSBill Krier 
261fe1c642dSBill Krier 	arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
262fe1c642dSBill Krier 	arg.unknown2_00000001 = 0x00000001;
263fe1c642dSBill Krier 	arg.unknown3_00000001 = 0x00000001;
264fe1c642dSBill Krier 	arg.unknown4_00000003 = 0x00000003;
265fe1c642dSBill Krier 	arg.unknown5_00000000 = 0x00000000;
266fe1c642dSBill Krier 
267fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
268fe1c642dSBill Krier 		status = NT_STATUS_UNSUCCESSFUL;
269fe1c642dSBill Krier 	} else if (arg.status != 0) {
270fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
271fe1c642dSBill Krier 	} else {
272fe1c642dSBill Krier 
273fe1c642dSBill Krier 		(void) memcpy(&samr_handle->handle, &arg.handle,
274fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
275fe1c642dSBill Krier 
276fe1c642dSBill Krier 		if (ndr_is_null_handle(samr_handle))
277fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
278fe1c642dSBill Krier 	}
279fe1c642dSBill Krier 
280fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
281fe1c642dSBill Krier 	return (status);
282fe1c642dSBill Krier }
283fe1c642dSBill Krier 
284fe1c642dSBill Krier 
285fe1c642dSBill Krier /*
286fe1c642dSBill Krier  * samr_close_handle
287fe1c642dSBill Krier  *
288fe1c642dSBill Krier  * This is function closes any valid handle, i.e. sam, domain, user etc.
289fe1c642dSBill Krier  * If the handle being closed is the top level connect handle, we unbind.
290fe1c642dSBill Krier  * Then we zero out the handle to invalidate it.
291fe1c642dSBill Krier  */
2921ed6b69aSGordon Ross void
samr_close_handle(mlsvc_handle_t * samr_handle)293fe1c642dSBill Krier samr_close_handle(mlsvc_handle_t *samr_handle)
294fe1c642dSBill Krier {
295fe1c642dSBill Krier 	struct samr_CloseHandle arg;
296fe1c642dSBill Krier 	int opnum;
297fe1c642dSBill Krier 
298fe1c642dSBill Krier 	if (ndr_is_null_handle(samr_handle))
2991ed6b69aSGordon Ross 		return;
300fe1c642dSBill Krier 
301fe1c642dSBill Krier 	opnum = SAMR_OPNUM_CloseHandle;
302fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_CloseHandle));
303fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
304fe1c642dSBill Krier 
305fe1c642dSBill Krier 	(void) ndr_rpc_call(samr_handle, opnum, &arg);
306fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
307fe1c642dSBill Krier 
308fe1c642dSBill Krier 	if (ndr_is_bind_handle(samr_handle))
309fe1c642dSBill Krier 		ndr_rpc_unbind(samr_handle);
310fe1c642dSBill Krier 
311fe1c642dSBill Krier 	bzero(samr_handle, sizeof (mlsvc_handle_t));
312fe1c642dSBill Krier }
313fe1c642dSBill Krier 
314fe1c642dSBill Krier /*
315fe1c642dSBill Krier  * samr_open_domain
316fe1c642dSBill Krier  *
317fe1c642dSBill Krier  * We use a SAM handle to obtain a handle for a domain, specified by
318fe1c642dSBill Krier  * the SID. The SID can be obtain via the LSA interface. A handle for
319fe1c642dSBill Krier  * the domain is returned in domain_handle.
320fe1c642dSBill Krier  */
321fe1c642dSBill Krier DWORD
samr_open_domain(mlsvc_handle_t * samr_handle,DWORD access_mask,struct samr_sid * sid,mlsvc_handle_t * domain_handle)322fe1c642dSBill Krier samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
323fe1c642dSBill Krier     struct samr_sid *sid, mlsvc_handle_t *domain_handle)
324fe1c642dSBill Krier {
325fe1c642dSBill Krier 	struct samr_OpenDomain arg;
326fe1c642dSBill Krier 	int opnum;
327fe1c642dSBill Krier 	DWORD status;
328fe1c642dSBill Krier 
329fe1c642dSBill Krier 	if (ndr_is_null_handle(samr_handle) ||
330fe1c642dSBill Krier 	    sid == NULL || domain_handle == NULL) {
331fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
332fe1c642dSBill Krier 	}
333fe1c642dSBill Krier 
334fe1c642dSBill Krier 	opnum = SAMR_OPNUM_OpenDomain;
335fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_OpenDomain));
336fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
337fe1c642dSBill Krier 
338fe1c642dSBill Krier 	arg.access_mask = access_mask;
339fe1c642dSBill Krier 	arg.sid = sid;
340fe1c642dSBill Krier 
341fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
342fe1c642dSBill Krier 		status = NT_STATUS_UNSUCCESSFUL;
343fe1c642dSBill Krier 	} else if (arg.status != 0) {
344fe1c642dSBill Krier 		status = arg.status;
345fe1c642dSBill Krier 	} else {
346fe1c642dSBill Krier 		status = NT_STATUS_SUCCESS;
347fe1c642dSBill Krier 		ndr_inherit_handle(domain_handle, samr_handle);
348fe1c642dSBill Krier 
349fe1c642dSBill Krier 		(void) memcpy(&domain_handle->handle, &arg.domain_handle,
350fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
351fe1c642dSBill Krier 
352fe1c642dSBill Krier 		if (ndr_is_null_handle(domain_handle))
353fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
354fe1c642dSBill Krier 	}
355fe1c642dSBill Krier 
356fe1c642dSBill Krier 	if (status != NT_STATUS_SUCCESS)
357fe1c642dSBill Krier 		ndr_rpc_status(samr_handle, opnum, status);
358fe1c642dSBill Krier 
359fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
360fe1c642dSBill Krier 	return (status);
361fe1c642dSBill Krier }
362fe1c642dSBill Krier 
363fe1c642dSBill Krier /*
364fe1c642dSBill Krier  * samr_open_user
365fe1c642dSBill Krier  *
366fe1c642dSBill Krier  * Use a domain handle to obtain a handle for a user, specified by the
367fe1c642dSBill Krier  * user RID. A user RID (effectively a uid) can be obtained via the
368fe1c642dSBill Krier  * LSA interface. A handle for the user is returned in user_handle.
369fe1c642dSBill Krier  * Once you have a user handle it should be possible to query the SAM
370fe1c642dSBill Krier  * for information on that user.
371fe1c642dSBill Krier  */
372fe1c642dSBill Krier DWORD
samr_open_user(mlsvc_handle_t * domain_handle,DWORD access_mask,DWORD rid,mlsvc_handle_t * user_handle)373fe1c642dSBill Krier samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid,
374fe1c642dSBill Krier     mlsvc_handle_t *user_handle)
375fe1c642dSBill Krier {
376fe1c642dSBill Krier 	struct samr_OpenUser arg;
377fe1c642dSBill Krier 	int opnum;
378fe1c642dSBill Krier 	DWORD status = NT_STATUS_SUCCESS;
379fe1c642dSBill Krier 
380fe1c642dSBill Krier 	if (ndr_is_null_handle(domain_handle) || user_handle == NULL)
381fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
382fe1c642dSBill Krier 
383fe1c642dSBill Krier 	opnum = SAMR_OPNUM_OpenUser;
384fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_OpenUser));
385fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &domain_handle->handle,
386fe1c642dSBill Krier 	    sizeof (ndr_hdid_t));
387fe1c642dSBill Krier 	arg.access_mask = access_mask;
388fe1c642dSBill Krier 	arg.rid = rid;
389fe1c642dSBill Krier 
390fe1c642dSBill Krier 	if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
391fe1c642dSBill Krier 		status = NT_STATUS_UNSUCCESSFUL;
392fe1c642dSBill Krier 	} else if (arg.status != 0) {
393fe1c642dSBill Krier 		ndr_rpc_status(domain_handle, opnum, arg.status);
394fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
395fe1c642dSBill Krier 	} else {
396fe1c642dSBill Krier 		ndr_inherit_handle(user_handle, domain_handle);
397fe1c642dSBill Krier 
398fe1c642dSBill Krier 		(void) memcpy(&user_handle->handle, &arg.user_handle,
399fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
400fe1c642dSBill Krier 
401fe1c642dSBill Krier 		if (ndr_is_null_handle(user_handle))
402fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
403fe1c642dSBill Krier 	}
404fe1c642dSBill Krier 
405fe1c642dSBill Krier 	ndr_rpc_release(domain_handle);
406fe1c642dSBill Krier 	return (status);
407fe1c642dSBill Krier }
408fe1c642dSBill Krier 
409fe1c642dSBill Krier /*
410fe1c642dSBill Krier  * samr_delete_user
411fe1c642dSBill Krier  *
412fe1c642dSBill Krier  * Delete the user specified by the user_handle.
413fe1c642dSBill Krier  */
414fe1c642dSBill Krier DWORD
samr_delete_user(mlsvc_handle_t * user_handle)415fe1c642dSBill Krier samr_delete_user(mlsvc_handle_t *user_handle)
416fe1c642dSBill Krier {
417fe1c642dSBill Krier 	struct samr_DeleteUser arg;
418fe1c642dSBill Krier 	int opnum;
419fe1c642dSBill Krier 	DWORD status;
420fe1c642dSBill Krier 
421fe1c642dSBill Krier 	if (ndr_is_null_handle(user_handle))
422fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
423fe1c642dSBill Krier 
424fe1c642dSBill Krier 	opnum = SAMR_OPNUM_DeleteUser;
425fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_DeleteUser));
426fe1c642dSBill Krier 	(void) memcpy(&arg.user_handle, &user_handle->handle,
427fe1c642dSBill Krier 	    sizeof (ndr_hdid_t));
428fe1c642dSBill Krier 
429fe1c642dSBill Krier 	if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
430fe1c642dSBill Krier 		status = NT_STATUS_INVALID_PARAMETER;
431fe1c642dSBill Krier 	} else if (arg.status != 0) {
432fe1c642dSBill Krier 		ndr_rpc_status(user_handle, opnum, arg.status);
433fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
434fe1c642dSBill Krier 	} else {
435fe1c642dSBill Krier 		status = 0;
436fe1c642dSBill Krier 	}
437fe1c642dSBill Krier 
438fe1c642dSBill Krier 	ndr_rpc_release(user_handle);
439fe1c642dSBill Krier 	return (status);
440fe1c642dSBill Krier }
441fe1c642dSBill Krier 
442fe1c642dSBill Krier /*
443fe1c642dSBill Krier  * samr_open_group
444fe1c642dSBill Krier  *
445fe1c642dSBill Krier  * Use a domain handle to obtain a handle for a group, specified by the
446fe1c642dSBill Krier  * group RID. A group RID (effectively a gid) can be obtained via the
447fe1c642dSBill Krier  * LSA interface. A handle for the group is returned in group_handle.
448fe1c642dSBill Krier  * Once you have a group handle it should be possible to query the SAM
449fe1c642dSBill Krier  * for information on that group.
450fe1c642dSBill Krier  */
451fe1c642dSBill Krier int
samr_open_group(mlsvc_handle_t * domain_handle,DWORD rid,mlsvc_handle_t * group_handle)452fe1c642dSBill Krier samr_open_group(
453fe1c642dSBill Krier 	mlsvc_handle_t *domain_handle,
454fe1c642dSBill Krier 	DWORD rid,
455fe1c642dSBill Krier 	mlsvc_handle_t *group_handle)
456fe1c642dSBill Krier {
457fe1c642dSBill Krier 	struct samr_OpenGroup arg;
458fe1c642dSBill Krier 	int opnum;
459fe1c642dSBill Krier 	int rc;
460fe1c642dSBill Krier 
461fe1c642dSBill Krier 	if (ndr_is_null_handle(domain_handle) || group_handle == NULL)
462fe1c642dSBill Krier 		return (-1);
463fe1c642dSBill Krier 
464fe1c642dSBill Krier 	opnum = SAMR_OPNUM_OpenGroup;
465fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_OpenUser));
466fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &domain_handle->handle,
467fe1c642dSBill Krier 	    sizeof (ndr_hdid_t));
468fe1c642dSBill Krier 	arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ;
469fe1c642dSBill Krier 	arg.rid = rid;
470fe1c642dSBill Krier 
471fe1c642dSBill Krier 	if ((rc = ndr_rpc_call(domain_handle, opnum, &arg)) != 0)
472fe1c642dSBill Krier 		return (-1);
473fe1c642dSBill Krier 
474fe1c642dSBill Krier 	if (arg.status != 0) {
475fe1c642dSBill Krier 		ndr_rpc_status(domain_handle, opnum, arg.status);
476fe1c642dSBill Krier 		rc = -1;
477fe1c642dSBill Krier 	} else {
478fe1c642dSBill Krier 		ndr_inherit_handle(group_handle, domain_handle);
479fe1c642dSBill Krier 
480fe1c642dSBill Krier 		(void) memcpy(&group_handle->handle, &arg.group_handle,
481fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
482fe1c642dSBill Krier 
483fe1c642dSBill Krier 		if (ndr_is_null_handle(group_handle))
484fe1c642dSBill Krier 			rc = -1;
485fe1c642dSBill Krier 	}
486fe1c642dSBill Krier 
487fe1c642dSBill Krier 	ndr_rpc_release(domain_handle);
488fe1c642dSBill Krier 	return (rc);
489fe1c642dSBill Krier }
490fe1c642dSBill Krier 
491fe1c642dSBill Krier /*
492fe1c642dSBill Krier  * samr_create_user
493fe1c642dSBill Krier  *
494fe1c642dSBill Krier  * Create a user in the domain specified by the domain handle. If this
495fe1c642dSBill Krier  * call is successful, the server will return the RID for the user and
496fe1c642dSBill Krier  * a user handle, which may be used to set or query the SAM.
497fe1c642dSBill Krier  *
498fe1c642dSBill Krier  * Observed status codes:
499fe1c642dSBill Krier  *	NT_STATUS_INVALID_PARAMETER
500fe1c642dSBill Krier  *	NT_STATUS_INVALID_ACCOUNT_NAME
501fe1c642dSBill Krier  *	NT_STATUS_ACCESS_DENIED
502fe1c642dSBill Krier  *	NT_STATUS_USER_EXISTS
503fe1c642dSBill Krier  *
504fe1c642dSBill Krier  * Returns 0 on success. Otherwise returns an NT status code.
505fe1c642dSBill Krier  */
506fe1c642dSBill Krier DWORD
samr_create_user(mlsvc_handle_t * domain_handle,char * username,DWORD account_flags,DWORD * rid,mlsvc_handle_t * user_handle)507fe1c642dSBill Krier samr_create_user(mlsvc_handle_t *domain_handle, char *username,
508fe1c642dSBill Krier     DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle)
509fe1c642dSBill Krier {
510fe1c642dSBill Krier 	struct samr_CreateUser arg;
511fe1c642dSBill Krier 	ndr_heap_t *heap;
512fe1c642dSBill Krier 	int opnum;
513fe1c642dSBill Krier 	int rc;
514fe1c642dSBill Krier 	DWORD status = 0;
515fe1c642dSBill Krier 
516fe1c642dSBill Krier 	if (ndr_is_null_handle(domain_handle) ||
517fe1c642dSBill Krier 	    username == NULL || rid == NULL) {
518fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
519fe1c642dSBill Krier 	}
520fe1c642dSBill Krier 
521fe1c642dSBill Krier 	opnum = SAMR_OPNUM_CreateUser;
522fe1c642dSBill Krier 
523fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_CreateUser));
524fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &domain_handle->handle,
525fe1c642dSBill Krier 	    sizeof (ndr_hdid_t));
526fe1c642dSBill Krier 
527fe1c642dSBill Krier 	heap = ndr_rpc_get_heap(domain_handle);
528fe1c642dSBill Krier 	ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username);
529fe1c642dSBill Krier 
530fe1c642dSBill Krier 	arg.account_flags = account_flags;
531fe1c642dSBill Krier 	arg.desired_access = 0xE00500B0;
532fe1c642dSBill Krier 
533fe1c642dSBill Krier 	rc = ndr_rpc_call(domain_handle, opnum, &arg);
534fe1c642dSBill Krier 	if (rc != 0) {
535fe1c642dSBill Krier 		status = NT_STATUS_INVALID_PARAMETER;
536fe1c642dSBill Krier 	} else if (arg.status != 0) {
537fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
538fe1c642dSBill Krier 
539fe1c642dSBill Krier 		if (status != NT_STATUS_USER_EXISTS) {
5401ed6b69aSGordon Ross 			smb_tracef("SamrCreateUser[%s]: %s",
5411ed6b69aSGordon Ross 			    username, xlate_nt_status(status));
542fe1c642dSBill Krier 		}
543fe1c642dSBill Krier 	} else {
544fe1c642dSBill Krier 		ndr_inherit_handle(user_handle, domain_handle);
545fe1c642dSBill Krier 
546fe1c642dSBill Krier 		(void) memcpy(&user_handle->handle, &arg.user_handle,
547fe1c642dSBill Krier 		    sizeof (ndr_hdid_t));
548fe1c642dSBill Krier 
549fe1c642dSBill Krier 		*rid = arg.rid;
550fe1c642dSBill Krier 
551fe1c642dSBill Krier 		if (ndr_is_null_handle(user_handle))
552fe1c642dSBill Krier 			status = NT_STATUS_INVALID_HANDLE;
553fe1c642dSBill Krier 		else
554fe1c642dSBill Krier 			status = 0;
555fe1c642dSBill Krier 	}
556fe1c642dSBill Krier 
557fe1c642dSBill Krier 	ndr_rpc_release(domain_handle);
558fe1c642dSBill Krier 	return (status);
559fe1c642dSBill Krier }
560fe1c642dSBill Krier 
561fe1c642dSBill Krier /*
562fe1c642dSBill Krier  * samr_lookup_domain
563fe1c642dSBill Krier  *
564fe1c642dSBill Krier  * Lookup up the domain SID for the specified domain name. The handle
565fe1c642dSBill Krier  * should be one returned from samr_connect. The allocated memory for
566fe1c642dSBill Krier  * the returned SID must be freed by caller.
567fe1c642dSBill Krier  */
568fe1c642dSBill Krier smb_sid_t *
samr_lookup_domain(mlsvc_handle_t * samr_handle,char * domain_name)569fe1c642dSBill Krier samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name)
570fe1c642dSBill Krier {
571fe1c642dSBill Krier 	struct samr_LookupDomain	arg;
572fe1c642dSBill Krier 	smb_sid_t	*domsid = NULL;
573fe1c642dSBill Krier 	int		opnum;
574fe1c642dSBill Krier 	size_t		length;
575fe1c642dSBill Krier 
576fe1c642dSBill Krier 	if (ndr_is_null_handle(samr_handle) || domain_name == NULL)
577fe1c642dSBill Krier 		return (NULL);
578fe1c642dSBill Krier 
579fe1c642dSBill Krier 	opnum = SAMR_OPNUM_LookupDomain;
580fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_LookupDomain));
581fe1c642dSBill Krier 
582fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &samr_handle->handle,
583fe1c642dSBill Krier 	    sizeof (samr_handle_t));
584fe1c642dSBill Krier 
585fe1c642dSBill Krier 	length = smb_wcequiv_strlen(domain_name);
586fe1c642dSBill Krier 	length += sizeof (smb_wchar_t);
587fe1c642dSBill Krier 
588fe1c642dSBill Krier 	arg.domain_name.length = length;
589fe1c642dSBill Krier 	arg.domain_name.allosize = length;
590fe1c642dSBill Krier 	arg.domain_name.str = (unsigned char *)domain_name;
591fe1c642dSBill Krier 
592fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) == 0)
593fe1c642dSBill Krier 		domsid = smb_sid_dup((smb_sid_t *)arg.sid);
594fe1c642dSBill Krier 
595fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
596fe1c642dSBill Krier 	return (domsid);
597fe1c642dSBill Krier }
598fe1c642dSBill Krier 
599fe1c642dSBill Krier /*
600fe1c642dSBill Krier  * samr_enum_local_domains
601fe1c642dSBill Krier  *
602fe1c642dSBill Krier  * Get the list of local domains supported by a server.
603fe1c642dSBill Krier  *
604fe1c642dSBill Krier  * Returns NT status codes.
605fe1c642dSBill Krier  */
606fe1c642dSBill Krier DWORD
samr_enum_local_domains(mlsvc_handle_t * samr_handle)607fe1c642dSBill Krier samr_enum_local_domains(mlsvc_handle_t *samr_handle)
608fe1c642dSBill Krier {
609fe1c642dSBill Krier 	struct samr_EnumLocalDomain	arg;
610fe1c642dSBill Krier 	int	opnum;
611fe1c642dSBill Krier 	DWORD	status;
612fe1c642dSBill Krier 
613fe1c642dSBill Krier 	if (ndr_is_null_handle(samr_handle))
614fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
615fe1c642dSBill Krier 
616fe1c642dSBill Krier 	opnum = SAMR_OPNUM_EnumLocalDomains;
617fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_EnumLocalDomain));
618fe1c642dSBill Krier 
619fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &samr_handle->handle,
620fe1c642dSBill Krier 	    sizeof (samr_handle_t));
621fe1c642dSBill Krier 	arg.enum_context = 0;
622fe1c642dSBill Krier 	arg.max_length = 0x00002000;	/* Value used by NT */
623fe1c642dSBill Krier 
624fe1c642dSBill Krier 	if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
625fe1c642dSBill Krier 		status = NT_STATUS_INVALID_PARAMETER;
626fe1c642dSBill Krier 	} else {
627fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
628fe1c642dSBill Krier 
629fe1c642dSBill Krier 		/*
630fe1c642dSBill Krier 		 * Handle none-mapped status quietly.
631fe1c642dSBill Krier 		 */
632fe1c642dSBill Krier 		if (status != NT_STATUS_NONE_MAPPED)
633fe1c642dSBill Krier 			ndr_rpc_status(samr_handle, opnum, arg.status);
634fe1c642dSBill Krier 	}
635fe1c642dSBill Krier 
636fe1c642dSBill Krier 	ndr_rpc_release(samr_handle);
637fe1c642dSBill Krier 	return (status);
638fe1c642dSBill Krier }
639fe1c642dSBill Krier 
640fe1c642dSBill Krier /*
641fe1c642dSBill Krier  * samr_lookup_domain_names
642fe1c642dSBill Krier  *
643fe1c642dSBill Krier  * Lookup up the given name in the domain specified by domain_handle.
644fe1c642dSBill Krier  * Upon a successful lookup the information is returned in the account
645fe1c642dSBill Krier  * arg and caller must free allocated memories by calling smb_account_free().
646fe1c642dSBill Krier  *
647fe1c642dSBill Krier  * Returns NT status codes.
648fe1c642dSBill Krier  */
649fe1c642dSBill Krier uint32_t
samr_lookup_domain_names(mlsvc_handle_t * domain_handle,char * name,smb_account_t * account)650fe1c642dSBill Krier samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
651fe1c642dSBill Krier     smb_account_t *account)
652fe1c642dSBill Krier {
653fe1c642dSBill Krier 	struct samr_LookupNames	arg;
654fe1c642dSBill Krier 	int			opnum;
655fe1c642dSBill Krier 	uint32_t		status;
656fe1c642dSBill Krier 	size_t			length;
657fe1c642dSBill Krier 
658fe1c642dSBill Krier 	if (ndr_is_null_handle(domain_handle) ||
659fe1c642dSBill Krier 	    name == NULL || account == NULL) {
660fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
661fe1c642dSBill Krier 	}
662fe1c642dSBill Krier 
663fe1c642dSBill Krier 	bzero(account, sizeof (smb_account_t));
664fe1c642dSBill Krier 	opnum = SAMR_OPNUM_LookupNames;
665fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_LookupNames));
666fe1c642dSBill Krier 
667fe1c642dSBill Krier 	(void) memcpy(&arg.handle, &domain_handle->handle,
668fe1c642dSBill Krier 	    sizeof (samr_handle_t));
669fe1c642dSBill Krier 	arg.n_entry = 1;
670fe1c642dSBill Krier 	arg.max_n_entry = 1000;
671fe1c642dSBill Krier 	arg.index = 0;
672fe1c642dSBill Krier 	arg.total = 1;
673fe1c642dSBill Krier 
674fe1c642dSBill Krier 	length = smb_wcequiv_strlen(name);
675fe1c642dSBill Krier 	length += sizeof (smb_wchar_t);
676fe1c642dSBill Krier 
677fe1c642dSBill Krier 	arg.name.length = length;
678fe1c642dSBill Krier 	arg.name.allosize = length;
679fe1c642dSBill Krier 	arg.name.str = (unsigned char *)name;
680fe1c642dSBill Krier 
681fe1c642dSBill Krier 	if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
682fe1c642dSBill Krier 		status = NT_STATUS_INVALID_PARAMETER;
683fe1c642dSBill Krier 	} else if (arg.status != NT_STATUS_SUCCESS) {
684fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
685fe1c642dSBill Krier 
686fe1c642dSBill Krier 		/*
687fe1c642dSBill Krier 		 * Handle none-mapped status quietly.
688fe1c642dSBill Krier 		 */
689fe1c642dSBill Krier 		if (status != NT_STATUS_NONE_MAPPED)
690fe1c642dSBill Krier 			ndr_rpc_status(domain_handle, opnum, arg.status);
691fe1c642dSBill Krier 	} else {
692fe1c642dSBill Krier 		account->a_type = arg.rid_types.rid_type[0];
693fe1c642dSBill Krier 		account->a_rid = arg.rids.rid[0];
694fe1c642dSBill Krier 		status = NT_STATUS_SUCCESS;
695fe1c642dSBill Krier 	}
696fe1c642dSBill Krier 
697fe1c642dSBill Krier 	ndr_rpc_release(domain_handle);
698fe1c642dSBill Krier 	return (status);
699fe1c642dSBill Krier }
700fe1c642dSBill Krier 
701fe1c642dSBill Krier /*
702fe1c642dSBill Krier  * samr_query_user_info
703fe1c642dSBill Krier  *
704fe1c642dSBill Krier  * Query information on a specific user. The handle must be a valid
705fe1c642dSBill Krier  * user handle obtained via samr_open_user.
706fe1c642dSBill Krier  *
7071ed6b69aSGordon Ross  * Returns 0 on success, otherwise returns NT status code.
708fe1c642dSBill Krier  */
7091ed6b69aSGordon Ross DWORD
samr_query_user_info(mlsvc_handle_t * user_handle,WORD switch_value,union samr_user_info * user_info)710fe1c642dSBill Krier samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
711fe1c642dSBill Krier     union samr_user_info *user_info)
712fe1c642dSBill Krier {
713fe1c642dSBill Krier 	struct samr_QueryUserInfo	arg;
714fe1c642dSBill Krier 	int	opnum;
715fe1c642dSBill Krier 
716fe1c642dSBill Krier 	if (ndr_is_null_handle(user_handle) || user_info == 0)
7171ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
718fe1c642dSBill Krier 
719fe1c642dSBill Krier 	opnum = SAMR_OPNUM_QueryUserInfo;
720fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_QueryUserInfo));
721fe1c642dSBill Krier 
722fe1c642dSBill Krier 	(void) memcpy(&arg.user_handle, &user_handle->handle,
723fe1c642dSBill Krier 	    sizeof (samr_handle_t));
724fe1c642dSBill Krier 	arg.switch_value = switch_value;
725fe1c642dSBill Krier 
7261ed6b69aSGordon Ross 	if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
7271ed6b69aSGordon Ross 		arg.status = RPC_NT_CALL_FAILED;
728fe1c642dSBill Krier 
7291ed6b69aSGordon Ross 	if (arg.status == 0)
7301ed6b69aSGordon Ross 		(void) samr_setup_user_info(switch_value, &arg, user_info);
731fe1c642dSBill Krier 
7321ed6b69aSGordon Ross 	return (arg.status);
733fe1c642dSBill Krier }
734fe1c642dSBill Krier 
735fe1c642dSBill Krier /*
736fe1c642dSBill Krier  * samr_setup_user_info
737fe1c642dSBill Krier  *
738fe1c642dSBill Krier  * Private function to set up the samr_user_info data. Dependent on
739fe1c642dSBill Krier  * the switch value this function may use strdup which will malloc
740fe1c642dSBill Krier  * memory. The caller is responsible for deallocating this memory.
741fe1c642dSBill Krier  *
742fe1c642dSBill Krier  * Returns 0 on success, otherwise returns -1.
743fe1c642dSBill Krier  */
744fe1c642dSBill Krier static int
samr_setup_user_info(WORD switch_value,struct samr_QueryUserInfo * arg,union samr_user_info * user_info)745fe1c642dSBill Krier samr_setup_user_info(WORD switch_value,
746fe1c642dSBill Krier     struct samr_QueryUserInfo *arg, union samr_user_info *user_info)
747fe1c642dSBill Krier {
748fe1c642dSBill Krier 	struct samr_QueryUserInfo1	*info1;
749fe1c642dSBill Krier 	struct samr_QueryUserInfo6	*info6;
750fe1c642dSBill Krier 
751fe1c642dSBill Krier 	switch (switch_value) {
752fe1c642dSBill Krier 	case 1:
753fe1c642dSBill Krier 		info1 = &arg->ru.info1;
754fe1c642dSBill Krier 		user_info->info1.username = strdup(
755fe1c642dSBill Krier 		    (char const *)info1->username.str);
756fe1c642dSBill Krier 		user_info->info1.fullname = strdup(
757fe1c642dSBill Krier 		    (char const *)info1->fullname.str);
758fe1c642dSBill Krier 		user_info->info1.description = strdup(
759fe1c642dSBill Krier 		    (char const *)info1->description.str);
760fe1c642dSBill Krier 		user_info->info1.unknown = 0;
761fe1c642dSBill Krier 		user_info->info1.group_rid = info1->group_rid;
762fe1c642dSBill Krier 		return (0);
763fe1c642dSBill Krier 
764fe1c642dSBill Krier 	case 6:
765fe1c642dSBill Krier 		info6 = &arg->ru.info6;
766fe1c642dSBill Krier 		user_info->info6.username = strdup(
767fe1c642dSBill Krier 		    (char const *)info6->username.str);
768fe1c642dSBill Krier 		user_info->info6.fullname = strdup(
769fe1c642dSBill Krier 		    (char const *)info6->fullname.str);
770fe1c642dSBill Krier 		return (0);
771fe1c642dSBill Krier 
772fe1c642dSBill Krier 	case 7:
773fe1c642dSBill Krier 		user_info->info7.username = strdup(
774fe1c642dSBill Krier 		    (char const *)arg->ru.info7.username.str);
775fe1c642dSBill Krier 		return (0);
776fe1c642dSBill Krier 
777fe1c642dSBill Krier 	case 8:
778fe1c642dSBill Krier 		user_info->info8.fullname = strdup(
779fe1c642dSBill Krier 		    (char const *)arg->ru.info8.fullname.str);
780fe1c642dSBill Krier 		return (0);
781fe1c642dSBill Krier 
782fe1c642dSBill Krier 	case 9:
783fe1c642dSBill Krier 		user_info->info9.group_rid = arg->ru.info9.group_rid;
784fe1c642dSBill Krier 		return (0);
785fe1c642dSBill Krier 
786fe1c642dSBill Krier 	case 16:
7871ed6b69aSGordon Ross 		user_info->info16.acct_ctrl =
7881ed6b69aSGordon Ross 		    arg->ru.info16.UserAccountControl;
789fe1c642dSBill Krier 		return (0);
790fe1c642dSBill Krier 
791fe1c642dSBill Krier 	default:
792fe1c642dSBill Krier 		break;
793fe1c642dSBill Krier 	};
794fe1c642dSBill Krier 
795fe1c642dSBill Krier 	return (-1);
796fe1c642dSBill Krier }
797fe1c642dSBill Krier 
798fe1c642dSBill Krier /*
799fe1c642dSBill Krier  * samr_query_user_groups
800fe1c642dSBill Krier  *
801fe1c642dSBill Krier  * Query the groups for a specific user. The handle must be a valid
802fe1c642dSBill Krier  * user handle obtained via samr_open_user. The list of groups is
803fe1c642dSBill Krier  * returned in group_info. Note that group_info->groups is allocated
804fe1c642dSBill Krier  * using malloc. The caller is responsible for deallocating this
805fe1c642dSBill Krier  * memory when it is no longer required. If group_info->n_entry is 0
806fe1c642dSBill Krier  * then no memory was allocated.
807fe1c642dSBill Krier  *
808fe1c642dSBill Krier  * Returns 0 on success, otherwise returns -1.
809fe1c642dSBill Krier  */
810fe1c642dSBill Krier int
samr_query_user_groups(mlsvc_handle_t * user_handle,int * n_groups,struct samr_UserGroups ** groups)811fe1c642dSBill Krier samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups,
812fe1c642dSBill Krier     struct samr_UserGroups **groups)
813fe1c642dSBill Krier {
814fe1c642dSBill Krier 	struct samr_QueryUserGroups arg;
815fe1c642dSBill Krier 	int	opnum;
816fe1c642dSBill Krier 	int	rc;
817fe1c642dSBill Krier 	int	nbytes;
818fe1c642dSBill Krier 
819fe1c642dSBill Krier 	if (ndr_is_null_handle(user_handle))
820fe1c642dSBill Krier 		return (-1);
821fe1c642dSBill Krier 
822fe1c642dSBill Krier 	opnum = SAMR_OPNUM_QueryUserGroups;
823fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_QueryUserGroups));
824fe1c642dSBill Krier 
825fe1c642dSBill Krier 	(void) memcpy(&arg.user_handle, &user_handle->handle,
826fe1c642dSBill Krier 	    sizeof (samr_handle_t));
827fe1c642dSBill Krier 
828fe1c642dSBill Krier 	rc = ndr_rpc_call(user_handle, opnum, &arg);
829fe1c642dSBill Krier 	if (rc == 0) {
830fe1c642dSBill Krier 		if (arg.info == 0) {
831fe1c642dSBill Krier 			rc = -1;
832fe1c642dSBill Krier 		} else {
833fe1c642dSBill Krier 			nbytes = arg.info->n_entry *
834fe1c642dSBill Krier 			    sizeof (struct samr_UserGroups);
835fe1c642dSBill Krier 
836fe1c642dSBill Krier 			if ((*groups = malloc(nbytes)) == NULL) {
837fe1c642dSBill Krier 				*n_groups = 0;
838fe1c642dSBill Krier 				rc = -1;
839fe1c642dSBill Krier 			} else {
840fe1c642dSBill Krier 				*n_groups = arg.info->n_entry;
841fe1c642dSBill Krier 				bcopy(arg.info->groups, *groups, nbytes);
842fe1c642dSBill Krier 			}
843fe1c642dSBill Krier 		}
844fe1c642dSBill Krier 	}
845fe1c642dSBill Krier 
846fe1c642dSBill Krier 	ndr_rpc_release(user_handle);
847fe1c642dSBill Krier 	return (rc);
848fe1c642dSBill Krier }
849fe1c642dSBill Krier 
850fe1c642dSBill Krier /*
851fe1c642dSBill Krier  * samr_get_user_pwinfo
852fe1c642dSBill Krier  *
853fe1c642dSBill Krier  * Get some user password info. I'm not sure what this is yet but it is
854fe1c642dSBill Krier  * part of the create user sequence. The handle must be a valid user
855fe1c642dSBill Krier  * handle. Since I don't know what this is returning, I haven't provided
856fe1c642dSBill Krier  * any return data yet.
857fe1c642dSBill Krier  *
858fe1c642dSBill Krier  * Returns 0 on success. Otherwise returns an NT status code.
859fe1c642dSBill Krier  */
860fe1c642dSBill Krier DWORD
samr_get_user_pwinfo(mlsvc_handle_t * user_handle)861fe1c642dSBill Krier samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
862fe1c642dSBill Krier {
863fe1c642dSBill Krier 	struct samr_GetUserPwInfo arg;
864fe1c642dSBill Krier 	int	opnum;
865fe1c642dSBill Krier 	DWORD	status;
866fe1c642dSBill Krier 
867fe1c642dSBill Krier 	if (ndr_is_null_handle(user_handle))
868fe1c642dSBill Krier 		return (NT_STATUS_INVALID_PARAMETER);
869fe1c642dSBill Krier 
870fe1c642dSBill Krier 	opnum = SAMR_OPNUM_GetUserPwInfo;
871fe1c642dSBill Krier 	bzero(&arg, sizeof (struct samr_GetUserPwInfo));
872fe1c642dSBill Krier 	(void) memcpy(&arg.user_handle, &user_handle->handle,
873fe1c642dSBill Krier 	    sizeof (samr_handle_t));
874fe1c642dSBill Krier 
875fe1c642dSBill Krier 	if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
876fe1c642dSBill Krier 		status = NT_STATUS_INVALID_PARAMETER;
877fe1c642dSBill Krier 	} else if (arg.status != 0) {
878fe1c642dSBill Krier 		ndr_rpc_status(user_handle, opnum, arg.status);
879fe1c642dSBill Krier 		status = NT_SC_VALUE(arg.status);
880fe1c642dSBill Krier 	} else {
881fe1c642dSBill Krier 		status = 0;
882fe1c642dSBill Krier 	}
883fe1c642dSBill Krier 
884fe1c642dSBill Krier 	ndr_rpc_release(user_handle);
885fe1c642dSBill Krier 	return (status);
886fe1c642dSBill Krier }
887fe1c642dSBill Krier 
8881ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo_u);
8891ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo_s);
8901ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo);
8911ed6b69aSGordon Ross 
892fe1c642dSBill Krier /*
893fe1c642dSBill Krier  * samr_set_user_info
894fe1c642dSBill Krier  *
895fe1c642dSBill Krier  * Returns 0 on success. Otherwise returns an NT status code.
896fe1c642dSBill Krier  * NT status codes observed so far:
897fe1c642dSBill Krier  *	NT_STATUS_WRONG_PASSWORD
898fe1c642dSBill Krier  */
899fe1c642dSBill Krier DWORD
samr_set_user_info(mlsvc_handle_t * user_handle,int info_level,void * info_buf)9001ed6b69aSGordon Ross samr_set_user_info(
9011ed6b69aSGordon Ross 	mlsvc_handle_t *user_handle,
9021ed6b69aSGordon Ross 	int info_level,
9031ed6b69aSGordon Ross 	void *info_buf)
904fe1c642dSBill Krier {
905fe1c642dSBill Krier 	struct samr_SetUserInfo arg;
9061ed6b69aSGordon Ross 	uint16_t usize, tsize;
907fe1c642dSBill Krier 	int opnum;
908fe1c642dSBill Krier 
909fe1c642dSBill Krier 	if (ndr_is_null_handle(user_handle))
9101ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
911fe1c642dSBill Krier 
9121ed6b69aSGordon Ross 	/*
9131ed6b69aSGordon Ross 	 * Only support a few levels
9141ed6b69aSGordon Ross 	 * MS-SAMR: UserInternal4Information
9151ed6b69aSGordon Ross 	 */
9161ed6b69aSGordon Ross 	switch (info_level) {
9171ed6b69aSGordon Ross 	case 16: /* samr_SetUserInfo16 */
9181ed6b69aSGordon Ross 		usize = sizeof (struct samr_SetUserInfo16);
9191ed6b69aSGordon Ross 		break;
9201ed6b69aSGordon Ross 	case 21: /* samr_SetUserInfo21 */
9211ed6b69aSGordon Ross 		usize = sizeof (struct samr_SetUserInfo21);
9221ed6b69aSGordon Ross 		break;
9231ed6b69aSGordon Ross 	case 23: /* samr_SetUserInfo23 */
9241ed6b69aSGordon Ross 		usize = sizeof (struct samr_SetUserInfo23);
9251ed6b69aSGordon Ross 		break;
9261ed6b69aSGordon Ross 	case 24: /* samr_SetUserInfo24 */
9271ed6b69aSGordon Ross 		usize = sizeof (struct samr_SetUserInfo24);
9281ed6b69aSGordon Ross 		break;
9291ed6b69aSGordon Ross 	default:
9301ed6b69aSGordon Ross 		return (NT_STATUS_INVALID_LEVEL);
9311ed6b69aSGordon Ross 	}
9321ed6b69aSGordon Ross 
9331ed6b69aSGordon Ross 	/*
9341ed6b69aSGordon Ross 	 * OK, now this gets really ugly, because
9351ed6b69aSGordon Ross 	 * ndrgen doesn't do unions correctly.
9361ed6b69aSGordon Ross 	 */
9371ed6b69aSGordon Ross 	FIXUP_PDU_SIZE(samr_SetUserInfo_u, usize);
9381ed6b69aSGordon Ross 	tsize = usize + (2 * sizeof (WORD));
9391ed6b69aSGordon Ross 	FIXUP_PDU_SIZE(samr_SetUserInfo_s, tsize);
9401ed6b69aSGordon Ross 	tsize += sizeof (ndr_request_hdr_t) + sizeof (DWORD);
9411ed6b69aSGordon Ross 	FIXUP_PDU_SIZE(samr_SetUserInfo, tsize);
942fe1c642dSBill Krier 
943fe1c642dSBill Krier 	opnum = SAMR_OPNUM_SetUserInfo;
9441ed6b69aSGordon Ross 	bzero(&arg, sizeof (arg));
945fe1c642dSBill Krier 	(void) memcpy(&arg.user_handle, &user_handle->handle,
946fe1c642dSBill Krier 	    sizeof (samr_handle_t));
9471ed6b69aSGordon Ross 	arg.info.info_level = info_level;
9481ed6b69aSGordon Ross 	arg.info.switch_value = info_level;
9491ed6b69aSGordon Ross 	(void) memcpy(&arg.info.ru, info_buf, usize);
950fe1c642dSBill Krier 
9511ed6b69aSGordon Ross 	if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
9521ed6b69aSGordon Ross 		arg.status = RPC_NT_CALL_FAILED;
9531ed6b69aSGordon Ross 	else if (arg.status != 0)
954fe1c642dSBill Krier 		ndr_rpc_status(user_handle, opnum, arg.status);
955fe1c642dSBill Krier 
956fe1c642dSBill Krier 	ndr_rpc_release(user_handle);
9571ed6b69aSGordon Ross 	return (arg.status);
958fe1c642dSBill Krier }
959fe1c642dSBill Krier 
960fe1c642dSBill Krier /*
9611ed6b69aSGordon Ross  * Client side wrapper for SamrUnicodeChangePasswordUser2
9621ed6b69aSGordon Ross  * [MS-SAMR 3.1.5.10.3]
963fe1c642dSBill Krier  */
9641ed6b69aSGordon Ross 
9651ed6b69aSGordon Ross DWORD
samr_change_password(mlsvc_handle_t * handle,char * server,char * account,struct samr_encr_passwd * newpw,struct samr_encr_hash * oldpw)9661ed6b69aSGordon Ross samr_change_password(
9671ed6b69aSGordon Ross 	mlsvc_handle_t *handle,
9681ed6b69aSGordon Ross 	char *server,
9691ed6b69aSGordon Ross 	char *account,
9701ed6b69aSGordon Ross 	struct samr_encr_passwd *newpw,
9711ed6b69aSGordon Ross 	struct samr_encr_hash *oldpw)
972fe1c642dSBill Krier {
9731ed6b69aSGordon Ross 	static struct samr_encr_passwd zero_newpw;
9741ed6b69aSGordon Ross 	static struct samr_encr_hash zero_oldpw;
9751ed6b69aSGordon Ross 	struct samr_ChangePasswordUser2 arg;
9761ed6b69aSGordon Ross 	int opnum = SAMR_OPNUM_ChangePasswordUser2;
9771ed6b69aSGordon Ross 	char *slashserver;
9781ed6b69aSGordon Ross 	int len;
979fe1c642dSBill Krier 
9801ed6b69aSGordon Ross 	(void) memset(&arg, 0, sizeof (arg));
981fe1c642dSBill Krier 
9821ed6b69aSGordon Ross 	/* Need server name with slashes */
9831ed6b69aSGordon Ross 	len = 2 + strlen(server) + 1;
9841ed6b69aSGordon Ross 	slashserver = ndr_rpc_malloc(handle, len);
9851ed6b69aSGordon Ross 	if (slashserver == NULL)
9861ed6b69aSGordon Ross 		return (NT_STATUS_NO_MEMORY);
9871ed6b69aSGordon Ross 	(void) snprintf(slashserver, len, "\\\\%s", server);
988fe1c642dSBill Krier 
9891ed6b69aSGordon Ross 	arg.servername = ndr_rpc_malloc(handle, sizeof (samr_string_t));
9901ed6b69aSGordon Ross 	if (arg.servername == NULL)
9911ed6b69aSGordon Ross 		return (NT_STATUS_NO_MEMORY);
9921ed6b69aSGordon Ross 	len = smb_wcequiv_strlen(slashserver);
9931ed6b69aSGordon Ross 	if (len < 1)
9941ed6b69aSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
9951ed6b69aSGordon Ross 	len += 2;	/* the WC null */
9961ed6b69aSGordon Ross 	arg.servername->length = len;
9971ed6b69aSGordon Ross 	arg.servername->allosize = len;
9981ed6b69aSGordon Ross 	arg.servername->str = (uint8_t *)slashserver;
999fe1c642dSBill Krier 
10001ed6b69aSGordon Ross 	arg.username = ndr_rpc_malloc(handle, sizeof (samr_string_t));
10011ed6b69aSGordon Ross 	if (arg.username == NULL)
10021ed6b69aSGordon Ross 		return (NT_STATUS_NO_MEMORY);
10031ed6b69aSGordon Ross 	len = smb_wcequiv_strlen(account);
10041ed6b69aSGordon Ross 	if (len < 1)
10051ed6b69aSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
10061ed6b69aSGordon Ross 	len += 2;	/* the WC null */
10071ed6b69aSGordon Ross 	arg.username->length = len;
10081ed6b69aSGordon Ross 	arg.username->allosize = len;
10091ed6b69aSGordon Ross 	arg.username->str = (uint8_t *)account;
1010fe1c642dSBill Krier 
10111ed6b69aSGordon Ross 	arg.nt_newpw = newpw;
10121ed6b69aSGordon Ross 	arg.nt_oldpw = oldpw;
1013fe1c642dSBill Krier 
10141ed6b69aSGordon Ross 	arg.lm_newpw = &zero_newpw;
10151ed6b69aSGordon Ross 	arg.lm_oldpw = &zero_oldpw;
10161ed6b69aSGordon Ross 
10171ed6b69aSGordon Ross 	if (ndr_rpc_call(handle, opnum, &arg) != 0)
10181ed6b69aSGordon Ross 		arg.status = RPC_NT_CALL_FAILED;
10191ed6b69aSGordon Ross 	else if (arg.status != 0)
10201ed6b69aSGordon Ross 		ndr_rpc_status(handle, opnum, arg.status);
10211ed6b69aSGordon Ross 
10221ed6b69aSGordon Ross 	ndr_rpc_release(handle);
10231ed6b69aSGordon Ross 	return (arg.status);
1024fe1c642dSBill Krier }
1025