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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This module provides the high level interface to the LSA RPC functions. 30 */ 31 32 #include <strings.h> 33 #include <unistd.h> 34 #include <netdb.h> 35 36 #include <smbsrv/libsmb.h> 37 #include <smbsrv/libsmbns.h> 38 #include <smbsrv/libmlsvc.h> 39 #include <smbsrv/lsalib.h> 40 #include <smbsrv/ntstatus.h> 41 #include <smbsrv/smbinfo.h> 42 #include <smbsrv/ntsid.h> 43 #include <smbsrv/smb_token.h> 44 45 static int lsa_list_accounts(mlsvc_handle_t *); 46 47 /* 48 * lsa_query_primary_domain_info 49 * 50 * Obtains the primary domain SID and name from the specified server 51 * (domain controller). The information is stored in the NT domain 52 * database by the lower level lsar_query_info_policy call. The caller 53 * should query the database to obtain a reference to the primary 54 * domain information. 55 * 56 * Returns NT status codes. 57 */ 58 DWORD 59 lsa_query_primary_domain_info(void) 60 { 61 mlsvc_handle_t domain_handle; 62 DWORD status; 63 64 if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0) 65 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 66 67 status = lsar_query_info_policy(&domain_handle, 68 MSLSA_POLICY_PRIMARY_DOMAIN_INFO); 69 70 (void) lsar_close(&domain_handle); 71 return (status); 72 } 73 74 /* 75 * lsa_query_account_domain_info 76 * 77 * Obtains the account domain SID and name from the current server 78 * (domain controller). The information is stored in the NT domain 79 * database by the lower level lsar_query_info_policy call. The caller 80 * should query the database to obtain a reference to the account 81 * domain information. 82 * 83 * Returns NT status codes. 84 */ 85 DWORD 86 lsa_query_account_domain_info(void) 87 { 88 mlsvc_handle_t domain_handle; 89 DWORD status; 90 91 if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0) 92 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 93 94 status = lsar_query_info_policy(&domain_handle, 95 MSLSA_POLICY_ACCOUNT_DOMAIN_INFO); 96 97 (void) lsar_close(&domain_handle); 98 return (status); 99 } 100 101 /* 102 * lsa_enum_trusted_domains 103 * 104 * Enumerate the trusted domains in our primary domain. The information 105 * is stored in the NT domain database by the lower level 106 * lsar_enum_trusted_domains call. The caller should query the database 107 * to obtain a reference to the trusted domain information. 108 * 109 * Returns NT status codes. 110 */ 111 DWORD 112 lsa_enum_trusted_domains(void) 113 { 114 mlsvc_handle_t domain_handle; 115 DWORD enum_context; 116 DWORD status; 117 118 if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0) 119 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 120 121 enum_context = 0; 122 123 status = lsar_enum_trusted_domains(&domain_handle, &enum_context); 124 if (status == MLSVC_NO_MORE_DATA) { 125 /* 126 * MLSVC_NO_MORE_DATA indicates that we 127 * have all of the available information. 128 */ 129 status = NT_STATUS_SUCCESS; 130 } 131 132 (void) lsar_close(&domain_handle); 133 return (status); 134 } 135 136 /* 137 * lsa_test_lookup 138 * 139 * Test routine for lsa_lookup_name and lsa_lookup_sid. 140 */ 141 void 142 lsa_test_lookup(char *name) 143 { 144 smb_userinfo_t *user_info; 145 nt_sid_t *sid; 146 DWORD status; 147 smb_ntdomain_t *di; 148 149 if ((di = smb_getdomaininfo(0)) == 0) 150 return; 151 152 user_info = mlsvc_alloc_user_info(); 153 154 if (lsa_lookup_builtin_name(name, user_info) != 0) { 155 status = lsa_lookup_name(di->server, di->domain, name, 156 user_info); 157 158 if (status == 0) { 159 sid = nt_sid_splice(user_info->domain_sid, 160 user_info->rid); 161 162 (void) lsa_lookup_sid(sid, user_info); 163 free(sid); 164 } 165 } 166 167 mlsvc_free_user_info(user_info); 168 } 169 170 /* 171 * lsa_lookup_builtin_name 172 * 173 * lookup builtin account table to see if account_name is 174 * there. If it is there, set sid_name_use, domain_sid, 175 * domain_name, and rid fields of the passed user_info 176 * structure and return 0. If lookup fails return 1. 177 */ 178 int 179 lsa_lookup_builtin_name(char *account_name, smb_userinfo_t *user_info) 180 { 181 char *domain; 182 int res; 183 184 user_info->domain_sid = nt_builtin_lookup_name(account_name, 185 &user_info->sid_name_use); 186 187 if (user_info->domain_sid == 0) 188 return (1); 189 190 res = nt_sid_split(user_info->domain_sid, &user_info->rid); 191 if (res < 0) 192 return (1); 193 194 domain = nt_builtin_lookup_domain(account_name); 195 if (domain) { 196 user_info->domain_name = strdup(domain); 197 return (0); 198 } 199 200 return (1); 201 } 202 203 /* 204 * lsa_lookup_local_sam 205 * 206 * lookup for the given account name in the local SAM database. 207 * Returns 0 on success. If lookup fails return 1. 208 */ 209 int 210 lsa_lookup_local_sam(char *domain, char *account_name, 211 smb_userinfo_t *user_info) 212 { 213 nt_group_t *grp; 214 215 if (*domain == '\0' || *account_name == '\0') 216 return (1); 217 218 grp = nt_group_getinfo(account_name, RWLOCK_READER); 219 if (grp == 0) 220 return (1); 221 222 user_info->sid_name_use = *grp->sid_name_use; 223 user_info->domain_sid = nt_sid_dup(grp->sid); 224 nt_group_putinfo(grp); 225 226 if (user_info->domain_sid == 0) 227 return (1); 228 229 (void) nt_sid_split(user_info->domain_sid, &user_info->rid); 230 user_info->domain_name = strdup(domain); 231 232 if (user_info->domain_name == 0) { 233 free(user_info->domain_sid); 234 user_info->domain_sid = 0; 235 return (1); 236 } 237 238 return (0); 239 } 240 241 /* 242 * lsa_lookup_local 243 * 244 * if given account name has domain part, check to see if 245 * it matches with host name or any of host's primary addresses. 246 * if any match found first lookup in builtin accounts table and 247 * then in local SAM table. 248 * 249 * if account name doesn't have domain part, first do local lookups 250 * if nothing is found return 1. This means that caller function should 251 * do domain lookup. 252 * if any error happened return -1, if name is found return 0. 253 */ 254 int 255 lsa_lookup_local(char *name, smb_userinfo_t *user_info) 256 { 257 char hostname[MAXHOSTNAMELEN]; 258 int res = 0; 259 int local_lookup = 0; 260 char *tmp; 261 net_cfg_t cfg; 262 uint32_t addr; 263 264 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) 265 return (-1); 266 267 tmp = strchr(name, '\\'); 268 if (tmp != 0) { 269 *tmp = 0; 270 if (strcasecmp(name, hostname) == 0) 271 local_lookup = 1; 272 273 if (!local_lookup) { 274 addr = inet_addr(name); 275 if (smb_nic_get_byip(addr, &cfg) != NULL) { 276 local_lookup = 1; 277 } 278 } 279 280 if (!local_lookup) { 281 /* do domain lookup */ 282 *tmp = '\\'; 283 return (1); 284 } 285 286 name = tmp + 1; 287 local_lookup = 1; 288 } 289 290 res = lsa_lookup_builtin_name(name, user_info); 291 if (res != 0) 292 res = lsa_lookup_local_sam(hostname, name, user_info); 293 294 if (res == 0) 295 return (0); 296 297 if (local_lookup) 298 return (-1); 299 300 return (1); 301 } 302 303 /* 304 * lsa_lookup_name 305 * 306 * Lookup a name on the specified server (domain controller) and obtain 307 * the appropriate SID. The information is returned in the user_info 308 * structure. The caller is responsible for allocating and releasing 309 * this structure. On success sid_name_use will be set to indicate the 310 * type of SID. If the name is the domain name, this function will be 311 * identical to lsa_domain_info. Otherwise the rid and name fields will 312 * also be valid. On failure sid_name_use will be set to SidTypeUnknown. 313 * 314 * On success 0 is returned. Otherwise a -ve error code. 315 */ 316 int lsa_lookup_name(char *server, char *domain, char *account_name, 317 smb_userinfo_t *user_info) 318 { 319 mlsvc_handle_t domain_handle; 320 int rc; 321 322 rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle); 323 if (rc != 0) 324 return (-1); 325 326 rc = lsar_lookup_names(&domain_handle, account_name, user_info); 327 328 (void) lsar_close(&domain_handle); 329 return (rc); 330 } 331 332 /* 333 * lsa_lookup_name2 334 * 335 * Returns NT status codes. 336 */ 337 DWORD lsa_lookup_name2(char *server, char *domain, char *account_name, 338 smb_userinfo_t *user_info) 339 { 340 mlsvc_handle_t domain_handle; 341 DWORD status; 342 int rc; 343 344 rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle); 345 if (rc != 0) 346 return (NT_STATUS_INVALID_PARAMETER); 347 348 status = lsar_lookup_names2(&domain_handle, account_name, user_info); 349 if (status == NT_STATUS_REVISION_MISMATCH) { 350 /* 351 * Not a Windows 2000 domain controller: 352 * use the NT compatible call. 353 */ 354 if (lsar_lookup_names(&domain_handle, account_name, 355 user_info) != 0) 356 status = NT_STATUS_NONE_MAPPED; 357 else 358 status = 0; 359 } 360 361 (void) lsar_close(&domain_handle); 362 return (status); 363 } 364 365 /* 366 * lsa_lookup_sid 367 * 368 * Lookup a SID on the specified server (domain controller) and obtain 369 * the appropriate name. The information is returned in the user_info 370 * structure. The caller is responsible for allocating and releasing 371 * this structure. On success sid_name_use will be set to indicate the 372 * type of SID. On failure sid_name_use will be set to SidTypeUnknown. 373 * 374 * On success 0 is returned. Otherwise a -ve error code. 375 */ 376 int 377 lsa_lookup_sid(nt_sid_t *sid, smb_userinfo_t *user_info) 378 { 379 mlsvc_handle_t domain_handle; 380 int rc; 381 382 rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle); 383 if (rc != 0) 384 return (-1); 385 386 rc = lsar_lookup_sids(&domain_handle, 387 (struct mslsa_sid *)sid, user_info); 388 389 (void) lsar_close(&domain_handle); 390 return (rc); 391 } 392 393 /* 394 * lsa_lookup_sid2 395 * 396 * Returns NT status codes. 397 */ 398 DWORD 399 lsa_lookup_sid2(nt_sid_t *sid, smb_userinfo_t *user_info) 400 { 401 mlsvc_handle_t domain_handle; 402 DWORD status; 403 int rc; 404 405 rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle); 406 if (rc != 0) 407 return (NT_STATUS_INVALID_PARAMETER); 408 409 status = lsar_lookup_sids2(&domain_handle, 410 (struct mslsa_sid *)sid, user_info); 411 412 if (status == NT_STATUS_REVISION_MISMATCH) { 413 /* 414 * Not a Windows 2000 domain controller: 415 * use the NT compatible call. 416 */ 417 if (lsar_lookup_sids(&domain_handle, (struct mslsa_sid *)sid, 418 user_info) != 0) 419 status = NT_STATUS_NONE_MAPPED; 420 else 421 status = 0; 422 } 423 424 (void) lsar_close(&domain_handle); 425 return (status); 426 } 427 428 /* 429 * lsa_test_lookup2 430 * 431 * Test routine for lsa_lookup_name2 and lsa_lookup_sid2. 432 */ 433 void 434 lsa_test_lookup2(char *name) 435 { 436 smb_userinfo_t *user_info; 437 nt_sid_t *sid; 438 DWORD status; 439 smb_ntdomain_t *di; 440 441 if ((di = smb_getdomaininfo(0)) == 0) 442 return; 443 444 user_info = mlsvc_alloc_user_info(); 445 446 if (lsa_lookup_builtin_name(name, user_info) != 0) { 447 status = lsa_lookup_name2(di->server, di->domain, name, 448 user_info); 449 450 if (status == 0) { 451 sid = nt_sid_splice(user_info->domain_sid, 452 user_info->rid); 453 454 (void) lsa_lookup_sid2(sid, user_info); 455 free(sid); 456 } 457 } 458 459 mlsvc_free_user_info(user_info); 460 } 461 462 /* 463 * lsa_lookup_privs 464 * 465 * Request the privileges associated with the specified account. In 466 * order to get the privileges, we first have to lookup the name on 467 * the specified domain controller and obtain the appropriate SID. 468 * The SID can then be used to open the account and obtain the 469 * account privileges. The results from both the name lookup and the 470 * privileges are returned in the user_info structure. The caller is 471 * responsible for allocating and releasing this structure. 472 * 473 * On success 0 is returned. Otherwise a -ve error code. 474 */ 475 /*ARGSUSED*/ 476 int 477 lsa_lookup_privs(char *server, char *account_name, char *target_name, 478 smb_userinfo_t *user_info) 479 { 480 mlsvc_handle_t domain_handle; 481 int rc; 482 #if 0 483 mlsvc_handle_t account_handle; 484 struct mslsa_sid *sid; 485 486 lsa_lookup_name(0, 0, target_name, user_info); 487 488 sid = (struct mslsa_sid *) 489 nt_sid_splice(user_info->domain_sid, user_info->rid); 490 491 lsa_lookup_sid(server, account_name, (nt_sid_t *)sid, user_info); 492 #endif 493 if ((lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle)) != 0) 494 return (-1); 495 496 rc = lsa_list_accounts(&domain_handle); 497 #if 0 498 rc = lsar_open_account(&domain_handle, sid, &account_handle); 499 if (rc == 0) { 500 (void) lsar_enum_privs_account(&account_handle, user_info); 501 (void) lsar_close(&account_handle); 502 } 503 504 free(sid); 505 #endif 506 (void) lsar_close(&domain_handle); 507 return (rc); 508 } 509 510 /* 511 * lsa_list_privs 512 * 513 * List the privileges supported by the specified server. 514 * This function is only intended for diagnostics. 515 * 516 * Returns NT status codes. 517 */ 518 DWORD 519 lsa_list_privs(char *server, char *domain) 520 { 521 static char name[128]; 522 static struct ms_luid luid; 523 mlsvc_handle_t domain_handle; 524 int rc; 525 int i; 526 527 rc = lsar_open(MLSVC_IPC_ANON, server, domain, 0, 0, &domain_handle); 528 if (rc != 0) 529 return (NT_STATUS_INVALID_PARAMETER); 530 531 for (i = 0; i < 30; ++i) { 532 luid.low_part = i; 533 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128); 534 if (rc != 0) 535 continue; 536 537 (void) lsar_lookup_priv_value(&domain_handle, name, &luid); 538 (void) lsar_lookup_priv_display_name(&domain_handle, name, 539 name, 128); 540 } 541 542 (void) lsar_close(&domain_handle); 543 return (NT_STATUS_SUCCESS); 544 } 545 546 /* 547 * lsa_test 548 * 549 * LSA test routine: open and close the LSA interface. 550 * TBD: the parameters should be server and domain. 551 * 552 * On success 0 is returned. Otherwise a -ve error code. 553 */ 554 /*ARGSUSED*/ 555 int 556 lsa_test(char *server, char *account_name) 557 { 558 mlsvc_handle_t domain_handle; 559 int rc; 560 561 rc = lsar_open(MLSVC_IPC_ANON, 0, 0, 0, 0, &domain_handle); 562 if (rc != 0) 563 return (-1); 564 565 if (lsar_close(&domain_handle) != 0) 566 return (-1); 567 568 return (0); 569 } 570 571 /* 572 * lsa_list_accounts 573 * 574 * This function can be used to list the accounts in the specified 575 * domain. For now the SIDs are just listed in the system log. 576 * 577 * On success 0 is returned. Otherwise a -ve error code. 578 */ 579 static int 580 lsa_list_accounts(mlsvc_handle_t *domain_handle) 581 { 582 mlsvc_handle_t account_handle; 583 struct mslsa_EnumAccountBuf accounts; 584 struct mslsa_sid *sid; 585 char *name; 586 WORD sid_name_use; 587 smb_userinfo_t *user_info; 588 DWORD enum_context = 0; 589 int rc; 590 int i; 591 592 user_info = mlsvc_alloc_user_info(); 593 bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf)); 594 595 do { 596 rc = lsar_enum_accounts(domain_handle, &enum_context, 597 &accounts); 598 if (rc != 0) 599 return (rc); 600 601 for (i = 0; i < accounts.entries_read; ++i) { 602 sid = accounts.info[i].sid; 603 604 name = nt_builtin_lookup_sid((nt_sid_t *)sid, 605 &sid_name_use); 606 607 if (name == 0) { 608 if (lsar_lookup_sids(domain_handle, sid, 609 user_info) == 0) { 610 name = user_info->name; 611 sid_name_use = user_info->sid_name_use; 612 } else { 613 name = "unknown"; 614 sid_name_use = SidTypeUnknown; 615 } 616 } 617 618 nt_sid_logf((nt_sid_t *)sid); 619 620 if (lsar_open_account(domain_handle, sid, 621 &account_handle) == 0) { 622 (void) lsar_enum_privs_account(&account_handle, 623 user_info); 624 (void) lsar_close(&account_handle); 625 } 626 627 free(accounts.info[i].sid); 628 mlsvc_release_user_info(user_info); 629 } 630 631 if (accounts.info) 632 free(accounts.info); 633 } while (rc == 0 && accounts.entries_read != 0); 634 635 mlsvc_free_user_info(user_info); 636 return (0); 637 } 638