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