1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21148c5f43SAlan Wright
22da6c28aaSamw /*
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.
25da6c28aaSamw */
26da6c28aaSamw
27da6c28aaSamw /*
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.
38da6c28aaSamw */
39da6c28aaSamw
40da6c28aaSamw #include <stdio.h>
41da6c28aaSamw #include <strings.h>
42fe1c642dSBill Krier #include <stdlib.h>
43da6c28aaSamw #include <unistd.h>
44da6c28aaSamw #include <netdb.h>
45da6c28aaSamw #include <sys/param.h>
46da6c28aaSamw
473299f39fSGordon Ross #include <libmlrpc/libmlrpc.h>
48da6c28aaSamw #include <smbsrv/libsmb.h>
498d7e4166Sjose borrego #include <smbsrv/libmlsvc.h>
50da6c28aaSamw #include <smbsrv/smbinfo.h>
51*adee6784SGordon Ross #include <smb/ntaccess.h>
52fe1c642dSBill Krier #include <smbsrv/smb_sid.h>
538d7e4166Sjose borrego #include <samlib.h>
54da6c28aaSamw
55da6c28aaSamw static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
56da6c28aaSamw static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
57cb174861Sjoyce mcintosh static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *);
58da6c28aaSamw
59a0aa776eSAlan Wright typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD,
60a0aa776eSAlan Wright mlsvc_handle_t *);
61a0aa776eSAlan Wright
62fe1c642dSBill Krier static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
63fe1c642dSBill Krier union samr_user_info *);
64fe1c642dSBill Krier
65da6c28aaSamw /*
66da6c28aaSamw * samr_open
67da6c28aaSamw *
688d7e4166Sjose borrego * Wrapper round samr_connect to ensure that we connect using the server
698d7e4166Sjose borrego * and domain. We default to the resource domain if the caller doesn't
708d7e4166Sjose borrego * supply a server name and a domain name.
71da6c28aaSamw *
7255bf511dSas * If username argument is NULL, an anonymous connection will be established.
7355bf511dSas * Otherwise, an authenticated connection will be established.
7455bf511dSas *
75da6c28aaSamw * On success 0 is returned. Otherwise a -ve error code.
76da6c28aaSamw */
771ed6b69aSGordon Ross DWORD
samr_open(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)7855bf511dSas samr_open(char *server, char *domain, char *username, DWORD access_mask,
7955bf511dSas mlsvc_handle_t *samr_handle)
80da6c28aaSamw {
81a0aa776eSAlan Wright smb_domainex_t di;
821ed6b69aSGordon Ross DWORD status;
83da6c28aaSamw
84da6c28aaSamw if (server == NULL || domain == NULL) {
858d7e4166Sjose borrego if (!smb_domain_getinfo(&di))
861ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
87b3700b07SGordon Ross server = di.d_dci.dc_name;
88a0aa776eSAlan Wright domain = di.d_primary.di_nbname;
89da6c28aaSamw }
90da6c28aaSamw
9155bf511dSas if (username == NULL)
9255bf511dSas username = MLSVC_ANON_USER;
93da6c28aaSamw
941ed6b69aSGordon Ross status = samr_connect(server, domain, username, access_mask,
951ed6b69aSGordon Ross samr_handle);
961ed6b69aSGordon Ross
971ed6b69aSGordon Ross return (status);
98da6c28aaSamw }
99da6c28aaSamw
100da6c28aaSamw
101da6c28aaSamw /*
102da6c28aaSamw * samr_connect
103da6c28aaSamw *
104a0aa776eSAlan Wright * Connect to the SAMR service on the specified server (domain controller).
105a0aa776eSAlan Wright * New SAM connect calls have been added to Windows over time:
106da6c28aaSamw *
107a0aa776eSAlan Wright * Windows NT3.x: SamrConnect
108a0aa776eSAlan Wright * Windows NT4.0: SamrConnect2
109cb174861Sjoyce mcintosh * Windows 2000: SamrConnect4
110cb174861Sjoyce mcintosh * Windows XP: SamrConnect5
111a0aa776eSAlan Wright *
112a0aa776eSAlan Wright * Try the calls from most recent to oldest until the server responds with
113a0aa776eSAlan Wright * something other than an RPC protocol error. We don't use the original
114a0aa776eSAlan Wright * connect call because all supported servers should support SamrConnect2.
115da6c28aaSamw */
1161ed6b69aSGordon Ross DWORD
samr_connect(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)117da6c28aaSamw samr_connect(char *server, char *domain, char *username, DWORD access_mask,
118da6c28aaSamw mlsvc_handle_t *samr_handle)
119da6c28aaSamw {
120a0aa776eSAlan Wright static samr_connop_t samr_connop[] = {
121cb174861Sjoyce mcintosh samr_connect5,
122a0aa776eSAlan Wright samr_connect4,
123a0aa776eSAlan Wright samr_connect2
124a0aa776eSAlan Wright };
125a0aa776eSAlan Wright
126a0aa776eSAlan Wright int n_op = (sizeof (samr_connop) / sizeof (samr_connop[0]));
127a0aa776eSAlan Wright DWORD status;
128a0aa776eSAlan Wright int i;
129da6c28aaSamw
1301ed6b69aSGordon Ross status = ndr_rpc_bind(samr_handle, server, domain, username, "SAMR");
1311ed6b69aSGordon Ross if (status)
1321ed6b69aSGordon Ross return (status);
133da6c28aaSamw
134a0aa776eSAlan Wright for (i = 0; i < n_op; ++i) {
135a0aa776eSAlan Wright status = (*samr_connop[i])(server, domain, username,
136a0aa776eSAlan Wright access_mask, samr_handle);
137a0aa776eSAlan Wright
138cb174861Sjoyce mcintosh if (status == NT_STATUS_SUCCESS)
1391ed6b69aSGordon Ross return (status);
140da6c28aaSamw }
141da6c28aaSamw
142cb174861Sjoyce mcintosh ndr_rpc_unbind(samr_handle);
143da6c28aaSamw return (status);
144da6c28aaSamw }
145da6c28aaSamw
146da6c28aaSamw /*
147da6c28aaSamw * samr_connect2
148da6c28aaSamw *
149da6c28aaSamw * Connect to the SAM on a Windows NT 4.0 server (domain controller).
150da6c28aaSamw * We need the domain controller name and, if everything works, we
151da6c28aaSamw * return a handle. This function adds the double backslash prefx to
152da6c28aaSamw * make it easy for applications.
153da6c28aaSamw *
154da6c28aaSamw * Returns 0 on success. Otherwise returns a -ve error code.
155da6c28aaSamw */
156da6c28aaSamw /*ARGSUSED*/
157da6c28aaSamw static DWORD
samr_connect2(char * server,char * domain,char * username,DWORD access_mask,mlsvc_handle_t * samr_handle)158da6c28aaSamw samr_connect2(char *server, char *domain, char *username, DWORD access_mask,
159da6c28aaSamw mlsvc_handle_t *samr_handle)
160da6c28aaSamw {
161cb174861Sjoyce mcintosh struct samr_Connect2 arg;
162da6c28aaSamw int opnum;
163da6c28aaSamw DWORD status;
164da6c28aaSamw int len;
165da6c28aaSamw
166cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect2));
167cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect2;
168da6c28aaSamw status = NT_STATUS_SUCCESS;
169da6c28aaSamw
170da6c28aaSamw len = strlen(server) + 4;
1718d7e4166Sjose borrego arg.servername = ndr_rpc_malloc(samr_handle, len);
172da6c28aaSamw (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
173da6c28aaSamw arg.access_mask = access_mask;
174da6c28aaSamw
1758d7e4166Sjose borrego if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
176da6c28aaSamw status = NT_STATUS_UNSUCCESSFUL;
177da6c28aaSamw } else if (arg.status != 0) {
178da6c28aaSamw status = NT_SC_VALUE(arg.status);
179da6c28aaSamw } else {
180da6c28aaSamw (void) memcpy(&samr_handle->handle, &arg.handle,
1818d7e4166Sjose borrego sizeof (ndr_hdid_t));
182da6c28aaSamw
1838d7e4166Sjose borrego if (ndr_is_null_handle(samr_handle))
184da6c28aaSamw status = NT_STATUS_INVALID_HANDLE;
185da6c28aaSamw }
186da6c28aaSamw
1878d7e4166Sjose borrego ndr_rpc_release(samr_handle);
188da6c28aaSamw return (status);
189da6c28aaSamw }
190da6c28aaSamw
191da6c28aaSamw /*
192cb174861Sjoyce mcintosh * samr_connect4
193da6c28aaSamw *
194da6c28aaSamw * Connect to the SAM on a Windows 2000 domain controller.
195da6c28aaSamw */
196da6c28aaSamw /*ARGSUSED*/
197da6c28aaSamw 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,
199da6c28aaSamw mlsvc_handle_t *samr_handle)
200da6c28aaSamw {
201cb174861Sjoyce mcintosh struct samr_Connect4 arg;
202da6c28aaSamw int opnum;
203da6c28aaSamw DWORD status;
204da6c28aaSamw int len;
205da6c28aaSamw
206cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect4));
207cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect4;
208da6c28aaSamw status = NT_STATUS_SUCCESS;
209da6c28aaSamw
210da6c28aaSamw len = strlen(server) + 4;
2118d7e4166Sjose borrego arg.servername = ndr_rpc_malloc(samr_handle, len);
212da6c28aaSamw (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
213a0aa776eSAlan Wright arg.revision = SAMR_REVISION_2;
214da6c28aaSamw arg.access_mask = access_mask;
215da6c28aaSamw
2168d7e4166Sjose borrego if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
217da6c28aaSamw status = NT_STATUS_UNSUCCESSFUL;
218da6c28aaSamw } else if (arg.status != 0) {
219da6c28aaSamw status = NT_SC_VALUE(arg.status);
220da6c28aaSamw } else {
221da6c28aaSamw (void) memcpy(&samr_handle->handle, &arg.handle,
2228d7e4166Sjose borrego sizeof (ndr_hdid_t));
223da6c28aaSamw
2248d7e4166Sjose borrego if (ndr_is_null_handle(samr_handle))
225da6c28aaSamw status = NT_STATUS_INVALID_HANDLE;
226da6c28aaSamw }
227da6c28aaSamw
2288d7e4166Sjose borrego ndr_rpc_release(samr_handle);
229da6c28aaSamw return (status);
230da6c28aaSamw }
231da6c28aaSamw
232da6c28aaSamw /*
233cb174861Sjoyce mcintosh * samr_connect5
234da6c28aaSamw *
235da6c28aaSamw * Connect to the SAM on a Windows XP domain controller. On Windows
236da6c28aaSamw * XP, the server should be the fully qualified DNS domain name with
237da6c28aaSamw * a double backslash prefix. At this point, it is assumed that we
238da6c28aaSamw * need to add the prefix and the DNS domain name here.
239da6c28aaSamw *
240da6c28aaSamw * If this call succeeds, a SAMR handle is placed in samr_handle and
241da6c28aaSamw * zero is returned. Otherwise, a -ve error code is returned.
242da6c28aaSamw */
243da6c28aaSamw /*ARGSUSED*/
244da6c28aaSamw 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,
246da6c28aaSamw mlsvc_handle_t *samr_handle)
247da6c28aaSamw {
248cb174861Sjoyce mcintosh struct samr_Connect5 arg;
249da6c28aaSamw int len;
250da6c28aaSamw int opnum;
251da6c28aaSamw DWORD status;
252da6c28aaSamw
253cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect5));
254cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect5;
255da6c28aaSamw status = NT_STATUS_SUCCESS;
256da6c28aaSamw
2571ed6b69aSGordon Ross len = strlen(server) + 4;
2588d7e4166Sjose borrego arg.servername = ndr_rpc_malloc(samr_handle, len);
2591ed6b69aSGordon Ross (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
260da6c28aaSamw
261da6c28aaSamw arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
262da6c28aaSamw arg.unknown2_00000001 = 0x00000001;
263da6c28aaSamw arg.unknown3_00000001 = 0x00000001;
264da6c28aaSamw arg.unknown4_00000003 = 0x00000003;
265da6c28aaSamw arg.unknown5_00000000 = 0x00000000;
266da6c28aaSamw
2678d7e4166Sjose borrego if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
268da6c28aaSamw status = NT_STATUS_UNSUCCESSFUL;
269da6c28aaSamw } else if (arg.status != 0) {
270da6c28aaSamw status = NT_SC_VALUE(arg.status);
271da6c28aaSamw } else {
272da6c28aaSamw
273da6c28aaSamw (void) memcpy(&samr_handle->handle, &arg.handle,
2748d7e4166Sjose borrego sizeof (ndr_hdid_t));
275da6c28aaSamw
2768d7e4166Sjose borrego if (ndr_is_null_handle(samr_handle))
277da6c28aaSamw status = NT_STATUS_INVALID_HANDLE;
278da6c28aaSamw }
279da6c28aaSamw
2808d7e4166Sjose borrego ndr_rpc_release(samr_handle);
281da6c28aaSamw return (status);
282da6c28aaSamw }
283da6c28aaSamw
284da6c28aaSamw
285da6c28aaSamw /*
286da6c28aaSamw * samr_close_handle
287da6c28aaSamw *
288da6c28aaSamw * This is function closes any valid handle, i.e. sam, domain, user etc.
2898d7e4166Sjose borrego * If the handle being closed is the top level connect handle, we unbind.
2908d7e4166Sjose borrego * Then we zero out the handle to invalidate it.
291da6c28aaSamw */
2921ed6b69aSGordon Ross void
samr_close_handle(mlsvc_handle_t * samr_handle)2938d7e4166Sjose borrego samr_close_handle(mlsvc_handle_t *samr_handle)
294da6c28aaSamw {
295da6c28aaSamw struct samr_CloseHandle arg;
296da6c28aaSamw int opnum;
297da6c28aaSamw
2988d7e4166Sjose borrego if (ndr_is_null_handle(samr_handle))
2991ed6b69aSGordon Ross return;
300da6c28aaSamw
301da6c28aaSamw opnum = SAMR_OPNUM_CloseHandle;
302da6c28aaSamw bzero(&arg, sizeof (struct samr_CloseHandle));
3038d7e4166Sjose borrego (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
304da6c28aaSamw
3058d7e4166Sjose borrego (void) ndr_rpc_call(samr_handle, opnum, &arg);
3068d7e4166Sjose borrego ndr_rpc_release(samr_handle);
307da6c28aaSamw
3088d7e4166Sjose borrego if (ndr_is_bind_handle(samr_handle))
3098d7e4166Sjose borrego ndr_rpc_unbind(samr_handle);
310da6c28aaSamw
3118d7e4166Sjose borrego bzero(samr_handle, sizeof (mlsvc_handle_t));
312da6c28aaSamw }
313da6c28aaSamw
314da6c28aaSamw /*
315da6c28aaSamw * samr_open_domain
316da6c28aaSamw *
317da6c28aaSamw * We use a SAM handle to obtain a handle for a domain, specified by
318da6c28aaSamw * the SID. The SID can be obtain via the LSA interface. A handle for
319da6c28aaSamw * the domain is returned in domain_handle.
320da6c28aaSamw */
321da6c28aaSamw DWORD
samr_open_domain(mlsvc_handle_t * samr_handle,DWORD access_mask,struct samr_sid * sid,mlsvc_handle_t * domain_handle)322da6c28aaSamw samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
323da6c28aaSamw struct samr_sid *sid, mlsvc_handle_t *domain_handle)
324da6c28aaSamw {
325da6c28aaSamw struct samr_OpenDomain arg;
326da6c28aaSamw int opnum;
327da6c28aaSamw DWORD status;
328da6c28aaSamw
3298d7e4166Sjose borrego if (ndr_is_null_handle(samr_handle) ||
3308d7e4166Sjose borrego sid == NULL || domain_handle == NULL) {
331da6c28aaSamw return (NT_STATUS_INVALID_PARAMETER);
332da6c28aaSamw }
333da6c28aaSamw
334da6c28aaSamw opnum = SAMR_OPNUM_OpenDomain;
335da6c28aaSamw bzero(&arg, sizeof (struct samr_OpenDomain));
3368d7e4166Sjose borrego (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
337da6c28aaSamw
338da6c28aaSamw arg.access_mask = access_mask;
339da6c28aaSamw arg.sid = sid;
340da6c28aaSamw
3418d7e4166Sjose borrego if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
342da6c28aaSamw status = NT_STATUS_UNSUCCESSFUL;
343da6c28aaSamw } else if (arg.status != 0) {
344da6c28aaSamw status = arg.status;
345da6c28aaSamw } else {
346da6c28aaSamw status = NT_STATUS_SUCCESS;
3478d7e4166Sjose borrego ndr_inherit_handle(domain_handle, samr_handle);
3488d7e4166Sjose borrego
349da6c28aaSamw (void) memcpy(&domain_handle->handle, &arg.domain_handle,
3508d7e4166Sjose borrego sizeof (ndr_hdid_t));
3518d7e4166Sjose borrego
3528d7e4166Sjose borrego if (ndr_is_null_handle(domain_handle))
353da6c28aaSamw status = NT_STATUS_INVALID_HANDLE;
354da6c28aaSamw }
355da6c28aaSamw
356da6c28aaSamw if (status != NT_STATUS_SUCCESS)
3578d7e4166Sjose borrego ndr_rpc_status(samr_handle, opnum, status);
358da6c28aaSamw
3598d7e4166Sjose borrego ndr_rpc_release(samr_handle);
360da6c28aaSamw return (status);
361da6c28aaSamw }
362da6c28aaSamw
363da6c28aaSamw /*
364da6c28aaSamw * samr_open_user
365da6c28aaSamw *
366da6c28aaSamw * Use a domain handle to obtain a handle for a user, specified by the
367da6c28aaSamw * user RID. A user RID (effectively a uid) can be obtained via the
368da6c28aaSamw * LSA interface. A handle for the user is returned in user_handle.
369da6c28aaSamw * Once you have a user handle it should be possible to query the SAM
370da6c28aaSamw * for information on that user.
371da6c28aaSamw */
37255bf511dSas DWORD
samr_open_user(mlsvc_handle_t * domain_handle,DWORD access_mask,DWORD rid,mlsvc_handle_t * user_handle)373da6c28aaSamw samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid,
374da6c28aaSamw mlsvc_handle_t *user_handle)
375da6c28aaSamw {
376da6c28aaSamw struct samr_OpenUser arg;
3778d7e4166Sjose borrego int opnum;
37855bf511dSas DWORD status = NT_STATUS_SUCCESS;
379da6c28aaSamw
3808d7e4166Sjose borrego if (ndr_is_null_handle(domain_handle) || user_handle == NULL)
38155bf511dSas return (NT_STATUS_INVALID_PARAMETER);
382da6c28aaSamw
383da6c28aaSamw opnum = SAMR_OPNUM_OpenUser;
384da6c28aaSamw bzero(&arg, sizeof (struct samr_OpenUser));
385da6c28aaSamw (void) memcpy(&arg.handle, &domain_handle->handle,
3868d7e4166Sjose borrego sizeof (ndr_hdid_t));
387da6c28aaSamw arg.access_mask = access_mask;
388da6c28aaSamw arg.rid = rid;
389da6c28aaSamw
3908d7e4166Sjose borrego if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
39155bf511dSas status = NT_STATUS_UNSUCCESSFUL;
39255bf511dSas } else if (arg.status != 0) {
3938d7e4166Sjose borrego ndr_rpc_status(domain_handle, opnum, arg.status);
39455bf511dSas status = NT_SC_VALUE(arg.status);
39555bf511dSas } else {
3968d7e4166Sjose borrego ndr_inherit_handle(user_handle, domain_handle);
3978d7e4166Sjose borrego
39855bf511dSas (void) memcpy(&user_handle->handle, &arg.user_handle,
3998d7e4166Sjose borrego sizeof (ndr_hdid_t));
40055bf511dSas
4018d7e4166Sjose borrego if (ndr_is_null_handle(user_handle))
40255bf511dSas status = NT_STATUS_INVALID_HANDLE;
403da6c28aaSamw }
404da6c28aaSamw
4058d7e4166Sjose borrego ndr_rpc_release(domain_handle);
40655bf511dSas return (status);
407da6c28aaSamw }
408da6c28aaSamw
409da6c28aaSamw /*
410da6c28aaSamw * samr_delete_user
411da6c28aaSamw *
412da6c28aaSamw * Delete the user specified by the user_handle.
413da6c28aaSamw */
414da6c28aaSamw DWORD
samr_delete_user(mlsvc_handle_t * user_handle)415da6c28aaSamw samr_delete_user(mlsvc_handle_t *user_handle)
416da6c28aaSamw {
417da6c28aaSamw struct samr_DeleteUser arg;
418da6c28aaSamw int opnum;
419da6c28aaSamw DWORD status;
420da6c28aaSamw
4218d7e4166Sjose borrego if (ndr_is_null_handle(user_handle))
422da6c28aaSamw return (NT_STATUS_INVALID_PARAMETER);
423da6c28aaSamw
424da6c28aaSamw opnum = SAMR_OPNUM_DeleteUser;
425da6c28aaSamw bzero(&arg, sizeof (struct samr_DeleteUser));
426da6c28aaSamw (void) memcpy(&arg.user_handle, &user_handle->handle,
4278d7e4166Sjose borrego sizeof (ndr_hdid_t));
428da6c28aaSamw
4298d7e4166Sjose borrego if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
430da6c28aaSamw status = NT_STATUS_INVALID_PARAMETER;
431da6c28aaSamw } else if (arg.status != 0) {
4328d7e4166Sjose borrego ndr_rpc_status(user_handle, opnum, arg.status);
433da6c28aaSamw status = NT_SC_VALUE(arg.status);
434da6c28aaSamw } else {
435da6c28aaSamw status = 0;
436da6c28aaSamw }
437da6c28aaSamw
4388d7e4166Sjose borrego ndr_rpc_release(user_handle);
439da6c28aaSamw return (status);
440da6c28aaSamw }
441da6c28aaSamw
442da6c28aaSamw /*
443da6c28aaSamw * samr_open_group
444da6c28aaSamw *
445da6c28aaSamw * Use a domain handle to obtain a handle for a group, specified by the
446da6c28aaSamw * group RID. A group RID (effectively a gid) can be obtained via the
447da6c28aaSamw * LSA interface. A handle for the group is returned in group_handle.
448da6c28aaSamw * Once you have a group handle it should be possible to query the SAM
449da6c28aaSamw * for information on that group.
450da6c28aaSamw */
451da6c28aaSamw int
samr_open_group(mlsvc_handle_t * domain_handle,DWORD rid,mlsvc_handle_t * group_handle)452da6c28aaSamw samr_open_group(
453da6c28aaSamw mlsvc_handle_t *domain_handle,
454da6c28aaSamw DWORD rid,
455da6c28aaSamw mlsvc_handle_t *group_handle)
456da6c28aaSamw {
457da6c28aaSamw struct samr_OpenGroup arg;
458da6c28aaSamw int opnum;
459da6c28aaSamw int rc;
460da6c28aaSamw
4618d7e4166Sjose borrego if (ndr_is_null_handle(domain_handle) || group_handle == NULL)
462da6c28aaSamw return (-1);
463da6c28aaSamw
464da6c28aaSamw opnum = SAMR_OPNUM_OpenGroup;
465da6c28aaSamw bzero(&arg, sizeof (struct samr_OpenUser));
466da6c28aaSamw (void) memcpy(&arg.handle, &domain_handle->handle,
4678d7e4166Sjose borrego sizeof (ndr_hdid_t));
468da6c28aaSamw arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ;
469da6c28aaSamw arg.rid = rid;
470da6c28aaSamw
4718d7e4166Sjose borrego if ((rc = ndr_rpc_call(domain_handle, opnum, &arg)) != 0)
4728d7e4166Sjose borrego return (-1);
4738d7e4166Sjose borrego
4748d7e4166Sjose borrego if (arg.status != 0) {
4758d7e4166Sjose borrego ndr_rpc_status(domain_handle, opnum, arg.status);
4768d7e4166Sjose borrego rc = -1;
4778d7e4166Sjose borrego } else {
4788d7e4166Sjose borrego ndr_inherit_handle(group_handle, domain_handle);
479da6c28aaSamw
4808d7e4166Sjose borrego (void) memcpy(&group_handle->handle, &arg.group_handle,
4818d7e4166Sjose borrego sizeof (ndr_hdid_t));
4828d7e4166Sjose borrego
4838d7e4166Sjose borrego if (ndr_is_null_handle(group_handle))
484da6c28aaSamw rc = -1;
485da6c28aaSamw }
486da6c28aaSamw
4878d7e4166Sjose borrego ndr_rpc_release(domain_handle);
488da6c28aaSamw return (rc);
489da6c28aaSamw }
490da6c28aaSamw
491da6c28aaSamw /*
492da6c28aaSamw * samr_create_user
493da6c28aaSamw *
494da6c28aaSamw * Create a user in the domain specified by the domain handle. If this
495da6c28aaSamw * call is successful, the server will return the RID for the user and
496da6c28aaSamw * a user handle, which may be used to set or query the SAM.
497da6c28aaSamw *
498da6c28aaSamw * Observed status codes:
499da6c28aaSamw * NT_STATUS_INVALID_PARAMETER
500da6c28aaSamw * NT_STATUS_INVALID_ACCOUNT_NAME
501da6c28aaSamw * NT_STATUS_ACCESS_DENIED
502da6c28aaSamw * NT_STATUS_USER_EXISTS
503da6c28aaSamw *
504da6c28aaSamw * Returns 0 on success. Otherwise returns an NT status code.
505da6c28aaSamw */
506da6c28aaSamw DWORD
samr_create_user(mlsvc_handle_t * domain_handle,char * username,DWORD account_flags,DWORD * rid,mlsvc_handle_t * user_handle)507da6c28aaSamw samr_create_user(mlsvc_handle_t *domain_handle, char *username,
508da6c28aaSamw DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle)
509da6c28aaSamw {
510da6c28aaSamw struct samr_CreateUser arg;
5118d7e4166Sjose borrego ndr_heap_t *heap;
512da6c28aaSamw int opnum;
513da6c28aaSamw int rc;
514da6c28aaSamw DWORD status = 0;
515da6c28aaSamw
5168d7e4166Sjose borrego if (ndr_is_null_handle(domain_handle) ||
517da6c28aaSamw username == NULL || rid == NULL) {
518da6c28aaSamw return (NT_STATUS_INVALID_PARAMETER);
519da6c28aaSamw }
520da6c28aaSamw
521da6c28aaSamw opnum = SAMR_OPNUM_CreateUser;
522da6c28aaSamw
523da6c28aaSamw bzero(&arg, sizeof (struct samr_CreateUser));
524da6c28aaSamw (void) memcpy(&arg.handle, &domain_handle->handle,
5258d7e4166Sjose borrego sizeof (ndr_hdid_t));
526da6c28aaSamw
5278d7e4166Sjose borrego heap = ndr_rpc_get_heap(domain_handle);
5288d7e4166Sjose borrego ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username);
529da6c28aaSamw
530da6c28aaSamw arg.account_flags = account_flags;
531a0aa776eSAlan Wright arg.desired_access = 0xE00500B0;
532da6c28aaSamw
5338d7e4166Sjose borrego rc = ndr_rpc_call(domain_handle, opnum, &arg);
534da6c28aaSamw if (rc != 0) {
535da6c28aaSamw status = NT_STATUS_INVALID_PARAMETER;
536da6c28aaSamw } else if (arg.status != 0) {
537da6c28aaSamw status = NT_SC_VALUE(arg.status);
538da6c28aaSamw
539da6c28aaSamw if (status != NT_STATUS_USER_EXISTS) {
5401ed6b69aSGordon Ross smb_tracef("SamrCreateUser[%s]: %s",
5411ed6b69aSGordon Ross username, xlate_nt_status(status));
542da6c28aaSamw }
543da6c28aaSamw } else {
5448d7e4166Sjose borrego ndr_inherit_handle(user_handle, domain_handle);
5458d7e4166Sjose borrego
546da6c28aaSamw (void) memcpy(&user_handle->handle, &arg.user_handle,
5478d7e4166Sjose borrego sizeof (ndr_hdid_t));
5488d7e4166Sjose borrego
549da6c28aaSamw *rid = arg.rid;
550da6c28aaSamw
5518d7e4166Sjose borrego if (ndr_is_null_handle(user_handle))
552da6c28aaSamw status = NT_STATUS_INVALID_HANDLE;
553da6c28aaSamw else
554da6c28aaSamw status = 0;
555da6c28aaSamw }
556da6c28aaSamw
5578d7e4166Sjose borrego ndr_rpc_release(domain_handle);
558da6c28aaSamw return (status);
559da6c28aaSamw }
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);
5861ed6b69aSGordon Ross 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);
6751ed6b69aSGordon Ross 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 */
964fe1c642dSBill Krier
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;
9991ed6b69aSGordon Ross
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;
10131ed6b69aSGordon Ross
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