1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * This module provides the high level interface to the LSA RPC functions. 29 */ 30 31 #include <strings.h> 32 #include <unistd.h> 33 34 #include <smbsrv/libsmb.h> 35 #include <smbsrv/libmlsvc.h> 36 #include <smbsrv/smbinfo.h> 37 #include <smbsrv/smb_token.h> 38 39 #include <lsalib.h> 40 41 static uint32_t lsa_lookup_name_int(char *, uint16_t, smb_account_t *, 42 boolean_t); 43 static uint32_t lsa_lookup_sid_int(smb_sid_t *, smb_account_t *, boolean_t); 44 45 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *); 46 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *); 47 48 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *); 49 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *); 50 51 static uint32_t lsa_list_accounts(mlsvc_handle_t *); 52 static uint32_t lsa_map_status(uint32_t); 53 54 /* 55 * Lookup the given account and returns the account information 56 * in the passed smb_account_t structure. 57 * 58 * The lookup is performed in the following order: 59 * well known accounts 60 * local accounts 61 * domain accounts 62 * 63 * If it's established the given account is well know or local 64 * but the lookup fails for some reason, the next step(s) won't be 65 * performed. 66 * 67 * If the name is a domain account, it may refer to a user, group or 68 * alias. If it is a local account, its type should be specified 69 * in the sid_type parameter. In case the account type is unknown 70 * sid_type should be set to SidTypeUnknown. 71 * 72 * account argument could be either [domain\]name or [domain/]name. 73 * 74 * Return status: 75 * 76 * NT_STATUS_SUCCESS Account is successfully translated 77 * NT_STATUS_NONE_MAPPED Couldn't translate the account 78 */ 79 uint32_t 80 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info) 81 { 82 return (lsa_lookup_name_int(account, type, info, B_TRUE)); 83 } 84 85 /* Variant that avoids the call out to AD. */ 86 uint32_t 87 lsa_lookup_lname(char *account, uint16_t type, smb_account_t *info) 88 { 89 return (lsa_lookup_name_int(account, type, info, B_FALSE)); 90 } 91 92 uint32_t 93 lsa_lookup_name_int(char *account, uint16_t type, smb_account_t *info, 94 boolean_t try_ad) 95 { 96 char nambuf[SMB_USERNAME_MAXLEN]; 97 char dombuf[SMB_PI_MAX_DOMAIN]; 98 char *name, *domain; 99 uint32_t status; 100 char *slash; 101 102 if (account == NULL) 103 return (NT_STATUS_NONE_MAPPED); 104 105 (void) strsubst(account, '/', '\\'); 106 (void) strcanon(account, "\\"); 107 /* \john -> john */ 108 account += strspn(account, "\\"); 109 110 if ((slash = strchr(account, '\\')) != NULL) { 111 *slash = '\0'; 112 (void) strlcpy(dombuf, account, sizeof (dombuf)); 113 (void) strlcpy(nambuf, slash + 1, sizeof (nambuf)); 114 *slash = '\\'; 115 name = nambuf; 116 domain = dombuf; 117 } else { 118 name = account; 119 domain = NULL; 120 } 121 122 status = lsa_lookup_name_builtin(domain, name, info); 123 if (status == NT_STATUS_NOT_FOUND) { 124 status = smb_sam_lookup_name(domain, name, type, info); 125 if (status == NT_STATUS_SUCCESS) 126 return (status); 127 128 if (try_ad && ((domain == NULL) || 129 (status == NT_STATUS_NOT_FOUND))) { 130 status = lsa_lookup_name_domain(account, info); 131 } 132 } 133 134 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 135 } 136 137 uint32_t 138 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info) 139 { 140 return (lsa_lookup_sid_int(sid, info, B_TRUE)); 141 } 142 143 /* Variant that avoids the call out to AD. */ 144 uint32_t 145 lsa_lookup_lsid(smb_sid_t *sid, smb_account_t *info) 146 { 147 return (lsa_lookup_sid_int(sid, info, B_FALSE)); 148 } 149 150 static uint32_t 151 lsa_lookup_sid_int(smb_sid_t *sid, smb_account_t *info, boolean_t try_ad) 152 { 153 uint32_t status; 154 155 if (!smb_sid_isvalid(sid)) 156 return (NT_STATUS_INVALID_SID); 157 158 status = lsa_lookup_sid_builtin(sid, info); 159 if (status == NT_STATUS_NOT_FOUND) { 160 status = smb_sam_lookup_sid(sid, info); 161 if (try_ad && status == NT_STATUS_NOT_FOUND) { 162 status = lsa_lookup_sid_domain(sid, info); 163 } 164 } 165 166 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 167 } 168 169 /* 170 * Obtains the primary domain SID and name from the specified server 171 * (domain controller). 172 * 173 * The requested information will be returned via 'info' argument. 174 * 175 * Returns NT status codes. (Raw, not LSA-ized) 176 */ 177 DWORD 178 lsa_query_primary_domain_info(char *server, char *domain, 179 smb_domain_t *info) 180 { 181 mlsvc_handle_t domain_handle; 182 char user[SMB_USERNAME_MAXLEN]; 183 DWORD status; 184 185 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 186 187 status = lsar_open(server, domain, user, &domain_handle); 188 if (status != 0) 189 return (status); 190 191 status = lsar_query_info_policy(&domain_handle, 192 MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info); 193 194 (void) lsar_close(&domain_handle); 195 return (status); 196 } 197 198 /* 199 * Obtains the account domain SID and name from the current server 200 * (domain controller). 201 * 202 * The requested information will be returned via 'info' argument. 203 * 204 * Returns NT status codes. (Raw, not LSA-ized) 205 */ 206 DWORD 207 lsa_query_account_domain_info(char *server, char *domain, 208 smb_domain_t *info) 209 { 210 mlsvc_handle_t domain_handle; 211 char user[SMB_USERNAME_MAXLEN]; 212 DWORD status; 213 214 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 215 216 status = lsar_open(server, domain, user, &domain_handle); 217 if (status != 0) 218 return (status); 219 220 status = lsar_query_info_policy(&domain_handle, 221 MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info); 222 223 (void) lsar_close(&domain_handle); 224 return (status); 225 } 226 227 /* 228 * lsa_query_dns_domain_info 229 * 230 * Obtains the DNS domain info from the specified server 231 * (domain controller). 232 * 233 * The requested information will be returned via 'info' argument. 234 * 235 * Returns NT status codes. (Raw, not LSA-ized) 236 */ 237 DWORD 238 lsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info) 239 { 240 mlsvc_handle_t domain_handle; 241 char user[SMB_USERNAME_MAXLEN]; 242 DWORD status; 243 244 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 245 246 status = lsar_open(server, domain, user, &domain_handle); 247 if (status != 0) 248 return (status); 249 250 status = lsar_query_info_policy(&domain_handle, 251 MSLSA_POLICY_DNS_DOMAIN_INFO, info); 252 253 (void) lsar_close(&domain_handle); 254 return (status); 255 } 256 257 /* 258 * Enumerate the trusted domains of primary domain. 259 * This is the basic enumaration call which only returns the 260 * NetBIOS name of the domain and its SID. 261 * 262 * The requested information will be returned via 'info' argument. 263 * 264 * Returns NT status codes. (Raw, not LSA-ized) 265 */ 266 DWORD 267 lsa_enum_trusted_domains(char *server, char *domain, 268 smb_trusted_domains_t *info) 269 { 270 mlsvc_handle_t domain_handle; 271 char user[SMB_USERNAME_MAXLEN]; 272 DWORD enum_context; 273 DWORD status; 274 275 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 276 277 status = lsar_open(server, domain, user, &domain_handle); 278 if (status != 0) 279 return (status); 280 281 enum_context = 0; 282 283 status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info); 284 if (status == NT_STATUS_NO_MORE_ENTRIES) { 285 /* 286 * STATUS_NO_MORE_ENTRIES indicates that we 287 * have all of the available information. 288 */ 289 status = NT_STATUS_SUCCESS; 290 } 291 292 (void) lsar_close(&domain_handle); 293 return (status); 294 } 295 296 /* 297 * Enumerate the trusted domains of the primary domain. 298 * This is the extended enumaration call which besides 299 * NetBIOS name of the domain and its SID, it will return 300 * the FQDN plus some trust information which is not used. 301 * 302 * The requested information will be returned via 'info' argument. 303 * 304 * Returns NT status codes. (Raw, not LSA-ized) 305 */ 306 DWORD 307 lsa_enum_trusted_domains_ex(char *server, char *domain, 308 smb_trusted_domains_t *info) 309 { 310 mlsvc_handle_t domain_handle; 311 char user[SMB_USERNAME_MAXLEN]; 312 DWORD enum_context; 313 DWORD status; 314 315 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 316 317 status = lsar_open(server, domain, user, &domain_handle); 318 if (status != 0) 319 return (status); 320 321 enum_context = 0; 322 323 status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context, 324 info); 325 if (status == NT_STATUS_NO_MORE_ENTRIES) { 326 /* 327 * STATUS_NO_MORE_ENTRIES indicates that we 328 * have all of the available information. 329 */ 330 status = NT_STATUS_SUCCESS; 331 } 332 333 (void) lsar_close(&domain_handle); 334 return (status); 335 } 336 337 /* 338 * Lookup well known accounts table 339 * 340 * Return status: 341 * 342 * NT_STATUS_SUCCESS Account is translated successfully 343 * NT_STATUS_NOT_FOUND This is not a well known account 344 * NT_STATUS_NONE_MAPPED Account is found but domains don't match 345 * NT_STATUS_NO_MEMORY Memory shortage 346 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 347 */ 348 static uint32_t 349 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info) 350 { 351 smb_wka_t *wka; 352 char *wkadom; 353 354 bzero(info, sizeof (smb_account_t)); 355 356 if ((wka = smb_wka_lookup_name(name)) == NULL) 357 return (NT_STATUS_NOT_FOUND); 358 359 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 360 return (NT_STATUS_INTERNAL_ERROR); 361 362 if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0)) 363 return (NT_STATUS_NONE_MAPPED); 364 365 info->a_name = strdup(name); 366 info->a_sid = smb_sid_dup(wka->wka_binsid); 367 info->a_domain = strdup(wkadom); 368 info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid); 369 info->a_type = wka->wka_type; 370 371 if (!smb_account_validate(info)) { 372 smb_account_free(info); 373 return (NT_STATUS_NO_MEMORY); 374 } 375 376 return (NT_STATUS_SUCCESS); 377 } 378 379 /* 380 * Lookup a domain account by its name. 381 * 382 * The information is returned in the user_info structure. 383 * The caller is responsible for allocating and releasing 384 * this structure. 385 * 386 * Returns NT status codes. (LSA-ized) 387 */ 388 static uint32_t 389 lsa_lookup_name_domain(char *account_name, smb_account_t *info) 390 { 391 mlsvc_handle_t domain_handle; 392 smb_domainex_t dinfo; 393 char user[SMB_USERNAME_MAXLEN]; 394 uint32_t status; 395 396 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 397 398 if (!smb_domain_getinfo(&dinfo)) 399 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 400 401 status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname, 402 user, &domain_handle); 403 if (status != 0) 404 return (lsa_map_status(status)); 405 406 status = lsar_lookup_names(&domain_handle, account_name, info); 407 408 (void) lsar_close(&domain_handle); 409 return (status); 410 } 411 412 /* 413 * lsa_lookup_privs 414 * 415 * Request the privileges associated with the specified account. In 416 * order to get the privileges, we first have to lookup the name on 417 * the specified domain controller and obtain the appropriate SID. 418 * The SID can then be used to open the account and obtain the 419 * account privileges. The results from both the name lookup and the 420 * privileges are returned in the user_info structure. The caller is 421 * responsible for allocating and releasing this structure. 422 * 423 * Returns NT status codes. (LSA-ized) 424 */ 425 /*ARGSUSED*/ 426 DWORD 427 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo) 428 { 429 mlsvc_handle_t domain_handle; 430 smb_domainex_t dinfo; 431 char user[SMB_USERNAME_MAXLEN]; 432 DWORD status; 433 434 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 435 436 if (!smb_domain_getinfo(&dinfo)) 437 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 438 439 status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname, 440 user, &domain_handle); 441 if (status != 0) 442 return (lsa_map_status(status)); 443 444 status = lsa_list_accounts(&domain_handle); 445 (void) lsar_close(&domain_handle); 446 return (status); 447 } 448 449 /* 450 * lsa_list_privs 451 * 452 * List the privileges supported by the specified server. 453 * This function is only intended for diagnostics. 454 * 455 * Returns NT status codes. (LSA-ized) 456 */ 457 DWORD 458 lsa_list_privs(char *server, char *domain) 459 { 460 static char name[128]; 461 static struct ms_luid luid; 462 mlsvc_handle_t domain_handle; 463 char user[SMB_USERNAME_MAXLEN]; 464 DWORD status; 465 int rc; 466 int i; 467 468 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 469 470 status = lsar_open(server, domain, user, &domain_handle); 471 if (status != 0) 472 return (lsa_map_status(status)); 473 474 for (i = 0; i < 30; ++i) { 475 luid.low_part = i; 476 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128); 477 if (rc != 0) 478 continue; 479 480 (void) lsar_lookup_priv_value(&domain_handle, name, &luid); 481 (void) lsar_lookup_priv_display_name(&domain_handle, name, 482 name, 128); 483 } 484 485 (void) lsar_close(&domain_handle); 486 return (NT_STATUS_SUCCESS); 487 } 488 489 /* 490 * lsa_list_accounts 491 * 492 * This function can be used to list the accounts in the specified 493 * domain. For now the SIDs are just listed in the system log. 494 * 495 * Returns NT status 496 */ 497 static DWORD 498 lsa_list_accounts(mlsvc_handle_t *domain_handle) 499 { 500 mlsvc_handle_t account_handle; 501 struct mslsa_EnumAccountBuf accounts; 502 struct mslsa_sid *sid; 503 smb_account_t ainfo; 504 DWORD enum_context = 0; 505 DWORD status; 506 int i; 507 508 bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf)); 509 510 do { 511 status = lsar_enum_accounts(domain_handle, &enum_context, 512 &accounts); 513 if (status != 0) 514 return (status); 515 516 for (i = 0; i < accounts.entries_read; ++i) { 517 sid = accounts.info[i].sid; 518 519 if (lsar_open_account(domain_handle, sid, 520 &account_handle) == 0) { 521 (void) lsar_enum_privs_account(&account_handle, 522 &ainfo); 523 (void) lsar_close(&account_handle); 524 } 525 526 free(accounts.info[i].sid); 527 } 528 529 if (accounts.info) 530 free(accounts.info); 531 } while (status == 0 && accounts.entries_read != 0); 532 533 return (0); 534 } 535 536 /* 537 * Lookup well known accounts table for the given SID 538 * 539 * Return status: 540 * 541 * NT_STATUS_SUCCESS Account is translated successfully 542 * NT_STATUS_NOT_FOUND This is not a well known account 543 * NT_STATUS_NO_MEMORY Memory shortage 544 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 545 */ 546 static uint32_t 547 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo) 548 { 549 smb_wka_t *wka; 550 char *wkadom; 551 552 bzero(ainfo, sizeof (smb_account_t)); 553 554 if ((wka = smb_wka_lookup_sid(sid)) == NULL) 555 return (NT_STATUS_NOT_FOUND); 556 557 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 558 return (NT_STATUS_INTERNAL_ERROR); 559 560 ainfo->a_name = strdup(wka->wka_name); 561 ainfo->a_sid = smb_sid_dup(wka->wka_binsid); 562 ainfo->a_domain = strdup(wkadom); 563 ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid); 564 ainfo->a_type = wka->wka_type; 565 566 if (!smb_account_validate(ainfo)) { 567 smb_account_free(ainfo); 568 return (NT_STATUS_NO_MEMORY); 569 } 570 571 return (NT_STATUS_SUCCESS); 572 } 573 574 /* 575 * Lookup a domain account by its SID. 576 * 577 * The information is returned in the user_info structure. 578 * The caller is responsible for allocating and releasing 579 * this structure. 580 * 581 * Returns NT status codes. (LSA-ized) 582 */ 583 static uint32_t 584 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo) 585 { 586 mlsvc_handle_t domain_handle; 587 smb_domainex_t dinfo; 588 char user[SMB_USERNAME_MAXLEN]; 589 uint32_t status; 590 591 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 592 593 if (!smb_domain_getinfo(&dinfo)) 594 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 595 596 status = lsar_open(dinfo.d_dci.dc_name, dinfo.d_primary.di_nbname, 597 user, &domain_handle); 598 if (status != 0) 599 return (lsa_map_status(status)); 600 601 status = lsar_lookup_sids(&domain_handle, sid, ainfo); 602 603 (void) lsar_close(&domain_handle); 604 return (status); 605 } 606 607 /* 608 * Most functions that call the local security authority expect 609 * only a limited set of status returns. This function maps the 610 * status we get from talking to our domain controller into one 611 * that LSA functions can return. Most common errors become: 612 * NT_STATUS_CANT_ACCESS_DOMAIN_INFO (when no DC etc.) 613 */ 614 static uint32_t 615 lsa_map_status(uint32_t status) 616 { 617 switch (status) { 618 case NT_STATUS_SUCCESS: 619 break; 620 case NT_STATUS_INVALID_PARAMETER: /* rpc bind */ 621 break; 622 case NT_STATUS_NO_MEMORY: 623 break; 624 case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND: 625 case NT_STATUS_BAD_NETWORK_PATH: /* get server addr */ 626 case NT_STATUS_NETWORK_ACCESS_DENIED: /* authentication */ 627 case NT_STATUS_BAD_NETWORK_NAME: /* tree connect */ 628 case NT_STATUS_ACCESS_DENIED: /* open pipe */ 629 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 630 break; 631 default: 632 status = NT_STATUS_UNSUCCESSFUL; 633 break; 634 } 635 return (status); 636 } 637