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