xref: /titanic_50/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c (revision fbaf5b3e92ba3bfee8b866a9e1f3cf089e58b2ab)
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  * Local Security Authority RPC (LSAR) client-side interface.
28  */
29 
30 #include <sys/errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 
35 #include <smbsrv/libsmb.h>
36 #include <smbsrv/libmlsvc.h>
37 #include <smbsrv/smbinfo.h>
38 #include <smbsrv/ntaccess.h>
39 #include <smbsrv/ntstatus.h>
40 #include <smbsrv/ntlocale.h>
41 #include <smbsrv/string.h>
42 #include <lsalib.h>
43 
44 /*
45  * The maximum number of bytes we are prepared to deal with in a
46  * response.
47  */
48 #define	MLSVC_MAX_RESPONSE_LEN		1024
49 
50 /*
51  * This structure is used when looking up names. We only lookup one
52  * name at a time but the structure will allow for more.
53  */
54 typedef struct lsa_names {
55 	uint32_t	n_entry;
56 	mslsa_string_t	name[8];
57 } lsa_names_t;
58 
59 typedef DWORD (*lsar_nameop_t)(mlsvc_handle_t *, lsa_names_t *,
60     smb_account_t *);
61 
62 static uint32_t lsar_lookup_names1(mlsvc_handle_t *, lsa_names_t *,
63     smb_account_t *);
64 static uint32_t lsar_lookup_names2(mlsvc_handle_t *, lsa_names_t *,
65     smb_account_t *);
66 static uint32_t lsar_lookup_names3(mlsvc_handle_t *, lsa_names_t *,
67     smb_account_t *);
68 static uint32_t lsar_lookup_sids1(mlsvc_handle_t *, lsa_sid_t *,
69     smb_account_t *);
70 static uint32_t lsar_lookup_sids2(mlsvc_handle_t *, lsa_sid_t *,
71     smb_account_t *account);
72 
73 static char *lsar_get_username(const char *);
74 static void smb_account_trace(const smb_account_t *);
75 
76 static void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *,
77     smb_trusted_domains_t *);
78 static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *,
79     smb_trusted_domains_t *);
80 
81 /*
82  * lsar_open
83  *
84  * This is a wrapper round lsar_open_policy2 to ensure that we connect
85  * using the appropriate domain information.
86  *
87  * If username argument is NULL, an anonymous connection will be established.
88  * Otherwise, an authenticated connection will be established.
89  *
90  * On success 0 is returned. Otherwise a -ve error code.
91  */
92 int lsar_open(char *server, char *domain, char *username,
93     mlsvc_handle_t *domain_handle)
94 {
95 	if (server == NULL || domain == NULL)
96 		return (-1);
97 
98 	if (username == NULL)
99 		username = MLSVC_ANON_USER;
100 
101 	return (lsar_open_policy2(server, domain, username, domain_handle));
102 }
103 
104 /*
105  * lsar_open_policy2
106  *
107  * Obtain an LSA policy handle. A policy handle is required to access
108  * LSA resources on a remote server. The server name supplied here does
109  * not need the double backslash prefix; it is added here. Call this
110  * function via lsar_open to ensure that the appropriate connection is
111  * in place.
112  *
113  * I'm not sure if it makes a difference whether we use GENERIC_EXECUTE
114  * or STANDARD_RIGHTS_EXECUTE. For a long time I used the standard bit
115  * and then I added the generic bit while working on privileges because
116  * NT sets that bit. I don't think it matters.
117  *
118  * Returns 0 on success. Otherwise non-zero to indicate a failure.
119  */
120 int
121 lsar_open_policy2(char *server, char *domain, char *username,
122     mlsvc_handle_t *lsa_handle)
123 {
124 	struct mslsa_OpenPolicy2 arg;
125 	int opnum;
126 	int len;
127 	int rc;
128 
129 	rc = ndr_rpc_bind(lsa_handle, server, domain, username, "LSARPC");
130 	if (rc != 0)
131 		return (-1);
132 
133 	opnum = LSARPC_OPNUM_OpenPolicy2;
134 	bzero(&arg, sizeof (struct mslsa_OpenPolicy2));
135 
136 	len = strlen(server) + 4;
137 	arg.servername = ndr_rpc_malloc(lsa_handle, len);
138 	if (arg.servername == NULL) {
139 		ndr_rpc_unbind(lsa_handle);
140 		return (-1);
141 	}
142 
143 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
144 	arg.attributes.length = sizeof (struct mslsa_object_attributes);
145 
146 	if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
147 		arg.desiredAccess = MAXIMUM_ALLOWED;
148 	} else {
149 		arg.desiredAccess = GENERIC_EXECUTE
150 		    | STANDARD_RIGHTS_EXECUTE
151 		    | POLICY_VIEW_LOCAL_INFORMATION
152 		    | POLICY_LOOKUP_NAMES;
153 	}
154 
155 	if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) {
156 		ndr_rpc_unbind(lsa_handle);
157 		return (-1);
158 	}
159 
160 	if (arg.status != 0) {
161 		rc = -1;
162 	} else {
163 		(void) memcpy(&lsa_handle->handle, &arg.domain_handle,
164 		    sizeof (ndr_hdid_t));
165 
166 		if (ndr_is_null_handle(lsa_handle))
167 			rc = -1;
168 	}
169 
170 	ndr_rpc_release(lsa_handle);
171 
172 	if (rc != 0)
173 		ndr_rpc_unbind(lsa_handle);
174 	return (rc);
175 }
176 
177 /*
178  * lsar_open_account
179  *
180  * Obtain an LSA account handle. The lsa_handle must be a valid handle
181  * obtained via lsar_open_policy2. The main thing to remember here is
182  * to set up the context in the lsa_account_handle. I'm not sure what
183  * the requirements are for desired access. Some values require admin
184  * access.
185  *
186  * Returns 0 on success. Otherwise non-zero to indicate a failure.
187  */
188 int
189 lsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
190     mlsvc_handle_t *lsa_account_handle)
191 {
192 	struct mslsa_OpenAccount arg;
193 	int opnum;
194 	int rc;
195 
196 	if (ndr_is_null_handle(lsa_handle) || sid == NULL)
197 		return (-1);
198 
199 	opnum = LSARPC_OPNUM_OpenAccount;
200 	bzero(&arg, sizeof (struct mslsa_OpenAccount));
201 
202 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
203 	arg.sid = sid;
204 	arg.access_mask = STANDARD_RIGHTS_REQUIRED
205 #if 0
206 	    | POLICY_VIEW_AUDIT_INFORMATION
207 	    | POLICY_GET_PRIVATE_INFORMATION
208 	    | POLICY_TRUST_ADMIN
209 #endif
210 	    | POLICY_VIEW_LOCAL_INFORMATION;
211 
212 	if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0)
213 		return (-1);
214 
215 	if (arg.status != 0) {
216 		rc = -1;
217 	} else {
218 		ndr_inherit_handle(lsa_account_handle, lsa_handle);
219 
220 		(void) memcpy(&lsa_account_handle->handle,
221 		    &arg.account_handle, sizeof (ndr_hdid_t));
222 
223 		if (ndr_is_null_handle(lsa_account_handle))
224 			rc = -1;
225 	}
226 
227 	ndr_rpc_release(lsa_handle);
228 	return (rc);
229 }
230 
231 /*
232  * lsar_close
233  *
234  * Close the LSA connection associated with the handle. The lsa_handle
235  * must be a valid handle obtained via a call to lsar_open_policy2 or
236  * lsar_open_account. On success the handle will be zeroed out to
237  * ensure that it is not used again. If this is the top level handle
238  * (i.e. the one obtained via lsar_open_policy2) the pipe is closed.
239  *
240  * Returns 0 on success. Otherwise non-zero to indicate a failure.
241  */
242 int
243 lsar_close(mlsvc_handle_t *lsa_handle)
244 {
245 	struct mslsa_CloseHandle arg;
246 	int opnum;
247 
248 	if (ndr_is_null_handle(lsa_handle))
249 		return (-1);
250 
251 	opnum = LSARPC_OPNUM_CloseHandle;
252 	bzero(&arg, sizeof (struct mslsa_CloseHandle));
253 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
254 
255 	(void) ndr_rpc_call(lsa_handle, opnum, &arg);
256 	ndr_rpc_release(lsa_handle);
257 
258 	if (ndr_is_bind_handle(lsa_handle))
259 		ndr_rpc_unbind(lsa_handle);
260 
261 	bzero(lsa_handle, sizeof (mlsvc_handle_t));
262 	return (0);
263 }
264 
265 /*
266  * lsar_query_security_desc
267  *
268  * Don't use this call yet. It is just a place holder for now.
269  */
270 int
271 lsar_query_security_desc(mlsvc_handle_t *lsa_handle)
272 {
273 	struct mslsa_QuerySecurityObject	arg;
274 	int	rc;
275 	int	opnum;
276 
277 	opnum = LSARPC_OPNUM_QuerySecurityObject;
278 
279 	bzero(&arg, sizeof (struct mslsa_QuerySecurityObject));
280 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
281 
282 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
283 	ndr_rpc_release(lsa_handle);
284 	return (rc);
285 }
286 
287 /*
288  * lsar_query_info_policy
289  *
290  * The general purpose of this function is to allow various pieces of
291  * information to be queried on the domain controller. The only
292  * information queries supported are MSLSA_POLICY_PRIMARY_DOMAIN_INFO
293  * and MSLSA_POLICY_ACCOUNT_DOMAIN_INFO.
294  *
295  * On success, the return code will be 0 and the user_info structure
296  * will be set up. The sid_name_use field will be set to SidTypeDomain
297  * indicating that the domain name and domain sid fields are vaild. If
298  * the infoClass returned from the server is not one of the supported
299  * values, the sid_name_use willbe set to SidTypeUnknown. If the RPC
300  * fails, a negative error code will be returned, in which case the
301  * user_info will not have been updated.
302  */
303 DWORD
304 lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
305     smb_domain_t *info)
306 {
307 	struct mslsa_QueryInfoPolicy	arg;
308 	struct mslsa_PrimaryDomainInfo	*pd_info;
309 	struct mslsa_AccountDomainInfo	*ad_info;
310 	struct mslsa_DnsDomainInfo	*dns_info;
311 	char	guid_str[UUID_PRINTABLE_STRING_LENGTH];
312 	char	sidstr[SMB_SID_STRSZ];
313 	int	opnum;
314 	DWORD	status;
315 
316 	if (lsa_handle == NULL || info == NULL)
317 		return (NT_STATUS_INVALID_PARAMETER);
318 
319 	opnum = LSARPC_OPNUM_QueryInfoPolicy;
320 
321 	bzero(info, sizeof (smb_domain_t));
322 	bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
323 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
324 
325 	arg.info_class = infoClass;
326 
327 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
328 		status = NT_STATUS_INVALID_PARAMETER;
329 	} else if (arg.status != 0) {
330 		ndr_rpc_status(lsa_handle, opnum, arg.status);
331 		status = NT_SC_VALUE(arg.status);
332 	} else {
333 
334 		switch (infoClass) {
335 		case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
336 			pd_info = &arg.ru.pd_info;
337 
338 			smb_sid_tostr((smb_sid_t *)pd_info->sid, sidstr);
339 			info->di_type = SMB_DOMAIN_PRIMARY;
340 			smb_domain_set_basic_info(sidstr,
341 			    (char *)pd_info->name.str, "", info);
342 
343 			status = NT_STATUS_SUCCESS;
344 			break;
345 
346 		case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
347 			ad_info = &arg.ru.ad_info;
348 
349 			smb_sid_tostr((smb_sid_t *)ad_info->sid, sidstr);
350 			info->di_type = SMB_DOMAIN_ACCOUNT;
351 			smb_domain_set_basic_info(sidstr,
352 			    (char *)ad_info->name.str, "", info);
353 
354 			status = NT_STATUS_SUCCESS;
355 			break;
356 
357 		case MSLSA_POLICY_DNS_DOMAIN_INFO:
358 			dns_info = &arg.ru.dns_info;
359 			ndr_uuid_unparse((ndr_uuid_t *)&dns_info->guid,
360 			    guid_str);
361 			smb_sid_tostr((smb_sid_t *)dns_info->sid, sidstr);
362 
363 			info->di_type = SMB_DOMAIN_PRIMARY;
364 			smb_domain_set_dns_info(sidstr,
365 			    (char *)dns_info->nb_domain.str,
366 			    (char *)dns_info->dns_domain.str,
367 			    (char *)dns_info->forest.str,
368 			    guid_str, info);
369 			status = NT_STATUS_SUCCESS;
370 			break;
371 
372 		default:
373 			status = NT_STATUS_INVALID_INFO_CLASS;
374 			break;
375 		}
376 	}
377 
378 	ndr_rpc_release(lsa_handle);
379 	return (status);
380 }
381 
382 /*
383  * Lookup a name and obtain the sid/rid.
384  * This is a wrapper for the various lookup sid RPCs.
385  */
386 uint32_t
387 lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info)
388 {
389 	static lsar_nameop_t ops[] = {
390 		lsar_lookup_names3,
391 		lsar_lookup_names2,
392 		lsar_lookup_names1
393 	};
394 
395 	const srvsvc_server_info_t	*svinfo;
396 	lsa_names_t	names;
397 	char		*p;
398 	uint32_t	length;
399 	uint32_t	status = NT_STATUS_INVALID_PARAMETER;
400 	int		n_op = (sizeof (ops) / sizeof (ops[0]));
401 	int		i;
402 
403 	if (lsa_handle == NULL || name == NULL || info == NULL)
404 		return (NT_STATUS_INVALID_PARAMETER);
405 
406 	bzero(info, sizeof (smb_account_t));
407 
408 	svinfo = ndr_rpc_server_info(lsa_handle);
409 	if (svinfo->sv_os == NATIVE_OS_WIN2000 &&
410 	    svinfo->sv_version_major == 5 && svinfo->sv_version_minor == 0) {
411 		/*
412 		 * Windows 2000 doesn't like an LSA lookup for
413 		 * DOMAIN\Administrator.
414 		 */
415 		if ((p = strchr(name, '\\')) != 0) {
416 			++p;
417 
418 			if (strcasecmp(p, "administrator") == 0)
419 				name = p;
420 		}
421 
422 	}
423 
424 	length = smb_wcequiv_strlen(name);
425 	names.name[0].length = length;
426 	names.name[0].allosize = length;
427 	names.name[0].str = (unsigned char *)name;
428 	names.n_entry = 1;
429 
430 	if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
431 		for (i = 0; i < n_op; ++i) {
432 			ndr_rpc_set_nonull(lsa_handle);
433 			status = (*ops[i])(lsa_handle, &names, info);
434 
435 			if (status != NT_STATUS_INVALID_PARAMETER)
436 				break;
437 		}
438 	} else {
439 		ndr_rpc_set_nonull(lsa_handle);
440 		status = lsar_lookup_names1(lsa_handle, &names, info);
441 	}
442 
443 	if (status == NT_STATUS_SUCCESS) {
444 		info->a_name = lsar_get_username(name);
445 
446 		if (!smb_account_validate(info)) {
447 			smb_account_free(info);
448 			status = NT_STATUS_NO_MEMORY;
449 		} else {
450 			smb_account_trace(info);
451 		}
452 	}
453 
454 	return (status);
455 }
456 
457 /*
458  * The name may be in one of the following forms:
459  *
460  *	domain\username
461  *	domain/username
462  *	username
463  *	username@domain
464  *
465  * Return a strdup'd copy of the username.  The caller is responsible
466  * for freeing the allocated memory.
467  */
468 static char *
469 lsar_get_username(const char *name)
470 {
471 	char	tmp[MAXNAMELEN];
472 	char	*dp = NULL;
473 	char	*np = NULL;
474 
475 	(void) strlcpy(tmp, name, MAXNAMELEN);
476 	smb_name_parse(tmp, &np, &dp);
477 
478 	if (dp != NULL && np != NULL)
479 		return (strdup(np));
480 	else
481 		return (strdup(name));
482 }
483 
484 /*
485  * lsar_lookup_names1
486  *
487  * Lookup a name and obtain the domain and user rid.
488  *
489  * Note: NT returns an error if the mapped_count is non-zero when the RPC
490  * is called.
491  *
492  * If the lookup fails, the status will typically be NT_STATUS_NONE_MAPPED.
493  */
494 static uint32_t
495 lsar_lookup_names1(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
496     smb_account_t *info)
497 {
498 	struct mslsa_LookupNames	arg;
499 	struct mslsa_rid_entry		*rid_entry;
500 	struct mslsa_domain_entry	*domain_entry;
501 	uint32_t			status = NT_STATUS_SUCCESS;
502 	char				*domname;
503 	int				opnum = LSARPC_OPNUM_LookupNames;
504 
505 	bzero(&arg, sizeof (struct mslsa_LookupNames));
506 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
507 	arg.lookup_level = LSA_LOOKUP_WKSTA;
508 	arg.name_table = (struct mslsa_lup_name_table *)names;
509 
510 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
511 		ndr_rpc_release(lsa_handle);
512 		return (NT_STATUS_INVALID_PARAMETER);
513 	}
514 
515 	if (arg.status != NT_STATUS_SUCCESS) {
516 		ndr_rpc_status(lsa_handle, opnum, arg.status);
517 		ndr_rpc_release(lsa_handle);
518 		return (NT_SC_VALUE(arg.status));
519 	}
520 
521 	if (arg.mapped_count == 0) {
522 		ndr_rpc_release(lsa_handle);
523 		return (NT_STATUS_NONE_MAPPED);
524 	}
525 
526 	rid_entry = &arg.translated_sids.rids[0];
527 	if (rid_entry->domain_index != 0) {
528 		ndr_rpc_release(lsa_handle);
529 		return (NT_STATUS_NONE_MAPPED);
530 	}
531 
532 	domain_entry = &arg.domain_table->entries[0];
533 
534 	info->a_type = rid_entry->sid_name_use;
535 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
536 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
537 		info->a_domain = strdup(domname);
538 	info->a_rid = rid_entry->rid;
539 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
540 
541 	ndr_rpc_release(lsa_handle);
542 	return (status);
543 }
544 
545 /*
546  * lsar_lookup_names2
547  */
548 static uint32_t
549 lsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
550     smb_account_t *info)
551 {
552 	struct lsar_LookupNames2	arg;
553 	struct lsar_rid_entry2		*rid_entry;
554 	struct mslsa_domain_entry	*domain_entry;
555 	uint32_t			status = NT_STATUS_SUCCESS;
556 	char				*domname;
557 	int				opnum = LSARPC_OPNUM_LookupNames2;
558 
559 	bzero(&arg, sizeof (struct lsar_LookupNames2));
560 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
561 	arg.lookup_level = LSA_LOOKUP_WKSTA;
562 	arg.client_revision = LSA_CLIENT_REVISION_AD;
563 	arg.name_table = (struct mslsa_lup_name_table *)names;
564 
565 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
566 		ndr_rpc_release(lsa_handle);
567 		return (NT_STATUS_INVALID_PARAMETER);
568 	}
569 
570 	if (arg.status != NT_STATUS_SUCCESS) {
571 		ndr_rpc_status(lsa_handle, opnum, arg.status);
572 		ndr_rpc_release(lsa_handle);
573 		return (NT_SC_VALUE(arg.status));
574 	}
575 
576 	if (arg.mapped_count == 0) {
577 		ndr_rpc_release(lsa_handle);
578 		return (NT_STATUS_NONE_MAPPED);
579 	}
580 
581 	rid_entry = &arg.translated_sids.rids[0];
582 	if (rid_entry->domain_index != 0) {
583 		ndr_rpc_release(lsa_handle);
584 		return (NT_STATUS_NONE_MAPPED);
585 	}
586 
587 	domain_entry = &arg.domain_table->entries[0];
588 
589 	info->a_type = rid_entry->sid_name_use;
590 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
591 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
592 		info->a_domain = strdup(domname);
593 	info->a_rid = rid_entry->rid;
594 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
595 
596 	ndr_rpc_release(lsa_handle);
597 	return (status);
598 }
599 
600 /*
601  * lsar_lookup_names3
602  */
603 static uint32_t
604 lsar_lookup_names3(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
605     smb_account_t *info)
606 {
607 	struct lsar_LookupNames3	arg;
608 	lsar_translated_sid_ex2_t	*sid_entry;
609 	struct mslsa_domain_entry	*domain_entry;
610 	uint32_t			status = NT_STATUS_SUCCESS;
611 	char				*domname;
612 	int				opnum = LSARPC_OPNUM_LookupNames3;
613 
614 	bzero(&arg, sizeof (struct lsar_LookupNames3));
615 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
616 	arg.lookup_level = LSA_LOOKUP_WKSTA;
617 	arg.client_revision = LSA_CLIENT_REVISION_AD;
618 	arg.name_table = (struct mslsa_lup_name_table *)names;
619 
620 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
621 		ndr_rpc_release(lsa_handle);
622 		return (NT_STATUS_INVALID_PARAMETER);
623 	}
624 
625 	if (arg.status != NT_STATUS_SUCCESS) {
626 		ndr_rpc_status(lsa_handle, opnum, arg.status);
627 		ndr_rpc_release(lsa_handle);
628 		return (NT_SC_VALUE(arg.status));
629 	}
630 
631 	if (arg.mapped_count == 0) {
632 		ndr_rpc_release(lsa_handle);
633 		return (NT_STATUS_NONE_MAPPED);
634 	}
635 
636 	sid_entry = &arg.translated_sids.sids[0];
637 	if (sid_entry->domain_index != 0) {
638 		ndr_rpc_release(lsa_handle);
639 		return (NT_STATUS_NONE_MAPPED);
640 	}
641 
642 	domain_entry = &arg.domain_table->entries[0];
643 
644 	info->a_type = sid_entry->sid_name_use;
645 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
646 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
647 		info->a_domain = strdup(domname);
648 	info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
649 	(void) smb_sid_getrid(info->a_sid, &info->a_rid);
650 
651 	ndr_rpc_release(lsa_handle);
652 	return (status);
653 }
654 
655 /*
656  * lsar_lookup_names4
657  *
658  * This function is only valid if the remote RPC server is a domain
659  * controller and requires the security extensions defined in MS-RPCE.
660  *
661  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
662  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
663  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
664  */
665 static uint32_t /*LINTED E_STATIC_UNUSED*/
666 lsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
667     smb_account_t *info)
668 {
669 	struct lsar_LookupNames4	arg;
670 	lsar_translated_sid_ex2_t	*sid_entry;
671 	struct mslsa_domain_entry	*domain_entry;
672 	uint32_t			status = NT_STATUS_SUCCESS;
673 	char				*domname;
674 	int				opnum = LSARPC_OPNUM_LookupNames4;
675 
676 	bzero(&arg, sizeof (struct lsar_LookupNames4));
677 	arg.lookup_level = LSA_LOOKUP_WKSTA;
678 	arg.client_revision = LSA_CLIENT_REVISION_AD;
679 	arg.name_table = (struct mslsa_lup_name_table *)names;
680 
681 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
682 		ndr_rpc_release(lsa_handle);
683 		return (NT_STATUS_INVALID_PARAMETER);
684 	}
685 
686 	if (arg.status != NT_STATUS_SUCCESS) {
687 		ndr_rpc_status(lsa_handle, opnum, arg.status);
688 		ndr_rpc_release(lsa_handle);
689 		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
690 		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
691 			return (NT_STATUS_INVALID_PARAMETER);
692 		return (NT_SC_VALUE(arg.status));
693 	}
694 
695 	if (arg.mapped_count == 0) {
696 		ndr_rpc_release(lsa_handle);
697 		return (NT_STATUS_NONE_MAPPED);
698 	}
699 
700 	sid_entry = &arg.translated_sids.sids[0];
701 	if (sid_entry->domain_index != 0) {
702 		ndr_rpc_release(lsa_handle);
703 		return (NT_STATUS_NONE_MAPPED);
704 	}
705 
706 	domain_entry = &arg.domain_table->entries[0];
707 
708 	info->a_type = sid_entry->sid_name_use;
709 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
710 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
711 		info->a_domain = strdup(domname);
712 	info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
713 	(void) smb_sid_getrid(info->a_sid, &info->a_rid);
714 
715 	ndr_rpc_release(lsa_handle);
716 	return (status);
717 }
718 
719 /*
720  * Lookup a sid and obtain the domain sid and account name.
721  * This is a wrapper for the various lookup sid RPCs.
722  */
723 uint32_t
724 lsar_lookup_sids(mlsvc_handle_t *lsa_handle, smb_sid_t *sid,
725     smb_account_t *account)
726 {
727 	char		sidbuf[SMB_SID_STRSZ];
728 	uint32_t	status;
729 
730 	if (lsa_handle == NULL || sid == NULL || account == NULL)
731 		return (NT_STATUS_INVALID_PARAMETER);
732 
733 	bzero(account, sizeof (smb_account_t));
734 	bzero(sidbuf, SMB_SID_STRSZ);
735 	smb_sid_tostr(sid, sidbuf);
736 	smb_tracef("%s", sidbuf);
737 
738 	if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
739 		status = lsar_lookup_sids2(lsa_handle, (lsa_sid_t *)sid,
740 		    account);
741 	else
742 		status = lsar_lookup_sids1(lsa_handle, (lsa_sid_t *)sid,
743 		    account);
744 
745 	if (status == NT_STATUS_SUCCESS) {
746 		if (!smb_account_validate(account)) {
747 			smb_account_free(account);
748 			status = NT_STATUS_NO_MEMORY;
749 		} else {
750 			smb_account_trace(account);
751 		}
752 	}
753 
754 	return (status);
755 }
756 
757 /*
758  * lsar_lookup_sids1
759  */
760 static uint32_t
761 lsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
762     smb_account_t *account)
763 {
764 	struct mslsa_LookupSids		arg;
765 	struct mslsa_lup_sid_entry	sid_entry;
766 	struct mslsa_name_entry		*name_entry;
767 	struct mslsa_domain_entry	*domain_entry;
768 	uint32_t			status = NT_STATUS_SUCCESS;
769 	char				*name;
770 	int				opnum = LSARPC_OPNUM_LookupSids;
771 
772 	bzero(&arg, sizeof (struct mslsa_LookupSids));
773 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
774 	arg.lookup_level = LSA_LOOKUP_WKSTA;
775 
776 	sid_entry.psid = sid;
777 	arg.lup_sid_table.n_entry = 1;
778 	arg.lup_sid_table.entries = &sid_entry;
779 
780 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
781 		ndr_rpc_release(lsa_handle);
782 		return (NT_STATUS_INVALID_PARAMETER);
783 	}
784 
785 	if (arg.status != NT_STATUS_SUCCESS) {
786 		ndr_rpc_status(lsa_handle, opnum, arg.status);
787 		ndr_rpc_release(lsa_handle);
788 		return (NT_SC_VALUE(arg.status));
789 	}
790 
791 	if (arg.mapped_count == 0) {
792 		ndr_rpc_release(lsa_handle);
793 		return (NT_STATUS_NONE_MAPPED);
794 	}
795 
796 	name_entry = &arg.name_table.entries[0];
797 	if (name_entry->domain_ix != 0) {
798 		ndr_rpc_release(lsa_handle);
799 		return (NT_STATUS_NONE_MAPPED);
800 	}
801 
802 	name = (char *)name_entry->name.str;
803 	account->a_name = (name) ? strdup(name) : strdup("");
804 	account->a_type = name_entry->sid_name_use;
805 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
806 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
807 
808 	domain_entry = &arg.domain_table->entries[0];
809 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
810 		account->a_domain = strdup(name);
811 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
812 
813 	ndr_rpc_release(lsa_handle);
814 	return (status);
815 }
816 
817 /*
818  * lsar_lookup_sids2
819  */
820 static uint32_t
821 lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
822     smb_account_t *account)
823 {
824 	struct lsar_lookup_sids2	arg;
825 	struct lsar_name_entry2		*name_entry;
826 	struct mslsa_lup_sid_entry	sid_entry;
827 	struct mslsa_domain_entry	*domain_entry;
828 	uint32_t			status = NT_STATUS_SUCCESS;
829 	char				*name;
830 	int				opnum = LSARPC_OPNUM_LookupSids2;
831 
832 	bzero(&arg, sizeof (struct lsar_lookup_sids2));
833 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
834 
835 	sid_entry.psid = sid;
836 	arg.lup_sid_table.n_entry = 1;
837 	arg.lup_sid_table.entries = &sid_entry;
838 	arg.lookup_level = LSA_LOOKUP_WKSTA;
839 	arg.client_revision = LSA_CLIENT_REVISION_AD;
840 
841 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
842 		ndr_rpc_release(lsa_handle);
843 		return (NT_STATUS_INVALID_PARAMETER);
844 	}
845 
846 	if (arg.status != NT_STATUS_SUCCESS) {
847 		ndr_rpc_status(lsa_handle, opnum, arg.status);
848 		ndr_rpc_release(lsa_handle);
849 		return (NT_SC_VALUE(arg.status));
850 	}
851 
852 	if (arg.mapped_count == 0) {
853 		ndr_rpc_release(lsa_handle);
854 		return (NT_STATUS_NONE_MAPPED);
855 	}
856 
857 	name_entry = &arg.name_table.entries[0];
858 	if (name_entry->domain_ix != 0) {
859 		ndr_rpc_release(lsa_handle);
860 		return (NT_STATUS_NONE_MAPPED);
861 	}
862 
863 	name = (char *)name_entry->name.str;
864 	account->a_name = (name) ? strdup(name) : strdup("");
865 	account->a_type = name_entry->sid_name_use;
866 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
867 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
868 
869 	domain_entry = &arg.domain_table->entries[0];
870 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
871 		account->a_domain = strdup(name);
872 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
873 
874 	ndr_rpc_release(lsa_handle);
875 	return (status);
876 }
877 
878 /*
879  * lsar_lookup_sids3
880  *
881  * This function is only valid if the remote RPC server is a domain
882  * controller and requires the security extensions defined in MS-RPCE.
883  *
884  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
885  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
886  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
887  */
888 static uint32_t /*LINTED E_STATIC_UNUSED*/
889 lsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
890     smb_account_t *account)
891 {
892 	struct lsar_lookup_sids3	arg;
893 	lsar_translated_name_ex_t	*name_entry;
894 	struct mslsa_lup_sid_entry	sid_entry;
895 	struct mslsa_domain_entry	*domain_entry;
896 	uint32_t			status = NT_STATUS_SUCCESS;
897 	char				*name;
898 	int				opnum = LSARPC_OPNUM_LookupSids3;
899 
900 	bzero(&arg, sizeof (struct lsar_lookup_sids3));
901 
902 	sid_entry.psid = sid;
903 	arg.lup_sid_table.n_entry = 1;
904 	arg.lup_sid_table.entries = &sid_entry;
905 	arg.lookup_level = LSA_LOOKUP_WKSTA;
906 	arg.client_revision = LSA_CLIENT_REVISION_AD;
907 
908 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
909 		ndr_rpc_release(lsa_handle);
910 		return (NT_STATUS_INVALID_PARAMETER);
911 	}
912 
913 	if (arg.status != NT_STATUS_SUCCESS) {
914 		ndr_rpc_status(lsa_handle, opnum, arg.status);
915 		ndr_rpc_release(lsa_handle);
916 		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
917 		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
918 			return (NT_STATUS_INVALID_PARAMETER);
919 		return (NT_SC_VALUE(arg.status));
920 	}
921 
922 	if (arg.mapped_count == 0) {
923 		ndr_rpc_release(lsa_handle);
924 		return (NT_STATUS_NONE_MAPPED);
925 	}
926 
927 	name_entry = &arg.name_table.entries[0];
928 	if (name_entry->domain_ix != 0) {
929 		ndr_rpc_release(lsa_handle);
930 		return (NT_STATUS_NONE_MAPPED);
931 	}
932 
933 	name = (char *)name_entry->name.str;
934 	account->a_name = (name) ? strdup(name) : strdup("");
935 	account->a_type = name_entry->sid_name_use;
936 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
937 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
938 
939 	domain_entry = &arg.domain_table->entries[0];
940 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
941 		account->a_domain = strdup(name);
942 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
943 
944 	ndr_rpc_release(lsa_handle);
945 	return (status);
946 }
947 
948 /*
949  * lsar_enum_accounts
950  *
951  * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
952  * from lsa_open_policy2. The enum_context is used to support multiple
953  * calls to this enumeration function. It should be set to 0 on the
954  * first call. It will be updated by the domain controller and should
955  * simply be passed unchanged to subsequent calls until there are no
956  * more accounts. A warning status of 0x1A indicates that no more data
957  * is available. The list of accounts will be returned in accounts.
958  * This list is dynamically allocated using malloc, it should be freed
959  * by the caller when it is no longer required.
960  */
961 int
962 lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
963     struct mslsa_EnumAccountBuf *accounts)
964 {
965 	struct mslsa_EnumerateAccounts	arg;
966 	struct mslsa_AccountInfo	*info;
967 	int	opnum;
968 	int	rc;
969 	DWORD	n_entries;
970 	DWORD	i;
971 	int	nbytes;
972 
973 	if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
974 		return (-1);
975 
976 	accounts->entries_read = 0;
977 	accounts->info = 0;
978 
979 	opnum = LSARPC_OPNUM_EnumerateAccounts;
980 
981 	bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
982 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
983 	arg.enum_context = *enum_context;
984 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
985 
986 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
987 	if (rc == 0) {
988 		if (arg.status != 0) {
989 			if ((arg.status & 0x00FFFFFF) ==
990 			    NT_STATUS_NO_MORE_DATA) {
991 				*enum_context = arg.enum_context;
992 			} else {
993 				ndr_rpc_status(lsa_handle, opnum, arg.status);
994 				rc = -1;
995 			}
996 		} else if (arg.enum_buf->entries_read != 0) {
997 			n_entries = arg.enum_buf->entries_read;
998 			nbytes = n_entries * sizeof (struct mslsa_AccountInfo);
999 
1000 			if ((info = malloc(nbytes)) == NULL) {
1001 				ndr_rpc_release(lsa_handle);
1002 				return (-1);
1003 			}
1004 
1005 			for (i = 0; i < n_entries; ++i)
1006 				info[i].sid = (lsa_sid_t *)smb_sid_dup(
1007 				    (smb_sid_t *)arg.enum_buf->info[i].sid);
1008 
1009 			accounts->entries_read = n_entries;
1010 			accounts->info = info;
1011 			*enum_context = arg.enum_context;
1012 		}
1013 	}
1014 
1015 	ndr_rpc_release(lsa_handle);
1016 	return (rc);
1017 }
1018 
1019 /*
1020  * lsar_enum_trusted_domains
1021  *
1022  * Enumerate the list of trusted domains. Use the handle returned from
1023  * lsa_open_policy2. The enum_context is used to support multiple calls
1024  * to this enumeration function. It should be set to 0 on the first
1025  * call. It will be updated by the domain controller and should simply
1026  * be passed unchanged to subsequent calls until there are no more
1027  * domains.
1028  *
1029  * The trusted domains aren't actually returned here. They are added
1030  * to the NT domain database. After all of the trusted domains have
1031  * been discovered, the database can be interrogated to find all of
1032  * the trusted domains.
1033  */
1034 DWORD
1035 lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1036     smb_trusted_domains_t *list)
1037 {
1038 	struct mslsa_EnumTrustedDomain	arg;
1039 	int	opnum;
1040 	DWORD	status;
1041 
1042 	if (list == NULL)
1043 		return (NT_STATUS_INVALID_PARAMETER);
1044 
1045 	opnum = LSARPC_OPNUM_EnumTrustedDomain;
1046 
1047 	bzero(list, sizeof (smb_trusted_domains_t));
1048 	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
1049 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1050 	arg.enum_context = *enum_context;
1051 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1052 
1053 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1054 		status = NT_STATUS_INVALID_PARAMETER;
1055 	} else if (arg.status != 0) {
1056 		*enum_context = arg.enum_context;
1057 		status = NT_SC_VALUE(arg.status);
1058 
1059 		/*
1060 		 * status 0x8000001A means NO_MORE_DATA,
1061 		 * which is not an error.
1062 		 */
1063 		if (status != NT_STATUS_NO_MORE_DATA)
1064 			ndr_rpc_status(lsa_handle, opnum, arg.status);
1065 	} else if (arg.enum_buf->entries_read == 0) {
1066 		*enum_context = arg.enum_context;
1067 		status = 0;
1068 	} else {
1069 		lsar_set_trusted_domains(arg.enum_buf, list);
1070 		*enum_context = arg.enum_context;
1071 		status = 0;
1072 	}
1073 
1074 	ndr_rpc_release(lsa_handle);
1075 	return (status);
1076 }
1077 
1078 DWORD
1079 lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1080     smb_trusted_domains_t *list)
1081 {
1082 	struct mslsa_EnumTrustedDomainEx	arg;
1083 	int	opnum;
1084 	DWORD	status;
1085 
1086 	if (list == NULL)
1087 		return (NT_STATUS_INVALID_PARAMETER);
1088 
1089 	opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;
1090 
1091 	bzero(list, sizeof (smb_trusted_domains_t));
1092 	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomainEx));
1093 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1094 	arg.enum_context = *enum_context;
1095 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1096 
1097 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1098 		status = NT_STATUS_INVALID_PARAMETER;
1099 	} else if (arg.status != 0) {
1100 		*enum_context = arg.enum_context;
1101 		status = NT_SC_VALUE(arg.status);
1102 
1103 		/*
1104 		 * status 0x8000001A means NO_MORE_DATA,
1105 		 * which is not an error.
1106 		 */
1107 		if (status != NT_STATUS_NO_MORE_DATA)
1108 			ndr_rpc_status(lsa_handle, opnum, arg.status);
1109 	} else if (arg.enum_buf->entries_read == 0) {
1110 		*enum_context = arg.enum_context;
1111 		status = 0;
1112 	} else {
1113 		lsar_set_trusted_domains_ex(arg.enum_buf, list);
1114 		*enum_context = arg.enum_context;
1115 		status = 0;
1116 	}
1117 
1118 	ndr_rpc_release(lsa_handle);
1119 	return (status);
1120 }
1121 
1122 /*
1123  * lsar_enum_privs_account
1124  *
1125  * Privileges enum? Need an account handle.
1126  */
1127 /*ARGSUSED*/
1128 int
1129 lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account)
1130 {
1131 	struct mslsa_EnumPrivsAccount	arg;
1132 	int	opnum;
1133 	int	rc;
1134 
1135 	opnum = LSARPC_OPNUM_EnumPrivsAccount;
1136 
1137 	bzero(&arg, sizeof (struct mslsa_EnumPrivsAccount));
1138 	(void) memcpy(&arg.account_handle, &account_handle->handle,
1139 	    sizeof (mslsa_handle_t));
1140 
1141 	rc = ndr_rpc_call(account_handle, opnum, &arg);
1142 	if ((rc == 0) && (arg.status != 0)) {
1143 		ndr_rpc_status(account_handle, opnum, arg.status);
1144 		rc = -1;
1145 	}
1146 	ndr_rpc_release(account_handle);
1147 	return (rc);
1148 }
1149 
1150 /*
1151  * lsar_lookup_priv_value
1152  *
1153  * Map a privilege name to a local unique id (LUID). Privilege names
1154  * are consistent across the network. LUIDs are machine specific.
1155  * This function provides the means to map a privilege name to the
1156  * LUID used by a remote server to represent it. The handle here is
1157  * a policy handle.
1158  */
1159 int
1160 lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name,
1161     struct ms_luid *luid)
1162 {
1163 	struct mslsa_LookupPrivValue	arg;
1164 	int	opnum;
1165 	int	rc;
1166 	size_t	length;
1167 
1168 	if (lsa_handle == NULL || name == NULL || luid == NULL)
1169 		return (-1);
1170 
1171 	opnum = LSARPC_OPNUM_LookupPrivValue;
1172 
1173 	bzero(&arg, sizeof (struct mslsa_LookupPrivValue));
1174 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1175 
1176 	length = smb_wcequiv_strlen(name);
1177 	if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
1178 		length += sizeof (smb_wchar_t);
1179 
1180 	arg.name.length = length;
1181 	arg.name.allosize = length;
1182 	arg.name.str = (unsigned char *)name;
1183 
1184 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1185 	if (rc == 0) {
1186 		if (arg.status != 0)
1187 			rc = -1;
1188 		else
1189 			(void) memcpy(luid, &arg.luid, sizeof (struct ms_luid));
1190 	}
1191 
1192 	ndr_rpc_release(lsa_handle);
1193 	return (rc);
1194 }
1195 
1196 /*
1197  * lsar_lookup_priv_name
1198  *
1199  * Map a local unique id (LUID) to a privilege name. Privilege names
1200  * are consistent across the network. LUIDs are machine specific.
1201  * This function the means to map the LUID used by a remote server to
1202  * the appropriate privilege name. The handle here is a policy handle.
1203  */
1204 int
1205 lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid,
1206     char *name, int namelen)
1207 {
1208 	struct mslsa_LookupPrivName	arg;
1209 	int	opnum;
1210 	int	rc;
1211 
1212 	if (lsa_handle == NULL || luid == NULL || name == NULL)
1213 		return (-1);
1214 
1215 	opnum = LSARPC_OPNUM_LookupPrivName;
1216 
1217 	bzero(&arg, sizeof (struct mslsa_LookupPrivName));
1218 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1219 	(void) memcpy(&arg.luid, luid, sizeof (struct ms_luid));
1220 
1221 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1222 	if (rc == 0) {
1223 		if (arg.status != 0)
1224 			rc = -1;
1225 		else
1226 			(void) strlcpy(name, (char const *)arg.name->str,
1227 			    namelen);
1228 	}
1229 
1230 	ndr_rpc_release(lsa_handle);
1231 	return (rc);
1232 }
1233 
1234 /*
1235  * lsar_lookup_priv_display_name
1236  *
1237  * Map a privilege name to a privilege display name. The input handle
1238  * should be an LSA policy handle and the name would normally be one
1239  * of the privileges defined in smb_privilege.h
1240  *
1241  * There's something peculiar about the return status from NT servers,
1242  * it's not always present. So for now, I'm ignoring the status in the
1243  * RPC response.
1244  *
1245  * Returns NT status codes.
1246  */
1247 DWORD
1248 lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
1249     char *display_name, int display_len)
1250 {
1251 	struct mslsa_LookupPrivDisplayName	arg;
1252 	int	opnum;
1253 	size_t	length;
1254 	DWORD	status;
1255 
1256 	if (lsa_handle == NULL || name == NULL || display_name == NULL)
1257 		return (NT_STATUS_INVALID_PARAMETER);
1258 
1259 	opnum = LSARPC_OPNUM_LookupPrivDisplayName;
1260 
1261 	bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
1262 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1263 
1264 	length = smb_wcequiv_strlen(name);
1265 	arg.name.length = length;
1266 	arg.name.allosize = length;
1267 	arg.name.str = (unsigned char *)name;
1268 
1269 	arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1270 	arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
1271 
1272 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0)
1273 		status = NT_STATUS_INVALID_PARAMETER;
1274 #if 0
1275 	else if (arg.status != 0)
1276 		status = NT_SC_VALUE(arg.status);
1277 #endif
1278 	else {
1279 		(void) strlcpy(display_name,
1280 		    (char const *)arg.display_name->str, display_len);
1281 		status = NT_STATUS_SUCCESS;
1282 	}
1283 
1284 	ndr_rpc_release(lsa_handle);
1285 	return (status);
1286 }
1287 
1288 static void
1289 lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf,
1290     smb_trusted_domains_t *list)
1291 {
1292 	char	sidstr[SMB_SID_STRSZ];
1293 	int	i;
1294 
1295 	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1296 		return;
1297 
1298 	list->td_num = 0;
1299 	list->td_domains = calloc(enum_buf->entries_read,
1300 	    sizeof (smb_domain_t));
1301 
1302 	if (list->td_domains == NULL)
1303 		return;
1304 
1305 	list->td_num = enum_buf->entries_read;
1306 	for (i = 0; i < list->td_num; i++) {
1307 		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1308 		smb_domain_set_trust_info(
1309 		    sidstr,
1310 		    (char *)enum_buf->info[i].nb_name.str,
1311 		    (char *)enum_buf->info[i].dns_name.str,
1312 		    enum_buf->info[i].trust_direction,
1313 		    enum_buf->info[i].trust_type,
1314 		    enum_buf->info[i].trust_attrs,
1315 		    &list->td_domains[i]);
1316 	}
1317 }
1318 
1319 static void
1320 lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf,
1321     smb_trusted_domains_t *list)
1322 {
1323 	char	sidstr[SMB_SID_STRSZ];
1324 	int	i;
1325 
1326 	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1327 		return;
1328 
1329 	list->td_num = 0;
1330 	list->td_domains = calloc(enum_buf->entries_read,
1331 	    sizeof (smb_domain_t));
1332 
1333 	if (list->td_domains == NULL)
1334 		return;
1335 
1336 	list->td_num = enum_buf->entries_read;
1337 	for (i = 0; i < list->td_num; i++) {
1338 		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1339 		smb_domain_set_trust_info(
1340 		    sidstr, (char *)enum_buf->info[i].name.str,
1341 		    "", 0, 0, 0, &list->td_domains[i]);
1342 	}
1343 }
1344 
1345 static void
1346 smb_account_trace(const smb_account_t *info)
1347 {
1348 	char	sidbuf[SMB_SID_STRSZ];
1349 
1350 	bzero(sidbuf, SMB_SID_STRSZ);
1351 	smb_sid_tostr(info->a_sid, sidbuf);
1352 
1353 	smb_tracef("%s %s %s %lu %s", info->a_domain, info->a_name,
1354 	    sidbuf, info->a_rid, smb_sid_type2str(info->a_type));
1355 }
1356