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