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