xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
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  */
21da6c28aaSamw /*
22*dc20a302Sas  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * This module provides the high level interface to the LSA RPC functions.
30da6c28aaSamw  */
31da6c28aaSamw 
32da6c28aaSamw #include <strings.h>
33da6c28aaSamw #include <unistd.h>
34da6c28aaSamw #include <netdb.h>
35*dc20a302Sas #include <pwd.h>
36*dc20a302Sas #include <grp.h>
37da6c28aaSamw 
38da6c28aaSamw #include <smbsrv/libsmb.h>
39da6c28aaSamw #include <smbsrv/libsmbns.h>
40da6c28aaSamw #include <smbsrv/libmlsvc.h>
4155bf511dSas #include <smbsrv/libsmbrdr.h>
42da6c28aaSamw #include <smbsrv/lsalib.h>
43da6c28aaSamw #include <smbsrv/ntstatus.h>
44da6c28aaSamw #include <smbsrv/smbinfo.h>
45da6c28aaSamw #include <smbsrv/ntsid.h>
46da6c28aaSamw #include <smbsrv/smb_token.h>
47da6c28aaSamw 
48*dc20a302Sas /*
49*dc20a302Sas  * Name Lookup modes
50*dc20a302Sas  */
51*dc20a302Sas #define	MLSVC_LOOKUP_BUILTIN	1
52*dc20a302Sas #define	MLSVC_LOOKUP_LOCAL	2
53*dc20a302Sas #define	MLSVC_LOOKUP_DOMAIN	3
54*dc20a302Sas #define	MLSVC_LOOKUP_DOMLOC	4
55*dc20a302Sas 
56*dc20a302Sas static int lsa_lookup_mode(const char *, const char *);
57*dc20a302Sas static uint32_t lsa_lookup_name_builtin(char *, smb_userinfo_t *);
58*dc20a302Sas static uint32_t lsa_lookup_name_local(char *, char *, uint16_t,
59*dc20a302Sas     smb_userinfo_t *);
60*dc20a302Sas static uint32_t lsa_lookup_name_lusr(char *, nt_sid_t **);
61*dc20a302Sas static uint32_t lsa_lookup_name_lgrp(char *, nt_sid_t **);
62*dc20a302Sas static uint32_t lsa_lookup_name_domain(char *, char *, char *,
63*dc20a302Sas     smb_userinfo_t *);
64*dc20a302Sas 
65*dc20a302Sas static uint32_t lsa_lookup_sid_builtin(nt_sid_t *, smb_userinfo_t *);
66*dc20a302Sas static uint32_t lsa_lookup_sid_local(nt_sid_t *, smb_userinfo_t *);
67*dc20a302Sas static uint32_t lsa_lookup_sid_domain(nt_sid_t *, smb_userinfo_t *);
68*dc20a302Sas 
69da6c28aaSamw static int lsa_list_accounts(mlsvc_handle_t *);
70da6c28aaSamw 
71*dc20a302Sas /*
72*dc20a302Sas  * lsa_lookup_name
73*dc20a302Sas  *
74*dc20a302Sas  * Lookup the given account and returns the account information
75*dc20a302Sas  * in 'ainfo'
76*dc20a302Sas  *
77*dc20a302Sas  * If the name is a domain account, it may refer to a user, group or
78*dc20a302Sas  * alias. If it is a local account, its type should be specified
79*dc20a302Sas  * in the sid_type parameter. In case the account type is unknown
80*dc20a302Sas  * sid_type should be set to SidTypeUnknown.
81*dc20a302Sas  *
82*dc20a302Sas  * account argument could be either [domain\\]name or [domain/]name.
83*dc20a302Sas  * If domain is not specified and service is in domain mode then it
84*dc20a302Sas  * first does a domain lookup and then a local lookup.
85*dc20a302Sas  */
86*dc20a302Sas uint32_t
87*dc20a302Sas lsa_lookup_name(char *server, char *account, uint16_t sid_type,
88*dc20a302Sas     smb_userinfo_t *ainfo)
89*dc20a302Sas {
90*dc20a302Sas 	nt_domain_t *dominfo;
91*dc20a302Sas 	int lookup_mode;
92*dc20a302Sas 	char *name;
93*dc20a302Sas 	char *domain;
94*dc20a302Sas 	uint32_t status = NT_STATUS_NONE_MAPPED;
95*dc20a302Sas 
96*dc20a302Sas 	(void) strsubst(account, '\\', '/');
97*dc20a302Sas 	name = strchr(account, '/');
98*dc20a302Sas 	if (name) {
99*dc20a302Sas 		/* domain is specified */
100*dc20a302Sas 		*name++ = '\0';
101*dc20a302Sas 		domain = account;
102*dc20a302Sas 	} else {
103*dc20a302Sas 		name = account;
104*dc20a302Sas 		domain = NULL;
105*dc20a302Sas 	}
106*dc20a302Sas 
107*dc20a302Sas 	lookup_mode = lsa_lookup_mode(domain, name);
108*dc20a302Sas 
109*dc20a302Sas 	switch (lookup_mode) {
110*dc20a302Sas 	case MLSVC_LOOKUP_BUILTIN:
111*dc20a302Sas 		return (lsa_lookup_name_builtin(name, ainfo));
112*dc20a302Sas 
113*dc20a302Sas 	case MLSVC_LOOKUP_LOCAL:
114*dc20a302Sas 		return (lsa_lookup_name_local(domain, name, sid_type, ainfo));
115*dc20a302Sas 
116*dc20a302Sas 	case MLSVC_LOOKUP_DOMAIN:
117*dc20a302Sas 		return (lsa_lookup_name_domain(server, domain, name, ainfo));
118*dc20a302Sas 
119*dc20a302Sas 	default:
120*dc20a302Sas 		/* lookup the name in domain */
121*dc20a302Sas 		dominfo = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY);
122*dc20a302Sas 		if (dominfo == NULL)
123*dc20a302Sas 			return (NT_STATUS_INTERNAL_ERROR);
124*dc20a302Sas 		status = lsa_lookup_name_domain(server, dominfo->name, name,
125*dc20a302Sas 		    ainfo);
126*dc20a302Sas 		if (status != NT_STATUS_NONE_MAPPED)
127*dc20a302Sas 			return (status);
128*dc20a302Sas 
129*dc20a302Sas 		mlsvc_release_user_info(ainfo);
130*dc20a302Sas 		/* lookup the name locally */
131*dc20a302Sas 		status = lsa_lookup_name_local(domain, name, sid_type, ainfo);
132*dc20a302Sas 	}
133*dc20a302Sas 
134*dc20a302Sas 	return (status);
135*dc20a302Sas }
136*dc20a302Sas 
137*dc20a302Sas uint32_t
138*dc20a302Sas lsa_lookup_sid(nt_sid_t *sid, smb_userinfo_t *ainfo)
139*dc20a302Sas {
140*dc20a302Sas 	if (!nt_sid_is_valid(sid))
141*dc20a302Sas 		return (NT_STATUS_INVALID_SID);
142*dc20a302Sas 
143*dc20a302Sas 	if (nt_sid_is_local(sid))
144*dc20a302Sas 		return (lsa_lookup_sid_local(sid, ainfo));
145*dc20a302Sas 
146*dc20a302Sas 	if (nt_builtin_lookup_sid(sid, NULL))
147*dc20a302Sas 		return (lsa_lookup_sid_builtin(sid, ainfo));
148*dc20a302Sas 
149*dc20a302Sas 	return (lsa_lookup_sid_domain(sid, ainfo));
150*dc20a302Sas }
151*dc20a302Sas 
152da6c28aaSamw /*
153da6c28aaSamw  * lsa_query_primary_domain_info
154da6c28aaSamw  *
155da6c28aaSamw  * Obtains the primary domain SID and name from the specified server
156da6c28aaSamw  * (domain controller). The information is stored in the NT domain
157da6c28aaSamw  * database by the lower level lsar_query_info_policy call. The caller
158da6c28aaSamw  * should query the database to obtain a reference to the primary
159da6c28aaSamw  * domain information.
160da6c28aaSamw  *
161da6c28aaSamw  * Returns NT status codes.
162da6c28aaSamw  */
163da6c28aaSamw DWORD
164da6c28aaSamw lsa_query_primary_domain_info(void)
165da6c28aaSamw {
166da6c28aaSamw 	mlsvc_handle_t domain_handle;
167da6c28aaSamw 	DWORD status;
16855bf511dSas 	char *user = smbrdr_ipc_get_user();
169da6c28aaSamw 
17055bf511dSas 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
171da6c28aaSamw 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
172da6c28aaSamw 
173da6c28aaSamw 	status = lsar_query_info_policy(&domain_handle,
174da6c28aaSamw 	    MSLSA_POLICY_PRIMARY_DOMAIN_INFO);
175da6c28aaSamw 
176da6c28aaSamw 	(void) lsar_close(&domain_handle);
177da6c28aaSamw 	return (status);
178da6c28aaSamw }
179da6c28aaSamw 
180da6c28aaSamw /*
181da6c28aaSamw  * lsa_query_account_domain_info
182da6c28aaSamw  *
183da6c28aaSamw  * Obtains the account domain SID and name from the current server
184da6c28aaSamw  * (domain controller). The information is stored in the NT domain
185da6c28aaSamw  * database by the lower level lsar_query_info_policy call. The caller
186da6c28aaSamw  * should query the database to obtain a reference to the account
187da6c28aaSamw  * domain information.
188da6c28aaSamw  *
189da6c28aaSamw  * Returns NT status codes.
190da6c28aaSamw  */
191da6c28aaSamw DWORD
192da6c28aaSamw lsa_query_account_domain_info(void)
193da6c28aaSamw {
194da6c28aaSamw 	mlsvc_handle_t domain_handle;
195da6c28aaSamw 	DWORD status;
19655bf511dSas 	char *user = smbrdr_ipc_get_user();
197da6c28aaSamw 
19855bf511dSas 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
199da6c28aaSamw 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
200da6c28aaSamw 
201da6c28aaSamw 	status = lsar_query_info_policy(&domain_handle,
202da6c28aaSamw 	    MSLSA_POLICY_ACCOUNT_DOMAIN_INFO);
203da6c28aaSamw 
204da6c28aaSamw 	(void) lsar_close(&domain_handle);
205da6c28aaSamw 	return (status);
206da6c28aaSamw }
207da6c28aaSamw 
208da6c28aaSamw /*
209da6c28aaSamw  * lsa_enum_trusted_domains
210da6c28aaSamw  *
211da6c28aaSamw  * Enumerate the trusted domains in our primary domain. The information
212da6c28aaSamw  * is stored in the NT domain database by the lower level
213da6c28aaSamw  * lsar_enum_trusted_domains call. The caller should query the database
214da6c28aaSamw  * to obtain a reference to the trusted domain information.
215da6c28aaSamw  *
216da6c28aaSamw  * Returns NT status codes.
217da6c28aaSamw  */
218da6c28aaSamw DWORD
219da6c28aaSamw lsa_enum_trusted_domains(void)
220da6c28aaSamw {
221da6c28aaSamw 	mlsvc_handle_t domain_handle;
222da6c28aaSamw 	DWORD enum_context;
223da6c28aaSamw 	DWORD status;
22455bf511dSas 	char *user = smbrdr_ipc_get_user();
225da6c28aaSamw 
22655bf511dSas 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
227da6c28aaSamw 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
228da6c28aaSamw 
229da6c28aaSamw 	enum_context = 0;
230da6c28aaSamw 
231da6c28aaSamw 	status = lsar_enum_trusted_domains(&domain_handle, &enum_context);
232da6c28aaSamw 	if (status == MLSVC_NO_MORE_DATA) {
233da6c28aaSamw 		/*
234da6c28aaSamw 		 * MLSVC_NO_MORE_DATA indicates that we
235da6c28aaSamw 		 * have all of the available information.
236da6c28aaSamw 		 */
237da6c28aaSamw 		status = NT_STATUS_SUCCESS;
238da6c28aaSamw 	}
239da6c28aaSamw 
240da6c28aaSamw 	(void) lsar_close(&domain_handle);
241da6c28aaSamw 	return (status);
242da6c28aaSamw }
243da6c28aaSamw 
244da6c28aaSamw /*
245*dc20a302Sas  * lsa_lookup_name_builtin
246da6c28aaSamw  *
247da6c28aaSamw  * lookup builtin account table to see if account_name is
248da6c28aaSamw  * there. If it is there, set sid_name_use, domain_sid,
249da6c28aaSamw  * domain_name, and rid fields of the passed user_info
250*dc20a302Sas  * structure.
251da6c28aaSamw  */
252*dc20a302Sas static uint32_t
253*dc20a302Sas lsa_lookup_name_builtin(char *account_name, smb_userinfo_t *user_info)
254da6c28aaSamw {
255da6c28aaSamw 	char *domain;
256da6c28aaSamw 	int res;
257da6c28aaSamw 
258*dc20a302Sas 	user_info->user_sid = nt_builtin_lookup_name(account_name,
259da6c28aaSamw 	    &user_info->sid_name_use);
260da6c28aaSamw 
261*dc20a302Sas 	if (user_info->user_sid == NULL)
262*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
263da6c28aaSamw 
264*dc20a302Sas 	user_info->domain_sid = nt_sid_dup(user_info->user_sid);
265da6c28aaSamw 	res = nt_sid_split(user_info->domain_sid, &user_info->rid);
266da6c28aaSamw 	if (res < 0)
267*dc20a302Sas 		return (NT_STATUS_INTERNAL_ERROR);
268da6c28aaSamw 
269da6c28aaSamw 	domain = nt_builtin_lookup_domain(account_name);
270da6c28aaSamw 	if (domain) {
271da6c28aaSamw 		user_info->domain_name = strdup(domain);
272*dc20a302Sas 		return (NT_STATUS_SUCCESS);
273da6c28aaSamw 	}
274da6c28aaSamw 
275*dc20a302Sas 	return (NT_STATUS_INTERNAL_ERROR);
276da6c28aaSamw }
277da6c28aaSamw 
278da6c28aaSamw /*
279*dc20a302Sas  * lsa_lookup_name_local
280da6c28aaSamw  *
281*dc20a302Sas  * Obtains the infomation for the given local account name if it
282*dc20a302Sas  * can be found. The type of account is specified by sid_type,
283*dc20a302Sas  * which can be of user, group or unknown type. If the caller
284*dc20a302Sas  * doesn't know whether the name is a user or group name then
285*dc20a302Sas  * SidTypeUnknown should be passed, in which case this
286*dc20a302Sas  * function first tries to find a user and then a group match.
287da6c28aaSamw  *
288*dc20a302Sas  * CAVEAT: if there are both a user and a group account with
289*dc20a302Sas  * the same name, user SID will always be returned.
290da6c28aaSamw  */
291*dc20a302Sas static uint32_t
292*dc20a302Sas lsa_lookup_name_local(char *domain, char *name, uint16_t sid_type,
293*dc20a302Sas     smb_userinfo_t *ainfo)
294da6c28aaSamw {
295da6c28aaSamw 	char hostname[MAXHOSTNAMELEN];
296*dc20a302Sas 	nt_sid_t *sid;
297*dc20a302Sas 	uint32_t status;
298*dc20a302Sas 
299*dc20a302Sas 	switch (sid_type) {
300*dc20a302Sas 	case SidTypeUser:
301*dc20a302Sas 		status = lsa_lookup_name_lusr(name, &sid);
302*dc20a302Sas 		if (status != NT_STATUS_SUCCESS)
303*dc20a302Sas 			return (status);
304*dc20a302Sas 		break;
305*dc20a302Sas 
306*dc20a302Sas 	case SidTypeGroup:
307*dc20a302Sas 	case SidTypeAlias:
308*dc20a302Sas 		status = lsa_lookup_name_lgrp(name, &sid);
309*dc20a302Sas 		if (status != NT_STATUS_SUCCESS)
310*dc20a302Sas 			return (status);
311*dc20a302Sas 		break;
312*dc20a302Sas 
313*dc20a302Sas 	case SidTypeUnknown:
314*dc20a302Sas 		sid_type = SidTypeUser;
315*dc20a302Sas 		status = lsa_lookup_name_lusr(name, &sid);
316*dc20a302Sas 		if (status == NT_STATUS_SUCCESS)
317*dc20a302Sas 			break;
318*dc20a302Sas 
319*dc20a302Sas 		if (status == NT_STATUS_NONE_MAPPED)
320*dc20a302Sas 			return (status);
321*dc20a302Sas 
322*dc20a302Sas 		sid_type = SidTypeAlias;
323*dc20a302Sas 		status = lsa_lookup_name_lgrp(name, &sid);
324*dc20a302Sas 		if (status != NT_STATUS_SUCCESS)
325*dc20a302Sas 			return (status);
326*dc20a302Sas 		break;
327*dc20a302Sas 
328*dc20a302Sas 	default:
329*dc20a302Sas 			return (NT_STATUS_INVALID_PARAMETER);
330da6c28aaSamw 	}
331da6c28aaSamw 
332*dc20a302Sas 	ainfo->sid_name_use = sid_type;
333*dc20a302Sas 	ainfo->user_sid = sid;
334*dc20a302Sas 	ainfo->domain_sid = nt_sid_dup(sid);
335*dc20a302Sas 	if (ainfo->domain_sid == NULL)
336*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
337*dc20a302Sas 
338*dc20a302Sas 	(void) nt_sid_split(ainfo->domain_sid, &ainfo->rid);
339*dc20a302Sas 	if ((domain == NULL) || (*domain == '\0')) {
340*dc20a302Sas 		(void) smb_getnetbiosname(hostname, sizeof (hostname));
341*dc20a302Sas 		ainfo->domain_name = strdup(hostname);
342*dc20a302Sas 	} else {
343*dc20a302Sas 		ainfo->domain_name = strdup(domain);
344*dc20a302Sas 	}
345da6c28aaSamw 
346*dc20a302Sas 	if (ainfo->domain_name == NULL)
347*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
348da6c28aaSamw 
349*dc20a302Sas 	return (NT_STATUS_SUCCESS);
350da6c28aaSamw }
351da6c28aaSamw 
352da6c28aaSamw /*
353*dc20a302Sas  * lsa_lookup_name_domain
354da6c28aaSamw  *
355da6c28aaSamw  * Lookup a name on the specified server (domain controller) and obtain
356da6c28aaSamw  * the appropriate SID. The information is returned in the user_info
357da6c28aaSamw  * structure. The caller is responsible for allocating and releasing
358da6c28aaSamw  * this structure. On success sid_name_use will be set to indicate the
359da6c28aaSamw  * type of SID. If the name is the domain name, this function will be
360da6c28aaSamw  * identical to lsa_domain_info. Otherwise the rid and name fields will
361da6c28aaSamw  * also be valid. On failure sid_name_use will be set to SidTypeUnknown.
362da6c28aaSamw  */
363*dc20a302Sas static uint32_t
364*dc20a302Sas lsa_lookup_name_domain(char *server, char *domain, char *account_name,
365da6c28aaSamw     smb_userinfo_t *user_info)
366da6c28aaSamw {
367da6c28aaSamw 	mlsvc_handle_t domain_handle;
36855bf511dSas 	char *user = smbrdr_ipc_get_user();
369*dc20a302Sas 	uint32_t status;
370da6c28aaSamw 
371*dc20a302Sas 	if (lsar_open(server, domain, user, &domain_handle) != 0)
372da6c28aaSamw 		return (NT_STATUS_INVALID_PARAMETER);
373da6c28aaSamw 
374da6c28aaSamw 	status = lsar_lookup_names2(&domain_handle, account_name, user_info);
375da6c28aaSamw 	if (status == NT_STATUS_REVISION_MISMATCH) {
376da6c28aaSamw 		/*
377da6c28aaSamw 		 * Not a Windows 2000 domain controller:
378da6c28aaSamw 		 * use the NT compatible call.
379da6c28aaSamw 		 */
380*dc20a302Sas 		status = lsar_lookup_names(&domain_handle, account_name,
381*dc20a302Sas 		    user_info);
382da6c28aaSamw 	}
383da6c28aaSamw 
384da6c28aaSamw 	(void) lsar_close(&domain_handle);
385da6c28aaSamw 	return (status);
386da6c28aaSamw }
387da6c28aaSamw 
388da6c28aaSamw /*
389*dc20a302Sas  * lsa_test_lookup
390da6c28aaSamw  *
391*dc20a302Sas  * Test routine for lsa_lookup_name_domain and lsa_lookup_sid2.
392da6c28aaSamw  */
393da6c28aaSamw void
394*dc20a302Sas lsa_test_lookup(char *name)
395da6c28aaSamw {
396da6c28aaSamw 	smb_userinfo_t *user_info;
397da6c28aaSamw 	nt_sid_t *sid;
398da6c28aaSamw 	DWORD status;
399da6c28aaSamw 	smb_ntdomain_t *di;
400da6c28aaSamw 
401da6c28aaSamw 	if ((di = smb_getdomaininfo(0)) == 0)
402da6c28aaSamw 		return;
403da6c28aaSamw 
404da6c28aaSamw 	user_info = mlsvc_alloc_user_info();
405da6c28aaSamw 
406*dc20a302Sas 	if (lsa_lookup_name_builtin(name, user_info) != 0) {
407*dc20a302Sas 		status = lsa_lookup_name_domain(di->server, di->domain, name,
408da6c28aaSamw 		    user_info);
409da6c28aaSamw 
410da6c28aaSamw 		if (status == 0) {
411da6c28aaSamw 			sid = nt_sid_splice(user_info->domain_sid,
412da6c28aaSamw 			    user_info->rid);
413da6c28aaSamw 
414*dc20a302Sas 			(void) lsa_lookup_sid_domain(sid, user_info);
415da6c28aaSamw 			free(sid);
416da6c28aaSamw 		}
417da6c28aaSamw 	}
418da6c28aaSamw 
419da6c28aaSamw 	mlsvc_free_user_info(user_info);
420da6c28aaSamw }
421da6c28aaSamw 
422da6c28aaSamw /*
423da6c28aaSamw  * lsa_lookup_privs
424da6c28aaSamw  *
425da6c28aaSamw  * Request the privileges associated with the specified account. In
426da6c28aaSamw  * order to get the privileges, we first have to lookup the name on
427da6c28aaSamw  * the specified domain controller and obtain the appropriate SID.
428da6c28aaSamw  * The SID can then be used to open the account and obtain the
429da6c28aaSamw  * account privileges. The results from both the name lookup and the
430da6c28aaSamw  * privileges are returned in the user_info structure. The caller is
431da6c28aaSamw  * responsible for allocating and releasing this structure.
432da6c28aaSamw  *
433da6c28aaSamw  * On success 0 is returned. Otherwise a -ve error code.
434da6c28aaSamw  */
435da6c28aaSamw /*ARGSUSED*/
436da6c28aaSamw int
437da6c28aaSamw lsa_lookup_privs(char *server, char *account_name, char *target_name,
438da6c28aaSamw     smb_userinfo_t *user_info)
439da6c28aaSamw {
440da6c28aaSamw 	mlsvc_handle_t domain_handle;
441da6c28aaSamw 	int rc;
44255bf511dSas 	char *user = smbrdr_ipc_get_user();
443da6c28aaSamw 
44455bf511dSas 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
445da6c28aaSamw 		return (-1);
446da6c28aaSamw 
447da6c28aaSamw 	rc = lsa_list_accounts(&domain_handle);
448da6c28aaSamw 	(void) lsar_close(&domain_handle);
449da6c28aaSamw 	return (rc);
450da6c28aaSamw }
451da6c28aaSamw 
452da6c28aaSamw /*
453da6c28aaSamw  * lsa_list_privs
454da6c28aaSamw  *
455da6c28aaSamw  * List the privileges supported by the specified server.
456da6c28aaSamw  * This function is only intended for diagnostics.
457da6c28aaSamw  *
458da6c28aaSamw  * Returns NT status codes.
459da6c28aaSamw  */
460da6c28aaSamw DWORD
461da6c28aaSamw lsa_list_privs(char *server, char *domain)
462da6c28aaSamw {
463da6c28aaSamw 	static char name[128];
464da6c28aaSamw 	static struct ms_luid luid;
465da6c28aaSamw 	mlsvc_handle_t domain_handle;
466da6c28aaSamw 	int rc;
467da6c28aaSamw 	int i;
46855bf511dSas 	char *user = smbrdr_ipc_get_user();
469da6c28aaSamw 
47055bf511dSas 	rc = lsar_open(server, domain, user, &domain_handle);
471da6c28aaSamw 	if (rc != 0)
472da6c28aaSamw 		return (NT_STATUS_INVALID_PARAMETER);
473da6c28aaSamw 
474da6c28aaSamw 	for (i = 0; i < 30; ++i) {
475da6c28aaSamw 		luid.low_part = i;
476da6c28aaSamw 		rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
477da6c28aaSamw 		if (rc != 0)
478da6c28aaSamw 			continue;
479da6c28aaSamw 
480da6c28aaSamw 		(void) lsar_lookup_priv_value(&domain_handle, name, &luid);
481da6c28aaSamw 		(void) lsar_lookup_priv_display_name(&domain_handle, name,
482da6c28aaSamw 		    name, 128);
483da6c28aaSamw 	}
484da6c28aaSamw 
485da6c28aaSamw 	(void) lsar_close(&domain_handle);
486da6c28aaSamw 	return (NT_STATUS_SUCCESS);
487da6c28aaSamw }
488da6c28aaSamw 
489da6c28aaSamw /*
490da6c28aaSamw  * lsa_test
491da6c28aaSamw  *
492da6c28aaSamw  * LSA test routine: open and close the LSA interface.
493da6c28aaSamw  * TBD: the parameters should be server and domain.
494da6c28aaSamw  *
495da6c28aaSamw  * On success 0 is returned. Otherwise a -ve error code.
496da6c28aaSamw  */
497da6c28aaSamw /*ARGSUSED*/
498da6c28aaSamw int
499da6c28aaSamw lsa_test(char *server, char *account_name)
500da6c28aaSamw {
501da6c28aaSamw 	mlsvc_handle_t domain_handle;
502da6c28aaSamw 	int rc;
50355bf511dSas 	char *user = smbrdr_ipc_get_user();
504da6c28aaSamw 
50555bf511dSas 	rc = lsar_open(NULL, NULL, user, &domain_handle);
506da6c28aaSamw 	if (rc != 0)
507da6c28aaSamw 		return (-1);
508da6c28aaSamw 
509da6c28aaSamw 	if (lsar_close(&domain_handle) != 0)
510da6c28aaSamw 		return (-1);
511da6c28aaSamw 
512da6c28aaSamw 	return (0);
513da6c28aaSamw }
514da6c28aaSamw 
515da6c28aaSamw /*
516da6c28aaSamw  * lsa_list_accounts
517da6c28aaSamw  *
518da6c28aaSamw  * This function can be used to list the accounts in the specified
519da6c28aaSamw  * domain. For now the SIDs are just listed in the system log.
520da6c28aaSamw  *
521da6c28aaSamw  * On success 0 is returned. Otherwise a -ve error code.
522da6c28aaSamw  */
523da6c28aaSamw static int
524da6c28aaSamw lsa_list_accounts(mlsvc_handle_t *domain_handle)
525da6c28aaSamw {
526da6c28aaSamw 	mlsvc_handle_t account_handle;
527da6c28aaSamw 	struct mslsa_EnumAccountBuf accounts;
528da6c28aaSamw 	struct mslsa_sid *sid;
529da6c28aaSamw 	char *name;
530da6c28aaSamw 	WORD sid_name_use;
531da6c28aaSamw 	smb_userinfo_t *user_info;
532da6c28aaSamw 	DWORD enum_context = 0;
533da6c28aaSamw 	int rc;
534da6c28aaSamw 	int i;
535da6c28aaSamw 
536da6c28aaSamw 	user_info = mlsvc_alloc_user_info();
537da6c28aaSamw 	bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
538da6c28aaSamw 
539da6c28aaSamw 	do {
540da6c28aaSamw 		rc = lsar_enum_accounts(domain_handle, &enum_context,
541da6c28aaSamw 		    &accounts);
542da6c28aaSamw 		if (rc != 0)
543da6c28aaSamw 			return (rc);
544da6c28aaSamw 
545da6c28aaSamw 		for (i = 0; i < accounts.entries_read; ++i) {
546da6c28aaSamw 			sid = accounts.info[i].sid;
547da6c28aaSamw 
548da6c28aaSamw 			name = nt_builtin_lookup_sid((nt_sid_t *)sid,
549da6c28aaSamw 			    &sid_name_use);
550da6c28aaSamw 
551da6c28aaSamw 			if (name == 0) {
552da6c28aaSamw 				if (lsar_lookup_sids(domain_handle, sid,
553da6c28aaSamw 				    user_info) == 0) {
554da6c28aaSamw 					name = user_info->name;
555da6c28aaSamw 					sid_name_use = user_info->sid_name_use;
556da6c28aaSamw 				} else {
557da6c28aaSamw 					name = "unknown";
558da6c28aaSamw 					sid_name_use = SidTypeUnknown;
559da6c28aaSamw 				}
560da6c28aaSamw 			}
561da6c28aaSamw 
562da6c28aaSamw 			nt_sid_logf((nt_sid_t *)sid);
563da6c28aaSamw 
564da6c28aaSamw 			if (lsar_open_account(domain_handle, sid,
565da6c28aaSamw 			    &account_handle) == 0) {
566da6c28aaSamw 				(void) lsar_enum_privs_account(&account_handle,
567da6c28aaSamw 				    user_info);
568da6c28aaSamw 				(void) lsar_close(&account_handle);
569da6c28aaSamw 			}
570da6c28aaSamw 
571da6c28aaSamw 			free(accounts.info[i].sid);
572da6c28aaSamw 			mlsvc_release_user_info(user_info);
573da6c28aaSamw 		}
574da6c28aaSamw 
575da6c28aaSamw 		if (accounts.info)
576da6c28aaSamw 			free(accounts.info);
577da6c28aaSamw 	} while (rc == 0 && accounts.entries_read != 0);
578da6c28aaSamw 
579da6c28aaSamw 	mlsvc_free_user_info(user_info);
580da6c28aaSamw 	return (0);
581da6c28aaSamw }
582*dc20a302Sas 
583*dc20a302Sas /*
584*dc20a302Sas  * lsa_lookup_name_lusr
585*dc20a302Sas  *
586*dc20a302Sas  * Obtains the SID for the given local user name if it
587*dc20a302Sas  * can be found. Upon successful return the allocated memory
588*dc20a302Sas  * for the returned SID must be freed by the caller.
589*dc20a302Sas  *
590*dc20a302Sas  * Note that in domain mode this function might actually return
591*dc20a302Sas  * a domain SID if local users are mapped to domain users.
592*dc20a302Sas  */
593*dc20a302Sas static uint32_t
594*dc20a302Sas lsa_lookup_name_lusr(char *name, nt_sid_t **sid)
595*dc20a302Sas {
596*dc20a302Sas 	struct passwd *pw;
597*dc20a302Sas 
598*dc20a302Sas 	if ((pw = getpwnam(name)) == NULL)
599*dc20a302Sas 		return (NT_STATUS_NO_SUCH_USER);
600*dc20a302Sas 
601*dc20a302Sas 	if (smb_idmap_getsid(pw->pw_uid, SMB_IDMAP_USER, sid) != IDMAP_SUCCESS)
602*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
603*dc20a302Sas 
604*dc20a302Sas 	return (NT_STATUS_SUCCESS);
605*dc20a302Sas }
606*dc20a302Sas 
607*dc20a302Sas /*
608*dc20a302Sas  * lsa_lookup_name_lgrp
609*dc20a302Sas  *
610*dc20a302Sas  * Obtains the SID for the given local group name if it
611*dc20a302Sas  * can be found. Upon successful return the allocated memory
612*dc20a302Sas  * for the returned SID must be freed by the caller.
613*dc20a302Sas  *
614*dc20a302Sas  * Note that in domain mode this function might actually return
615*dc20a302Sas  * a domain SID if local groups are mapped to domain groups.
616*dc20a302Sas  */
617*dc20a302Sas static uint32_t
618*dc20a302Sas lsa_lookup_name_lgrp(char *name, nt_sid_t **sid)
619*dc20a302Sas {
620*dc20a302Sas 	struct group *gr;
621*dc20a302Sas 
622*dc20a302Sas 	if ((gr = getgrnam(name)) == NULL)
623*dc20a302Sas 		return (NT_STATUS_NO_SUCH_ALIAS);
624*dc20a302Sas 
625*dc20a302Sas 	if (smb_idmap_getsid(gr->gr_gid, SMB_IDMAP_GROUP, sid) != IDMAP_SUCCESS)
626*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
627*dc20a302Sas 
628*dc20a302Sas 	return (NT_STATUS_SUCCESS);
629*dc20a302Sas }
630*dc20a302Sas 
631*dc20a302Sas static int
632*dc20a302Sas lsa_lookup_mode(const char *domain, const char *name)
633*dc20a302Sas {
634*dc20a302Sas 	int lookup_mode;
635*dc20a302Sas 
636*dc20a302Sas 	if (nt_builtin_lookup((char *)name))
637*dc20a302Sas 		return (MLSVC_LOOKUP_BUILTIN);
638*dc20a302Sas 
639*dc20a302Sas 	if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP)
640*dc20a302Sas 		return (MLSVC_LOOKUP_LOCAL);
641*dc20a302Sas 
642*dc20a302Sas 	if ((domain == NULL) || (*domain == '\0'))
643*dc20a302Sas 		return (MLSVC_LOOKUP_DOMLOC);
644*dc20a302Sas 
645*dc20a302Sas 	if (mlsvc_is_local_domain(domain) == 1)
646*dc20a302Sas 		lookup_mode = MLSVC_LOOKUP_LOCAL;
647*dc20a302Sas 	else
648*dc20a302Sas 		lookup_mode = MLSVC_LOOKUP_DOMAIN;
649*dc20a302Sas 
650*dc20a302Sas 	return (lookup_mode);
651*dc20a302Sas }
652*dc20a302Sas 
653*dc20a302Sas static uint32_t
654*dc20a302Sas lsa_lookup_sid_local(nt_sid_t *sid, smb_userinfo_t *ainfo)
655*dc20a302Sas {
656*dc20a302Sas 	char hostname[MAXHOSTNAMELEN];
657*dc20a302Sas 	struct passwd *pw;
658*dc20a302Sas 	struct group *gr;
659*dc20a302Sas 	uid_t id;
660*dc20a302Sas 	int id_type;
661*dc20a302Sas 
662*dc20a302Sas 	id_type = SMB_IDMAP_UNKNOWN;
663*dc20a302Sas 	if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
664*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
665*dc20a302Sas 
666*dc20a302Sas 	switch (id_type) {
667*dc20a302Sas 	case SMB_IDMAP_USER:
668*dc20a302Sas 		ainfo->sid_name_use = SidTypeUser;
669*dc20a302Sas 		if ((pw = getpwuid(id)) == NULL)
670*dc20a302Sas 			return (NT_STATUS_NO_SUCH_USER);
671*dc20a302Sas 
672*dc20a302Sas 		ainfo->name = strdup(pw->pw_name);
673*dc20a302Sas 		break;
674*dc20a302Sas 
675*dc20a302Sas 	case SMB_IDMAP_GROUP:
676*dc20a302Sas 		ainfo->sid_name_use = SidTypeAlias;
677*dc20a302Sas 		if ((gr = getgrgid(id)) == NULL)
678*dc20a302Sas 			return (NT_STATUS_NO_SUCH_ALIAS);
679*dc20a302Sas 
680*dc20a302Sas 		ainfo->name = strdup(gr->gr_name);
681*dc20a302Sas 		break;
682*dc20a302Sas 
683*dc20a302Sas 	default:
684*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
685*dc20a302Sas 	}
686*dc20a302Sas 
687*dc20a302Sas 	if (ainfo->name == NULL)
688*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
689*dc20a302Sas 
690*dc20a302Sas 	ainfo->domain_sid = nt_sid_dup(sid);
691*dc20a302Sas 	if (nt_sid_split(ainfo->domain_sid, &ainfo->rid) < 0)
692*dc20a302Sas 		return (NT_STATUS_INTERNAL_ERROR);
693*dc20a302Sas 	*hostname = '\0';
694*dc20a302Sas 	(void) smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
695*dc20a302Sas 	if ((ainfo->domain_name = strdup(hostname)) == NULL)
696*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
697*dc20a302Sas 
698*dc20a302Sas 	return (NT_STATUS_SUCCESS);
699*dc20a302Sas }
700*dc20a302Sas 
701*dc20a302Sas static uint32_t
702*dc20a302Sas lsa_lookup_sid_builtin(nt_sid_t *sid, smb_userinfo_t *ainfo)
703*dc20a302Sas {
704*dc20a302Sas 	char *name;
705*dc20a302Sas 	WORD sid_name_use;
706*dc20a302Sas 
707*dc20a302Sas 	if ((name = nt_builtin_lookup_sid(sid, &sid_name_use)) == NULL)
708*dc20a302Sas 		return (NT_STATUS_NONE_MAPPED);
709*dc20a302Sas 
710*dc20a302Sas 	ainfo->sid_name_use = sid_name_use;
711*dc20a302Sas 	ainfo->name = strdup(name);
712*dc20a302Sas 	ainfo->domain_sid = nt_sid_dup(sid);
713*dc20a302Sas 
714*dc20a302Sas 	if (ainfo->name == NULL || ainfo->domain_sid == NULL)
715*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
716*dc20a302Sas 
717*dc20a302Sas 	if (sid_name_use != SidTypeDomain)
718*dc20a302Sas 		(void) nt_sid_split(ainfo->domain_sid, &ainfo->rid);
719*dc20a302Sas 
720*dc20a302Sas 	if ((name = nt_builtin_lookup_domain(ainfo->name)) != NULL)
721*dc20a302Sas 		ainfo->domain_name = strdup(name);
722*dc20a302Sas 	else
723*dc20a302Sas 		ainfo->domain_name = strdup("UNKNOWN");
724*dc20a302Sas 
725*dc20a302Sas 	if (ainfo->domain_name == NULL)
726*dc20a302Sas 		return (NT_STATUS_NO_MEMORY);
727*dc20a302Sas 
728*dc20a302Sas 	return (NT_STATUS_SUCCESS);
729*dc20a302Sas }
730*dc20a302Sas 
731*dc20a302Sas static uint32_t
732*dc20a302Sas lsa_lookup_sid_domain(nt_sid_t *sid, smb_userinfo_t *ainfo)
733*dc20a302Sas {
734*dc20a302Sas 	mlsvc_handle_t domain_handle;
735*dc20a302Sas 	char *user = smbrdr_ipc_get_user();
736*dc20a302Sas 	uint32_t status;
737*dc20a302Sas 
738*dc20a302Sas 	if (lsar_open(NULL, NULL, user, &domain_handle) != 0)
739*dc20a302Sas 		return (NT_STATUS_INVALID_PARAMETER);
740*dc20a302Sas 
741*dc20a302Sas 	status = lsar_lookup_sids2(&domain_handle,
742*dc20a302Sas 	    (struct mslsa_sid *)sid, ainfo);
743*dc20a302Sas 
744*dc20a302Sas 	if (status == NT_STATUS_REVISION_MISMATCH) {
745*dc20a302Sas 		/*
746*dc20a302Sas 		 * Not a Windows 2000 domain controller:
747*dc20a302Sas 		 * use the NT compatible call.
748*dc20a302Sas 		 */
749*dc20a302Sas 		status = lsar_lookup_sids(&domain_handle,
750*dc20a302Sas 		    (struct mslsa_sid *)sid, ainfo);
751*dc20a302Sas 	}
752*dc20a302Sas 
753*dc20a302Sas 	(void) lsar_close(&domain_handle);
754*dc20a302Sas 	return (status);
755*dc20a302Sas }
756