xref: /titanic_41/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c (revision dc5982c9e1ebe3315aac975f1c4f1ad46c83c2d2)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Security Accounts Manager RPC (SAMR) server-side interface.
27  *
28  * The SAM is a hierarchical database:
29  * - If you want to talk to the SAM you need a SAM handle.
30  * - If you want to work with a domain, use the SAM handle.
31  *   to obtain a domain handle.
32  * - Use domain handles to obtain user handles etc.
33  */
34 
35 #include <strings.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <assert.h>
39 #include <grp.h>
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libmlrpc.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/ntstatus.h>
44 #include <smbsrv/nterror.h>
45 #include <smbsrv/smbinfo.h>
46 #include <smbsrv/nmpipes.h>
47 #include <smbsrv/ndl/samrpc.ndl>
48 #include <samlib.h>
49 
50 /*
51  * The keys associated with the various handles dispensed by the SAMR
52  * server.  These keys can be used to validate client activity.
53  * These values are never passed over the wire so security shouldn't
54  * be an issue.
55  */
56 typedef enum {
57 	SAMR_KEY_NULL = 0,
58 	SAMR_KEY_CONNECT,
59 	SAMR_KEY_DOMAIN,
60 	SAMR_KEY_USER,
61 	SAMR_KEY_GROUP,
62 	SAMR_KEY_ALIAS
63 } samr_key_t;
64 
65 typedef struct samr_keydata {
66 	samr_key_t kd_key;
67 	smb_domain_type_t kd_type;
68 	DWORD kd_rid;
69 } samr_keydata_t;
70 
71 /*
72  * DomainDisplayUser	All user objects (or those derived from user) with
73  * 			userAccountControl containing the UF_NORMAL_ACCOUNT bit.
74  *
75  * DomainDisplayMachine	All user objects (or those derived from user) with
76  * 			userAccountControl containing the
77  * 			UF_WORKSTATION_TRUST_ACCOUNT or UF_SERVER_TRUST_ACCOUNT
78  * 			bit.
79  *
80  * DomainDisplayGroup	All group objects (or those derived from group) with
81  * 			groupType equal to GROUP_TYPE_SECURITY_UNIVERSAL or
82  * 			GROUP_TYPE_SECURITY_ACCOUNT.
83  *
84  * DomainDisplayOemUser	Same as DomainDisplayUser with OEM strings
85  *
86  * DomainDisplayOemGroup Same as DomainDisplayGroup with OEM strings
87  */
88 typedef enum {
89 	DomainDisplayUser = 1,
90 	DomainDisplayMachine,
91 	DomainDispalyGroup,
92 	DomainDisplayOemUser,
93 	DomainDisplayOemGroup
94 } samr_displvl_t;
95 
96 #define	SAMR_VALID_DISPLEVEL(lvl) \
97 	(((lvl) >= DomainDisplayUser) && ((lvl) <= DomainDisplayOemGroup))
98 
99 #define	SAMR_SUPPORTED_DISPLEVEL(lvl) (lvl == DomainDisplayUser)
100 
101 static ndr_hdid_t *samr_hdalloc(ndr_xa_t *, samr_key_t, smb_domain_type_t,
102     DWORD);
103 static void samr_hdfree(ndr_xa_t *, ndr_hdid_t *);
104 static ndr_handle_t *samr_hdlookup(ndr_xa_t *, ndr_hdid_t *, samr_key_t);
105 static int samr_call_stub(ndr_xa_t *mxa);
106 static DWORD samr_s_enum_local_domains(struct samr_EnumLocalDomain *,
107     ndr_xa_t *);
108 
109 static ndr_stub_table_t samr_stub_table[];
110 
111 static ndr_service_t samr_service = {
112 	"SAMR",				/* name */
113 	"Security Accounts Manager",	/* desc */
114 	"\\samr",			/* endpoint */
115 	PIPE_LSASS,			/* sec_addr_port */
116 	"12345778-1234-abcd-ef00-0123456789ac", 1,	/* abstract */
117 	NDR_TRANSFER_SYNTAX_UUID,		2,	/* transfer */
118 	0,				/* no bind_instance_size */
119 	NULL,				/* no bind_req() */
120 	NULL,				/* no unbind_and_close() */
121 	samr_call_stub,			/* call_stub() */
122 	&TYPEINFO(samr_interface),	/* interface ti */
123 	samr_stub_table			/* stub_table */
124 };
125 
126 /*
127  * samr_initialize
128  *
129  * This function registers the SAM RPC interface with the RPC runtime
130  * library. It must be called in order to use either the client side
131  * or the server side functions.
132  */
133 void
134 samr_initialize(void)
135 {
136 	(void) ndr_svc_register(&samr_service);
137 }
138 
139 /*
140  * Custom call_stub to set the stream string policy.
141  */
142 static int
143 samr_call_stub(ndr_xa_t *mxa)
144 {
145 	NDS_SETF(&mxa->send_nds, NDS_F_NOTERM);
146 	NDS_SETF(&mxa->recv_nds, NDS_F_NOTERM);
147 
148 	return (ndr_generic_call_stub(mxa));
149 }
150 
151 /*
152  * Handle allocation wrapper to setup the local context.
153  */
154 static ndr_hdid_t *
155 samr_hdalloc(ndr_xa_t *mxa, samr_key_t key, smb_domain_type_t domain_type,
156     DWORD rid)
157 {
158 	ndr_handle_t	*hd;
159 	ndr_hdid_t	*id;
160 	samr_keydata_t	*data;
161 
162 	if ((data = malloc(sizeof (samr_keydata_t))) == NULL)
163 		return (NULL);
164 
165 	data->kd_key = key;
166 	data->kd_type = domain_type;
167 	data->kd_rid = rid;
168 
169 	if ((id = ndr_hdalloc(mxa, data)) == NULL) {
170 		free(data);
171 		return (NULL);
172 	}
173 
174 	if ((hd = ndr_hdlookup(mxa, id)) != NULL)
175 		hd->nh_data_free = free;
176 
177 	return (id);
178 }
179 
180 /*
181  * Handle deallocation wrapper to free the local context.
182  */
183 static void
184 samr_hdfree(ndr_xa_t *mxa, ndr_hdid_t *id)
185 {
186 	ndr_handle_t *hd;
187 
188 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
189 		free(hd->nh_data);
190 		hd->nh_data = NULL;
191 		ndr_hdfree(mxa, id);
192 	}
193 }
194 
195 /*
196  * Handle lookup wrapper to validate the local context.
197  */
198 static ndr_handle_t *
199 samr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id, samr_key_t key)
200 {
201 	ndr_handle_t *hd;
202 	samr_keydata_t *data;
203 
204 	if ((hd = ndr_hdlookup(mxa, id)) == NULL)
205 		return (NULL);
206 
207 	if ((data = (samr_keydata_t *)hd->nh_data) == NULL)
208 		return (NULL);
209 
210 	if (data->kd_key != key)
211 		return (NULL);
212 
213 	return (hd);
214 }
215 
216 /*
217  * samr_s_ConnectAnon
218  *
219  * This is a request to connect to the local SAM database. We don't
220  * support any form of update request and our database doesn't
221  * contain any private information, so there is little point in
222  * doing any access access checking here.
223  *
224  * Return a handle for use with subsequent SAM requests.
225  */
226 static int
227 samr_s_ConnectAnon(void *arg, ndr_xa_t *mxa)
228 {
229 	struct samr_ConnectAnon *param = arg;
230 	ndr_hdid_t *id;
231 
232 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
233 	if (id) {
234 		bcopy(id, &param->handle, sizeof (samr_handle_t));
235 		param->status = 0;
236 	} else {
237 		bzero(&param->handle, sizeof (samr_handle_t));
238 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
239 	}
240 
241 	return (NDR_DRC_OK);
242 }
243 
244 /*
245  * samr_s_CloseHandle
246  *
247  * Close the SAM interface specified by the handle.
248  * Free the handle and zero out the result handle for the client.
249  */
250 static int
251 samr_s_CloseHandle(void *arg, ndr_xa_t *mxa)
252 {
253 	struct samr_CloseHandle *param = arg;
254 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
255 
256 	samr_hdfree(mxa, id);
257 
258 	bzero(&param->result_handle, sizeof (samr_handle_t));
259 	param->status = 0;
260 	return (NDR_DRC_OK);
261 }
262 
263 /*
264  * samr_s_LookupDomain
265  *
266  * This is a request to map a domain name to a domain SID. We can map
267  * the primary domain name, our local domain name (hostname) and the
268  * builtin domain names to the appropriate SID. Anything else will be
269  * rejected.
270  */
271 static int
272 samr_s_LookupDomain(void *arg, ndr_xa_t *mxa)
273 {
274 	struct samr_LookupDomain *param = arg;
275 	char *domain_name;
276 	smb_domain_t di;
277 
278 	if ((domain_name = (char *)param->domain_name.str) == NULL) {
279 		bzero(param, sizeof (struct samr_LookupDomain));
280 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
281 		return (NDR_DRC_OK);
282 	}
283 
284 	if (!smb_domain_lookup_name(domain_name, &di)) {
285 		bzero(param, sizeof (struct samr_LookupDomain));
286 		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN);
287 		return (NDR_DRC_OK);
288 	}
289 
290 	param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, di.di_binsid);
291 	if (param->sid == NULL) {
292 		bzero(param, sizeof (struct samr_LookupDomain));
293 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
294 		return (NDR_DRC_OK);
295 	}
296 
297 	param->status = NT_STATUS_SUCCESS;
298 	return (NDR_DRC_OK);
299 }
300 
301 /*
302  * samr_s_EnumLocalDomains
303  *
304  * This is a request for the local domains supported by this server.
305  * All we do here is validate the handle and set the status. The real
306  * work is done in samr_s_enum_local_domains.
307  */
308 static int
309 samr_s_EnumLocalDomains(void *arg, ndr_xa_t *mxa)
310 {
311 	struct samr_EnumLocalDomain *param = arg;
312 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
313 	DWORD status;
314 
315 	if (samr_hdlookup(mxa, id, SAMR_KEY_CONNECT) == NULL)
316 		status = NT_STATUS_ACCESS_DENIED;
317 	else
318 		status = samr_s_enum_local_domains(param, mxa);
319 
320 	if (status == NT_STATUS_SUCCESS) {
321 		param->enum_context = param->info->entries_read;
322 		param->total_entries = param->info->entries_read;
323 		param->status = NT_STATUS_SUCCESS;
324 	} else {
325 		bzero(param, sizeof (struct samr_EnumLocalDomain));
326 		param->status = NT_SC_ERROR(status);
327 	}
328 
329 	return (NDR_DRC_OK);
330 }
331 
332 
333 /*
334  * samr_s_enum_local_domains
335  *
336  * This function should only be called via samr_s_EnumLocalDomains to
337  * ensure that the appropriate validation is performed. We will answer
338  * queries about two domains: the local domain, synonymous with the
339  * local hostname, and the BUILTIN domain. So we return these two
340  * strings.
341  *
342  * Returns NT status values.
343  */
344 static DWORD
345 samr_s_enum_local_domains(struct samr_EnumLocalDomain *param,
346     ndr_xa_t *mxa)
347 {
348 	struct samr_LocalDomainInfo *info;
349 	struct samr_LocalDomainEntry *entry;
350 	char *hostname;
351 
352 	hostname = NDR_MALLOC(mxa, NETBIOS_NAME_SZ);
353 	if (hostname == NULL)
354 		return (NT_STATUS_NO_MEMORY);
355 
356 	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0)
357 		return (NT_STATUS_NO_MEMORY);
358 
359 	entry = NDR_NEWN(mxa, struct samr_LocalDomainEntry, 2);
360 	if (entry == NULL)
361 		return (NT_STATUS_NO_MEMORY);
362 
363 	bzero(entry, (sizeof (struct samr_LocalDomainEntry) * 2));
364 	(void) NDR_MSTRING(mxa, hostname, (ndr_mstring_t *)&entry[0].name);
365 	(void) NDR_MSTRING(mxa, "Builtin", (ndr_mstring_t *)&entry[1].name);
366 
367 	info = NDR_NEW(mxa, struct samr_LocalDomainInfo);
368 	if (info == NULL)
369 		return (NT_STATUS_NO_MEMORY);
370 
371 	info->entries_read = 2;
372 	info->entry = entry;
373 	param->info = info;
374 	return (NT_STATUS_SUCCESS);
375 }
376 
377 /*
378  * samr_s_OpenDomain
379  *
380  * This is a request to open a domain within the local SAM database.
381  * The caller must supply a valid connect handle.
382  * We return a handle to be used to access objects within this domain.
383  */
384 static int
385 samr_s_OpenDomain(void *arg, ndr_xa_t *mxa)
386 {
387 	struct samr_OpenDomain *param = arg;
388 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
389 	smb_domain_t domain;
390 
391 	if (samr_hdlookup(mxa, id, SAMR_KEY_CONNECT) == NULL) {
392 		bzero(&param->domain_handle, sizeof (samr_handle_t));
393 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
394 		return (NDR_DRC_OK);
395 	}
396 
397 	if (!smb_domain_lookup_sid((smb_sid_t *)param->sid, &domain)) {
398 		bzero(&param->domain_handle, sizeof (samr_handle_t));
399 		param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
400 		return (NDR_DRC_OK);
401 	}
402 
403 	if ((domain.di_type != SMB_DOMAIN_BUILTIN) &&
404 	    (domain.di_type != SMB_DOMAIN_LOCAL)) {
405 		bzero(&param->domain_handle, sizeof (samr_handle_t));
406 		param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
407 		return (NDR_DRC_OK);
408 	}
409 
410 	id = samr_hdalloc(mxa, SAMR_KEY_DOMAIN, domain.di_type, 0);
411 	if (id) {
412 		bcopy(id, &param->domain_handle, sizeof (samr_handle_t));
413 		param->status = 0;
414 	} else {
415 		bzero(&param->domain_handle, sizeof (samr_handle_t));
416 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
417 	}
418 
419 	return (NDR_DRC_OK);
420 }
421 
422 /*
423  * samr_s_QueryDomainInfo
424  *
425  * The caller should pass a domain handle.
426  *
427  * Windows 95 Server Manager sends requests for levels 6 and 7 when
428  * the services menu item is selected. Level 2 is basically for getting
429  * number of users, groups, and aliases in a domain.
430  * We have no information on what the various information levels mean.
431  */
432 static int
433 samr_s_QueryDomainInfo(void *arg, ndr_xa_t *mxa)
434 {
435 	struct samr_QueryDomainInfo *param = arg;
436 	struct samr_QueryDomainInfoRes *info;
437 	ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
438 	ndr_handle_t *hd;
439 	samr_keydata_t *data;
440 	char *domain;
441 	char hostname[NETBIOS_NAME_SZ];
442 	int alias_cnt, user_cnt;
443 	int rc = 0;
444 
445 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
446 		bzero(param, sizeof (struct samr_QueryDomainInfo));
447 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
448 		return (NDR_DRC_OK);
449 	}
450 
451 	info = NDR_NEW(mxa, struct samr_QueryDomainInfoRes);
452 	if (info == NULL) {
453 		bzero(param, sizeof (struct samr_QueryDomainInfo));
454 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
455 		return (NDR_DRC_OK);
456 	}
457 	info->switch_value = param->info_level;
458 	param->info = info;
459 
460 	data = (samr_keydata_t *)hd->nh_data;
461 
462 	switch (data->kd_type) {
463 	case SMB_DOMAIN_BUILTIN:
464 		domain = "BUILTIN";
465 		user_cnt = 0;
466 		alias_cnt = smb_sam_grp_cnt(data->kd_type);
467 		break;
468 
469 	case SMB_DOMAIN_LOCAL:
470 		rc = smb_getnetbiosname(hostname, sizeof (hostname));
471 		if (rc == 0) {
472 			domain = hostname;
473 			user_cnt = smb_sam_usr_cnt();
474 			alias_cnt = smb_sam_grp_cnt(data->kd_type);
475 		}
476 		break;
477 
478 	default:
479 		bzero(param, sizeof (struct samr_QueryDomainInfo));
480 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
481 		return (NDR_DRC_OK);
482 	}
483 
484 	if (rc != 0) {
485 		bzero(param, sizeof (struct samr_QueryDomainInfo));
486 		param->status = NT_SC_ERROR(NT_STATUS_INTERNAL_ERROR);
487 		return (NDR_DRC_OK);
488 	}
489 
490 	switch (param->info_level) {
491 	case SAMR_QUERY_DOMAIN_INFO_6:
492 		info->ru.info6.unknown1 = 0x00000000;
493 		info->ru.info6.unknown2 = 0x00147FB0;
494 		info->ru.info6.unknown3 = 0x00000000;
495 		info->ru.info6.unknown4 = 0x00000000;
496 		info->ru.info6.unknown5 = 0x00000000;
497 		param->status = NT_STATUS_SUCCESS;
498 		break;
499 
500 	case SAMR_QUERY_DOMAIN_INFO_7:
501 		info->ru.info7.unknown1 = 0x00000003;
502 		param->status = NT_STATUS_SUCCESS;
503 		break;
504 
505 	case SAMR_QUERY_DOMAIN_INFO_2:
506 		info->ru.info2.unknown1 = 0x00000000;
507 		info->ru.info2.unknown2 = 0x80000000;
508 
509 		(void) NDR_MSTRING(mxa, "",
510 		    (ndr_mstring_t *)&(info->ru.info2.s1));
511 		(void) NDR_MSTRING(mxa, domain,
512 		    (ndr_mstring_t *)&(info->ru.info2.domain));
513 		(void) NDR_MSTRING(mxa, "",
514 		    (ndr_mstring_t *)&(info->ru.info2.s2));
515 
516 		info->ru.info2.sequence_num = 0x0000002B;
517 		info->ru.info2.unknown3 = 0x00000000;
518 		info->ru.info2.unknown4 = 0x00000001;
519 		info->ru.info2.unknown5 = 0x00000003;
520 		info->ru.info2.unknown6 = 0x00000001;
521 		info->ru.info2.num_users = user_cnt;
522 		info->ru.info2.num_groups = 0;
523 		info->ru.info2.num_aliases = alias_cnt;
524 		param->status = NT_STATUS_SUCCESS;
525 		break;
526 
527 	default:
528 		bzero(param, sizeof (struct samr_QueryDomainInfo));
529 		return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
530 	};
531 
532 	return (NDR_DRC_OK);
533 }
534 
535 /*
536  * QueryInfoDomain2: Identical to QueryDomainInfo.
537  */
538 static int
539 samr_s_QueryInfoDomain2(void *arg, ndr_xa_t *mxa)
540 {
541 	return (samr_s_QueryDomainInfo(arg, mxa));
542 }
543 
544 /*
545  * Looks up the given name in the specified domain which could
546  * be either the built-in or local domain.
547  *
548  * CAVEAT: this function should be able to handle a list of
549  * names but currently it can only handle one name at a time.
550  */
551 static int
552 samr_s_LookupNames(void *arg, ndr_xa_t *mxa)
553 {
554 	struct samr_LookupNames *param = arg;
555 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
556 	ndr_handle_t *hd;
557 	samr_keydata_t *data;
558 	smb_account_t account;
559 	smb_wka_t *wka;
560 	uint32_t status = NT_STATUS_SUCCESS;
561 
562 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL)
563 		status = NT_STATUS_INVALID_HANDLE;
564 
565 	if (param->n_entry != 1)
566 		status = NT_STATUS_ACCESS_DENIED;
567 
568 	if (param->name.str == NULL) {
569 		/*
570 		 * Windows NT returns NT_STATUS_NONE_MAPPED.
571 		 * Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME.
572 		 */
573 		status = NT_STATUS_NONE_MAPPED;
574 	}
575 
576 	if (status != NT_STATUS_SUCCESS) {
577 		bzero(param, sizeof (struct samr_LookupNames));
578 		param->status = NT_SC_ERROR(status);
579 		return (NDR_DRC_OK);
580 	}
581 
582 	param->rids.rid = NDR_NEW(mxa, DWORD);
583 	param->rid_types.rid_type = NDR_NEW(mxa, DWORD);
584 
585 	data = (samr_keydata_t *)hd->nh_data;
586 
587 	switch (data->kd_type) {
588 	case SMB_DOMAIN_BUILTIN:
589 		wka = smb_wka_lookup_builtin((char *)param->name.str);
590 		if (wka != NULL) {
591 			param->rids.n_entry = 1;
592 			(void) smb_sid_getrid(wka->wka_binsid,
593 			    &param->rids.rid[0]);
594 			param->rid_types.n_entry = 1;
595 			param->rid_types.rid_type[0] = wka->wka_type;
596 			param->status = NT_STATUS_SUCCESS;
597 			return (NDR_DRC_OK);
598 		}
599 		break;
600 
601 	case SMB_DOMAIN_LOCAL:
602 		status = smb_sam_lookup_name(NULL, (char *)param->name.str,
603 		    SidTypeUnknown, &account);
604 		if (status == NT_STATUS_SUCCESS) {
605 			param->rids.n_entry = 1;
606 			param->rids.rid[0] = account.a_rid;
607 			param->rid_types.n_entry = 1;
608 			param->rid_types.rid_type[0] = account.a_type;
609 			param->status = NT_STATUS_SUCCESS;
610 			smb_account_free(&account);
611 			return (NDR_DRC_OK);
612 		}
613 		break;
614 
615 	default:
616 		bzero(param, sizeof (struct samr_LookupNames));
617 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
618 		return (NDR_DRC_OK);
619 	}
620 
621 	param->rids.n_entry = 0;
622 	param->rid_types.n_entry = 0;
623 	param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED);
624 	return (NDR_DRC_OK);
625 }
626 
627 /*
628  * samr_s_OpenUser
629  *
630  * This is a request to open a user within a specified domain in the
631  * local SAM database. The caller must supply a valid domain handle,
632  * obtained via a successful domain open request. The user is
633  * specified by the rid in the request.
634  */
635 static int
636 samr_s_OpenUser(void *arg, ndr_xa_t *mxa)
637 {
638 	struct samr_OpenUser *param = arg;
639 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
640 	ndr_handle_t *hd;
641 	samr_keydata_t *data;
642 
643 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
644 		bzero(&param->user_handle, sizeof (samr_handle_t));
645 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
646 		return (NDR_DRC_OK);
647 	}
648 
649 	data = (samr_keydata_t *)hd->nh_data;
650 
651 	id = samr_hdalloc(mxa, SAMR_KEY_USER, data->kd_type, param->rid);
652 	if (id == NULL) {
653 		bzero(&param->user_handle, sizeof (samr_handle_t));
654 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
655 	} else {
656 		bcopy(id, &param->user_handle, sizeof (samr_handle_t));
657 		param->status = NT_STATUS_SUCCESS;
658 	}
659 
660 	return (NDR_DRC_OK);
661 }
662 
663 /*
664  * samr_s_DeleteUser
665  *
666  * Request to delete a user within a specified domain in the local
667  * SAM database.  The caller should supply a valid user handle.
668  */
669 /*ARGSUSED*/
670 static int
671 samr_s_DeleteUser(void *arg, ndr_xa_t *mxa)
672 {
673 	struct samr_DeleteUser *param = arg;
674 
675 	bzero(param, sizeof (struct samr_DeleteUser));
676 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
677 	return (NDR_DRC_OK);
678 }
679 
680 /*
681  * samr_s_QueryUserInfo
682  *
683  * Returns:
684  * NT_STATUS_SUCCESS
685  * NT_STATUS_ACCESS_DENIED
686  * NT_STATUS_INVALID_INFO_CLASS
687  */
688 /*ARGSUSED*/
689 static int
690 samr_s_QueryUserInfo(void *arg, ndr_xa_t *mxa)
691 {
692 	static uint16_t			owf_buf[8];
693 	static uint8_t			hour_buf[SAMR_SET_USER_HOURS_SZ];
694 	struct samr_QueryUserInfo	*param = arg;
695 	struct samr_QueryUserInfo21	*all_info;
696 	ndr_hdid_t			*id;
697 	ndr_handle_t			*hd;
698 	samr_keydata_t			*data;
699 	smb_domain_t			di;
700 	smb_account_t			account;
701 	smb_sid_t			*sid;
702 	uint32_t			status;
703 
704 	id = (ndr_hdid_t *)&param->user_handle;
705 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_USER)) == NULL) {
706 		status = NT_STATUS_INVALID_HANDLE;
707 		goto QueryUserInfoError;
708 	}
709 
710 	data = (samr_keydata_t *)hd->nh_data;
711 
712 	if (param->switch_value != SAMR_QUERY_USER_ALL_INFO) {
713 		status = NT_STATUS_ACCESS_DENIED;
714 		goto QueryUserInfoError;
715 	}
716 
717 	if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) {
718 		status = NT_STATUS_ACCESS_DENIED;
719 		goto QueryUserInfoError;
720 	}
721 
722 	if ((sid = smb_sid_splice(di.di_binsid, data->kd_rid)) == NULL) {
723 		status = NT_STATUS_ACCESS_DENIED;
724 		goto QueryUserInfoError;
725 	}
726 
727 	if (smb_sam_lookup_sid(sid, &account) != NT_STATUS_SUCCESS) {
728 		status = NT_STATUS_ACCESS_DENIED;
729 		goto QueryUserInfoError;
730 	}
731 
732 	all_info = &param->ru.info21;
733 	bzero(all_info, sizeof (struct samr_QueryUserInfo21));
734 
735 	all_info->WhichFields = SAMR_USER_ALL_USERNAME | SAMR_USER_ALL_USERID;
736 
737 	(void) NDR_MSTRING(mxa, account.a_name,
738 	    (ndr_mstring_t *)&all_info->UserName);
739 	all_info->UserId = data->kd_rid;
740 
741 	all_info->LmOwfPassword.length = 16;
742 	all_info->LmOwfPassword.maxlen = 16;
743 	all_info->LmOwfPassword.buf = owf_buf;
744 	all_info->NtOwfPassword.length = 16;
745 	all_info->NtOwfPassword.maxlen = 16;
746 	all_info->NtOwfPassword.buf = owf_buf;
747 	all_info->LogonHours.units_per_week = SAMR_HOURS_PER_WEEK;
748 	all_info->LogonHours.hours = hour_buf;
749 
750 	param->address = 1;
751 	param->switch_index = SAMR_QUERY_USER_ALL_INFO;
752 	param->status = NT_STATUS_SUCCESS;
753 	smb_account_free(&account);
754 	smb_sid_free(sid);
755 	return (NDR_DRC_OK);
756 
757 QueryUserInfoError:
758 	smb_sid_free(sid);
759 	bzero(param, sizeof (struct samr_QueryUserInfo));
760 	param->status = NT_SC_ERROR(status);
761 	return (NDR_DRC_OK);
762 }
763 
764 /*
765  * samr_s_QueryUserGroups
766  *
767  * Request the list of groups of which a user is a member.
768  * The user is identified from the handle, which contains an
769  * rid in the discriminator field. Note that this is a local user.
770  */
771 static int
772 samr_s_QueryUserGroups(void *arg, ndr_xa_t *mxa)
773 {
774 	struct samr_QueryUserGroups *param = arg;
775 	struct samr_UserGroupInfo *info;
776 	struct samr_UserGroups *group;
777 	ndr_hdid_t *id = (ndr_hdid_t *)&param->user_handle;
778 	ndr_handle_t *hd;
779 	samr_keydata_t *data;
780 	smb_sid_t *user_sid = NULL;
781 	smb_group_t grp;
782 	smb_giter_t gi;
783 	smb_domain_t di;
784 	uint32_t status;
785 	int size;
786 	int ngrp_max;
787 
788 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_USER)) == NULL) {
789 		status = NT_STATUS_ACCESS_DENIED;
790 		goto query_error;
791 	}
792 
793 	data = (samr_keydata_t *)hd->nh_data;
794 	switch (data->kd_type) {
795 	case SMB_DOMAIN_BUILTIN:
796 	case SMB_DOMAIN_LOCAL:
797 		if (!smb_domain_lookup_type(data->kd_type, &di)) {
798 			status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
799 			goto query_error;
800 		}
801 		break;
802 	default:
803 		status = NT_STATUS_INVALID_HANDLE;
804 		goto query_error;
805 	}
806 
807 	user_sid = smb_sid_splice(di.di_binsid, data->kd_rid);
808 	if (user_sid == NULL) {
809 		status = NT_STATUS_NO_MEMORY;
810 		goto query_error;
811 	}
812 
813 	info = NDR_NEW(mxa, struct samr_UserGroupInfo);
814 	if (info == NULL) {
815 		status = NT_STATUS_NO_MEMORY;
816 		goto query_error;
817 	}
818 	bzero(info, sizeof (struct samr_UserGroupInfo));
819 
820 	size = 32 * 1024;
821 	info->groups = NDR_MALLOC(mxa, size);
822 	if (info->groups == NULL) {
823 		status = NT_STATUS_NO_MEMORY;
824 		goto query_error;
825 	}
826 	ngrp_max = size / sizeof (struct samr_UserGroups);
827 
828 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
829 		status = NT_STATUS_INTERNAL_ERROR;
830 		goto query_error;
831 	}
832 
833 	info->n_entry = 0;
834 	group = info->groups;
835 	while ((info->n_entry < ngrp_max) &&
836 	    (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS)) {
837 		if (smb_lgrp_is_member(&grp, user_sid)) {
838 			group->rid = grp.sg_rid;
839 			group->attr = grp.sg_attr;
840 			group++;
841 			info->n_entry++;
842 		}
843 		smb_lgrp_free(&grp);
844 	}
845 	smb_lgrp_iterclose(&gi);
846 
847 	free(user_sid);
848 	param->info = info;
849 	param->status = NT_STATUS_SUCCESS;
850 	return (NDR_DRC_OK);
851 
852 query_error:
853 	free(user_sid);
854 	bzero(param, sizeof (struct samr_QueryUserGroups));
855 	param->status = NT_SC_ERROR(status);
856 	return (NDR_DRC_OK);
857 }
858 
859 /*
860  * samr_s_OpenGroup
861  *
862  * This is a request to open a group within the specified domain in the
863  * local SAM database. The caller must supply a valid domain handle,
864  * obtained via a successful domain open request. The group is
865  * specified by the rid in the request. If this is a local RID it
866  * should already be encoded with type information.
867  *
868  * We return a handle to be used to access information about this group.
869  */
870 static int
871 samr_s_OpenGroup(void *arg, ndr_xa_t *mxa)
872 {
873 	struct samr_OpenGroup *param = arg;
874 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
875 	ndr_handle_t *hd;
876 	samr_keydata_t *data;
877 
878 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
879 		bzero(&param->group_handle, sizeof (samr_handle_t));
880 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
881 		return (NDR_DRC_OK);
882 	}
883 
884 	data = (samr_keydata_t *)hd->nh_data;
885 	id = samr_hdalloc(mxa, SAMR_KEY_GROUP, data->kd_type, param->rid);
886 
887 	if (id) {
888 		bcopy(id, &param->group_handle, sizeof (samr_handle_t));
889 		param->status = 0;
890 	} else {
891 		bzero(&param->group_handle, sizeof (samr_handle_t));
892 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
893 	}
894 
895 	return (NDR_DRC_OK);
896 }
897 
898 /*
899  * samr_s_AddAliasMember
900  *
901  * Add a member to a local SAM group.
902  * The caller must supply a valid group handle.
903  * The member is specified by the sid in the request.
904  */
905 static int
906 samr_s_AddAliasMember(void *arg, ndr_xa_t *mxa)
907 {
908 	struct samr_AddAliasMember *param = arg;
909 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
910 	ndr_handle_t *hd;
911 	samr_keydata_t *data;
912 	smb_group_t grp;
913 	uint32_t rc;
914 	uint32_t status = NT_STATUS_SUCCESS;
915 
916 	if (param->sid == NULL) {
917 		bzero(param, sizeof (struct samr_AddAliasMember));
918 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
919 		return (NDR_DRC_OK);
920 	}
921 
922 	if (!ndr_is_admin(mxa)) {
923 		bzero(param, sizeof (struct samr_AddAliasMember));
924 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
925 		return (NDR_DRC_OK);
926 	}
927 
928 
929 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
930 		bzero(param, sizeof (struct samr_AddAliasMember));
931 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
932 		return (NDR_DRC_OK);
933 	}
934 
935 	data = (samr_keydata_t *)hd->nh_data;
936 	rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
937 	if (rc != SMB_LGRP_SUCCESS) {
938 		bzero(param, sizeof (struct samr_AddAliasMember));
939 		status = smb_lgrp_err_to_ntstatus(rc);
940 		param->status = NT_SC_ERROR(status);
941 		return (NDR_DRC_OK);
942 	}
943 
944 	rc = smb_lgrp_add_member(grp.sg_name,
945 	    (smb_sid_t *)param->sid, SidTypeUser);
946 	if (rc != SMB_LGRP_SUCCESS) {
947 		bzero(param, sizeof (struct samr_AddAliasMember));
948 		status = smb_lgrp_err_to_ntstatus(rc);
949 		param->status = NT_SC_ERROR(status);
950 	}
951 	smb_lgrp_free(&grp);
952 
953 	param->status = status;
954 	return (NDR_DRC_OK);
955 }
956 
957 /*
958  * samr_s_DeleteAliasMember
959  *
960  * Delete a member from a local SAM group.
961  * The caller must supply a valid group handle.
962  * The member is specified by the sid in the request.
963  */
964 static int
965 samr_s_DeleteAliasMember(void *arg, ndr_xa_t *mxa)
966 {
967 	struct samr_DeleteAliasMember *param = arg;
968 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
969 	ndr_handle_t *hd;
970 	samr_keydata_t *data;
971 	smb_group_t grp;
972 	uint32_t rc;
973 	uint32_t status = NT_STATUS_SUCCESS;
974 
975 	if (param->sid == NULL) {
976 		bzero(param, sizeof (struct samr_DeleteAliasMember));
977 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
978 		return (NDR_DRC_OK);
979 	}
980 
981 	if (!ndr_is_admin(mxa)) {
982 		bzero(param, sizeof (struct samr_DeleteAliasMember));
983 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
984 		return (NDR_DRC_OK);
985 	}
986 
987 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
988 		bzero(param, sizeof (struct samr_DeleteAliasMember));
989 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
990 		return (NDR_DRC_OK);
991 	}
992 
993 	data = (samr_keydata_t *)hd->nh_data;
994 	rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
995 	if (rc != SMB_LGRP_SUCCESS) {
996 		bzero(param, sizeof (struct samr_DeleteAliasMember));
997 		status = smb_lgrp_err_to_ntstatus(rc);
998 		param->status = NT_SC_ERROR(status);
999 		return (NDR_DRC_OK);
1000 	}
1001 
1002 	rc = smb_lgrp_del_member(grp.sg_name,
1003 	    (smb_sid_t *)param->sid, SidTypeUser);
1004 	if (rc != SMB_LGRP_SUCCESS) {
1005 		bzero(param, sizeof (struct samr_DeleteAliasMember));
1006 		status = smb_lgrp_err_to_ntstatus(rc);
1007 		param->status = NT_SC_ERROR(status);
1008 	}
1009 	smb_lgrp_free(&grp);
1010 
1011 	param->status = status;
1012 	return (NDR_DRC_OK);
1013 }
1014 
1015 /*
1016  * samr_s_ListAliasMembers
1017  *
1018  * List members from a local SAM group.
1019  * The caller must supply a valid group handle.
1020  * A list of user SIDs in the specified group is returned to the caller.
1021  */
1022 static int
1023 samr_s_ListAliasMembers(void *arg, ndr_xa_t *mxa)
1024 {
1025 	struct samr_ListAliasMembers *param = arg;
1026 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1027 	ndr_handle_t *hd;
1028 	samr_keydata_t *data;
1029 	smb_group_t grp;
1030 	smb_gsid_t *members;
1031 	struct samr_SidInfo info;
1032 	struct samr_SidList *user;
1033 	uint32_t num = 0, size;
1034 	int i;
1035 	uint32_t rc;
1036 	uint32_t status = NT_STATUS_SUCCESS;
1037 
1038 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1039 		bzero(param, sizeof (struct samr_ListAliasMembers));
1040 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1041 		return (NDR_DRC_OK);
1042 	}
1043 
1044 	bzero(&info, sizeof (struct samr_SidInfo));
1045 	data = (samr_keydata_t *)hd->nh_data;
1046 	rc = smb_lgrp_getbyrid(data->kd_rid, data->kd_type, &grp);
1047 	if (rc != SMB_LGRP_SUCCESS) {
1048 		bzero(param, sizeof (struct samr_ListAliasMembers));
1049 		status = smb_lgrp_err_to_ntstatus(rc);
1050 		param->status = NT_SC_ERROR(status);
1051 		return (NDR_DRC_OK);
1052 	}
1053 
1054 	num = grp.sg_nmembers;
1055 	members = grp.sg_members;
1056 	size = num * sizeof (struct samr_SidList);
1057 	info.sidlist = NDR_MALLOC(mxa, size);
1058 	if (info.sidlist == NULL) {
1059 		bzero(param, sizeof (struct samr_ListAliasMembers));
1060 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1061 		smb_lgrp_free(&grp);
1062 		return (NDR_DRC_OK);
1063 	}
1064 
1065 	info.n_entry = num;
1066 	user = info.sidlist;
1067 	for (i = 0; i < num; i++) {
1068 		user->sid = (struct samr_sid *)NDR_SIDDUP(mxa,
1069 		    members[i].gs_sid);
1070 		if (user->sid == NULL) {
1071 			bzero(param, sizeof (struct samr_ListAliasMembers));
1072 			param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1073 			smb_lgrp_free(&grp);
1074 			return (NDR_DRC_OK);
1075 		}
1076 		user++;
1077 	}
1078 	smb_lgrp_free(&grp);
1079 
1080 	param->info = info;
1081 	param->status = status;
1082 	return (NDR_DRC_OK);
1083 }
1084 
1085 /*
1086  * samr_s_Connect
1087  *
1088  * This is a request to connect to the local SAM database.
1089  * We don't support any form of update request and our database doesn't
1090  * contain any private information, so there is little point in doing
1091  * any access access checking here.
1092  *
1093  * Return a handle for use with subsequent SAM requests.
1094  */
1095 static int
1096 samr_s_Connect(void *arg, ndr_xa_t *mxa)
1097 {
1098 	struct samr_Connect *param = arg;
1099 	ndr_hdid_t *id;
1100 
1101 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
1102 	if (id) {
1103 		bcopy(id, &param->handle, sizeof (samr_handle_t));
1104 		param->status = 0;
1105 	} else {
1106 		bzero(&param->handle, sizeof (samr_handle_t));
1107 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1108 	}
1109 
1110 	return (NDR_DRC_OK);
1111 }
1112 
1113 /*
1114  * samr_s_GetUserPwInfo
1115  *
1116  * Request for a user's password policy information.
1117  */
1118 /*ARGSUSED*/
1119 static int
1120 samr_s_GetUserPwInfo(void *arg, ndr_xa_t *mxa)
1121 {
1122 	static samr_password_info_t	pwinfo;
1123 	struct samr_GetUserPwInfo	*param = arg;
1124 
1125 	param->pwinfo = &pwinfo;
1126 	param->status = NT_STATUS_SUCCESS;
1127 	return (NDR_DRC_OK);
1128 }
1129 
1130 /*
1131  * samr_s_CreateUser
1132  */
1133 /*ARGSUSED*/
1134 static int
1135 samr_s_CreateUser(void *arg, ndr_xa_t *mxa)
1136 {
1137 	struct samr_CreateUser *param = arg;
1138 
1139 	bzero(&param->user_handle, sizeof (samr_handle_t));
1140 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1141 	return (NDR_DRC_OK);
1142 }
1143 
1144 /*
1145  * samr_s_ChangeUserPasswd
1146  */
1147 /*ARGSUSED*/
1148 static int
1149 samr_s_ChangeUserPasswd(void *arg, ndr_xa_t *mxa)
1150 {
1151 	struct samr_ChangeUserPasswd *param = arg;
1152 
1153 	bzero(param, sizeof (struct samr_ChangeUserPasswd));
1154 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1155 	return (NDR_DRC_OK);
1156 }
1157 
1158 /*
1159  * samr_s_GetDomainPwInfo
1160  *
1161  * Request for the domain password policy information.
1162  */
1163 /*ARGSUSED*/
1164 static int
1165 samr_s_GetDomainPwInfo(void *arg, ndr_xa_t *mxa)
1166 {
1167 	static samr_password_info_t	pwinfo;
1168 	struct samr_GetDomainPwInfo	*param = arg;
1169 
1170 	param->pwinfo = &pwinfo;
1171 	param->status = NT_STATUS_SUCCESS;
1172 	return (NDR_DRC_OK);
1173 }
1174 
1175 /*
1176  * samr_s_SetUserInfo
1177  */
1178 /*ARGSUSED*/
1179 static int
1180 samr_s_SetUserInfo(void *arg, ndr_xa_t *mxa)
1181 {
1182 	struct samr_SetUserInfo *param = arg;
1183 
1184 	bzero(param, sizeof (struct samr_SetUserInfo));
1185 	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1186 	return (NDR_DRC_OK);
1187 }
1188 
1189 /*
1190  * samr_s_QueryDispInfo
1191  *
1192  * This function currently return local users' information only.
1193  * This RPC is called repeatedly until all the users info are
1194  * retrieved.
1195  *
1196  * The total count and the returned count are returned as total size
1197  * and returned size.  The client doesn't seem to care.
1198  */
1199 static int
1200 samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa)
1201 {
1202 	struct samr_QueryDispInfo *param = arg;
1203 	ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1204 	ndr_handle_t *hd;
1205 	samr_keydata_t *data;
1206 	DWORD status = NT_STATUS_SUCCESS;
1207 	struct user_acct_info *user;
1208 	smb_pwditer_t pwi;
1209 	smb_luser_t *uinfo;
1210 	int num_users;
1211 	int start_idx;
1212 	int max_retcnt, retcnt;
1213 	int skip;
1214 
1215 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1216 		status = NT_STATUS_INVALID_HANDLE;
1217 		goto error;
1218 	}
1219 
1220 	if (!SAMR_VALID_DISPLEVEL(param->level)) {
1221 		status = NT_STATUS_INVALID_INFO_CLASS;
1222 		goto error;
1223 	}
1224 
1225 	if (!SAMR_SUPPORTED_DISPLEVEL(param->level)) {
1226 		status = NT_STATUS_NOT_IMPLEMENTED;
1227 		goto error;
1228 	}
1229 
1230 	data = (samr_keydata_t *)hd->nh_data;
1231 
1232 	switch (data->kd_type) {
1233 	case SMB_DOMAIN_BUILTIN:
1234 		goto no_info;
1235 
1236 	case SMB_DOMAIN_LOCAL:
1237 		num_users = smb_sam_usr_cnt();
1238 		start_idx = param->start_idx;
1239 		if ((num_users == 0) || (start_idx >= num_users))
1240 			goto no_info;
1241 
1242 		max_retcnt = num_users - start_idx;
1243 		if (max_retcnt > param->max_entries)
1244 			max_retcnt = param->max_entries;
1245 		param->users.acct = NDR_MALLOC(mxa,
1246 		    max_retcnt * sizeof (struct user_acct_info));
1247 		user = param->users.acct;
1248 		if (user == NULL) {
1249 			status = NT_STATUS_NO_MEMORY;
1250 			goto error;
1251 		}
1252 		bzero(user, max_retcnt * sizeof (struct user_acct_info));
1253 
1254 		if (smb_pwd_iteropen(&pwi) != SMB_PWE_SUCCESS)
1255 			goto no_info;
1256 
1257 		skip = retcnt = 0;
1258 		while ((uinfo = smb_pwd_iterate(&pwi)) != NULL) {
1259 			if (skip++ < start_idx)
1260 				continue;
1261 
1262 			if (retcnt++ >= max_retcnt)
1263 				break;
1264 
1265 			assert(uinfo->su_name != NULL);
1266 
1267 			user->index = start_idx + retcnt;
1268 			user->rid = uinfo->su_rid;
1269 			user->ctrl = ACF_NORMUSER | ACF_PWDNOEXP;
1270 			if (uinfo->su_ctrl & SMB_PWF_DISABLE)
1271 				user->ctrl |= ACF_DISABLED;
1272 			if (NDR_MSTRING(mxa, uinfo->su_name,
1273 			    (ndr_mstring_t *)&user->name) == -1) {
1274 				smb_pwd_iterclose(&pwi);
1275 				status = NT_STATUS_NO_MEMORY;
1276 				goto error;
1277 			}
1278 			(void) NDR_MSTRING(mxa, uinfo->su_fullname,
1279 			    (ndr_mstring_t *)&user->fullname);
1280 			(void) NDR_MSTRING(mxa, uinfo->su_desc,
1281 			    (ndr_mstring_t *)&user->desc);
1282 			user++;
1283 		}
1284 		smb_pwd_iterclose(&pwi);
1285 
1286 		if (retcnt >= max_retcnt) {
1287 			retcnt = max_retcnt;
1288 			param->status = status;
1289 		} else {
1290 			param->status = ERROR_MORE_ENTRIES;
1291 		}
1292 
1293 		param->users.total_size = num_users;
1294 		param->users.returned_size = retcnt;
1295 		param->users.switch_value = param->level;
1296 		param->users.count = retcnt;
1297 
1298 		break;
1299 
1300 	default:
1301 		status = NT_STATUS_INVALID_HANDLE;
1302 		goto error;
1303 	}
1304 
1305 	return (NDR_DRC_OK);
1306 
1307 no_info:
1308 	param->users.total_size = 0;
1309 	param->users.returned_size = 0;
1310 	param->users.switch_value = param->level;
1311 	param->users.count = 0;
1312 	param->users.acct = NULL;
1313 	param->status = status;
1314 	return (NDR_DRC_OK);
1315 
1316 error:
1317 	bzero(param, sizeof (struct samr_QueryDispInfo));
1318 	param->status = NT_SC_ERROR(status);
1319 	return (NDR_DRC_OK);
1320 }
1321 
1322 /*
1323  * samr_s_EnumDomainGroups
1324  *
1325  *
1326  * This function is supposed to return local group information.
1327  * As we don't support local users, this function dosen't send
1328  * back any information.
1329  *
1330  * Added template that returns information for a domain group as None.
1331  * All information is hard-coded from packet captures.
1332  */
1333 static int
1334 samr_s_EnumDomainGroups(void *arg, ndr_xa_t *mxa)
1335 {
1336 	struct samr_EnumDomainGroups *param = arg;
1337 	ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1338 	DWORD status = NT_STATUS_SUCCESS;
1339 
1340 	if (samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN) == NULL)
1341 		status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1342 
1343 	param->total_size = 0;
1344 	param->returned_size = 0;
1345 	param->switch_value = 3;
1346 	param->count = 0;
1347 	param->groups = 0;
1348 	param->status = status;
1349 	return (NDR_DRC_OK);
1350 
1351 #ifdef SAMR_SUPPORT_GROUPS
1352 	if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) {
1353 		param->total_size = 0;
1354 		param->returned_size = 0;
1355 		param->switch_value = 3;
1356 		param->count = 0;
1357 		param->groups = 0;
1358 	} else {
1359 		param->total_size = 64;
1360 		param->returned_size = 64;
1361 		param->switch_value = 3;
1362 		param->count = 1;
1363 		param->groups = (struct group_disp_info *)NDR_MALLOC(
1364 		    mxa, sizeof (struct group_disp_info));
1365 
1366 		param->groups->count = 1;
1367 		param->groups->acct[0].index = 1;
1368 		param->groups->acct[0].rid = 513;
1369 		param->groups->acct[0].ctrl = 0x7;
1370 		(void) NDR_MSTRING(mxa, "None",
1371 		    (ndr_mstring_t *)&param->groups->acct[0].name);
1372 
1373 		(void) NDR_MSTRING(mxa, "Ordinary users",
1374 		    (ndr_mstring_t *)&param->groups->acct[0].desc);
1375 	}
1376 
1377 	param->status = NT_STATUS_SUCCESS;
1378 	return (NDR_DRC_OK);
1379 #endif
1380 }
1381 
1382 /*
1383  * samr_s_OpenAlias
1384  *
1385  * Lookup for requested alias, if it exists return a handle
1386  * for that alias. The alias domain sid should match with
1387  * the passed domain handle.
1388  */
1389 static int
1390 samr_s_OpenAlias(void *arg, ndr_xa_t *mxa)
1391 {
1392 	struct samr_OpenAlias *param = arg;
1393 	ndr_hdid_t	*id = (ndr_hdid_t *)&param->domain_handle;
1394 	ndr_handle_t	*hd;
1395 	samr_keydata_t	*data;
1396 	smb_domain_type_t gd_type;
1397 	smb_sid_t	*sid;
1398 	smb_wka_t	*wka;
1399 	char		sidstr[SMB_SID_STRSZ];
1400 	uint32_t	rid;
1401 	uint32_t	status;
1402 	int		rc;
1403 
1404 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1405 		status = NT_STATUS_INVALID_HANDLE;
1406 		goto open_alias_err;
1407 	}
1408 
1409 	if ((param->access_mask & SAMR_ALIAS_ACCESS_ALL_ACCESS) == 0) {
1410 		status = NT_STATUS_ACCESS_DENIED;
1411 		goto open_alias_err;
1412 	}
1413 
1414 	data = (samr_keydata_t *)hd->nh_data;
1415 	gd_type = (smb_domain_type_t)data->kd_type;
1416 	rid = param->rid;
1417 
1418 	switch (gd_type) {
1419 	case SMB_DOMAIN_BUILTIN:
1420 		(void) snprintf(sidstr, SMB_SID_STRSZ, "%s-%d",
1421 		    NT_BUILTIN_DOMAIN_SIDSTR, rid);
1422 		if ((sid = smb_sid_fromstr(sidstr)) == NULL) {
1423 			status = NT_STATUS_NO_SUCH_ALIAS;
1424 			goto open_alias_err;
1425 		}
1426 
1427 		wka = smb_wka_lookup_sid(sid);
1428 		smb_sid_free(sid);
1429 
1430 		if (wka == NULL) {
1431 			status = NT_STATUS_NO_SUCH_ALIAS;
1432 			goto open_alias_err;
1433 		}
1434 		break;
1435 
1436 	case SMB_DOMAIN_LOCAL:
1437 		rc = smb_lgrp_getbyrid(rid, gd_type, NULL);
1438 		if (rc != SMB_LGRP_SUCCESS) {
1439 			status = NT_STATUS_NO_SUCH_ALIAS;
1440 			goto open_alias_err;
1441 		}
1442 		break;
1443 
1444 	default:
1445 		status = NT_STATUS_NO_SUCH_ALIAS;
1446 		goto open_alias_err;
1447 	}
1448 
1449 	id = samr_hdalloc(mxa, SAMR_KEY_ALIAS, data->kd_type, param->rid);
1450 	if (id) {
1451 		bcopy(id, &param->alias_handle, sizeof (samr_handle_t));
1452 		param->status = NT_STATUS_SUCCESS;
1453 		return (NDR_DRC_OK);
1454 	}
1455 
1456 	status = NT_STATUS_NO_MEMORY;
1457 
1458 open_alias_err:
1459 	bzero(&param->alias_handle, sizeof (samr_handle_t));
1460 	param->status = NT_SC_ERROR(status);
1461 	return (NDR_DRC_OK);
1462 }
1463 
1464 /*
1465  * samr_s_CreateDomainAlias
1466  *
1467  * Create a local group in the security accounts manager (SAM) database.
1468  * A local SAM group can only be added if a Solaris group already exists
1469  * with the same name.  On success, a valid group handle is returned.
1470  *
1471  * The caller must have administrator rights to execute this function.
1472  */
1473 static int
1474 samr_s_CreateDomainAlias(void *arg, ndr_xa_t *mxa)
1475 {
1476 	struct samr_CreateDomainAlias *param = arg;
1477 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1478 	uint32_t status = NT_STATUS_SUCCESS;
1479 	smb_group_t grp;
1480 	uint32_t rc;
1481 	char *gname;
1482 
1483 	if (samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN) != NULL) {
1484 		bzero(param, sizeof (struct samr_CreateDomainAlias));
1485 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1486 		return (NDR_DRC_OK);
1487 	}
1488 
1489 	gname = (char *)param->alias_name.str;
1490 	if (gname == NULL) {
1491 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1492 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1493 		return (NDR_DRC_OK);
1494 	}
1495 
1496 	if ((!ndr_is_admin(mxa)) ||
1497 	    ((param->access_mask & SAMR_ALIAS_ACCESS_WRITE_ACCOUNT) == 0)) {
1498 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1499 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1500 		return (NDR_DRC_OK);
1501 	}
1502 
1503 	if (getgrnam(gname) == NULL) {
1504 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1505 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER);
1506 		return (NDR_DRC_OK);
1507 	}
1508 
1509 	rc = smb_lgrp_add(gname, "");
1510 	if (rc != SMB_LGRP_SUCCESS) {
1511 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1512 		status = smb_lgrp_err_to_ntstatus(rc);
1513 		param->status = NT_SC_ERROR(status);
1514 		return (NDR_DRC_OK);
1515 	}
1516 
1517 	rc = smb_lgrp_getbyname((char *)gname, &grp);
1518 	if (rc != SMB_LGRP_SUCCESS) {
1519 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1520 		status = smb_lgrp_err_to_ntstatus(rc);
1521 		param->status = NT_SC_ERROR(status);
1522 		return (NDR_DRC_OK);
1523 	}
1524 
1525 	id = samr_hdalloc(mxa, SAMR_KEY_ALIAS, SMB_DOMAIN_LOCAL, grp.sg_rid);
1526 	smb_lgrp_free(&grp);
1527 	if (id) {
1528 		bcopy(id, &param->alias_handle, sizeof (samr_handle_t));
1529 		param->status = status;
1530 	} else {
1531 		bzero(&param->alias_handle, sizeof (samr_handle_t));
1532 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1533 	}
1534 
1535 	return (NDR_DRC_OK);
1536 }
1537 
1538 /*
1539  * samr_s_SetAliasInfo
1540  *
1541  * Similar to NetLocalGroupSetInfo.
1542  */
1543 static int
1544 samr_s_SetAliasInfo(void *arg, ndr_xa_t *mxa)
1545 {
1546 	struct samr_SetAliasInfo *param = arg;
1547 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1548 	DWORD status = NT_STATUS_SUCCESS;
1549 
1550 	if (samr_hdlookup(mxa, id, SAMR_KEY_ALIAS) == NULL)
1551 		status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1552 
1553 	param->status = status;
1554 	return (NDR_DRC_OK);
1555 }
1556 
1557 /*
1558  * samr_s_QueryAliasInfo
1559  *
1560  * Retrieves information about the specified local group account
1561  * by given handle.
1562  */
1563 static int
1564 samr_s_QueryAliasInfo(void *arg, ndr_xa_t *mxa)
1565 {
1566 	struct samr_QueryAliasInfo *param = arg;
1567 	ndr_hdid_t	*id = (ndr_hdid_t *)&param->alias_handle;
1568 	ndr_handle_t	*hd;
1569 	samr_keydata_t	*data;
1570 	smb_group_t	grp;
1571 	smb_domain_type_t gd_type;
1572 	smb_sid_t	*sid;
1573 	smb_wka_t	*wka;
1574 	char		sidstr[SMB_SID_STRSZ];
1575 	char		*name;
1576 	char		*desc;
1577 	uint32_t	rid;
1578 	uint32_t	status;
1579 	int		rc;
1580 
1581 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1582 		status = NT_STATUS_INVALID_HANDLE;
1583 		goto query_alias_err;
1584 	}
1585 
1586 	data = (samr_keydata_t *)hd->nh_data;
1587 	gd_type = (smb_domain_type_t)data->kd_type;
1588 	rid = data->kd_rid;
1589 
1590 	switch (gd_type) {
1591 	case SMB_DOMAIN_BUILTIN:
1592 		(void) snprintf(sidstr, SMB_SID_STRSZ, "%s-%d",
1593 		    NT_BUILTIN_DOMAIN_SIDSTR, rid);
1594 		if ((sid = smb_sid_fromstr(sidstr)) == NULL) {
1595 			status = NT_STATUS_NO_SUCH_ALIAS;
1596 			goto query_alias_err;
1597 		}
1598 
1599 		wka = smb_wka_lookup_sid(sid);
1600 		smb_sid_free(sid);
1601 
1602 		if (wka == NULL) {
1603 			status = NT_STATUS_NO_SUCH_ALIAS;
1604 			goto query_alias_err;
1605 		}
1606 
1607 		name = wka->wka_name;
1608 		desc = (wka->wka_desc != NULL) ? wka->wka_desc : "";
1609 		break;
1610 
1611 	case SMB_DOMAIN_LOCAL:
1612 		rc = smb_lgrp_getbyrid(rid, gd_type, &grp);
1613 		if (rc != SMB_LGRP_SUCCESS) {
1614 			status = NT_STATUS_NO_SUCH_ALIAS;
1615 			goto query_alias_err;
1616 		}
1617 		name = grp.sg_name;
1618 		desc = grp.sg_cmnt;
1619 		break;
1620 
1621 	default:
1622 		status = NT_STATUS_NO_SUCH_ALIAS;
1623 		goto query_alias_err;
1624 	}
1625 
1626 	switch (param->level) {
1627 	case SAMR_QUERY_ALIAS_INFO_1:
1628 		param->ru.info1.level = param->level;
1629 		(void) NDR_MSTRING(mxa, name,
1630 		    (ndr_mstring_t *)&param->ru.info1.name);
1631 
1632 		(void) NDR_MSTRING(mxa, desc,
1633 		    (ndr_mstring_t *)&param->ru.info1.desc);
1634 
1635 		param->ru.info1.unknown = 1;
1636 		break;
1637 
1638 	case SAMR_QUERY_ALIAS_INFO_3:
1639 		param->ru.info3.level = param->level;
1640 		(void) NDR_MSTRING(mxa, desc,
1641 		    (ndr_mstring_t *)&param->ru.info3.desc);
1642 		break;
1643 
1644 	default:
1645 		if (gd_type == SMB_DOMAIN_LOCAL)
1646 			smb_lgrp_free(&grp);
1647 		status = NT_STATUS_INVALID_INFO_CLASS;
1648 		goto query_alias_err;
1649 	};
1650 
1651 	if (gd_type == SMB_DOMAIN_LOCAL)
1652 		smb_lgrp_free(&grp);
1653 	param->address = (DWORD)(uintptr_t)&param->ru;
1654 	param->status = 0;
1655 	return (NDR_DRC_OK);
1656 
1657 query_alias_err:
1658 	param->status = NT_SC_ERROR(status);
1659 	return (NDR_DRC_OK);
1660 }
1661 
1662 /*
1663  * samr_s_DeleteDomainAlias
1664  *
1665  * Deletes a local group in the security database, which is the
1666  * security accounts manager (SAM). A valid group handle is returned
1667  * to the caller upon success.
1668  *
1669  * The caller must have administrator rights to execute this function.
1670  */
1671 static int
1672 samr_s_DeleteDomainAlias(void *arg, ndr_xa_t *mxa)
1673 {
1674 	struct samr_DeleteDomainAlias *param = arg;
1675 	ndr_hdid_t *id = (ndr_hdid_t *)&param->alias_handle;
1676 	ndr_handle_t	*hd;
1677 	smb_group_t grp;
1678 	samr_keydata_t	*data;
1679 	smb_domain_type_t	gd_type;
1680 	uint32_t	rid;
1681 	uint32_t	rc;
1682 	uint32_t	status = NT_STATUS_SUCCESS;
1683 
1684 	if (!ndr_is_admin(mxa)) {
1685 		bzero(param, sizeof (struct samr_DeleteDomainAlias));
1686 		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1687 		return (NDR_DRC_OK);
1688 	}
1689 
1690 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1691 		bzero(param, sizeof (struct samr_DeleteDomainAlias));
1692 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1693 		return (NDR_DRC_OK);
1694 	}
1695 
1696 	data = (samr_keydata_t *)hd->nh_data;
1697 	gd_type = (smb_domain_type_t)data->kd_type;
1698 	rid = data->kd_rid;
1699 
1700 	switch (gd_type) {
1701 	case SMB_DOMAIN_BUILTIN:
1702 		bzero(param, sizeof (struct samr_DeleteDomainAlias));
1703 		status = NT_SC_ERROR(NT_STATUS_NOT_SUPPORTED);
1704 		break;
1705 
1706 	case SMB_DOMAIN_LOCAL:
1707 		rc = smb_lgrp_getbyrid(rid, gd_type, &grp);
1708 		if (rc != SMB_LGRP_SUCCESS) {
1709 			bzero(param, sizeof (struct samr_DeleteDomainAlias));
1710 			status = smb_lgrp_err_to_ntstatus(rc);
1711 			status = NT_SC_ERROR(status);
1712 			break;
1713 		}
1714 
1715 		rc = smb_lgrp_delete(grp.sg_name);
1716 		if (rc != SMB_LGRP_SUCCESS) {
1717 			bzero(param, sizeof (struct samr_DeleteDomainAlias));
1718 			status = smb_lgrp_err_to_ntstatus(rc);
1719 			status = NT_SC_ERROR(status);
1720 		}
1721 		smb_lgrp_free(&grp);
1722 		break;
1723 
1724 	default:
1725 		bzero(param, sizeof (struct samr_DeleteDomainAlias));
1726 		status = NT_SC_ERROR(NT_STATUS_NO_SUCH_ALIAS);
1727 	}
1728 
1729 	param->status = status;
1730 	return (NDR_DRC_OK);
1731 }
1732 
1733 /*
1734  * samr_s_EnumDomainAliases
1735  *
1736  * This function sends back a list which contains all local groups' name.
1737  */
1738 static int
1739 samr_s_EnumDomainAliases(void *arg, ndr_xa_t *mxa)
1740 {
1741 	struct samr_EnumDomainAliases *param = arg;
1742 	ndr_hdid_t *id = (ndr_hdid_t *)&param->domain_handle;
1743 	ndr_handle_t *hd;
1744 	samr_keydata_t *data;
1745 	smb_group_t grp;
1746 	smb_giter_t gi;
1747 	int cnt, skip, i;
1748 	struct name_rid *info;
1749 
1750 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1751 		bzero(param, sizeof (struct samr_EnumDomainAliases));
1752 		param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1753 		return (NDR_DRC_OK);
1754 	}
1755 
1756 	data = (samr_keydata_t *)hd->nh_data;
1757 
1758 	cnt = smb_sam_grp_cnt(data->kd_type);
1759 	if (cnt <= param->resume_handle) {
1760 		param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1761 		    sizeof (struct aliases_info));
1762 
1763 		if (param->aliases == NULL) {
1764 			bzero(param, sizeof (struct samr_EnumDomainAliases));
1765 			param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1766 			return (NDR_DRC_OK);
1767 		}
1768 
1769 		bzero(param->aliases, sizeof (struct aliases_info));
1770 		param->out_resume = 0;
1771 		param->entries = 0;
1772 		param->status = NT_STATUS_SUCCESS;
1773 		return (NDR_DRC_OK);
1774 	}
1775 
1776 	cnt -= param->resume_handle;
1777 	param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1778 	    sizeof (struct aliases_info) + (cnt-1) * sizeof (struct name_rid));
1779 
1780 	if (param->aliases == NULL) {
1781 		bzero(param, sizeof (struct samr_EnumDomainAliases));
1782 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1783 		return (NDR_DRC_OK);
1784 	}
1785 
1786 	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
1787 		bzero(param, sizeof (struct samr_EnumDomainAliases));
1788 		param->status = NT_SC_ERROR(NT_STATUS_INTERNAL_ERROR);
1789 		return (NDR_DRC_OK);
1790 	}
1791 
1792 	skip = i = 0;
1793 	info = param->aliases->info;
1794 	while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
1795 		if ((skip++ >= param->resume_handle) &&
1796 		    (grp.sg_domain == data->kd_type) && (i++ < cnt)) {
1797 			info->rid = grp.sg_rid;
1798 			(void) NDR_MSTRING(mxa, grp.sg_name,
1799 			    (ndr_mstring_t *)&info->name);
1800 
1801 			info++;
1802 		}
1803 		smb_lgrp_free(&grp);
1804 	}
1805 	smb_lgrp_iterclose(&gi);
1806 
1807 	param->aliases->count = i;
1808 	param->aliases->address = i;
1809 
1810 	param->out_resume = i;
1811 	param->entries = i;
1812 	param->status = 0;
1813 	return (NDR_DRC_OK);
1814 }
1815 
1816 /*
1817  * samr_s_Connect3
1818  */
1819 static int
1820 samr_s_Connect3(void *arg, ndr_xa_t *mxa)
1821 {
1822 	struct samr_Connect3	*param = arg;
1823 	ndr_hdid_t		*id;
1824 
1825 	id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
1826 	if (id) {
1827 		bcopy(id, &param->handle, sizeof (samr_handle_t));
1828 		param->status = 0;
1829 	} else {
1830 		bzero(&param->handle, sizeof (samr_handle_t));
1831 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1832 	}
1833 
1834 	return (NDR_DRC_OK);
1835 }
1836 
1837 /*
1838  * samr_s_Connect4
1839  *
1840  * This is the connect4 form of the connect request used by Windows XP.
1841  * Returns an RPC fault for now.
1842  */
1843 /*ARGSUSED*/
1844 static int
1845 samr_s_Connect4(void *arg, ndr_xa_t *mxa)
1846 {
1847 	struct samr_Connect4 *param = arg;
1848 
1849 	bzero(param, sizeof (struct samr_Connect4));
1850 	return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
1851 }
1852 
1853 static ndr_stub_table_t samr_stub_table[] = {
1854 	{ samr_s_ConnectAnon,		SAMR_OPNUM_ConnectAnon },
1855 	{ samr_s_CloseHandle,		SAMR_OPNUM_CloseHandle },
1856 	{ samr_s_LookupDomain,		SAMR_OPNUM_LookupDomain },
1857 	{ samr_s_EnumLocalDomains,	SAMR_OPNUM_EnumLocalDomains },
1858 	{ samr_s_OpenDomain,		SAMR_OPNUM_OpenDomain },
1859 	{ samr_s_QueryDomainInfo,	SAMR_OPNUM_QueryDomainInfo },
1860 	{ samr_s_QueryInfoDomain2,	SAMR_OPNUM_QueryInfoDomain2 },
1861 	{ samr_s_LookupNames,		SAMR_OPNUM_LookupNames },
1862 	{ samr_s_OpenUser,		SAMR_OPNUM_OpenUser },
1863 	{ samr_s_DeleteUser,		SAMR_OPNUM_DeleteUser },
1864 	{ samr_s_QueryUserInfo,		SAMR_OPNUM_QueryUserInfo },
1865 	{ samr_s_QueryUserGroups,	SAMR_OPNUM_QueryUserGroups },
1866 	{ samr_s_OpenGroup,		SAMR_OPNUM_OpenGroup },
1867 	{ samr_s_Connect,		SAMR_OPNUM_Connect },
1868 	{ samr_s_GetUserPwInfo,		SAMR_OPNUM_GetUserPwInfo },
1869 	{ samr_s_CreateUser,		SAMR_OPNUM_CreateUser },
1870 	{ samr_s_ChangeUserPasswd,	SAMR_OPNUM_ChangeUserPasswd },
1871 	{ samr_s_GetDomainPwInfo,	SAMR_OPNUM_GetDomainPwInfo },
1872 	{ samr_s_SetUserInfo,		SAMR_OPNUM_SetUserInfo },
1873 	{ samr_s_Connect3,		SAMR_OPNUM_Connect3 },
1874 	{ samr_s_Connect4,		SAMR_OPNUM_Connect4 },
1875 	{ samr_s_QueryDispInfo,		SAMR_OPNUM_QueryDispInfo },
1876 	{ samr_s_OpenAlias,		SAMR_OPNUM_OpenAlias },
1877 	{ samr_s_CreateDomainAlias,	SAMR_OPNUM_CreateDomainAlias },
1878 	{ samr_s_SetAliasInfo,		SAMR_OPNUM_SetAliasInfo },
1879 	{ samr_s_QueryAliasInfo,	SAMR_OPNUM_QueryAliasInfo },
1880 	{ samr_s_DeleteDomainAlias,	SAMR_OPNUM_DeleteDomainAlias },
1881 	{ samr_s_EnumDomainAliases,	SAMR_OPNUM_EnumDomainAliases },
1882 	{ samr_s_EnumDomainGroups,	SAMR_OPNUM_EnumDomainGroups },
1883 	{ samr_s_AddAliasMember,	SAMR_OPNUM_AddAliasMember },
1884 	{ samr_s_DeleteAliasMember,	SAMR_OPNUM_DeleteAliasMember },
1885 	{ samr_s_ListAliasMembers,	SAMR_OPNUM_ListAliasMembers },
1886 	{0}
1887 };
1888 
1889 /*
1890  * There is a bug in the way that midl and the marshalling code handles
1891  * unions so we need to fix some of the data offsets at runtime. The
1892  * following macros and the fixup functions handle the corrections.
1893  */
1894 
1895 DECL_FIXUP_STRUCT(samr_QueryAliasInfo_ru);
1896 DECL_FIXUP_STRUCT(samr_QueryAliasInfoRes);
1897 DECL_FIXUP_STRUCT(samr_QueryAliasInfo);
1898 
1899 DECL_FIXUP_STRUCT(QueryUserInfo_result_u);
1900 DECL_FIXUP_STRUCT(QueryUserInfo_result);
1901 DECL_FIXUP_STRUCT(samr_QueryUserInfo);
1902 
1903 void
1904 fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo *val)
1905 {
1906 	unsigned short size1 = 0;
1907 	unsigned short size2 = 0;
1908 	unsigned short size3 = 0;
1909 
1910 	switch (val->level) {
1911 		CASE_INFO_ENT(samr_QueryAliasInfo, 1);
1912 		CASE_INFO_ENT(samr_QueryAliasInfo, 3);
1913 
1914 		default:
1915 			return;
1916 	};
1917 
1918 	size2 = size1 + (2 * sizeof (DWORD));
1919 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1920 
1921 	FIXUP_PDU_SIZE(samr_QueryAliasInfo_ru, size1);
1922 	FIXUP_PDU_SIZE(samr_QueryAliasInfoRes, size2);
1923 	FIXUP_PDU_SIZE(samr_QueryAliasInfo, size3);
1924 }
1925 
1926 void
1927 fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val)
1928 {
1929 	unsigned short size1 = 0;
1930 	unsigned short size2 = 0;
1931 	unsigned short size3 = 0;
1932 
1933 	switch (val->switch_index) {
1934 		CASE_INFO_ENT(samr_QueryUserInfo, 1);
1935 		CASE_INFO_ENT(samr_QueryUserInfo, 6);
1936 		CASE_INFO_ENT(samr_QueryUserInfo, 7);
1937 		CASE_INFO_ENT(samr_QueryUserInfo, 8);
1938 		CASE_INFO_ENT(samr_QueryUserInfo, 9);
1939 		CASE_INFO_ENT(samr_QueryUserInfo, 16);
1940 		CASE_INFO_ENT(samr_QueryUserInfo, 21);
1941 
1942 		default:
1943 			return;
1944 	};
1945 
1946 	size2 = size1 + (2 * sizeof (DWORD));
1947 	size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1948 
1949 	FIXUP_PDU_SIZE(QueryUserInfo_result_u, size1);
1950 	FIXUP_PDU_SIZE(QueryUserInfo_result, size2);
1951 	FIXUP_PDU_SIZE(samr_QueryUserInfo, size3);
1952 }
1953 
1954 /*
1955  * As long as there is only one entry in the union, there is no need
1956  * to patch anything.
1957  */
1958 /*ARGSUSED*/
1959 void
1960 fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo *val)
1961 {
1962 }
1963