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