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