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