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