lsar_clnt.c revision 3299f39fdcbdab4be7a9c70daa3873f2b78a398d
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	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 */
448static char *
449lsar_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 */
474static uint32_t
475lsar_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 */
528static uint32_t
529lsar_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 */
583static uint32_t
584lsar_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 */
645static uint32_t /*LINTED E_STATIC_UNUSED*/
646lsar_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 */
703uint32_t
704lsar_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 */
738static uint32_t
739lsar_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 */
798static uint32_t
799lsar_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 */
866static uint32_t /*LINTED E_STATIC_UNUSED*/
867lsar_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 */
939DWORD
940lsar_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 */
1014DWORD
1015lsar_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
1058DWORD
1059lsar_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*/
1108int
1109lsar_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 */
1139int
1140lsar_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 */
1183int
1184lsar_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 */
1226DWORD
1227lsar_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
1267static void
1268lsar_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
1298static void
1299lsar_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
1324static void
1325smb_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