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