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