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