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