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