xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c (revision 6446bd46ed1b4e9f69da153665f82181ccaedad5)
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 2018 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 <smb/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 	lsa_names_t	names;
387 	char		*p;
388 	uint32_t	length;
389 	uint32_t	status = NT_STATUS_INVALID_PARAMETER;
390 	int		n_op = (sizeof (ops) / sizeof (ops[0]));
391 	int		i;
392 
393 	if (lsa_handle == NULL || name == NULL || info == NULL)
394 		return (NT_STATUS_INVALID_PARAMETER);
395 
396 	bzero(info, sizeof (smb_account_t));
397 
398 	/*
399 	 * Windows 2000 (or later) doesn't like an LSA lookup for
400 	 * DOMAIN\Administrator.
401 	 */
402 	if ((p = strchr(name, '\\')) != 0) {
403 		++p;
404 
405 		if (strcasecmp(p, "administrator") == 0)
406 			name = p;
407 	}
408 
409 	length = smb_wcequiv_strlen(name);
410 	names.name[0].length = length;
411 	names.name[0].allosize = length;
412 	names.name[0].str = (unsigned char *)name;
413 	names.n_entry = 1;
414 
415 	for (i = 0; i < n_op; ++i) {
416 		ndr_rpc_set_nonull(lsa_handle);
417 		status = (*ops[i])(lsa_handle, &names, info);
418 
419 		if (status != NT_STATUS_INVALID_PARAMETER)
420 			break;
421 	}
422 
423 	if (status == NT_STATUS_SUCCESS) {
424 		info->a_name = lsar_get_username(name);
425 
426 		if (!smb_account_validate(info)) {
427 			smb_account_free(info);
428 			status = NT_STATUS_NO_MEMORY;
429 		} else {
430 			smb_account_trace(info);
431 		}
432 	}
433 
434 	return (status);
435 }
436 
437 /*
438  * The name may be in one of the following forms:
439  *
440  *	domain\username
441  *	domain/username
442  *	username
443  *	username@domain
444  *
445  * Return a strdup'd copy of the username.  The caller is responsible
446  * for freeing the allocated memory.
447  */
448 static char *
449 lsar_get_username(const char *name)
450 {
451 	char	tmp[MAXNAMELEN];
452 	char	*dp = NULL;
453 	char	*np = NULL;
454 
455 	(void) strlcpy(tmp, name, MAXNAMELEN);
456 	smb_name_parse(tmp, &np, &dp);
457 
458 	if (dp != NULL && np != NULL)
459 		return (strdup(np));
460 	else
461 		return (strdup(name));
462 }
463 
464 /*
465  * lsar_lookup_names1
466  *
467  * Lookup a name and obtain the domain and user rid.
468  *
469  * Note: NT returns an error if the mapped_count is non-zero when the RPC
470  * is called.
471  *
472  * If the lookup fails, the status will typically be NT_STATUS_NONE_MAPPED.
473  */
474 static uint32_t
475 lsar_lookup_names1(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
476     smb_account_t *info)
477 {
478 	struct mslsa_LookupNames	arg;
479 	struct mslsa_rid_entry		*rid_entry;
480 	struct mslsa_domain_entry	*domain_entry;
481 	uint32_t			status = NT_STATUS_SUCCESS;
482 	char				*domname;
483 	int				opnum = LSARPC_OPNUM_LookupNames;
484 
485 	bzero(&arg, sizeof (struct mslsa_LookupNames));
486 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
487 	arg.lookup_level = LSA_LOOKUP_WKSTA;
488 	arg.name_table = (struct mslsa_lup_name_table *)names;
489 
490 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
491 		ndr_rpc_release(lsa_handle);
492 		return (NT_STATUS_INVALID_PARAMETER);
493 	}
494 
495 	if (arg.status != NT_STATUS_SUCCESS) {
496 		ndr_rpc_status(lsa_handle, opnum, arg.status);
497 		ndr_rpc_release(lsa_handle);
498 		return (NT_SC_VALUE(arg.status));
499 	}
500 
501 	if (arg.mapped_count == 0) {
502 		ndr_rpc_release(lsa_handle);
503 		return (NT_STATUS_NONE_MAPPED);
504 	}
505 
506 	rid_entry = &arg.translated_sids.rids[0];
507 	if (rid_entry->domain_index != 0) {
508 		ndr_rpc_release(lsa_handle);
509 		return (NT_STATUS_NONE_MAPPED);
510 	}
511 
512 	domain_entry = &arg.domain_table->entries[0];
513 
514 	info->a_type = rid_entry->sid_name_use;
515 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
516 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
517 		info->a_domain = strdup(domname);
518 	info->a_rid = rid_entry->rid;
519 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
520 
521 	ndr_rpc_release(lsa_handle);
522 	return (status);
523 }
524 
525 /*
526  * lsar_lookup_names2
527  */
528 static uint32_t
529 lsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
530     smb_account_t *info)
531 {
532 	struct lsar_LookupNames2	arg;
533 	struct lsar_rid_entry2		*rid_entry;
534 	struct mslsa_domain_entry	*domain_entry;
535 	uint32_t			status = NT_STATUS_SUCCESS;
536 	char				*domname;
537 	int				opnum = LSARPC_OPNUM_LookupNames2;
538 
539 	bzero(&arg, sizeof (struct lsar_LookupNames2));
540 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
541 	arg.lookup_level = LSA_LOOKUP_WKSTA;
542 	arg.client_revision = LSA_CLIENT_REVISION_AD;
543 	arg.name_table = (struct mslsa_lup_name_table *)names;
544 
545 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
546 		ndr_rpc_release(lsa_handle);
547 		return (NT_STATUS_INVALID_PARAMETER);
548 	}
549 
550 	if (arg.status != NT_STATUS_SUCCESS) {
551 		ndr_rpc_status(lsa_handle, opnum, arg.status);
552 		ndr_rpc_release(lsa_handle);
553 		return (NT_SC_VALUE(arg.status));
554 	}
555 
556 	if (arg.mapped_count == 0) {
557 		ndr_rpc_release(lsa_handle);
558 		return (NT_STATUS_NONE_MAPPED);
559 	}
560 
561 	rid_entry = &arg.translated_sids.rids[0];
562 	if (rid_entry->domain_index != 0) {
563 		ndr_rpc_release(lsa_handle);
564 		return (NT_STATUS_NONE_MAPPED);
565 	}
566 
567 	domain_entry = &arg.domain_table->entries[0];
568 
569 	info->a_type = rid_entry->sid_name_use;
570 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
571 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
572 		info->a_domain = strdup(domname);
573 	info->a_rid = rid_entry->rid;
574 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
575 
576 	ndr_rpc_release(lsa_handle);
577 	return (status);
578 }
579 
580 /*
581  * lsar_lookup_names3
582  */
583 static uint32_t
584 lsar_lookup_names3(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
585     smb_account_t *info)
586 {
587 	struct lsar_LookupNames3	arg;
588 	lsar_translated_sid_ex2_t	*sid_entry;
589 	struct mslsa_domain_entry	*domain_entry;
590 	uint32_t			status = NT_STATUS_SUCCESS;
591 	char				*domname;
592 	int				opnum = LSARPC_OPNUM_LookupNames3;
593 
594 	bzero(&arg, sizeof (struct lsar_LookupNames3));
595 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
596 	arg.lookup_level = LSA_LOOKUP_WKSTA;
597 	arg.client_revision = LSA_CLIENT_REVISION_AD;
598 	arg.name_table = (struct mslsa_lup_name_table *)names;
599 
600 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
601 		ndr_rpc_release(lsa_handle);
602 		return (NT_STATUS_INVALID_PARAMETER);
603 	}
604 
605 	if (arg.status != NT_STATUS_SUCCESS) {
606 		ndr_rpc_status(lsa_handle, opnum, arg.status);
607 		ndr_rpc_release(lsa_handle);
608 		return (NT_SC_VALUE(arg.status));
609 	}
610 
611 	if (arg.mapped_count == 0) {
612 		ndr_rpc_release(lsa_handle);
613 		return (NT_STATUS_NONE_MAPPED);
614 	}
615 
616 	sid_entry = &arg.translated_sids.sids[0];
617 	if (sid_entry->domain_index != 0) {
618 		ndr_rpc_release(lsa_handle);
619 		return (NT_STATUS_NONE_MAPPED);
620 	}
621 
622 	domain_entry = &arg.domain_table->entries[0];
623 
624 	info->a_type = sid_entry->sid_name_use;
625 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
626 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
627 		info->a_domain = strdup(domname);
628 	info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
629 	(void) smb_sid_getrid(info->a_sid, &info->a_rid);
630 
631 	ndr_rpc_release(lsa_handle);
632 	return (status);
633 }
634 
635 /*
636  * lsar_lookup_names4
637  *
638  * This function is only valid if the remote RPC server is a domain
639  * controller and requires the security extensions defined in MS-RPCE.
640  *
641  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
642  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
643  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
644  */
645 static uint32_t /*LINTED E_STATIC_UNUSED*/
646 lsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
647     smb_account_t *info)
648 {
649 	struct lsar_LookupNames4	arg;
650 	lsar_translated_sid_ex2_t	*sid_entry;
651 	struct mslsa_domain_entry	*domain_entry;
652 	uint32_t			status = NT_STATUS_SUCCESS;
653 	char				*domname;
654 	int				opnum = LSARPC_OPNUM_LookupNames4;
655 
656 	bzero(&arg, sizeof (struct lsar_LookupNames4));
657 	arg.lookup_level = LSA_LOOKUP_WKSTA;
658 	arg.client_revision = LSA_CLIENT_REVISION_AD;
659 	arg.name_table = (struct mslsa_lup_name_table *)names;
660 
661 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
662 		ndr_rpc_release(lsa_handle);
663 		return (NT_STATUS_INVALID_PARAMETER);
664 	}
665 
666 	if (arg.status != NT_STATUS_SUCCESS) {
667 		ndr_rpc_status(lsa_handle, opnum, arg.status);
668 		ndr_rpc_release(lsa_handle);
669 		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
670 		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
671 			return (NT_STATUS_INVALID_PARAMETER);
672 		return (NT_SC_VALUE(arg.status));
673 	}
674 
675 	if (arg.mapped_count == 0) {
676 		ndr_rpc_release(lsa_handle);
677 		return (NT_STATUS_NONE_MAPPED);
678 	}
679 
680 	sid_entry = &arg.translated_sids.sids[0];
681 	if (sid_entry->domain_index != 0) {
682 		ndr_rpc_release(lsa_handle);
683 		return (NT_STATUS_NONE_MAPPED);
684 	}
685 
686 	domain_entry = &arg.domain_table->entries[0];
687 
688 	info->a_type = sid_entry->sid_name_use;
689 	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
690 	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
691 		info->a_domain = strdup(domname);
692 	info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
693 	(void) smb_sid_getrid(info->a_sid, &info->a_rid);
694 
695 	ndr_rpc_release(lsa_handle);
696 	return (status);
697 }
698 
699 /*
700  * Lookup a sid and obtain the domain sid and account name.
701  * This is a wrapper for the various lookup sid RPCs.
702  */
703 uint32_t
704 lsar_lookup_sids(mlsvc_handle_t *lsa_handle, smb_sid_t *sid,
705     smb_account_t *account)
706 {
707 	char		sidbuf[SMB_SID_STRSZ];
708 	uint32_t	status;
709 
710 	if (lsa_handle == NULL || sid == NULL || account == NULL)
711 		return (NT_STATUS_INVALID_PARAMETER);
712 
713 	bzero(account, sizeof (smb_account_t));
714 	bzero(sidbuf, SMB_SID_STRSZ);
715 	smb_sid_tostr(sid, sidbuf);
716 	smb_tracef("%s", sidbuf);
717 
718 	status = lsar_lookup_sids2(lsa_handle, (lsa_sid_t *)sid, account);
719 	if (status == RPC_NT_PROCNUM_OUT_OF_RANGE)
720 		status = lsar_lookup_sids1(lsa_handle, (lsa_sid_t *)sid,
721 		    account);
722 
723 	if (status == NT_STATUS_SUCCESS) {
724 		if (!smb_account_validate(account)) {
725 			smb_account_free(account);
726 			status = NT_STATUS_NO_MEMORY;
727 		} else {
728 			smb_account_trace(account);
729 		}
730 	}
731 
732 	return (status);
733 }
734 
735 /*
736  * lsar_lookup_sids1
737  */
738 static uint32_t
739 lsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
740     smb_account_t *account)
741 {
742 	struct mslsa_LookupSids		arg;
743 	struct mslsa_lup_sid_entry	sid_entry;
744 	struct mslsa_name_entry		*name_entry;
745 	struct mslsa_domain_entry	*domain_entry;
746 	uint32_t			status = NT_STATUS_SUCCESS;
747 	char				*name;
748 	int				opnum = LSARPC_OPNUM_LookupSids;
749 
750 	bzero(&arg, sizeof (struct mslsa_LookupSids));
751 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
752 	arg.lookup_level = LSA_LOOKUP_WKSTA;
753 
754 	sid_entry.psid = sid;
755 	arg.lup_sid_table.n_entry = 1;
756 	arg.lup_sid_table.entries = &sid_entry;
757 
758 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
759 		ndr_rpc_release(lsa_handle);
760 		return (NT_STATUS_INVALID_PARAMETER);
761 	}
762 
763 	if (arg.status != NT_STATUS_SUCCESS) {
764 		ndr_rpc_status(lsa_handle, opnum, arg.status);
765 		ndr_rpc_release(lsa_handle);
766 		return (NT_SC_VALUE(arg.status));
767 	}
768 
769 	if (arg.mapped_count == 0) {
770 		ndr_rpc_release(lsa_handle);
771 		return (NT_STATUS_NONE_MAPPED);
772 	}
773 
774 	name_entry = &arg.name_table.entries[0];
775 	if (name_entry->domain_ix != 0) {
776 		ndr_rpc_release(lsa_handle);
777 		return (NT_STATUS_NONE_MAPPED);
778 	}
779 
780 	name = (char *)name_entry->name.str;
781 	account->a_name = (name) ? strdup(name) : strdup("");
782 	account->a_type = name_entry->sid_name_use;
783 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
784 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
785 
786 	domain_entry = &arg.domain_table->entries[0];
787 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
788 		account->a_domain = strdup(name);
789 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
790 
791 	ndr_rpc_release(lsa_handle);
792 	return (status);
793 }
794 
795 /*
796  * lsar_lookup_sids2
797  */
798 static uint32_t
799 lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
800     smb_account_t *account)
801 {
802 	struct lsar_lookup_sids2	arg;
803 	struct lsar_name_entry2		*name_entry;
804 	struct mslsa_lup_sid_entry	sid_entry;
805 	struct mslsa_domain_entry	*domain_entry;
806 	uint32_t			status = NT_STATUS_SUCCESS;
807 	char				*name;
808 	int				opnum = LSARPC_OPNUM_LookupSids2;
809 
810 	bzero(&arg, sizeof (struct lsar_lookup_sids2));
811 	(void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
812 
813 	sid_entry.psid = sid;
814 	arg.lup_sid_table.n_entry = 1;
815 	arg.lup_sid_table.entries = &sid_entry;
816 	arg.lookup_level = LSA_LOOKUP_WKSTA;
817 	arg.client_revision = LSA_CLIENT_REVISION_AD;
818 
819 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
820 		ndr_rpc_release(lsa_handle);
821 		return (NT_STATUS_INVALID_PARAMETER);
822 	}
823 
824 	if (arg.status != NT_STATUS_SUCCESS) {
825 		ndr_rpc_status(lsa_handle, opnum, arg.status);
826 		ndr_rpc_release(lsa_handle);
827 		return (NT_SC_VALUE(arg.status));
828 	}
829 
830 	if (arg.mapped_count == 0) {
831 		ndr_rpc_release(lsa_handle);
832 		return (NT_STATUS_NONE_MAPPED);
833 	}
834 
835 	name_entry = &arg.name_table.entries[0];
836 	if (name_entry->domain_ix != 0) {
837 		ndr_rpc_release(lsa_handle);
838 		return (NT_STATUS_NONE_MAPPED);
839 	}
840 
841 	name = (char *)name_entry->name.str;
842 	account->a_name = (name) ? strdup(name) : strdup("");
843 	account->a_type = name_entry->sid_name_use;
844 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
845 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
846 
847 	domain_entry = &arg.domain_table->entries[0];
848 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
849 		account->a_domain = strdup(name);
850 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
851 
852 	ndr_rpc_release(lsa_handle);
853 	return (status);
854 }
855 
856 /*
857  * lsar_lookup_sids3
858  *
859  * This function is only valid if the remote RPC server is a domain
860  * controller and requires the security extensions defined in MS-RPCE.
861  *
862  * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
863  * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
864  * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
865  */
866 static uint32_t /*LINTED E_STATIC_UNUSED*/
867 lsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
868     smb_account_t *account)
869 {
870 	struct lsar_lookup_sids3	arg;
871 	lsar_translated_name_ex_t	*name_entry;
872 	struct mslsa_lup_sid_entry	sid_entry;
873 	struct mslsa_domain_entry	*domain_entry;
874 	uint32_t			status = NT_STATUS_SUCCESS;
875 	char				*name;
876 	int				opnum = LSARPC_OPNUM_LookupSids3;
877 
878 	bzero(&arg, sizeof (struct lsar_lookup_sids3));
879 
880 	sid_entry.psid = sid;
881 	arg.lup_sid_table.n_entry = 1;
882 	arg.lup_sid_table.entries = &sid_entry;
883 	arg.lookup_level = LSA_LOOKUP_WKSTA;
884 	arg.client_revision = LSA_CLIENT_REVISION_AD;
885 
886 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
887 		ndr_rpc_release(lsa_handle);
888 		return (NT_STATUS_INVALID_PARAMETER);
889 	}
890 
891 	if (arg.status != NT_STATUS_SUCCESS) {
892 		ndr_rpc_status(lsa_handle, opnum, arg.status);
893 		ndr_rpc_release(lsa_handle);
894 		if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
895 		    arg.status == NT_STATUS_INVALID_SERVER_STATE)
896 			return (NT_STATUS_INVALID_PARAMETER);
897 		return (NT_SC_VALUE(arg.status));
898 	}
899 
900 	if (arg.mapped_count == 0) {
901 		ndr_rpc_release(lsa_handle);
902 		return (NT_STATUS_NONE_MAPPED);
903 	}
904 
905 	name_entry = &arg.name_table.entries[0];
906 	if (name_entry->domain_ix != 0) {
907 		ndr_rpc_release(lsa_handle);
908 		return (NT_STATUS_NONE_MAPPED);
909 	}
910 
911 	name = (char *)name_entry->name.str;
912 	account->a_name = (name) ? strdup(name) : strdup("");
913 	account->a_type = name_entry->sid_name_use;
914 	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
915 	(void) smb_sid_getrid(account->a_sid, &account->a_rid);
916 
917 	domain_entry = &arg.domain_table->entries[0];
918 	if ((name = (char *)domain_entry->domain_name.str) != NULL)
919 		account->a_domain = strdup(name);
920 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
921 
922 	ndr_rpc_release(lsa_handle);
923 	return (status);
924 }
925 
926 /*
927  * lsar_enum_accounts
928  *
929  * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
930  * from lsa_open_policy2. The enum_context is used to support multiple
931  * calls to this enumeration function. It should be set to 0 on the
932  * first call. It will be updated by the domain controller and should
933  * simply be passed unchanged to subsequent calls until there are no
934  * more accounts. A warning status of 0x1A indicates that no more data
935  * is available. The list of accounts will be returned in accounts.
936  * This list is dynamically allocated using malloc, it should be freed
937  * by the caller when it is no longer required.
938  */
939 DWORD
940 lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
941     struct mslsa_EnumAccountBuf *accounts)
942 {
943 	struct mslsa_EnumerateAccounts	arg;
944 	struct mslsa_AccountInfo	*info;
945 	int	opnum;
946 	int	rc;
947 	DWORD	status;
948 	DWORD	n_entries;
949 	DWORD	i;
950 	int	nbytes;
951 
952 	if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
953 		return (NT_STATUS_INTERNAL_ERROR);
954 
955 	accounts->entries_read = 0;
956 	accounts->info = 0;
957 
958 	opnum = LSARPC_OPNUM_EnumerateAccounts;
959 
960 	bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
961 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
962 	arg.enum_context = *enum_context;
963 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
964 
965 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
966 	if (rc == 0) {
967 		status = arg.status;
968 		if (arg.status != 0) {
969 			if (arg.status == NT_STATUS_NO_MORE_ENTRIES) {
970 				*enum_context = arg.enum_context;
971 			} else {
972 				ndr_rpc_status(lsa_handle, opnum, arg.status);
973 			}
974 		} else if (arg.enum_buf->entries_read != 0) {
975 			n_entries = arg.enum_buf->entries_read;
976 			nbytes = n_entries * sizeof (struct mslsa_AccountInfo);
977 
978 			if ((info = malloc(nbytes)) == NULL) {
979 				ndr_rpc_release(lsa_handle);
980 				return (NT_STATUS_NO_MEMORY);
981 			}
982 
983 			for (i = 0; i < n_entries; ++i)
984 				info[i].sid = (lsa_sid_t *)smb_sid_dup(
985 				    (smb_sid_t *)arg.enum_buf->info[i].sid);
986 
987 			accounts->entries_read = n_entries;
988 			accounts->info = info;
989 			*enum_context = arg.enum_context;
990 		}
991 	} else {
992 		status = NT_STATUS_INVALID_PARAMETER;
993 	}
994 
995 	ndr_rpc_release(lsa_handle);
996 	return (status);
997 }
998 
999 /*
1000  * lsar_enum_trusted_domains
1001  *
1002  * Enumerate the list of trusted domains. Use the handle returned from
1003  * lsa_open_policy2. The enum_context is used to support multiple calls
1004  * to this enumeration function. It should be set to 0 on the first
1005  * call. It will be updated by the domain controller and should simply
1006  * be passed unchanged to subsequent calls until there are no more
1007  * domains.
1008  *
1009  * The trusted domains aren't actually returned here. They are added
1010  * to the NT domain database. After all of the trusted domains have
1011  * been discovered, the database can be interrogated to find all of
1012  * the trusted domains.
1013  */
1014 DWORD
1015 lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1016     smb_trusted_domains_t *list)
1017 {
1018 	struct mslsa_EnumTrustedDomain	arg;
1019 	int	opnum;
1020 	DWORD	status;
1021 
1022 	if (list == NULL)
1023 		return (NT_STATUS_INVALID_PARAMETER);
1024 
1025 	opnum = LSARPC_OPNUM_EnumTrustedDomain;
1026 
1027 	bzero(list, sizeof (smb_trusted_domains_t));
1028 	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
1029 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1030 	arg.enum_context = *enum_context;
1031 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1032 
1033 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1034 		status = NT_STATUS_INVALID_PARAMETER;
1035 	} else if (arg.status != 0) {
1036 		*enum_context = arg.enum_context;
1037 		status = NT_SC_VALUE(arg.status);
1038 
1039 		/*
1040 		 * STATUS_NO_MORE_ENTRIES provides call
1041 		 * status but does not indicate an error.
1042 		 */
1043 		if (status != NT_STATUS_NO_MORE_ENTRIES)
1044 			ndr_rpc_status(lsa_handle, opnum, arg.status);
1045 	} else if (arg.enum_buf->entries_read == 0) {
1046 		*enum_context = arg.enum_context;
1047 		status = 0;
1048 	} else {
1049 		lsar_set_trusted_domains(arg.enum_buf, list);
1050 		*enum_context = arg.enum_context;
1051 		status = 0;
1052 	}
1053 
1054 	ndr_rpc_release(lsa_handle);
1055 	return (status);
1056 }
1057 
1058 DWORD
1059 lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
1060     smb_trusted_domains_t *list)
1061 {
1062 	struct mslsa_EnumTrustedDomainEx	arg;
1063 	int	opnum;
1064 	DWORD	status;
1065 
1066 	if (list == NULL)
1067 		return (NT_STATUS_INVALID_PARAMETER);
1068 
1069 	opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;
1070 
1071 	bzero(list, sizeof (smb_trusted_domains_t));
1072 	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomainEx));
1073 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1074 	arg.enum_context = *enum_context;
1075 	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
1076 
1077 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
1078 		status = NT_STATUS_INVALID_PARAMETER;
1079 	} else if (arg.status != 0) {
1080 		*enum_context = arg.enum_context;
1081 		status = NT_SC_VALUE(arg.status);
1082 
1083 		/*
1084 		 * STATUS_NO_MORE_ENTRIES provides call
1085 		 * status but does not indicate an error.
1086 		 */
1087 		if (status != NT_STATUS_NO_MORE_ENTRIES)
1088 			ndr_rpc_status(lsa_handle, opnum, arg.status);
1089 	} else if (arg.enum_buf->entries_read == 0) {
1090 		*enum_context = arg.enum_context;
1091 		status = 0;
1092 	} else {
1093 		lsar_set_trusted_domains_ex(arg.enum_buf, list);
1094 		*enum_context = arg.enum_context;
1095 		status = 0;
1096 	}
1097 
1098 	ndr_rpc_release(lsa_handle);
1099 	return (status);
1100 }
1101 
1102 /*
1103  * lsar_enum_privs_account
1104  *
1105  * Privileges enum? Need an account handle.
1106  */
1107 /*ARGSUSED*/
1108 int
1109 lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account)
1110 {
1111 	struct mslsa_EnumPrivsAccount	arg;
1112 	int	opnum;
1113 	int	rc;
1114 
1115 	opnum = LSARPC_OPNUM_EnumPrivsAccount;
1116 
1117 	bzero(&arg, sizeof (struct mslsa_EnumPrivsAccount));
1118 	(void) memcpy(&arg.account_handle, &account_handle->handle,
1119 	    sizeof (mslsa_handle_t));
1120 
1121 	rc = ndr_rpc_call(account_handle, opnum, &arg);
1122 	if ((rc == 0) && (arg.status != 0)) {
1123 		ndr_rpc_status(account_handle, opnum, arg.status);
1124 		rc = -1;
1125 	}
1126 	ndr_rpc_release(account_handle);
1127 	return (rc);
1128 }
1129 
1130 /*
1131  * lsar_lookup_priv_value
1132  *
1133  * Map a privilege name to a local unique id (LUID). Privilege names
1134  * are consistent across the network. LUIDs are machine specific.
1135  * This function provides the means to map a privilege name to the
1136  * LUID used by a remote server to represent it. The handle here is
1137  * a policy handle.
1138  */
1139 int
1140 lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name,
1141     struct ms_luid *luid)
1142 {
1143 	struct mslsa_LookupPrivValue	arg;
1144 	int	opnum;
1145 	int	rc;
1146 	size_t	length;
1147 
1148 	if (lsa_handle == NULL || name == NULL || luid == NULL)
1149 		return (-1);
1150 
1151 	opnum = LSARPC_OPNUM_LookupPrivValue;
1152 
1153 	bzero(&arg, sizeof (struct mslsa_LookupPrivValue));
1154 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1155 
1156 	length = smb_wcequiv_strlen(name);
1157 	length += sizeof (smb_wchar_t);
1158 
1159 	arg.name.length = length;
1160 	arg.name.allosize = length;
1161 	arg.name.str = (unsigned char *)name;
1162 
1163 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1164 	if (rc == 0) {
1165 		if (arg.status != 0)
1166 			rc = -1;
1167 		else
1168 			(void) memcpy(luid, &arg.luid, sizeof (struct ms_luid));
1169 	}
1170 
1171 	ndr_rpc_release(lsa_handle);
1172 	return (rc);
1173 }
1174 
1175 /*
1176  * lsar_lookup_priv_name
1177  *
1178  * Map a local unique id (LUID) to a privilege name. Privilege names
1179  * are consistent across the network. LUIDs are machine specific.
1180  * This function the means to map the LUID used by a remote server to
1181  * the appropriate privilege name. The handle here is a policy handle.
1182  */
1183 int
1184 lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid,
1185     char *name, int namelen)
1186 {
1187 	struct mslsa_LookupPrivName	arg;
1188 	int	opnum;
1189 	int	rc;
1190 
1191 	if (lsa_handle == NULL || luid == NULL || name == NULL)
1192 		return (-1);
1193 
1194 	opnum = LSARPC_OPNUM_LookupPrivName;
1195 
1196 	bzero(&arg, sizeof (struct mslsa_LookupPrivName));
1197 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1198 	(void) memcpy(&arg.luid, luid, sizeof (struct ms_luid));
1199 
1200 	rc = ndr_rpc_call(lsa_handle, opnum, &arg);
1201 	if (rc == 0) {
1202 		if (arg.status != 0)
1203 			rc = -1;
1204 		else
1205 			(void) strlcpy(name, (char const *)arg.name->str,
1206 			    namelen);
1207 	}
1208 
1209 	ndr_rpc_release(lsa_handle);
1210 	return (rc);
1211 }
1212 
1213 /*
1214  * lsar_lookup_priv_display_name
1215  *
1216  * Map a privilege name to a privilege display name. The input handle
1217  * should be an LSA policy handle and the name would normally be one
1218  * of the privileges defined in smb_privilege.h
1219  *
1220  * There's something peculiar about the return status from NT servers,
1221  * it's not always present. So for now, I'm ignoring the status in the
1222  * RPC response.
1223  *
1224  * Returns NT status codes.
1225  */
1226 DWORD
1227 lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
1228     char *display_name, int display_len)
1229 {
1230 	struct mslsa_LookupPrivDisplayName	arg;
1231 	int	opnum;
1232 	size_t	length;
1233 	DWORD	status;
1234 
1235 	if (lsa_handle == NULL || name == NULL || display_name == NULL)
1236 		return (NT_STATUS_INVALID_PARAMETER);
1237 
1238 	opnum = LSARPC_OPNUM_LookupPrivDisplayName;
1239 
1240 	bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
1241 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
1242 
1243 	length = smb_wcequiv_strlen(name);
1244 	arg.name.length = length;
1245 	arg.name.allosize = length;
1246 	arg.name.str = (unsigned char *)name;
1247 
1248 	arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
1249 	arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
1250 
1251 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0)
1252 		status = NT_STATUS_INVALID_PARAMETER;
1253 #if 0
1254 	else if (arg.status != 0)
1255 		status = NT_SC_VALUE(arg.status);
1256 #endif
1257 	else {
1258 		(void) strlcpy(display_name,
1259 		    (char const *)arg.display_name->str, display_len);
1260 		status = NT_STATUS_SUCCESS;
1261 	}
1262 
1263 	ndr_rpc_release(lsa_handle);
1264 	return (status);
1265 }
1266 
1267 static void
1268 lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf,
1269     smb_trusted_domains_t *list)
1270 {
1271 	char	sidstr[SMB_SID_STRSZ];
1272 	int	i;
1273 
1274 	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1275 		return;
1276 
1277 	list->td_num = 0;
1278 	list->td_domains = calloc(enum_buf->entries_read,
1279 	    sizeof (smb_domain_t));
1280 
1281 	if (list->td_domains == NULL)
1282 		return;
1283 
1284 	list->td_num = enum_buf->entries_read;
1285 	for (i = 0; i < list->td_num; i++) {
1286 		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1287 		smb_domain_set_trust_info(
1288 		    sidstr,
1289 		    (char *)enum_buf->info[i].nb_name.str,
1290 		    (char *)enum_buf->info[i].dns_name.str,
1291 		    enum_buf->info[i].trust_direction,
1292 		    enum_buf->info[i].trust_type,
1293 		    enum_buf->info[i].trust_attrs,
1294 		    &list->td_domains[i]);
1295 	}
1296 }
1297 
1298 static void
1299 lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf,
1300     smb_trusted_domains_t *list)
1301 {
1302 	char	sidstr[SMB_SID_STRSZ];
1303 	int	i;
1304 
1305 	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
1306 		return;
1307 
1308 	list->td_num = 0;
1309 	list->td_domains = calloc(enum_buf->entries_read,
1310 	    sizeof (smb_domain_t));
1311 
1312 	if (list->td_domains == NULL)
1313 		return;
1314 
1315 	list->td_num = enum_buf->entries_read;
1316 	for (i = 0; i < list->td_num; i++) {
1317 		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
1318 		smb_domain_set_trust_info(
1319 		    sidstr, (char *)enum_buf->info[i].name.str,
1320 		    "", 0, 0, 0, &list->td_domains[i]);
1321 	}
1322 }
1323 
1324 static void
1325 smb_account_trace(const smb_account_t *info)
1326 {
1327 	char	sidbuf[SMB_SID_STRSZ];
1328 
1329 	bzero(sidbuf, SMB_SID_STRSZ);
1330 	smb_sid_tostr(info->a_sid, sidbuf);
1331 
1332 	smb_tracef("%s %s %s %lu %s", info->a_domain, info->a_name,
1333 	    sidbuf, info->a_rid, smb_sid_type2str(info->a_type));
1334 }
1335