xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c (revision 3e95bd4ab92abca814bd28e854607d1975c7dc88)
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 static int
790 lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa)
791 {
792 	struct mslsa_LookupSids *param = arg;
793 	struct mslsa_domain_table *domain_table;
794 	struct mslsa_domain_entry *domain_entry;
795 	struct mslsa_name_entry *names;
796 	struct mslsa_name_entry *name;
797 	smb_account_t account;
798 	smb_sid_t *sid;
799 	DWORD n_entry;
800 	int result;
801 	int i;
802 
803 	n_entry = param->lup_sid_table.n_entry;
804 	names = NDR_NEWN(mxa, struct mslsa_name_entry, n_entry);
805 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
806 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
807 	    MLSVC_DOMAIN_MAX);
808 
809 	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
810 		bzero(param, sizeof (struct mslsa_LookupSids));
811 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
812 		return (NDR_DRC_OK);
813 	}
814 
815 	domain_table->entries = domain_entry;
816 	domain_table->n_entry = 0;
817 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
818 
819 	name = names;
820 	for (i = 0; i < n_entry; ++i, name++) {
821 		bzero(&names[i], sizeof (struct mslsa_name_entry));
822 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
823 
824 		result = lsa_lookup_sid(sid, &account);
825 		if (result != NT_STATUS_SUCCESS)
826 			goto lookup_sid_failed;
827 
828 		if (*account.a_name != '\0') {
829 			if (NDR_MSTRING(mxa, account.a_name,
830 			    (ndr_mstring_t *)&name->name) == -1) {
831 				result = NT_STATUS_NO_MEMORY;
832 				goto lookup_sid_failed;
833 			}
834 		}
835 		name->sid_name_use = account.a_type;
836 
837 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
838 		    domain_table, &name->domain_ix);
839 
840 		if (result == -1) {
841 			result = NT_STATUS_INTERNAL_ERROR;
842 			goto lookup_sid_failed;
843 		}
844 
845 		smb_account_free(&account);
846 	}
847 
848 	param->domain_table = domain_table;
849 	param->name_table.n_entry = n_entry;
850 	param->name_table.entries = names;
851 	param->mapped_count = n_entry;
852 	param->status = 0;
853 
854 	return (NDR_DRC_OK);
855 
856 lookup_sid_failed:
857 	param->domain_table = 0;
858 	param->name_table.n_entry = 0;
859 	param->name_table.entries = 0;
860 	param->mapped_count = 0;
861 	param->status = NT_SC_ERROR(result);
862 
863 	smb_account_free(&account);
864 	return (NDR_DRC_OK);
865 }
866 
867 /*
868  * lsarpc_s_UpdateDomainTable
869  *
870  * This routine is responsible for maintaining the domain table which
871  * will be returned from a SID lookup. Whenever a name is added to the
872  * name table, this function should be called with the corresponding
873  * domain name. If the domain information is not already in the table,
874  * it is added. On success return 0; Otherwise -1 is returned.
875  */
876 static int
877 lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa,
878     smb_account_t *account, struct mslsa_domain_table *domain_table,
879     DWORD *domain_idx)
880 {
881 	struct mslsa_domain_entry *dentry;
882 	DWORD n_entry;
883 	DWORD i;
884 	int rc;
885 
886 	if (account->a_type == SidTypeUnknown ||
887 	    account->a_type == SidTypeInvalid) {
888 		/*
889 		 * These types don't need to reference an entry in the
890 		 * domain table. So return -1.
891 		 */
892 		*domain_idx = (DWORD)-1;
893 		return (0);
894 	}
895 
896 	if ((dentry = domain_table->entries) == NULL)
897 		return (-1);
898 
899 	if ((n_entry = domain_table->n_entry) >= MLSVC_DOMAIN_MAX)
900 		return (-1);
901 
902 	for (i = 0; i < n_entry; ++i) {
903 		if (smb_sid_cmp((smb_sid_t *)dentry[i].domain_sid,
904 		    account->a_domsid)) {
905 			*domain_idx = i;
906 			return (0);
907 		}
908 	}
909 
910 	if (i == MLSVC_DOMAIN_MAX)
911 		return (-1);
912 
913 	rc = NDR_MSTRING(mxa, account->a_domain,
914 	    (ndr_mstring_t *)&dentry[i].domain_name);
915 	dentry[i].domain_sid =
916 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account->a_domsid);
917 
918 	if (rc == -1 || dentry[i].domain_sid == NULL)
919 		return (-1);
920 
921 	++domain_table->n_entry;
922 	*domain_idx = i;
923 	return (0);
924 }
925 
926 /*
927  * lsarpc_s_LookupSids2
928  *
929  * Other than the use of lsar_lookup_sids2 and lsar_name_entry2, this
930  * is identical to lsarpc_s_LookupSids.
931  *
932  * Ignore lookup_level, it is reserved and should be zero.
933  */
934 static int
935 lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa)
936 {
937 	struct lsar_lookup_sids2 *param = arg;
938 	struct lsar_name_entry2 *names;
939 	struct lsar_name_entry2 *name;
940 	struct mslsa_domain_table *domain_table;
941 	struct mslsa_domain_entry *domain_entry;
942 	smb_account_t account;
943 	smb_sid_t *sid;
944 	DWORD n_entry;
945 	int result;
946 	int i;
947 
948 	n_entry = param->lup_sid_table.n_entry;
949 	names = NDR_NEWN(mxa, struct lsar_name_entry2, n_entry);
950 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
951 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
952 	    MLSVC_DOMAIN_MAX);
953 
954 	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
955 		bzero(param, sizeof (struct lsar_lookup_sids2));
956 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
957 		return (NDR_DRC_OK);
958 	}
959 
960 	domain_table->entries = domain_entry;
961 	domain_table->n_entry = 0;
962 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
963 
964 	name = names;
965 	for (i = 0; i < n_entry; ++i, name++) {
966 		bzero(name, sizeof (struct lsar_name_entry2));
967 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
968 
969 		result = lsa_lookup_sid(sid, &account);
970 		if (result != NT_STATUS_SUCCESS)
971 			goto lookup_sid_failed;
972 
973 		if (*account.a_name != '\0') {
974 			if (NDR_MSTRING(mxa, account.a_name,
975 			    (ndr_mstring_t *)&name->name) == -1) {
976 				result = NT_STATUS_NO_MEMORY;
977 				goto lookup_sid_failed;
978 			}
979 		}
980 		name->sid_name_use = account.a_type;
981 
982 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
983 		    domain_table, &name->domain_ix);
984 
985 		if (result == -1) {
986 			result = NT_STATUS_INTERNAL_ERROR;
987 			goto lookup_sid_failed;
988 		}
989 
990 		smb_account_free(&account);
991 	}
992 
993 	param->domain_table = domain_table;
994 	param->name_table.n_entry = n_entry;
995 	param->name_table.entries = names;
996 	param->mapped_count = n_entry;
997 	param->status = 0;
998 
999 	return (NDR_DRC_OK);
1000 
1001 lookup_sid_failed:
1002 	param->domain_table = 0;
1003 	param->name_table.n_entry = 0;
1004 	param->name_table.entries = 0;
1005 	param->mapped_count = 0;
1006 	param->status = NT_SC_ERROR(result);
1007 
1008 	smb_account_free(&account);
1009 	return (NDR_DRC_OK);
1010 }
1011 
1012 /*
1013  * LookupSids3 is only valid on domain controllers.
1014  * Other servers must return NT_STATUS_INVALID_SERVER_STATE.
1015  */
1016 /*ARGSUSED*/
1017 static int
1018 lsarpc_s_LookupSids3(void *arg, ndr_xa_t *mxa)
1019 {
1020 	struct lsar_lookup_sids3 *param = arg;
1021 
1022 	bzero(param, sizeof (struct lsar_lookup_sids3));
1023 	param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE);
1024 	return (NDR_DRC_OK);
1025 }
1026 
1027 /*
1028  * lsarpc_s_LookupNames2
1029  *
1030  * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
1031  * is identical to lsarpc_s_LookupNames.
1032  *
1033  * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
1034  * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
1035  */
1036 static int
1037 lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa)
1038 {
1039 	struct lsar_LookupNames2 *param = arg;
1040 	struct lsar_rid_entry2 *rids;
1041 	struct mslsa_domain_table *domain_table;
1042 	struct mslsa_domain_entry *domain_entry;
1043 	smb_account_t account;
1044 	uint32_t status;
1045 	char *accname;
1046 	int rc = 0;
1047 
1048 	if (param->name_table->n_entry != 1)
1049 		return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1050 
1051 	if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) &&
1052 	    param->lookup_level != LSA_LOOKUP_WKSTA) {
1053 		bzero(param, sizeof (struct lsar_LookupNames2));
1054 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1055 		return (NDR_DRC_OK);
1056 	}
1057 
1058 	rids = NDR_NEW(mxa, struct lsar_rid_entry2);
1059 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
1060 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
1061 
1062 	if (rids == NULL || domain_table == NULL || domain_entry == NULL) {
1063 		bzero(param, sizeof (struct lsar_LookupNames2));
1064 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1065 		return (NDR_DRC_OK);
1066 	}
1067 
1068 	accname = (char *)param->name_table->names->str;
1069 	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
1070 	if (status != NT_STATUS_SUCCESS) {
1071 		bzero(param, sizeof (struct lsar_LookupNames2));
1072 		param->status = NT_SC_ERROR(status);
1073 		return (NDR_DRC_OK);
1074 	}
1075 
1076 	/*
1077 	 * Set up the rid table.
1078 	 */
1079 	bzero(rids, sizeof (struct lsar_rid_entry2));
1080 	rids[0].sid_name_use = account.a_type;
1081 	rids[0].rid = account.a_rid;
1082 	rids[0].domain_index = 0;
1083 	param->translated_sids.n_entry = 1;
1084 	param->translated_sids.rids = rids;
1085 
1086 	/*
1087 	 * Set up the domain table.
1088 	 */
1089 	domain_table->entries = domain_entry;
1090 	domain_table->n_entry = 1;
1091 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
1092 
1093 	rc = NDR_MSTRING(mxa, account.a_domain,
1094 	    (ndr_mstring_t *)&domain_entry->domain_name);
1095 
1096 	domain_entry->domain_sid =
1097 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
1098 
1099 	if (rc == -1 || domain_entry->domain_sid == NULL) {
1100 		smb_account_free(&account);
1101 		bzero(param, sizeof (struct lsar_LookupNames2));
1102 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1103 		return (NDR_DRC_OK);
1104 	}
1105 
1106 	param->domain_table = domain_table;
1107 	param->mapped_count = 1;
1108 	param->status = NT_STATUS_SUCCESS;
1109 
1110 	smb_account_free(&account);
1111 	return (NDR_DRC_OK);
1112 }
1113 
1114 /*
1115  * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this
1116  * is identical to lsarpc_s_LookupNames.
1117  *
1118  * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not
1119  * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER.
1120  */
1121 static int
1122 lsarpc_s_LookupNames3(void *arg, ndr_xa_t *mxa)
1123 {
1124 	struct lsar_LookupNames3	*param = arg;
1125 	struct lsar_translated_sid_ex2	*sids;
1126 	struct mslsa_domain_table	*domain_table;
1127 	struct mslsa_domain_entry	*domain_entry;
1128 	smb_account_t			account;
1129 	uint32_t			status;
1130 	char				*accname;
1131 	int				rc = 0;
1132 
1133 	if (param->name_table->n_entry != 1)
1134 		return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
1135 
1136 	if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) &&
1137 	    param->lookup_level != LSA_LOOKUP_WKSTA) {
1138 		bzero(param, sizeof (struct lsar_LookupNames3));
1139 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1140 		return (NDR_DRC_OK);
1141 	}
1142 
1143 	sids = NDR_NEW(mxa, struct lsar_translated_sid_ex2);
1144 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
1145 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
1146 
1147 	if (sids == NULL || domain_table == NULL || domain_entry == NULL) {
1148 		bzero(param, sizeof (struct lsar_LookupNames3));
1149 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1150 		return (NDR_DRC_OK);
1151 	}
1152 
1153 	accname = (char *)param->name_table->names->str;
1154 	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
1155 	if (status != NT_STATUS_SUCCESS) {
1156 		bzero(param, sizeof (struct lsar_LookupNames3));
1157 		param->status = NT_SC_ERROR(status);
1158 		return (NDR_DRC_OK);
1159 	}
1160 
1161 	/*
1162 	 * Set up the SID table.
1163 	 */
1164 	bzero(sids, sizeof (struct lsar_translated_sid_ex2));
1165 	sids[0].sid_name_use = account.a_type;
1166 	sids[0].sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_sid);
1167 	sids[0].domain_index = 0;
1168 	param->translated_sids.n_entry = 1;
1169 	param->translated_sids.sids = sids;
1170 
1171 	/*
1172 	 * Set up the domain table.
1173 	 */
1174 	domain_table->entries = domain_entry;
1175 	domain_table->n_entry = 1;
1176 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
1177 
1178 	rc = NDR_MSTRING(mxa, account.a_domain,
1179 	    (ndr_mstring_t *)&domain_entry->domain_name);
1180 
1181 	domain_entry->domain_sid =
1182 	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
1183 
1184 	if (rc == -1 || domain_entry->domain_sid == NULL) {
1185 		smb_account_free(&account);
1186 		bzero(param, sizeof (struct lsar_LookupNames3));
1187 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1188 		return (NDR_DRC_OK);
1189 	}
1190 
1191 	param->domain_table = domain_table;
1192 	param->mapped_count = 1;
1193 	param->status = NT_STATUS_SUCCESS;
1194 
1195 	smb_account_free(&account);
1196 	return (NDR_DRC_OK);
1197 }
1198 
1199 /*
1200  * LookupNames4 is only valid on domain controllers.
1201  * Other servers must return NT_STATUS_INVALID_SERVER_STATE.
1202  */
1203 /*ARGSUSED*/
1204 static int
1205 lsarpc_s_LookupNames4(void *arg, ndr_xa_t *mxa)
1206 {
1207 	struct lsar_LookupNames4 *param = arg;
1208 
1209 	bzero(param, sizeof (struct lsar_LookupNames4));
1210 	param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE);
1211 	return (NDR_DRC_OK);
1212 }
1213 
1214 /*
1215  * There is a bug in the way that ndrgen and the marshalling code handles
1216  * unions so we need to fix some of the data offsets at runtime. The
1217  * following macros and the fixup functions handle the corrections.
1218  */
1219 
1220 DECL_FIXUP_STRUCT(mslsa_PolicyInfoResUnion);
1221 DECL_FIXUP_STRUCT(mslsa_PolicyInfoRes);
1222 DECL_FIXUP_STRUCT(mslsa_QueryInfoPolicy);
1223 void
1224 fixup_mslsa_QueryInfoPolicy(struct mslsa_QueryInfoPolicy *val)
1225 {
1226 	unsigned short size1 = 0;
1227 	unsigned short size2 = 0;
1228 	unsigned short size3 = 0;
1229 
1230 	switch (val->info_class) {
1231 		case MSLSA_POLICY_AUDIT_EVENTS_INFO:
1232 			size1 = sizeof (struct mslsa_AuditEventsInfo);
1233 			break;
1234 
1235 		case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
1236 			size1 = sizeof (struct mslsa_PrimaryDomainInfo);
1237 			break;
1238 
1239 		case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
1240 			size1 = sizeof (struct mslsa_AccountDomainInfo);
1241 			break;
1242 
1243 		case MSLSA_POLICY_SERVER_ROLE_INFO:
1244 			size1 = sizeof (struct mslsa_ServerRoleInfo);
1245 			break;
1246 
1247 		case MSLSA_POLICY_DNS_DOMAIN_INFO:
1248 			size1 = sizeof (struct mslsa_DnsDomainInfo);
1249 			break;
1250 
1251 		default:
1252 			return;
1253 	};
1254 
1255 	size2 = size1 + (2 * sizeof (DWORD));
1256 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1257 
1258 	FIXUP_PDU_SIZE(mslsa_PolicyInfoResUnion, size1);
1259 	FIXUP_PDU_SIZE(mslsa_PolicyInfoRes, size2);
1260 	FIXUP_PDU_SIZE(mslsa_QueryInfoPolicy, size3);
1261 }
1262