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