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