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