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