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