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