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 * Utility functions to support the RPC interface library. 30 */ 31 32 #include <stdio.h> 33 #include <stdarg.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <netdb.h> 37 #include <stdlib.h> 38 #include <pwd.h> 39 #include <grp.h> 40 41 #include <sys/time.h> 42 #include <sys/systm.h> 43 44 #include <smbsrv/libsmb.h> 45 #include <smbsrv/libsmbrdr.h> 46 #include <smbsrv/libsmbns.h> 47 #include <smbsrv/libmlsvc.h> 48 49 #include <smbsrv/smbinfo.h> 50 #include <smbsrv/ntsid.h> 51 #include <smbsrv/lsalib.h> 52 #include <smbsrv/samlib.h> 53 #include <smbsrv/mlsvc_util.h> 54 #include <smbsrv/mlsvc.h> 55 56 extern int netr_open(char *, char *, mlsvc_handle_t *); 57 extern int netr_close(mlsvc_handle_t *); 58 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD); 59 extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); 60 61 static int mlsvc_lookup_local_name(char *name, nt_sid_t **sid); 62 static int mlsvc_lookup_nt_name(char *name, nt_sid_t **sid); 63 static int mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize); 64 65 /* 66 * Compare the supplied domain name with the local hostname. 67 * We need to deal with both server names and fully-qualified 68 * domain names. 69 * 70 * Returns: 71 * 0 The specified domain is not the local domain, 72 * 1 The Specified domain is the local domain. 73 * -1 Invalid parameter or unable to get the local 74 * system information. 75 */ 76 int 77 mlsvc_is_local_domain(const char *domain) 78 { 79 char hostname[MAXHOSTNAMELEN]; 80 uint32_t mode; 81 int rc; 82 83 if (strchr(domain, '.') != NULL) 84 rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 85 else 86 rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 87 88 if (rc != 0) 89 return (-1); 90 91 rc = strcasecmp(domain, hostname); 92 mode = smb_get_security_mode(); 93 94 if ((rc == 0) || (mode == SMB_SECMODE_WORKGRP)) 95 return (1); 96 97 return (0); 98 } 99 100 /* 101 * mlsvc_lookup_name 102 * 103 * Lookup a name in the specified domain and translate it to a SID. 104 * If the name is in the NT domain, it may refer to a user, group or 105 * alias. Otherwise it must refer to a UNIX username. The memory for 106 * the sid is allocated using malloc so the caller should call free 107 * when it is no longer required. 108 * 109 * On success, 0 will be returned and sid will point to a local domain 110 * user SID. Otherwise -1 will be returned. 111 */ 112 int 113 mlsvc_lookup_name(char *domain, char *name, nt_sid_t **sid) 114 { 115 if (domain == NULL || name == NULL || sid == NULL) 116 return (-1); 117 118 if (mlsvc_is_local_domain(domain) == 1) 119 return (mlsvc_lookup_local_name(name, sid)); 120 else 121 return (mlsvc_lookup_nt_name(name, sid)); 122 } 123 124 /* 125 * mlsvc_lookup_local_name 126 * 127 * Lookup a name in the local password file and translate it to a SID. 128 * The name must refer to a user. This is a private function intended 129 * to support mlsvc_lookup_name so it doesn't perform any parameter 130 * validation. The memory for the sid is allocated using malloc so the 131 * caller must call free when it is no longer required. 132 * 133 * On success, 0 will be returned and sid will point to a local domain 134 * user SID. Otherwise -1 will be returned. 135 */ 136 static int 137 mlsvc_lookup_local_name(char *name, nt_sid_t **sid) 138 { 139 struct passwd *pw; 140 nt_sid_t *domain_sid; 141 142 if ((pw = getpwnam(name)) == NULL) 143 return (-1); 144 145 if ((domain_sid = nt_domain_local_sid()) == NULL) 146 return (-1); 147 148 *sid = nt_sid_splice(domain_sid, pw->pw_uid); 149 return (0); 150 } 151 152 /* 153 * mlsvc_lookup_nt_name 154 * 155 * Lookup a name in the specified NT domain and translate it to a SID. 156 * The name may refer to a user, group or alias. This is a private 157 * function intended to support mlsvc_lookup_name so it doesn't do any 158 * parameter validation. The memory for the sid is allocated using 159 * malloc so the caller should call free when it is no longer required. 160 * 161 * On success, 0 will be returned and sid will point to an NT domain 162 * user SID. Otherwise -1 will be returned. 163 */ 164 static int 165 mlsvc_lookup_nt_name(char *name, nt_sid_t **sid) 166 { 167 smb_userinfo_t *user_info; 168 169 if ((user_info = mlsvc_alloc_user_info()) == NULL) 170 return (-1); 171 172 if (lsa_lookup_name(0, 0, name, user_info) != 0) 173 return (-1); 174 175 *sid = nt_sid_splice(user_info->domain_sid, user_info->rid); 176 mlsvc_free_user_info(user_info); 177 return (0); 178 } 179 180 /* 181 * mlsvc_lookup_sid 182 * 183 * Lookup a SID and translate it to a name. The name returned may refer 184 * to a domain, user, group or alias dependent on the SID. On success 0 185 * will be returned. Otherwise -1 will be returned. 186 */ 187 int 188 mlsvc_lookup_sid(nt_sid_t *sid, char *buf, int bufsize) 189 { 190 struct passwd *pw; 191 struct group *gr; 192 nt_group_t *grp; 193 DWORD rid; 194 195 if (sid == NULL || buf == NULL) 196 return (-1); 197 198 if (nt_sid_is_local(sid)) { 199 (void) nt_sid_get_rid(sid, &rid); 200 201 switch (SAM_RID_TYPE(rid)) { 202 case SAM_RT_NT_UID: 203 break; 204 205 case SAM_RT_NT_GID: 206 if ((grp = nt_groups_lookup_rid(rid)) == NULL) 207 return (-1); 208 209 (void) strlcpy(buf, grp->name, bufsize); 210 break; 211 212 case SAM_RT_UNIX_UID: 213 if ((pw = getpwuid(SAM_DECODE_RID(rid))) == NULL) 214 return (-1); 215 216 (void) strlcpy(buf, pw->pw_name, bufsize); 217 break; 218 219 case SAM_RT_UNIX_GID: 220 if ((gr = getgrgid(SAM_DECODE_RID(rid))) == NULL) 221 return (-1); 222 223 (void) strlcpy(buf, gr->gr_name, bufsize); 224 break; 225 } 226 227 return (0); 228 } 229 230 return (mlsvc_lookup_nt_sid(sid, buf, bufsize)); 231 } 232 233 /* 234 * mlsvc_lookup_nt_sid 235 * 236 * Lookup an NT SID and translate it to a name. This is a private 237 * function intended to support mlsvc_lookup_sid so it doesn't do any 238 * parameter validation. The input account_name specifies the logon/ 239 * session to be used for the lookup. It doesn't need to have any 240 * association with the SID being looked up. The name returned may 241 * refer to a domain, user, group or alias dependent on the SID. 242 * 243 * On success the name will be copied into buf and 0 will be returned. 244 * Otherwise -1 will be returned. 245 */ 246 static int 247 mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize) 248 { 249 smb_userinfo_t *user_info; 250 int rc; 251 252 if ((user_info = mlsvc_alloc_user_info()) == NULL) 253 return (-1); 254 255 if ((rc = lsa_lookup_sid(sid, user_info)) == 0) 256 (void) strlcpy(buf, user_info->name, bufsize); 257 258 mlsvc_free_user_info(user_info); 259 return (rc); 260 } 261 262 /* 263 * mlsvc_alloc_user_info 264 * 265 * Allocate a user_info structure and set the contents to zero. A 266 * pointer to the user_info structure is returned. 267 */ 268 smb_userinfo_t * 269 mlsvc_alloc_user_info(void) 270 { 271 smb_userinfo_t *user_info; 272 273 user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 274 if (user_info == NULL) 275 return (NULL); 276 277 bzero(user_info, sizeof (smb_userinfo_t)); 278 return (user_info); 279 } 280 281 /* 282 * mlsvc_free_user_info 283 * 284 * Free a user_info structure. This function ensures that the contents 285 * of the user_info are freed as well as the user_info itself. 286 */ 287 void 288 mlsvc_free_user_info(smb_userinfo_t *user_info) 289 { 290 if (user_info) { 291 mlsvc_release_user_info(user_info); 292 free(user_info); 293 } 294 } 295 296 /* 297 * mlsvc_release_user_info 298 * 299 * Release the contents of a user_info structure and zero out the 300 * elements but do not free the user_info structure itself. This 301 * function cleans out the structure so that it can be reused without 302 * worrying about stale contents. 303 */ 304 void 305 mlsvc_release_user_info(smb_userinfo_t *user_info) 306 { 307 int i; 308 309 if (user_info == NULL) 310 return; 311 312 free(user_info->name); 313 free(user_info->domain_sid); 314 free(user_info->domain_name); 315 free(user_info->groups); 316 317 if (user_info->n_other_grps) { 318 for (i = 0; i < user_info->n_other_grps; i++) 319 free(user_info->other_grps[i].sid); 320 321 free(user_info->other_grps); 322 } 323 324 free(user_info->user_sid); 325 free(user_info->pgrp_sid); 326 bzero(user_info, sizeof (smb_userinfo_t)); 327 } 328 329 /* 330 * mlsvc_setadmin_user_info 331 * 332 * Determines if the given user is the domain Administrator or a 333 * member of Domain Admins or Administrators group and set the 334 * user_info->flags accordingly. 335 */ 336 void 337 mlsvc_setadmin_user_info(smb_userinfo_t *user_info) 338 { 339 nt_domain_t *domain; 340 nt_group_t *grp; 341 int i; 342 343 if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) 344 return; 345 346 if (!nt_sid_is_equal((nt_sid_t *)user_info->domain_sid, domain->sid)) 347 return; 348 349 if (user_info->rid == DOMAIN_USER_RID_ADMIN) 350 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 351 else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) 352 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 353 else { 354 for (i = 0; i < user_info->n_groups; i++) 355 if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) 356 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 357 } 358 359 grp = nt_group_getinfo("Administrators", RWLOCK_READER); 360 if (grp) { 361 i = nt_group_is_member(grp, user_info->user_sid); 362 nt_group_putinfo(grp); 363 if (i) 364 user_info->flags |= SMB_UINFO_FLAG_LADMIN; 365 } 366 } 367 368 /* 369 * mlsvc_string_save 370 * 371 * This is a convenience function to prepare strings for an RPC call. 372 * An ms_string_t is set up with the appropriate lengths and str is 373 * set up to point to a copy of the original string on the heap. The 374 * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which 375 * extends the heap and copies the string into the new area. 376 */ 377 int 378 mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa) 379 { 380 if (str == NULL) 381 return (0); 382 383 ms->length = mts_wcequiv_strlen(str); 384 ms->allosize = ms->length + sizeof (mts_wchar_t); 385 386 if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) 387 return (0); 388 389 return (1); 390 } 391 392 /* 393 * mlsvc_sid_save 394 * 395 * Expand the heap and copy the sid into the new area. 396 * Returns a pointer to the copy of the sid on the heap. 397 */ 398 nt_sid_t * 399 mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa) 400 { 401 nt_sid_t *heap_sid; 402 unsigned size; 403 404 if (sid == NULL) 405 return (NULL); 406 407 size = nt_sid_length(sid); 408 409 if ((heap_sid = (nt_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL) 410 return (0); 411 412 bcopy(sid, heap_sid, size); 413 return (heap_sid); 414 } 415 416 /* 417 * mlsvc_is_null_handle 418 * 419 * Check a handle against a null handle. Returns 1 if the handle is 420 * null. Otherwise returns 0. 421 */ 422 int 423 mlsvc_is_null_handle(mlsvc_handle_t *handle) 424 { 425 static ms_handle_t zero_handle; 426 427 if (handle == NULL || handle->context == NULL) 428 return (1); 429 430 if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t))) 431 return (1); 432 433 return (0); 434 } 435 436 /* 437 * mlsvc_join 438 * 439 * Returns NT status codes. 440 */ 441 DWORD 442 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text) 443 { 444 smb_auth_info_t auth; 445 smb_ntdomain_t *di; 446 int erc; 447 DWORD status; 448 mlsvc_handle_t netr_handle; 449 char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX]; 450 451 machine_passwd[0] = '\0'; 452 453 /* 454 * Ensure that the domain name is uppercase. 455 */ 456 (void) utf8_strupr(domain); 457 458 /* 459 * There is no point continuing if the domain information is 460 * not available. Wait for up to 10 seconds and then give up. 461 */ 462 if ((di = smb_getdomaininfo(10)) == 0) { 463 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 464 return (status); 465 } 466 467 if (strcasecmp(domain, di->domain) != 0) { 468 status = NT_STATUS_INVALID_PARAMETER; 469 return (status); 470 } 471 472 erc = mlsvc_logon(server, domain, plain_user); 473 474 if (erc == AUTH_USER_GRANT) { 475 int isenabled; 476 477 smb_config_rdlock(); 478 isenabled = smb_config_getyorn(SMB_CI_ADS_ENABLE); 479 smb_config_unlock(); 480 if (isenabled) { 481 if (ads_join(plain_user, plain_text, machine_passwd, 482 sizeof (machine_passwd)) == ADJOIN_SUCCESS) 483 status = NT_STATUS_SUCCESS; 484 else 485 status = NT_STATUS_UNSUCCESSFUL; 486 } else { 487 if (mlsvc_user_getauth(server, plain_user, &auth) 488 != 0) { 489 status = NT_STATUS_INVALID_PARAMETER; 490 return (status); 491 } 492 493 status = sam_create_trust_account(server, domain, 494 &auth); 495 if (status == NT_STATUS_SUCCESS) { 496 (void) smb_gethostname(machine_passwd, 497 sizeof (machine_passwd), 0); 498 (void) utf8_strlwr(machine_passwd); 499 } 500 } 501 502 if (status == NT_STATUS_SUCCESS) { 503 if (smb_set_machine_pwd(machine_passwd) != 0) 504 return (NT_STATUS_UNSUCCESSFUL); 505 506 /* 507 * If we successfully create a trust account, we mark 508 * ourselves as a domain member in the environment so 509 * that we use the SAMLOGON version of the NETLOGON 510 * PDC location protocol. 511 */ 512 smb_set_domain_member(1); 513 514 if (netr_open(server, domain, &netr_handle) == 0) { 515 status = netlogon_auth(server, &netr_handle, 516 NETR_FLG_INIT); 517 (void) netr_close(&netr_handle); 518 } else { 519 status = NT_STATUS_OPEN_FAILED; 520 } 521 } 522 } else { 523 status = NT_STATUS_LOGON_FAILURE; 524 } 525 526 return (status); 527 } 528 529 /*ARGSUSED*/ 530 void 531 nt_group_ht_lock(krwmode_t locktype) 532 { 533 } 534 535 void 536 nt_group_ht_unlock(void) 537 { 538 } 539 540 int 541 nt_group_num_groups(void) 542 { 543 return (0); 544 } 545 546 /*ARGSUSED*/ 547 uint32_t 548 nt_group_add(char *gname, char *comment) 549 { 550 return (NT_STATUS_NOT_SUPPORTED); 551 } 552 553 /*ARGSUSED*/ 554 uint32_t 555 nt_group_modify(char *gname, char *new_gname, char *comment) 556 { 557 return (NT_STATUS_NOT_SUPPORTED); 558 } 559 560 /*ARGSUSED*/ 561 uint32_t 562 nt_group_delete(char *gname) 563 { 564 return (NT_STATUS_NOT_SUPPORTED); 565 } 566 567 /*ARGSUSED*/ 568 nt_group_t * 569 nt_group_getinfo(char *gname, krwmode_t locktype) 570 { 571 return (NULL); 572 } 573 574 /*ARGSUSED*/ 575 void 576 nt_group_putinfo(nt_group_t *grp) 577 { 578 } 579 580 /*ARGSUSED*/ 581 int 582 nt_group_getpriv(nt_group_t *grp, uint32_t priv_id) 583 { 584 return (SE_PRIVILEGE_DISABLED); 585 } 586 587 /*ARGSUSED*/ 588 uint32_t 589 nt_group_setpriv(nt_group_t *grp, uint32_t priv_id, uint32_t new_attr) 590 { 591 return (NT_STATUS_NOT_SUPPORTED); 592 } 593 594 /*ARGSUSED*/ 595 int 596 nt_group_is_member(nt_group_t *grp, nt_sid_t *sid) 597 { 598 return (0); 599 } 600 601 /*ARGSUSED*/ 602 uint32_t 603 nt_group_add_member(nt_group_t *grp, nt_sid_t *msid, uint16_t sid_name_use, 604 char *account) 605 { 606 return (NT_STATUS_NOT_SUPPORTED); 607 } 608 609 /*ARGSUSED*/ 610 uint32_t 611 nt_group_del_member(nt_group_t *grp, void *key, int keytype) 612 { 613 return (NT_STATUS_NOT_SUPPORTED); 614 } 615 616 /*ARGSUSED*/ 617 int 618 nt_group_num_members(nt_group_t *grp) 619 { 620 return (0); 621 } 622 623 nt_group_iterator_t * 624 nt_group_open_iterator(void) 625 { 626 return (NULL); 627 } 628 629 /*ARGSUSED*/ 630 void 631 nt_group_close_iterator(nt_group_iterator_t *gi) 632 { 633 } 634 635 /*ARGSUSED*/ 636 nt_group_t * 637 nt_group_iterate(nt_group_iterator_t *gi) 638 { 639 return (NULL); 640 } 641 642 int 643 nt_group_cache_size(void) 644 { 645 return (0); 646 } 647 648 uint32_t 649 sam_init(void) 650 { 651 return (NT_STATUS_SUCCESS); 652 } 653 654 /*ARGSUSED*/ 655 uint32_t 656 nt_group_add_member_byname(char *gname, char *account) 657 { 658 return (NT_STATUS_NOT_SUPPORTED); 659 } 660 661 /*ARGSUSED*/ 662 uint32_t 663 nt_group_del_member_byname(nt_group_t *grp, char *member_name) 664 { 665 return (NT_STATUS_NOT_SUPPORTED); 666 } 667 668 /*ARGSUSED*/ 669 void 670 nt_group_add_groupprivs(nt_group_t *grp, smb_privset_t *priv) 671 { 672 } 673 674 /*ARGSUSED*/ 675 uint32_t 676 nt_groups_member_privs(nt_sid_t *sid, smb_privset_t *priv) 677 { 678 return (NT_STATUS_SUCCESS); 679 } 680 681 /*ARGSUSED*/ 682 int 683 nt_groups_member_ngroups(nt_sid_t *sid) 684 { 685 return (0); 686 } 687 688 /*ARGSUSED*/ 689 uint32_t 690 nt_groups_member_groups(nt_sid_t *sid, smb_id_t *grps, int ngrps) 691 { 692 return (NT_STATUS_SUCCESS); 693 } 694 695 /*ARGSUSED*/ 696 nt_group_t * 697 nt_groups_lookup_rid(uint32_t rid) 698 { 699 return (NULL); 700 } 701 702 /*ARGSUSED*/ 703 int 704 nt_groups_count(int cnt_opt) 705 { 706 return (0); 707 } 708 709 /*ARGSUSED*/ 710 int 711 nt_group_member_list(int offset, nt_group_t *grp, 712 ntgrp_member_list_t *rmembers) 713 { 714 return (0); 715 } 716 717 /*ARGSUSED*/ 718 void 719 nt_group_list(int offset, char *pattern, ntgrp_list_t *list) 720 { 721 } 722