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 2012 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_1:
1622 param->ru.info1.level = param->level;
1623 (void) NDR_MSTRING(mxa, name,
1624 (ndr_mstring_t *)¶m->ru.info1.name);
1625
1626 (void) NDR_MSTRING(mxa, desc,
1627 (ndr_mstring_t *)¶m->ru.info1.desc);
1628
1629 param->ru.info1.unknown = 1;
1630 break;
1631
1632 case SAMR_QUERY_ALIAS_INFO_3:
1633 param->ru.info3.level = param->level;
1634 (void) NDR_MSTRING(mxa, desc,
1635 (ndr_mstring_t *)¶m->ru.info3.desc);
1636 break;
1637
1638 default:
1639 if (gd_type == SMB_DOMAIN_LOCAL)
1640 smb_lgrp_free(&grp);
1641 status = NT_STATUS_INVALID_INFO_CLASS;
1642 goto query_alias_err;
1643 };
1644
1645 if (gd_type == SMB_DOMAIN_LOCAL)
1646 smb_lgrp_free(&grp);
1647 param->address = (DWORD)(uintptr_t)¶m->ru;
1648 param->status = 0;
1649 return (NDR_DRC_OK);
1650
1651 query_alias_err:
1652 param->status = NT_SC_ERROR(status);
1653 return (NDR_DRC_OK);
1654 }
1655
1656 /*
1657 * samr_s_DeleteDomainAlias
1658 *
1659 * Deletes a local group in the security database, which is the
1660 * security accounts manager (SAM). A valid group handle is returned
1661 * to the caller upon success.
1662 *
1663 * The caller must have administrator rights to execute this function.
1664 */
1665 static int
samr_s_DeleteDomainAlias(void * arg,ndr_xa_t * mxa)1666 samr_s_DeleteDomainAlias(void *arg, ndr_xa_t *mxa)
1667 {
1668 struct samr_DeleteDomainAlias *param = arg;
1669 ndr_hdid_t *id = (ndr_hdid_t *)¶m->alias_handle;
1670 ndr_handle_t *hd;
1671 smb_group_t grp;
1672 samr_keydata_t *data;
1673 smb_domain_type_t gd_type;
1674 uint32_t rid;
1675 uint32_t rc;
1676 uint32_t status = NT_STATUS_SUCCESS;
1677
1678 if (!ndr_is_admin(mxa)) {
1679 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1680 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
1681 return (NDR_DRC_OK);
1682 }
1683
1684 if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_ALIAS)) == NULL) {
1685 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1686 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1687 return (NDR_DRC_OK);
1688 }
1689
1690 data = (samr_keydata_t *)hd->nh_data;
1691 gd_type = (smb_domain_type_t)data->kd_type;
1692 rid = data->kd_rid;
1693
1694 switch (gd_type) {
1695 case SMB_DOMAIN_BUILTIN:
1696 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1697 status = NT_SC_ERROR(NT_STATUS_NOT_SUPPORTED);
1698 break;
1699
1700 case SMB_DOMAIN_LOCAL:
1701 rc = smb_lgrp_getbyrid(rid, gd_type, &grp);
1702 if (rc != SMB_LGRP_SUCCESS) {
1703 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1704 status = smb_lgrp_err_to_ntstatus(rc);
1705 status = NT_SC_ERROR(status);
1706 break;
1707 }
1708
1709 rc = smb_lgrp_delete(grp.sg_name);
1710 if (rc != SMB_LGRP_SUCCESS) {
1711 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1712 status = smb_lgrp_err_to_ntstatus(rc);
1713 status = NT_SC_ERROR(status);
1714 }
1715 smb_lgrp_free(&grp);
1716 break;
1717
1718 default:
1719 bzero(param, sizeof (struct samr_DeleteDomainAlias));
1720 status = NT_SC_ERROR(NT_STATUS_NO_SUCH_ALIAS);
1721 }
1722
1723 param->status = status;
1724 return (NDR_DRC_OK);
1725 }
1726
1727 /*
1728 * samr_s_EnumDomainAliases
1729 *
1730 * This function sends back a list which contains all local groups' name.
1731 */
1732 static int
samr_s_EnumDomainAliases(void * arg,ndr_xa_t * mxa)1733 samr_s_EnumDomainAliases(void *arg, ndr_xa_t *mxa)
1734 {
1735 struct samr_EnumDomainAliases *param = arg;
1736 ndr_hdid_t *id = (ndr_hdid_t *)¶m->domain_handle;
1737 ndr_handle_t *hd;
1738 samr_keydata_t *data;
1739 smb_group_t grp;
1740 smb_giter_t gi;
1741 int cnt, skip, i;
1742 struct name_rid *info;
1743
1744 if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
1745 bzero(param, sizeof (struct samr_EnumDomainAliases));
1746 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
1747 return (NDR_DRC_OK);
1748 }
1749
1750 data = (samr_keydata_t *)hd->nh_data;
1751
1752 cnt = smb_sam_grp_cnt(data->kd_type);
1753 if (cnt <= param->resume_handle) {
1754 param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1755 sizeof (struct aliases_info));
1756
1757 if (param->aliases == NULL) {
1758 bzero(param, sizeof (struct samr_EnumDomainAliases));
1759 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1760 return (NDR_DRC_OK);
1761 }
1762
1763 bzero(param->aliases, sizeof (struct aliases_info));
1764 param->out_resume = 0;
1765 param->entries = 0;
1766 param->status = NT_STATUS_SUCCESS;
1767 return (NDR_DRC_OK);
1768 }
1769
1770 cnt -= param->resume_handle;
1771 param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
1772 sizeof (struct aliases_info) + (cnt-1) * sizeof (struct name_rid));
1773
1774 if (param->aliases == NULL) {
1775 bzero(param, sizeof (struct samr_EnumDomainAliases));
1776 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1777 return (NDR_DRC_OK);
1778 }
1779
1780 if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
1781 bzero(param, sizeof (struct samr_EnumDomainAliases));
1782 param->status = NT_SC_ERROR(NT_STATUS_INTERNAL_ERROR);
1783 return (NDR_DRC_OK);
1784 }
1785
1786 skip = i = 0;
1787 info = param->aliases->info;
1788 while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
1789 if ((skip++ >= param->resume_handle) &&
1790 (grp.sg_domain == data->kd_type) && (i++ < cnt)) {
1791 info->rid = grp.sg_rid;
1792 (void) NDR_MSTRING(mxa, grp.sg_name,
1793 (ndr_mstring_t *)&info->name);
1794
1795 info++;
1796 }
1797 smb_lgrp_free(&grp);
1798 }
1799 smb_lgrp_iterclose(&gi);
1800
1801 param->aliases->count = i;
1802 param->aliases->address = i;
1803
1804 param->out_resume = i;
1805 param->entries = i;
1806 param->status = 0;
1807 return (NDR_DRC_OK);
1808 }
1809
1810 /*
1811 * samr_s_Connect4
1812 */
1813 static int
samr_s_Connect4(void * arg,ndr_xa_t * mxa)1814 samr_s_Connect4(void *arg, ndr_xa_t *mxa)
1815 {
1816 struct samr_Connect4 *param = arg;
1817 ndr_hdid_t *id;
1818
1819 id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0);
1820 if (id) {
1821 bcopy(id, ¶m->handle, sizeof (samr_handle_t));
1822 param->status = 0;
1823 } else {
1824 bzero(¶m->handle, sizeof (samr_handle_t));
1825 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
1826 }
1827
1828 return (NDR_DRC_OK);
1829 }
1830
1831 /*
1832 * samr_s_Connect5
1833 *
1834 * This is the connect5 form of the connect request used by Windows XP.
1835 * Returns an RPC fault for now.
1836 */
1837 /*ARGSUSED*/
1838 static int
samr_s_Connect5(void * arg,ndr_xa_t * mxa)1839 samr_s_Connect5(void *arg, ndr_xa_t *mxa)
1840 {
1841 struct samr_Connect5 *param = arg;
1842
1843 bzero(param, sizeof (struct samr_Connect5));
1844 return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID);
1845 }
1846
1847 static ndr_stub_table_t samr_stub_table[] = {
1848 { samr_s_Connect, SAMR_OPNUM_Connect },
1849 { samr_s_CloseHandle, SAMR_OPNUM_CloseHandle },
1850 { samr_s_LookupDomain, SAMR_OPNUM_LookupDomain },
1851 { samr_s_EnumLocalDomains, SAMR_OPNUM_EnumLocalDomains },
1852 { samr_s_OpenDomain, SAMR_OPNUM_OpenDomain },
1853 { samr_s_QueryDomainInfo, SAMR_OPNUM_QueryDomainInfo },
1854 { samr_s_QueryInfoDomain2, SAMR_OPNUM_QueryInfoDomain2 },
1855 { samr_s_LookupNames, SAMR_OPNUM_LookupNames },
1856 { samr_s_OpenUser, SAMR_OPNUM_OpenUser },
1857 { samr_s_DeleteUser, SAMR_OPNUM_DeleteUser },
1858 { samr_s_QueryUserInfo, SAMR_OPNUM_QueryUserInfo },
1859 { samr_s_QueryUserGroups, SAMR_OPNUM_QueryUserGroups },
1860 { samr_s_OpenGroup, SAMR_OPNUM_OpenGroup },
1861 { samr_s_Connect2, SAMR_OPNUM_Connect2 },
1862 { samr_s_GetUserPwInfo, SAMR_OPNUM_GetUserPwInfo },
1863 { samr_s_CreateUser, SAMR_OPNUM_CreateUser },
1864 { samr_s_ChangePasswordUser2, SAMR_OPNUM_ChangePasswordUser2 },
1865 { samr_s_GetDomainPwInfo, SAMR_OPNUM_GetDomainPwInfo },
1866 { samr_s_SetUserInfo, SAMR_OPNUM_SetUserInfo },
1867 { samr_s_Connect4, SAMR_OPNUM_Connect4 },
1868 { samr_s_Connect5, SAMR_OPNUM_Connect5 },
1869 { samr_s_QueryDispInfo, SAMR_OPNUM_QueryDispInfo },
1870 { samr_s_OpenAlias, SAMR_OPNUM_OpenAlias },
1871 { samr_s_CreateDomainAlias, SAMR_OPNUM_CreateDomainAlias },
1872 { samr_s_SetAliasInfo, SAMR_OPNUM_SetAliasInfo },
1873 { samr_s_QueryAliasInfo, SAMR_OPNUM_QueryAliasInfo },
1874 { samr_s_DeleteDomainAlias, SAMR_OPNUM_DeleteDomainAlias },
1875 { samr_s_EnumDomainAliases, SAMR_OPNUM_EnumDomainAliases },
1876 { samr_s_EnumDomainGroups, SAMR_OPNUM_EnumDomainGroups },
1877 { samr_s_AddAliasMember, SAMR_OPNUM_AddAliasMember },
1878 { samr_s_DeleteAliasMember, SAMR_OPNUM_DeleteAliasMember },
1879 { samr_s_ListAliasMembers, SAMR_OPNUM_ListAliasMembers },
1880 {0}
1881 };
1882
1883 /*
1884 * There is a bug in the way that midl and the marshalling code handles
1885 * unions so we need to fix some of the data offsets at runtime. The
1886 * following macros and the fixup functions handle the corrections.
1887 */
1888
1889 DECL_FIXUP_STRUCT(samr_QueryAliasInfo_ru);
1890 DECL_FIXUP_STRUCT(samr_QueryAliasInfoRes);
1891 DECL_FIXUP_STRUCT(samr_QueryAliasInfo);
1892
1893 DECL_FIXUP_STRUCT(QueryUserInfo_result_u);
1894 DECL_FIXUP_STRUCT(QueryUserInfo_result);
1895 DECL_FIXUP_STRUCT(samr_QueryUserInfo);
1896
1897 void
fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo * val)1898 fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo *val)
1899 {
1900 unsigned short size1 = 0;
1901 unsigned short size2 = 0;
1902 unsigned short size3 = 0;
1903
1904 switch (val->level) {
1905 CASE_INFO_ENT(samr_QueryAliasInfo, 1);
1906 CASE_INFO_ENT(samr_QueryAliasInfo, 3);
1907
1908 default:
1909 return;
1910 };
1911
1912 size2 = size1 + (2 * sizeof (DWORD));
1913 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1914
1915 FIXUP_PDU_SIZE(samr_QueryAliasInfo_ru, size1);
1916 FIXUP_PDU_SIZE(samr_QueryAliasInfoRes, size2);
1917 FIXUP_PDU_SIZE(samr_QueryAliasInfo, size3);
1918 }
1919
1920 void
fixup_samr_QueryUserInfo(struct samr_QueryUserInfo * val)1921 fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val)
1922 {
1923 unsigned short size1 = 0;
1924 unsigned short size2 = 0;
1925 unsigned short size3 = 0;
1926
1927 switch (val->switch_index) {
1928 CASE_INFO_ENT(samr_QueryUserInfo, 1);
1929 CASE_INFO_ENT(samr_QueryUserInfo, 6);
1930 CASE_INFO_ENT(samr_QueryUserInfo, 7);
1931 CASE_INFO_ENT(samr_QueryUserInfo, 8);
1932 CASE_INFO_ENT(samr_QueryUserInfo, 9);
1933 CASE_INFO_ENT(samr_QueryUserInfo, 16);
1934 CASE_INFO_ENT(samr_QueryUserInfo, 21);
1935
1936 default:
1937 return;
1938 };
1939
1940 size2 = size1 + (2 * sizeof (DWORD));
1941 size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD);
1942
1943 FIXUP_PDU_SIZE(QueryUserInfo_result_u, size1);
1944 FIXUP_PDU_SIZE(QueryUserInfo_result, size2);
1945 FIXUP_PDU_SIZE(samr_QueryUserInfo, size3);
1946 }
1947
1948 /*
1949 * As long as there is only one entry in the union, there is no need
1950 * to patch anything.
1951 */
1952 /*ARGSUSED*/
1953 void
fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo * val)1954 fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo *val)
1955 {
1956 }
1957