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