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