xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c (revision 410cfc1c29e3c504b79366ddfd3584e9e69a33d5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Local Security Authority RPC (LSAR) server-side interface.
28  */
29 
30 #include <unistd.h>
31 #include <strings.h>
32 #include <pwd.h>
33 #include <grp.h>
34 
35 #include <smbsrv/libsmb.h>
36 #include <smbsrv/libmlrpc.h>
37 #include <smbsrv/libmlsvc.h>
38 #include <smbsrv/ndl/lsarpc.ndl>
39 #include <lsalib.h>
40 #include <smbsrv/smbinfo.h>
41 #include <smbsrv/nmpipes.h>
42 #include <smbsrv/ntlocale.h>
43 
44 struct local_group_table {
45 	WORD sid_name_use;
46 	WORD domain_ix;
47 	char *sid;
48 	char *name;
49 };
50 
51 static int lsarpc_key_domain;
52 static int lsarpc_key_account;
53 
54 static int lsarpc_call_stub(ndr_xa_t *mxa);
55 
56 static int lsarpc_s_CloseHandle(void *, ndr_xa_t *);
57 static int lsarpc_s_QuerySecurityObject(void *, ndr_xa_t *);
58 static int lsarpc_s_EnumAccounts(void *, ndr_xa_t *);
59 static int lsarpc_s_EnumTrustedDomain(void *, ndr_xa_t *);
60 static int lsarpc_s_EnumTrustedDomainsEx(void *, ndr_xa_t *);
61 static int lsarpc_s_OpenAccount(void *, ndr_xa_t *);
62 static int lsarpc_s_EnumPrivsAccount(void *, ndr_xa_t *);
63 static int lsarpc_s_LookupPrivValue(void *, ndr_xa_t *);
64 static int lsarpc_s_LookupPrivName(void *, ndr_xa_t *);
65 static int lsarpc_s_LookupPrivDisplayName(void *, ndr_xa_t *);
66 static int lsarpc_s_CreateSecret(void *, ndr_xa_t *);
67 static int lsarpc_s_OpenSecret(void *, ndr_xa_t *);
68 static int lsarpc_s_QueryInfoPolicy(void *, ndr_xa_t *);
69 static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *);
70 static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *);
71 static int lsarpc_s_LookupSids(void *, ndr_xa_t *);
72 static int lsarpc_s_LookupNames(void *, ndr_xa_t *);
73 static int lsarpc_s_GetConnectedUser(void *, ndr_xa_t *);
74 static int lsarpc_s_LookupSids2(void *, ndr_xa_t *);
75 static int lsarpc_s_LookupSids3(void *, ndr_xa_t *);
76 static int lsarpc_s_LookupNames2(void *, ndr_xa_t *);
77 static int lsarpc_s_LookupNames3(void *, ndr_xa_t *);
78 static int lsarpc_s_LookupNames4(void *, ndr_xa_t *);
79 
80 static DWORD lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *,
81     ndr_xa_t *);
82 static DWORD lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *,
83     ndr_xa_t *);
84 static int lsarpc_s_UpdateDomainTable(ndr_xa_t *,
85     smb_account_t *, struct mslsa_domain_table *, DWORD *);
86 
87 static ndr_stub_table_t lsarpc_stub_table[] = {
88 	{ lsarpc_s_CloseHandle,		  LSARPC_OPNUM_CloseHandle },
89 	{ lsarpc_s_QuerySecurityObject,	  LSARPC_OPNUM_QuerySecurityObject },
90 	{ lsarpc_s_EnumAccounts,	  LSARPC_OPNUM_EnumerateAccounts },
91 	{ lsarpc_s_EnumTrustedDomain,	  LSARPC_OPNUM_EnumTrustedDomain },
92 	{ lsarpc_s_EnumTrustedDomainsEx,  LSARPC_OPNUM_EnumTrustedDomainsEx },
93 	{ lsarpc_s_OpenAccount,		  LSARPC_OPNUM_OpenAccount },
94 	{ lsarpc_s_EnumPrivsAccount,	  LSARPC_OPNUM_EnumPrivsAccount },
95 	{ lsarpc_s_LookupPrivValue,	  LSARPC_OPNUM_LookupPrivValue },
96 	{ lsarpc_s_LookupPrivName,	  LSARPC_OPNUM_LookupPrivName },
97 	{ lsarpc_s_LookupPrivDisplayName, LSARPC_OPNUM_LookupPrivDisplayName },
98 	{ lsarpc_s_CreateSecret,	  LSARPC_OPNUM_CreateSecret },
99 	{ lsarpc_s_OpenSecret,		  LSARPC_OPNUM_OpenSecret },
100 	{ lsarpc_s_QueryInfoPolicy,	  LSARPC_OPNUM_QueryInfoPolicy },
101 	{ lsarpc_s_OpenDomainHandle,	  LSARPC_OPNUM_OpenPolicy },
102 	{ lsarpc_s_OpenDomainHandle,	  LSARPC_OPNUM_OpenPolicy2 },
103 	{ lsarpc_s_LookupSids,		  LSARPC_OPNUM_LookupSids },
104 	{ lsarpc_s_LookupNames,		  LSARPC_OPNUM_LookupNames },
105 	{ lsarpc_s_GetConnectedUser,	  LSARPC_OPNUM_GetConnectedUser },
106 	{ lsarpc_s_LookupSids2,		  LSARPC_OPNUM_LookupSids2 },
107 	{ lsarpc_s_LookupSids3,		  LSARPC_OPNUM_LookupSids3 },
108 	{ lsarpc_s_LookupNames2,	  LSARPC_OPNUM_LookupNames2 },
109 	{ lsarpc_s_LookupNames3,	  LSARPC_OPNUM_LookupNames3 },
110 	{ lsarpc_s_LookupNames4,	  LSARPC_OPNUM_LookupNames4 },
111 	{0}
112 };
113 
114 static ndr_service_t lsarpc_service = {
115 	"LSARPC",			/* name */
116 	"Local Security Authority",	/* desc */
117 	"\\lsarpc",			/* endpoint */
118 	PIPE_LSASS,			/* sec_addr_port */
119 	"12345778-1234-abcd-ef00-0123456789ab", 0,	/* abstract */
120 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
121 	0,				/* no bind_instance_size */
122 	NULL,				/* no bind_req() */
123 	NULL,				/* no unbind_and_close() */
124 	lsarpc_call_stub,		/* call_stub() */
125 	&TYPEINFO(lsarpc_interface),	/* interface ti */
126 	lsarpc_stub_table		/* stub_table */
127 };
128 
129 /*
130  * lsarpc_initialize
131  *
132  * This function registers the LSA RPC interface with the RPC runtime
133  * library. It must be called in order to use either the client side
134  * or the server side functions.
135  */
136 void
137 lsarpc_initialize(void)
138 {
139 	(void) ndr_svc_register(&lsarpc_service);
140 }
141 
142 /*
143  * Custom call_stub to set the stream string policy.
144  */
145 static int
146 lsarpc_call_stub(ndr_xa_t *mxa)
147 {
148 	NDS_SETF(&mxa->send_nds, NDS_F_NOTERM);
149 	NDS_SETF(&mxa->recv_nds, NDS_F_NOTERM);
150 
151 	return (ndr_generic_call_stub(mxa));
152 }
153 
154 /*
155  * lsarpc_s_OpenDomainHandle opnum=0x06
156  *
157  * This is a request to open the LSA (OpenPolicy and OpenPolicy2).
158  * The client is looking for an LSA domain handle.
159  */
160 static int
161 lsarpc_s_OpenDomainHandle(void *arg, ndr_xa_t *mxa)
162 {
163 	struct mslsa_OpenPolicy2 *param = arg;
164 	ndr_hdid_t *id;
165 
166 	if ((id = ndr_hdalloc(mxa, &lsarpc_key_domain)) != NULL) {
167 		bcopy(id, &param->domain_handle, sizeof (mslsa_handle_t));
168 		param->status = NT_STATUS_SUCCESS;
169 	} else {
170 		bzero(&param->domain_handle, sizeof (mslsa_handle_t));
171 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
172 	}
173 
174 	return (NDR_DRC_OK);
175 }
176 
177 /*
178  * lsarpc_s_CloseHandle opnum=0x00
179  *
180  * This is a request to close the LSA interface specified by the handle.
181  * We don't track handles (yet), so just zero out the handle and return
182  * NDR_DRC_OK. Setting the handle to zero appears to be standard
183  * behaviour and someone may rely on it, i.e. we do on the client side.
184  */
185 static int
186 lsarpc_s_CloseHandle(void *arg, ndr_xa_t *mxa)
187 {
188 	struct mslsa_CloseHandle *param = arg;
189 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
190 
191 	ndr_hdfree(mxa, id);
192 
193 	bzero(&param->result_handle, sizeof (param->result_handle));
194 	param->status = NT_STATUS_SUCCESS;
195 	return (NDR_DRC_OK);
196 }
197 
198 /*
199  * lsarpc_s_QuerySecurityObject
200  */
201 /*ARGSUSED*/
202 static int
203 lsarpc_s_QuerySecurityObject(void *arg, ndr_xa_t *mxa)
204 {
205 	struct mslsa_QuerySecurityObject *param = arg;
206 
207 	bzero(param, sizeof (struct mslsa_QuerySecurityObject));
208 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
209 
210 	return (NDR_DRC_OK);
211 }
212 
213 /*
214  * lsarpc_s_EnumAccounts
215  *
216  * Enumerate the list of local accounts SIDs. The client should supply
217  * a valid OpenPolicy2 handle. The enum_context is used to support
218  * multiple enumeration calls to obtain the complete list of SIDs.
219  * It should be set to 0 on the first call and passed unchanged on
220  * subsequent calls until there are no more accounts - the server will
221  * return STATUS_NO_MORE_ENTRIES.
222  *
223  * For now just set the status to access-denied. Note that we still have
224  * to provide a valid address for enum_buf because it's a reference and
225  * the marshalling rules require that references must not be null.
226  * The enum_context is used to support multiple
227  */
228 static int
229 lsarpc_s_EnumAccounts(void *arg, ndr_xa_t *mxa)
230 {
231 	struct mslsa_EnumerateAccounts *param = arg;
232 	struct mslsa_EnumAccountBuf *enum_buf;
233 
234 	bzero(param, sizeof (struct mslsa_EnumerateAccounts));
235 
236 	enum_buf = NDR_NEW(mxa, struct mslsa_EnumAccountBuf);
237 	if (enum_buf == NULL) {
238 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
239 		return (NDR_DRC_OK);
240 	}
241 
242 	bzero(enum_buf, sizeof (struct mslsa_EnumAccountBuf));
243 	param->enum_buf = enum_buf;
244 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
245 	return (NDR_DRC_OK);
246 }
247 
248 
249 /*
250  * lsarpc_s_EnumTrustedDomain
251  *
252  * This is the server side function for handling requests to enumerate
253  * the list of trusted domains: currently held in the NT domain database.
254  * This call requires an OpenPolicy2 handle. The enum_context is used to
255  * support multiple enumeration calls to obtain the complete list.
256  * It should be set to 0 on the first call and passed unchanged on
257  * subsequent calls until there are no more accounts - the server will
258  * return STATUS_NO_MORE_ENTRIES.
259  *
260  * For now just set the status to access-denied. Note that we still have
261  * to provide a valid address for enum_buf because it's a reference and
262  * the marshalling rules require that references must not be null.
263  */
264 static int
265 lsarpc_s_EnumTrustedDomain(void *arg, ndr_xa_t *mxa)
266 {
267 	struct mslsa_EnumTrustedDomain *param = arg;
268 	struct mslsa_EnumTrustedDomainBuf *enum_buf;
269 
270 	bzero(param, sizeof (struct mslsa_EnumTrustedDomain));
271 
272 	enum_buf = NDR_NEW(mxa, struct mslsa_EnumTrustedDomainBuf);
273 	if (enum_buf == NULL) {
274 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
275 		return (NDR_DRC_OK);
276 	}
277 
278 	bzero(enum_buf, sizeof (struct mslsa_EnumTrustedDomainBuf));
279 	param->enum_buf = enum_buf;
280 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
281 	return (NDR_DRC_OK);
282 }
283 
284 /*
285  * lsarpc_s_EnumTrustedDomainsEx
286  *
287  * This is the server side function for handling requests to enumerate
288  * the list of trusted domains: currently held in the NT domain database.
289  * This call requires an OpenPolicy2 handle. The enum_context is used to
290  * support multiple enumeration calls to obtain the complete list.
291  * It should be set to 0 on the first call and passed unchanged on
292  * subsequent calls until there are no more accounts - the server will
293  * return STATUS_NO_MORE_ENTRIES.
294  *
295  * For now just set the status to access-denied. Note that we still have
296  * to provide a valid address for enum_buf because it's a reference and
297  * the marshalling rules require that references must not be null.
298  */
299 static int
300 lsarpc_s_EnumTrustedDomainsEx(void *arg, ndr_xa_t *mxa)
301 {
302 	struct mslsa_EnumTrustedDomainEx *param = arg;
303 	struct mslsa_EnumTrustedDomainBufEx *enum_buf;
304 
305 	bzero(param, sizeof (struct mslsa_EnumTrustedDomainEx));
306 
307 	enum_buf = NDR_NEW(mxa, struct mslsa_EnumTrustedDomainBufEx);
308 	if (enum_buf == NULL) {
309 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
310 		return (NDR_DRC_OK);
311 	}
312 
313 	bzero(enum_buf, sizeof (struct mslsa_EnumTrustedDomainBufEx));
314 	param->enum_buf = enum_buf;
315 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
316 	return (NDR_DRC_OK);
317 }
318 
319 /*
320  * lsarpc_s_OpenAccount
321  *
322  * This is a request to open an account handle.
323  */
324 static int
325 lsarpc_s_OpenAccount(void *arg, ndr_xa_t *mxa)
326 {
327 	struct mslsa_OpenAccount *param = arg;
328 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
329 	ndr_handle_t *hd;
330 
331 	hd = ndr_hdlookup(mxa, id);
332 	if ((hd == NULL) || (hd->nh_data != &lsarpc_key_domain)) {
333 		bzero(param, sizeof (struct mslsa_OpenAccount));
334 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
335 		return (NDR_DRC_OK);
336 	}
337 
338 	if ((id = ndr_hdalloc(mxa, &lsarpc_key_account)) != NULL) {
339 		bcopy(id, &param->account_handle, sizeof (mslsa_handle_t));
340 		param->status = NT_STATUS_SUCCESS;
341 	} else {
342 		bzero(&param->account_handle, sizeof (mslsa_handle_t));
343 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
344 	}
345 
346 	return (NDR_DRC_OK);
347 }
348 
349 
350 /*
351  * lsarpc_s_EnumPrivsAccount
352  *
353  * This is the server side function for handling requests for account
354  * privileges. For now just set the status to not-supported status and
355  * return NDR_DRC_OK. Note that we still have to provide a valid
356  * address for enum_buf because it's a reference and the marshalling
357  * rules require that references must not be null.
358  */
359 /*ARGSUSED*/
360 static int
361 lsarpc_s_EnumPrivsAccount(void *arg, ndr_xa_t *mxa)
362 {
363 	struct mslsa_EnumPrivsAccount *param = arg;
364 
365 	bzero(param, sizeof (struct mslsa_EnumPrivsAccount));
366 	param->status = NT_SC_ERROR(NT_STATUS_NOT_SUPPORTED);
367 	return (NDR_DRC_OK);
368 }
369 
370 /*
371  * lsarpc_s_LookupPrivValue
372  *
373  * Server side function used to map a privilege name to a locally unique
374  * identifier (LUID).
375  */
376 /*ARGSUSED*/
377 static int
378 lsarpc_s_LookupPrivValue(void *arg, ndr_xa_t *mxa)
379 {
380 	struct mslsa_LookupPrivValue *param = arg;
381 	smb_privinfo_t *pi;
382 
383 	if ((pi = smb_priv_getbyname((char *)param->name.str)) == NULL) {
384 		bzero(param, sizeof (struct mslsa_LookupPrivValue));
385 		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
386 		return (NDR_DRC_OK);
387 	}
388 
389 	param->luid.low_part = pi->id;
390 	param->luid.high_part = 0;
391 	param->status = NT_STATUS_SUCCESS;
392 	return (NDR_DRC_OK);
393 }
394 
395 /*
396  * lsarpc_s_LookupPrivName
397  *
398  * Server side function used to map a locally unique identifier (LUID)
399  * to the appropriate privilege name string.
400  */
401 static int
402 lsarpc_s_LookupPrivName(void *arg, ndr_xa_t *mxa)
403 {
404 	struct mslsa_LookupPrivName *param = arg;
405 	smb_privinfo_t *pi;
406 	int rc;
407 
408 	if ((pi = smb_priv_getbyvalue(param->luid.low_part)) == NULL) {
409 		bzero(param, sizeof (struct mslsa_LookupPrivName));
410 		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
411 		return (NDR_DRC_OK);
412 	}
413 
414 	param->name = NDR_NEW(mxa, mslsa_string_t);
415 	if (param->name == NULL) {
416 		bzero(param, sizeof (struct mslsa_LookupPrivName));
417 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
418 		return (NDR_DRC_OK);
419 	}
420 
421 	rc = NDR_MSTRING(mxa, pi->name, (ndr_mstring_t *)param->name);
422 	if (rc == -1) {
423 		bzero(param, sizeof (struct mslsa_LookupPrivName));
424 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
425 		return (NDR_DRC_OK);
426 	}
427 
428 	param->status = NT_STATUS_SUCCESS;
429 	return (NDR_DRC_OK);
430 }
431 
432 /*
433  * lsarpc_s_LookupPrivDisplayName
434  *
435  * This is the server side function for handling requests for account
436  * privileges. For now just set the status to not-supported status and
437  * return NDR_DRC_OK.
438  */
439 static int
440 lsarpc_s_LookupPrivDisplayName(void *arg, ndr_xa_t *mxa)
441 {
442 	struct mslsa_LookupPrivDisplayName *param = arg;
443 	smb_privinfo_t *pi;
444 	int rc;
445 
446 	if ((pi = smb_priv_getbyname((char *)param->name.str)) == NULL) {
447 		bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
448 		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_PRIVILEGE);
449 		return (NDR_DRC_OK);
450 	}
451 
452 	param->display_name = NDR_NEW(mxa, mslsa_string_t);
453 	if (param->display_name == NULL) {
454 		bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
455 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
456 		return (NDR_DRC_OK);
457 	}
458 
459 	rc = NDR_MSTRING(mxa, pi->display_name,
460 	    (ndr_mstring_t *)param->display_name);
461 	if (rc == -1) {
462 		bzero(param, sizeof (struct mslsa_LookupPrivDisplayName));
463 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
464 		return (NDR_DRC_OK);
465 	}
466 
467 	param->language_ret = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
468 	param->status = NT_STATUS_SUCCESS;
469 	return (NDR_DRC_OK);
470 }
471 
472 static int
473 lsarpc_s_CreateSecret(void *arg, ndr_xa_t *mxa)
474 {
475 	struct mslsa_CreateSecret *param = arg;
476 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
477 	ndr_handle_t *hd;
478 
479 	hd = ndr_hdlookup(mxa, id);
480 	if ((hd == NULL) || (hd->nh_data != &lsarpc_key_domain)) {
481 		bzero(param, sizeof (struct mslsa_OpenAccount));
482 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
483 		return (NDR_DRC_OK);
484 	}
485 
486 	bzero(&param->secret_handle, sizeof (mslsa_handle_t));
487 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
488 	return (NDR_DRC_OK);
489 }
490 
491 static int
492 lsarpc_s_OpenSecret(void *arg, ndr_xa_t *mxa)
493 {
494 	struct mslsa_OpenSecret *param = arg;
495 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
496 	ndr_handle_t *hd;
497 
498 	hd = ndr_hdlookup(mxa, id);
499 	if ((hd == NULL) || (hd->nh_data != &lsarpc_key_domain)) {
500 		bzero(param, sizeof (struct mslsa_OpenAccount));
501 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
502 		return (NDR_DRC_OK);
503 	}
504 
505 	bzero(&param->secret_handle, sizeof (mslsa_handle_t));
506 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
507 	return (NDR_DRC_OK);
508 }
509 
510 /*
511  * lsarpc_s_GetConnectedUser
512  *
513  * Return the account name and NetBIOS domain name for the user making
514  * the request.  The hostname field should be ignored by the server.
515  */
516 static int
517 lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa)
518 {
519 	struct mslsa_GetConnectedUser *param = arg;
520 	smb_netuserinfo_t *user = &mxa->pipe->np_user;
521 	DWORD status = NT_STATUS_SUCCESS;
522 	smb_domainex_t di;
523 	int rc1;
524 	int rc2;
525 
526 	if (!smb_domain_getinfo(&di)) {
527 		bzero(param, sizeof (struct mslsa_GetConnectedUser));
528 		status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
529 		param->status = status;
530 		return (NDR_DRC_OK);
531 	}
532 
533 	param->owner = NDR_NEW(mxa, struct mslsa_string_desc);
534 	param->domain = NDR_NEW(mxa, struct mslsa_DomainName);
535 	if (param->owner == NULL || param->domain == NULL) {
536 		status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
537 		param->status = status;
538 		return (NDR_DRC_OK);
539 	}
540 
541 	param->domain->name = NDR_NEW(mxa, struct mslsa_string_desc);
542 	if (param->domain->name == NULL) {
543 		status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
544 		param->status = status;
545 		return (NDR_DRC_OK);
546 	}
547 
548 	rc1 = NDR_MSTRING(mxa, user->ui_account,
549 	    (ndr_mstring_t *)param->owner);
550 	rc2 = NDR_MSTRING(mxa, user->ui_domain,
551 	    (ndr_mstring_t *)param->domain->name);
552 
553 	if (rc1 == -1 || rc2 == -1)
554 		status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
555 
556 	param->status = status;
557 	return (NDR_DRC_OK);
558 }
559 
560 
561 /*
562  * lsarpc_s_QueryInfoPolicy
563  *
564  * This is the server side function for handling LSA information policy
565  * queries. Currently, we only support primary domain and account
566  * domain queries. This is just a front end to switch on the request
567  * and hand it off to the appropriate function to actually deal with
568  * obtaining and building the response.
569  */
570 static int
571 lsarpc_s_QueryInfoPolicy(void *arg, ndr_xa_t *mxa)
572 {
573 	struct mslsa_QueryInfoPolicy *param = arg;
574 	union mslsa_PolicyInfoResUnion *ru = &param->ru;
575 	int security_mode;
576 	DWORD status;
577 
578 	param->switch_value = param->info_class;
579 
580 	switch (param->info_class) {
581 	case MSLSA_POLICY_AUDIT_EVENTS_INFO:
582 		ru->audit_events.enabled = 0;
583 		ru->audit_events.count = 1;
584 		ru->audit_events.settings
585 		    = NDR_MALLOC(mxa, sizeof (DWORD));
586 		bzero(ru->audit_events.settings, sizeof (DWORD));
587 		status = NT_STATUS_SUCCESS;
588 		break;
589 
590 	case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
591 		status = lsarpc_s_PrimaryDomainInfo(&ru->pd_info, mxa);
592 		break;
593 
594 	case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
595 		status = lsarpc_s_AccountDomainInfo(&ru->ad_info, mxa);
596 		break;
597 
598 	case MSLSA_POLICY_SERVER_ROLE_INFO:
599 		security_mode = smb_config_get_secmode();
600 
601 		if (security_mode == SMB_SECMODE_DOMAIN)
602 			ru->server_role.role = LSA_ROLE_MEMBER_SERVER;
603 		else
604 			ru->server_role.role = LSA_ROLE_STANDALONE_SERVER;
605 
606 		ru->server_role.pad = 0;
607 		status = NT_STATUS_SUCCESS;
608 		break;
609 
610 	default:
611 		bzero(param, sizeof (struct mslsa_QueryInfoPolicy));
612 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_INFO_CLASS);
613 		return (NDR_DRC_OK);
614 	}
615 
616 	if (status != NT_STATUS_SUCCESS)
617 		param->status = NT_SC_ERROR(status);
618 	else
619 		param->status = NT_STATUS_SUCCESS;
620 	param->address = (DWORD)(uintptr_t)ru;
621 
622 	return (NDR_DRC_OK);
623 }
624 
625 
626 /*
627  * lsarpc_s_PrimaryDomainInfo
628  *
629  * Service primary domain policy queries.  In domain mode, return the
630  * primary domain name and SID.   In workgroup mode, return the local
631  * hostname and local domain SID.
632  *
633  * Note: info is zeroed on entry to ensure the SID and name do not
634  * contain spurious values if an error is returned.
635  */
636 static DWORD
637 lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *info,
638     ndr_xa_t *mxa)
639 {
640 	smb_domain_t di;
641 	boolean_t found;
642 	int rc;
643 
644 	bzero(info, sizeof (struct mslsa_PrimaryDomainInfo));
645 
646 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
647 		found = smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di);
648 	else
649 		found = smb_domain_lookup_type(SMB_DOMAIN_PRIMARY, &di);
650 
651 	if (!found)
652 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
653 
654 	rc = NDR_MSTRING(mxa, di.di_nbname, (ndr_mstring_t *)&info->name);
655 	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, di.di_binsid);
656 
657 	if ((rc == -1) || (info->sid == NULL))
658 		return (NT_STATUS_NO_MEMORY);
659 
660 	return (NT_STATUS_SUCCESS);
661 }
662 
663 
664 /*
665  * lsarpc_s_AccountDomainInfo
666  *
667  * Service account domain policy queries.  We return our local domain
668  * information so that the client knows who to query for information
669  * on local names and SIDs.  The domain name is the local hostname.
670  *
671  * Note: info is zeroed on entry to ensure the SID and name do not
672  * contain spurious values if an error is returned.
673  */
674 static DWORD
675 lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *info,
676     ndr_xa_t *mxa)
677 {
678 	smb_domain_t di;
679 	int rc;
680 
681 	bzero(info, sizeof (struct mslsa_AccountDomainInfo));
682 
683 	if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
684 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
685 
686 	rc = NDR_MSTRING(mxa, di.di_nbname, (ndr_mstring_t *)&info->name);
687 	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, di.di_binsid);
688 
689 	if ((rc == -1) || (info->sid == NULL))
690 		return (NT_STATUS_NO_MEMORY);
691 
692 	return (NT_STATUS_SUCCESS);
693 }
694 
695 /*
696  * lsarpc_s_LookupNames
697  *
698  * This is the service side function for handling name lookup requests.
699  * Currently, we only support lookups of a single name. This is also a
700  * pass through interface so all we do is act as a proxy between the
701  * client and the DC.
702  */
703 static int
704 lsarpc_s_LookupNames(void *arg, ndr_xa_t *mxa)
705 {
706 	struct mslsa_LookupNames *param = arg;
707 	struct mslsa_rid_entry *rids;
708 	struct mslsa_domain_table *domain_table;
709 	struct mslsa_domain_entry *domain_entry;
710 	smb_account_t account;
711 	uint32_t status;
712 	char *accname;
713 	int rc = 0;
714 
715 	if (param->name_table->n_entry != 1)
716 		return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
717 
718 	rids = NDR_NEW(mxa, struct mslsa_rid_entry);
719 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
720 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
721 
722 	if (rids == NULL || domain_table == NULL || domain_entry == NULL) {
723 		bzero(param, sizeof (struct mslsa_LookupNames));
724 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
725 		return (NDR_DRC_OK);
726 	}
727 
728 	accname = (char *)param->name_table->names->str;
729 	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
730 	if (status != NT_STATUS_SUCCESS) {
731 		bzero(param, sizeof (struct mslsa_LookupNames));
732 		param->status = NT_SC_ERROR(status);
733 		return (NDR_DRC_OK);
734 	}
735 
736 	/*
737 	 * Set up the rid table.
738 	 */
739 	rids[0].sid_name_use = account.a_type;
740 	rids[0].rid = account.a_rid;
741 	rids[0].domain_index = 0;
742 	param->translated_sids.n_entry = 1;
743 	param->translated_sids.rids = rids;
744 
745 	/*
746 	 * Set up the domain table.
747 	 */
748 	domain_table->entries = domain_entry;
749 	domain_table->n_entry = 1;
750 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
751 
752 	rc = NDR_MSTRING(mxa, account.a_domain,
753 	    (ndr_mstring_t *)&domain_entry->domain_name);
754 	domain_entry->domain_sid =
755 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
756 
757 	if (rc == -1 || domain_entry->domain_sid == NULL) {
758 		smb_account_free(&account);
759 		bzero(param, sizeof (struct mslsa_LookupNames));
760 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
761 		return (NDR_DRC_OK);
762 	}
763 
764 	param->domain_table = domain_table;
765 	param->mapped_count = 1;
766 	param->status = NT_STATUS_SUCCESS;
767 
768 	smb_account_free(&account);
769 	return (NDR_DRC_OK);
770 }
771 
772 /*
773  * lsarpc_s_LookupSids
774  *
775  * This is the service side function for handling sid lookup requests.
776  * We have to set up both the name table and the domain table in the
777  * response. For each SID, we check for UNIX domain (local lookup) or
778  * NT domain (DC lookup) and call the appropriate lookup function. This
779  * should resolve the SID to a name. Then we need to update the domain
780  * table and make the name entry point at the appropriate domain table
781  * entry.
782  *
783  *
784  * This RPC should behave as if LookupOptions is LSA_LOOKUP_OPT_ALL and
785  * ClientRevision is LSA_CLIENT_REVISION_NT.
786  *
787  * On success return 0. Otherwise return an RPC specific error code.
788  */
789 
790 static int
791 lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa)
792 {
793 	struct mslsa_LookupSids *param = arg;
794 	struct mslsa_domain_table *domain_table;
795 	struct mslsa_domain_entry *domain_entry;
796 	struct mslsa_name_entry *names;
797 	struct mslsa_name_entry *name;
798 	smb_account_t account;
799 	smb_sid_t *sid;
800 	DWORD n_entry;
801 	DWORD n_mapped;
802 	char sidstr[SMB_SID_STRSZ];
803 	int result;
804 	int i;
805 
806 	bzero(&account, sizeof (smb_account_t));
807 	n_mapped = 0;
808 	n_entry = param->lup_sid_table.n_entry;
809 
810 	names = NDR_NEWN(mxa, struct mslsa_name_entry, n_entry);
811 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
812 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
813 	    MLSVC_DOMAIN_MAX);
814 
815 	if (names == NULL || domain_table == NULL || domain_entry == NULL)
816 		goto lookup_sid_failed;
817 
818 	domain_table->entries = domain_entry;
819 	domain_table->n_entry = 0;
820 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
821 
822 	name = names;
823 	for (i = 0; i < n_entry; ++i, name++) {
824 		bzero(name, sizeof (struct mslsa_name_entry));
825 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
826 
827 		result = lsa_lookup_sid(sid, &account);
828 		if ((result != NT_STATUS_SUCCESS) ||
829 		    (account.a_name == NULL) || (*account.a_name == '\0')) {
830 			account.a_type = SidTypeUnknown;
831 			smb_sid_tostr(sid, sidstr);
832 
833 			if (NDR_MSTRING(mxa, sidstr,
834 			    (ndr_mstring_t *)&name->name) == -1)
835 				goto lookup_sid_failed;
836 
837 		} else {
838 			if (NDR_MSTRING(mxa, account.a_name,
839 			    (ndr_mstring_t *)&name->name) == -1)
840 				goto lookup_sid_failed;
841 
842 			++n_mapped;
843 		}
844 
845 		name->sid_name_use = account.a_type;
846 
847 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
848 		    domain_table, &name->domain_ix);
849 		if (result == -1)
850 			goto lookup_sid_failed;
851 
852 		smb_account_free(&account);
853 	}
854 
855 	param->domain_table = domain_table;
856 	param->name_table.n_entry = n_entry;
857 	param->name_table.entries = names;
858 	param->mapped_count = n_mapped;
859 
860 	if (n_mapped == n_entry)
861 		param->status = NT_STATUS_SUCCESS;
862 	else if (n_mapped == 0)
863 		param->status = NT_STATUS_NONE_MAPPED;
864 	else
865 		param->status = NT_STATUS_SOME_NOT_MAPPED;
866 
867 	return (NDR_DRC_OK);
868 
869 lookup_sid_failed:
870 	smb_account_free(&account);
871 	bzero(param, sizeof (struct mslsa_LookupSids));
872 	return (NDR_DRC_FAULT_OUT_OF_MEMORY);
873 }
874 
875 /*
876  * lsarpc_s_UpdateDomainTable
877  *
878  * This routine is responsible for maintaining the domain table which
879  * will be returned from a SID lookup. Whenever a name is added to the
880  * name table, this function should be called with the corresponding
881  * domain name. If the domain information is not already in the table,
882  * it is added. On success return 0; Otherwise -1 is returned.
883  */
884 static int
885 lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa,
886     smb_account_t *account, struct mslsa_domain_table *domain_table,
887     DWORD *domain_idx)
888 {
889 	struct mslsa_domain_entry *dentry;
890 	DWORD n_entry;
891 	DWORD i;
892 	int rc;
893 
894 	if (account->a_type == SidTypeUnknown ||
895 	    account->a_type == SidTypeInvalid) {
896 		/*
897 		 * These types don't need to reference an entry in the
898 		 * domain table. So return -1.
899 		 */
900 		*domain_idx = (DWORD)-1;
901 		return (0);
902 	}
903 
904 	if ((dentry = domain_table->entries) == NULL)
905 		return (-1);
906 
907 	if ((n_entry = domain_table->n_entry) >= MLSVC_DOMAIN_MAX)
908 		return (-1);
909 
910 	for (i = 0; i < n_entry; ++i) {
911 		if (smb_sid_cmp((smb_sid_t *)dentry[i].domain_sid,
912 		    account->a_domsid)) {
913 			*domain_idx = i;
914 			return (0);
915 		}
916 	}
917 
918 	if (i == MLSVC_DOMAIN_MAX)
919 		return (-1);
920 
921 	rc = NDR_MSTRING(mxa, account->a_domain,
922 	    (ndr_mstring_t *)&dentry[i].domain_name);
923 	dentry[i].domain_sid =
924 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account->a_domsid);
925 
926 	if (rc == -1 || dentry[i].domain_sid == NULL)
927 		return (-1);
928 
929 	++domain_table->n_entry;
930 	*domain_idx = i;
931 	return (0);
932 }
933 
934 /*
935  * lsarpc_s_LookupSids2
936  *
937  * Other than the use of lsar_lookup_sids2 and lsar_name_entry2, this
938  * is identical to lsarpc_s_LookupSids.
939  *
940  * Ignore lookup_level, it is reserved and should be zero.
941  */
942 static int
943 lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa)
944 {
945 	struct lsar_lookup_sids2 *param = arg;
946 	struct lsar_name_entry2 *names;
947 	struct lsar_name_entry2 *name;
948 	struct mslsa_domain_table *domain_table;
949 	struct mslsa_domain_entry *domain_entry;
950 	smb_account_t account;
951 	smb_sid_t *sid;
952 	DWORD n_entry;
953 	DWORD n_mapped;
954 	char sidstr[SMB_SID_STRSZ];
955 	int result;
956 	int i;
957 
958 	bzero(&account, sizeof (smb_account_t));
959 	n_mapped = 0;
960 	n_entry = param->lup_sid_table.n_entry;
961 
962 	names = NDR_NEWN(mxa, struct lsar_name_entry2, n_entry);
963 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
964 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
965 	    MLSVC_DOMAIN_MAX);
966 
967 	if (names == NULL || domain_table == NULL || domain_entry == NULL)
968 		goto lookup_sid_failed;
969 
970 	domain_table->entries = domain_entry;
971 	domain_table->n_entry = 0;
972 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
973 
974 	name = names;
975 	for (i = 0; i < n_entry; ++i, name++) {
976 		bzero(name, sizeof (struct lsar_name_entry2));
977 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
978 
979 		result = lsa_lookup_sid(sid, &account);
980 		if ((result != NT_STATUS_SUCCESS) ||
981 		    (account.a_name == NULL) || (*account.a_name == '\0')) {
982 			account.a_type = SidTypeUnknown;
983 			smb_sid_tostr(sid, sidstr);
984 
985 			if (NDR_MSTRING(mxa, sidstr,
986 			    (ndr_mstring_t *)&name->name) == -1)
987 				goto lookup_sid_failed;
988 
989 		} else {
990 			if (NDR_MSTRING(mxa, account.a_name,
991 			    (ndr_mstring_t *)&name->name) == -1)
992 				goto lookup_sid_failed;
993 
994 			++n_mapped;
995 		}
996 
997 		name->sid_name_use = account.a_type;
998 
999 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
1000 		    domain_table, &name->domain_ix);
1001 		if (result == -1)
1002 			goto lookup_sid_failed;
1003 
1004 		smb_account_free(&account);
1005 	}
1006 
1007 	param->domain_table = domain_table;
1008 	param->name_table.n_entry = n_entry;
1009 	param->name_table.entries = names;
1010 	param->mapped_count = n_mapped;
1011 
1012 	if (n_mapped == n_entry)
1013 		param->status = NT_STATUS_SUCCESS;
1014 	else if (n_mapped == 0)
1015 		param->status = NT_STATUS_NONE_MAPPED;
1016 	else
1017 		param->status = NT_STATUS_SOME_NOT_MAPPED;
1018 
1019 	return (NDR_DRC_OK);
1020 
1021 lookup_sid_failed:
1022 	smb_account_free(&account);
1023 	bzero(param, sizeof (struct lsar_lookup_sids2));
1024 	return (NDR_DRC_FAULT_OUT_OF_MEMORY);
1025 }
1026 
1027 /*
1028  * LookupSids3 is only valid on domain controllers.
1029  * Other servers must return NT_STATUS_INVALID_SERVER_STATE.
1030  */
1031 /*ARGSUSED*/
1032 static int
1033 lsarpc_s_LookupSids3(void *arg, ndr_xa_t *mxa)
1034 {
1035 	struct lsar_lookup_sids3 *param = arg;
1036 
1037 	bzero(param, sizeof (struct lsar_lookup_sids3));
1038 	param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE);
1039 	return (NDR_DRC_OK);
1040 }
1041 
1042 /*
1043  * lsarpc_s_LookupNames2
1044  *
1045  * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
1046  * is identical to lsarpc_s_LookupNames.
1047  *
1048  * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
1049  * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
1050  */
1051 static int
1052 lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa)
1053 {
1054 	struct lsar_LookupNames2 *param = arg;
1055 	struct lsar_rid_entry2 *rids;
1056 	struct mslsa_domain_table *domain_table;
1057 	struct mslsa_domain_entry *domain_entry;
1058 	smb_account_t account;
1059 	uint32_t status;
1060 	char *accname;
1061 	int rc = 0;
1062 
1063 	if (param->name_table->n_entry != 1)
1064 		return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1065 
1066 	if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) &&
1067 	    param->lookup_level != LSA_LOOKUP_WKSTA) {
1068 		bzero(param, sizeof (struct lsar_LookupNames2));
1069 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1070 		return (NDR_DRC_OK);
1071 	}
1072 
1073 	rids = NDR_NEW(mxa, struct lsar_rid_entry2);
1074 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
1075 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
1076 
1077 	if (rids == NULL || domain_table == NULL || domain_entry == NULL) {
1078 		bzero(param, sizeof (struct lsar_LookupNames2));
1079 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1080 		return (NDR_DRC_OK);
1081 	}
1082 
1083 	accname = (char *)param->name_table->names->str;
1084 	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
1085 	if (status != NT_STATUS_SUCCESS) {
1086 		bzero(param, sizeof (struct lsar_LookupNames2));
1087 		param->status = NT_SC_ERROR(status);
1088 		return (NDR_DRC_OK);
1089 	}
1090 
1091 	/*
1092 	 * Set up the rid table.
1093 	 */
1094 	bzero(rids, sizeof (struct lsar_rid_entry2));
1095 	rids[0].sid_name_use = account.a_type;
1096 	rids[0].rid = account.a_rid;
1097 	rids[0].domain_index = 0;
1098 	param->translated_sids.n_entry = 1;
1099 	param->translated_sids.rids = rids;
1100 
1101 	/*
1102 	 * Set up the domain table.
1103 	 */
1104 	domain_table->entries = domain_entry;
1105 	domain_table->n_entry = 1;
1106 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
1107 
1108 	rc = NDR_MSTRING(mxa, account.a_domain,
1109 	    (ndr_mstring_t *)&domain_entry->domain_name);
1110 
1111 	domain_entry->domain_sid =
1112 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
1113 
1114 	if (rc == -1 || domain_entry->domain_sid == NULL) {
1115 		smb_account_free(&account);
1116 		bzero(param, sizeof (struct lsar_LookupNames2));
1117 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1118 		return (NDR_DRC_OK);
1119 	}
1120 
1121 	param->domain_table = domain_table;
1122 	param->mapped_count = 1;
1123 	param->status = NT_STATUS_SUCCESS;
1124 
1125 	smb_account_free(&account);
1126 	return (NDR_DRC_OK);
1127 }
1128 
1129 /*
1130  * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
1131  * is identical to lsarpc_s_LookupNames.
1132  *
1133  * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
1134  * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
1135  */
1136 static int
1137 lsarpc_s_LookupNames3(void *arg, ndr_xa_t *mxa)
1138 {
1139 	struct lsar_LookupNames3	*param = arg;
1140 	struct lsar_translated_sid_ex2	*sids;
1141 	struct mslsa_domain_table	*domain_table;
1142 	struct mslsa_domain_entry	*domain_entry;
1143 	smb_account_t			account;
1144 	uint32_t			status;
1145 	char				*accname;
1146 	int				rc = 0;
1147 
1148 	if (param->name_table->n_entry != 1)
1149 		return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1150 
1151 	if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) &&
1152 	    param->lookup_level != LSA_LOOKUP_WKSTA) {
1153 		bzero(param, sizeof (struct lsar_LookupNames3));
1154 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1155 		return (NDR_DRC_OK);
1156 	}
1157 
1158 	sids = NDR_NEW(mxa, struct lsar_translated_sid_ex2);
1159 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
1160 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
1161 
1162 	if (sids == NULL || domain_table == NULL || domain_entry == NULL) {
1163 		bzero(param, sizeof (struct lsar_LookupNames3));
1164 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1165 		return (NDR_DRC_OK);
1166 	}
1167 
1168 	accname = (char *)param->name_table->names->str;
1169 	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
1170 	if (status != NT_STATUS_SUCCESS) {
1171 		bzero(param, sizeof (struct lsar_LookupNames3));
1172 		param->status = NT_SC_ERROR(status);
1173 		return (NDR_DRC_OK);
1174 	}
1175 
1176 	/*
1177 	 * Set up the SID table.
1178 	 */
1179 	bzero(sids, sizeof (struct lsar_translated_sid_ex2));
1180 	sids[0].sid_name_use = account.a_type;
1181 	sids[0].sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_sid);
1182 	sids[0].domain_index = 0;
1183 	param->translated_sids.n_entry = 1;
1184 	param->translated_sids.sids = sids;
1185 
1186 	/*
1187 	 * Set up the domain table.
1188 	 */
1189 	domain_table->entries = domain_entry;
1190 	domain_table->n_entry = 1;
1191 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
1192 
1193 	rc = NDR_MSTRING(mxa, account.a_domain,
1194 	    (ndr_mstring_t *)&domain_entry->domain_name);
1195 
1196 	domain_entry->domain_sid =
1197 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
1198 
1199 	if (rc == -1 || domain_entry->domain_sid == NULL) {
1200 		smb_account_free(&account);
1201 		bzero(param, sizeof (struct lsar_LookupNames3));
1202 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1203 		return (NDR_DRC_OK);
1204 	}
1205 
1206 	param->domain_table = domain_table;
1207 	param->mapped_count = 1;
1208 	param->status = NT_STATUS_SUCCESS;
1209 
1210 	smb_account_free(&account);
1211 	return (NDR_DRC_OK);
1212 }
1213 
1214 /*
1215  * LookupNames4 is only valid on domain controllers.
1216  * Other servers must return NT_STATUS_INVALID_SERVER_STATE.
1217  */
1218 /*ARGSUSED*/
1219 static int
1220 lsarpc_s_LookupNames4(void *arg, ndr_xa_t *mxa)
1221 {
1222 	struct lsar_LookupNames4 *param = arg;
1223 
1224 	bzero(param, sizeof (struct lsar_LookupNames4));
1225 	param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE);
1226 	return (NDR_DRC_OK);
1227 }
1228 
1229 /*
1230  * There is a bug in the way that ndrgen and the marshalling code handles
1231  * unions so we need to fix some of the data offsets at runtime. The
1232  * following macros and the fixup functions handle the corrections.
1233  */
1234 
1235 DECL_FIXUP_STRUCT(mslsa_PolicyInfoResUnion);
1236 DECL_FIXUP_STRUCT(mslsa_PolicyInfoRes);
1237 DECL_FIXUP_STRUCT(mslsa_QueryInfoPolicy);
1238 void
1239 fixup_mslsa_QueryInfoPolicy(struct mslsa_QueryInfoPolicy *val)
1240 {
1241 	unsigned short size1 = 0;
1242 	unsigned short size2 = 0;
1243 	unsigned short size3 = 0;
1244 
1245 	switch (val->info_class) {
1246 		case MSLSA_POLICY_AUDIT_EVENTS_INFO:
1247 			size1 = sizeof (struct mslsa_AuditEventsInfo);
1248 			break;
1249 
1250 		case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
1251 			size1 = sizeof (struct mslsa_PrimaryDomainInfo);
1252 			break;
1253 
1254 		case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
1255 			size1 = sizeof (struct mslsa_AccountDomainInfo);
1256 			break;
1257 
1258 		case MSLSA_POLICY_SERVER_ROLE_INFO:
1259 			size1 = sizeof (struct mslsa_ServerRoleInfo);
1260 			break;
1261 
1262 		case MSLSA_POLICY_DNS_DOMAIN_INFO:
1263 			size1 = sizeof (struct mslsa_DnsDomainInfo);
1264 			break;
1265 
1266 		default:
1267 			return;
1268 	};
1269 
1270 	size2 = size1 + (2 * sizeof (DWORD));
1271 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1272 
1273 	FIXUP_PDU_SIZE(mslsa_PolicyInfoResUnion, size1);
1274 	FIXUP_PDU_SIZE(mslsa_PolicyInfoRes, size2);
1275 	FIXUP_PDU_SIZE(mslsa_QueryInfoPolicy, size3);
1276 }
1277