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 SAM RPC 30 * functions. 31 */ 32 33 #include <unistd.h> 34 #include <netdb.h> 35 #include <alloca.h> 36 37 #include <smbsrv/libsmb.h> 38 #include <smbsrv/libsmbrdr.h> 39 #include <smbsrv/libmlsvc.h> 40 #include <smbsrv/ntstatus.h> 41 #include <smbsrv/ntaccess.h> 42 #include <smbsrv/ntsid.h> 43 #include <smbsrv/lsalib.h> 44 #include <smbsrv/samlib.h> 45 46 /* 47 * Valid values for the OEM OWF password encryption. 48 */ 49 #define SAM_PASSWORD_516 516 50 #define SAM_KEYLEN 16 51 52 extern DWORD samr_set_user_info(mlsvc_handle_t *, smb_auth_info_t *); 53 static int get_user_group_info(mlsvc_handle_t *, smb_userinfo_t *); 54 55 /* 56 * sam_lookup_user_info 57 * 58 * Lookup user information in the SAM database on the specified server 59 * (domain controller). The LSA interface is used to obtain the user 60 * RID, the domain name and the domain SID (user privileges are TBD). 61 * Then the various SAM layers are opened using the domain SID and the 62 * user RID to obtain the users's group membership information. 63 * 64 * The information is returned in the user_info structure. The caller 65 * is responsible for allocating and releasing this structure. If the 66 * lookup is successful, sid_name_use will be set to SidTypeUser. 67 * 68 * On success 0 is returned. Otherwise a -ve error code. 69 */ 70 int 71 sam_lookup_user_info(char *server, char *domain_name, 72 char *account_name, smb_userinfo_t *user_info) 73 { 74 mlsvc_handle_t samr_handle; 75 mlsvc_handle_t domain_handle; 76 mlsvc_handle_t user_handle; 77 struct samr_sid *sid; 78 int rc; 79 DWORD access_mask; 80 DWORD status; 81 82 if (lsa_lookup_name(server, domain_name, account_name, user_info) != 0) 83 return (-1); 84 85 if (user_info->sid_name_use != SidTypeUser || 86 user_info->rid == 0 || user_info->domain_sid == 0) { 87 return (-1); 88 } 89 90 rc = samr_open(server, domain_name, account_name, 91 SAM_LOOKUP_INFORMATION, &samr_handle); 92 if (rc != 0) 93 return (-1); 94 sid = (struct samr_sid *)user_info->domain_sid; 95 96 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, 97 sid, &domain_handle); 98 if (status == 0) { 99 access_mask = STANDARD_RIGHTS_EXECUTE | SAM_ACCESS_USER_READ; 100 101 status = samr_open_user(&domain_handle, access_mask, 102 user_info->rid, &user_handle); 103 104 if (status == NT_STATUS_SUCCESS) { 105 (void) get_user_group_info(&user_handle, user_info); 106 (void) samr_close_handle(&user_handle); 107 } else { 108 rc = -1; 109 } 110 111 (void) samr_close_handle(&domain_handle); 112 } else { 113 rc = -1; 114 } 115 116 (void) samr_close_handle(&samr_handle); 117 return (rc); 118 } 119 120 /* 121 * get_user_group_info 122 * 123 * This is a private function to obtain the primary group and group 124 * memberships for the user specified by the user_handle. This function 125 * should only be called from sam_lookup_user_info. 126 * 127 * On success 0 is returned. Otherwise -1 is returned. 128 */ 129 static int 130 get_user_group_info(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info) 131 { 132 union samr_user_info sui; 133 int rc; 134 135 rc = samr_query_user_info(user_handle, SAMR_QUERY_USER_GROUPRID, &sui); 136 if (rc != 0) 137 return (-1); 138 139 rc = samr_query_user_groups(user_handle, user_info); 140 if (rc != 0) 141 return (-1); 142 143 user_info->primary_group_rid = sui.info9.group_rid; 144 return (0); 145 } 146 147 /* 148 * sam_create_trust_account 149 * 150 * Create a trust account for this system. 151 * 152 * SAMR_AF_WORKSTATION_TRUST_ACCOUNT: servers and workstations. 153 * SAMR_AF_SERVER_TRUST_ACCOUNT: domain controllers. 154 * 155 * Returns NT status codes. 156 */ 157 DWORD 158 sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth) 159 { 160 smb_userinfo_t *user_info; 161 char account_name[MAXHOSTNAMELEN]; 162 DWORD status; 163 164 if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0) 165 return (NT_STATUS_NO_MEMORY); 166 167 (void) strlcat(account_name, "$", MAXHOSTNAMELEN); 168 169 if ((user_info = mlsvc_alloc_user_info()) == 0) 170 return (NT_STATUS_NO_MEMORY); 171 172 /* 173 * The trust account value here should match 174 * the value that will be used when the user 175 * information is set on this account. 176 */ 177 status = sam_create_account(server, domain, account_name, 178 auth, SAMR_AF_WORKSTATION_TRUST_ACCOUNT, user_info); 179 180 mlsvc_free_user_info(user_info); 181 182 183 /* 184 * Based on network traces, a Windows 2000 client will 185 * always try to create the computer account first. 186 * If it existed, then check the user permission to join 187 * the domain. 188 */ 189 190 if (status == NT_STATUS_USER_EXISTS) 191 status = sam_check_user(server, domain, account_name); 192 193 return (status); 194 } 195 196 197 /* 198 * sam_create_account 199 * 200 * Create the specified domain account in the SAM database on the 201 * domain controller. 202 * 203 * Account flags: 204 * SAMR_AF_NORMAL_ACCOUNT 205 * SAMR_AF_WORKSTATION_TRUST_ACCOUNT 206 * SAMR_AF_SERVER_TRUST_ACCOUNT 207 * 208 * Returns NT status codes. 209 */ 210 DWORD 211 sam_create_account(char *server, char *domain_name, char *account_name, 212 smb_auth_info_t *auth, DWORD account_flags, smb_userinfo_t *user_info) 213 { 214 mlsvc_handle_t samr_handle; 215 mlsvc_handle_t domain_handle; 216 mlsvc_handle_t user_handle; 217 union samr_user_info sui; 218 struct samr_sid *sid; 219 DWORD rid; 220 DWORD status; 221 int rc; 222 char *user = smbrdr_ipc_get_user(); 223 224 rc = samr_open(server, domain_name, user, SAM_CONNECT_CREATE_ACCOUNT, 225 &samr_handle); 226 227 if (rc != 0) { 228 status = NT_STATUS_OPEN_FAILED; 229 smb_tracef("SamCreateAccount[%s\\%s]: %s", 230 domain_name, account_name, xlate_nt_status(status)); 231 return (status); 232 } 233 234 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 235 nt_domain_t *ntdp; 236 237 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 238 (void) lsa_query_account_domain_info(); 239 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 240 (void) samr_close_handle(&samr_handle); 241 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 242 smb_tracef("SamCreateAccount[%s\\%s]: %s", 243 domain_name, account_name, 244 xlate_nt_status(status)); 245 return (status); 246 } 247 } 248 249 sid = (struct samr_sid *)ntdp->sid; 250 } else { 251 if (samr_lookup_domain(&samr_handle, 252 domain_name, user_info) != 0) { 253 (void) samr_close_handle(&samr_handle); 254 smb_tracef("SamCreateAccount[%s]: lookup failed", 255 account_name); 256 257 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 258 } 259 260 sid = (struct samr_sid *)user_info->domain_sid; 261 } 262 263 status = samr_open_domain(&samr_handle, 264 SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle); 265 266 if (status == NT_STATUS_SUCCESS) { 267 status = samr_create_user(&domain_handle, account_name, 268 account_flags, &rid, &user_handle); 269 270 if (status == NT_STATUS_SUCCESS) { 271 (void) samr_query_user_info(&user_handle, 272 SAMR_QUERY_USER_UNKNOWN16, &sui); 273 274 (void) samr_get_user_pwinfo(&user_handle); 275 (void) samr_set_user_info(&user_handle, auth); 276 (void) samr_close_handle(&user_handle); 277 } else if (status == NT_STATUS_USER_EXISTS) { 278 mlsvc_release_user_info(user_info); 279 280 rc = lsa_lookup_name(server, domain_name, account_name, 281 user_info); 282 if (rc == 0) 283 rid = user_info->rid; 284 } else { 285 smb_tracef("SamCreateAccount[%s]: %s", 286 account_name, xlate_nt_status(status)); 287 } 288 289 (void) samr_close_handle(&domain_handle); 290 } else { 291 smb_tracef("SamCreateAccount[%s]: open domain failed", 292 account_name); 293 status = (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 294 } 295 296 (void) samr_close_handle(&samr_handle); 297 return (status); 298 } 299 300 301 /* 302 * sam_remove_trust_account 303 * 304 * Attempt to remove the workstation trust account for this system. 305 * Administrator access is required to perform this operation. 306 * 307 * Returns NT status codes. 308 */ 309 DWORD 310 sam_remove_trust_account(char *server, char *domain) 311 { 312 char account_name[MAXHOSTNAMELEN]; 313 314 if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0) 315 return (NT_STATUS_NO_MEMORY); 316 317 (void) strcat(account_name, "$"); 318 319 return (sam_delete_account(server, domain, account_name)); 320 } 321 322 323 /* 324 * sam_delete_account 325 * 326 * Attempt to remove an account from the SAM database on the specified 327 * server. 328 * 329 * Returns NT status codes. 330 */ 331 DWORD 332 sam_delete_account(char *server, char *domain_name, char *account_name) 333 { 334 mlsvc_handle_t samr_handle; 335 mlsvc_handle_t domain_handle; 336 mlsvc_handle_t user_handle; 337 smb_userinfo_t *user_info; 338 struct samr_sid *sid; 339 DWORD rid; 340 DWORD access_mask; 341 DWORD status; 342 int rc; 343 char *user = smbrdr_ipc_get_user(); 344 345 if ((user_info = mlsvc_alloc_user_info()) == 0) 346 return (NT_STATUS_NO_MEMORY); 347 348 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 349 &samr_handle); 350 351 if (rc != 0) { 352 mlsvc_free_user_info(user_info); 353 return (NT_STATUS_OPEN_FAILED); 354 } 355 356 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 357 nt_domain_t *ntdp; 358 359 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 360 (void) lsa_query_account_domain_info(); 361 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 362 363 (void) samr_close_handle(&samr_handle); 364 return (NT_STATUS_NO_SUCH_DOMAIN); 365 } 366 } 367 368 sid = (struct samr_sid *)ntdp->sid; 369 } else { 370 if (samr_lookup_domain( 371 &samr_handle, domain_name, user_info) != 0) { 372 (void) samr_close_handle(&samr_handle); 373 mlsvc_free_user_info(user_info); 374 return (NT_STATUS_NO_SUCH_DOMAIN); 375 } 376 377 sid = (struct samr_sid *)user_info->domain_sid; 378 } 379 380 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, 381 sid, &domain_handle); 382 if (status == 0) { 383 mlsvc_release_user_info(user_info); 384 status = samr_lookup_domain_names(&domain_handle, 385 account_name, user_info); 386 387 if (status == 0) { 388 rid = user_info->rid; 389 access_mask = STANDARD_RIGHTS_EXECUTE | DELETE; 390 391 status = samr_open_user(&domain_handle, access_mask, 392 rid, &user_handle); 393 if (status == NT_STATUS_SUCCESS) { 394 if (samr_delete_user(&user_handle) != 0) 395 (void) samr_close_handle(&user_handle); 396 } 397 } 398 399 (void) samr_close_handle(&domain_handle); 400 } 401 402 (void) samr_close_handle(&samr_handle); 403 mlsvc_free_user_info(user_info); 404 return (status); 405 } 406 407 /* 408 * sam_check_user 409 * 410 * Check to see if user have permission to access computer account. 411 * The user being checked is the specified user for joining the Solaris 412 * host to the domain. 413 */ 414 DWORD 415 sam_check_user(char *server, char *domain_name, char *account_name) 416 { 417 mlsvc_handle_t samr_handle; 418 mlsvc_handle_t domain_handle; 419 mlsvc_handle_t user_handle; 420 smb_userinfo_t *user_info; 421 struct samr_sid *sid; 422 DWORD rid; 423 DWORD access_mask; 424 DWORD status; 425 int rc; 426 char *user = smbrdr_ipc_get_user(); 427 428 if ((user_info = mlsvc_alloc_user_info()) == 0) 429 return (NT_STATUS_NO_MEMORY); 430 431 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 432 &samr_handle); 433 434 if (rc != 0) { 435 mlsvc_free_user_info(user_info); 436 return (NT_STATUS_OPEN_FAILED); 437 } 438 439 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 440 nt_domain_t *ntdp; 441 442 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 443 (void) lsa_query_account_domain_info(); 444 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 445 (void) samr_close_handle(&samr_handle); 446 return (NT_STATUS_NO_SUCH_DOMAIN); 447 } 448 } 449 450 sid = (struct samr_sid *)ntdp->sid; 451 } else { 452 if (samr_lookup_domain(&samr_handle, domain_name, user_info) 453 != 0) { 454 (void) samr_close_handle(&samr_handle); 455 mlsvc_free_user_info(user_info); 456 return (NT_STATUS_NO_SUCH_DOMAIN); 457 } 458 459 sid = (struct samr_sid *)user_info->domain_sid; 460 } 461 462 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid, 463 &domain_handle); 464 if (status == 0) { 465 mlsvc_release_user_info(user_info); 466 status = samr_lookup_domain_names(&domain_handle, account_name, 467 user_info); 468 469 if (status == 0) { 470 rid = user_info->rid; 471 472 /* 473 * Win2000 client uses this access mask. The 474 * following SAMR user specific rights bits are 475 * set: set password, set attributes, and get 476 * attributes. 477 */ 478 479 access_mask = 0xb0; 480 481 status = samr_open_user(&domain_handle, 482 access_mask, rid, &user_handle); 483 if (status == NT_STATUS_SUCCESS) 484 (void) samr_close_handle(&user_handle); 485 } 486 487 (void) samr_close_handle(&domain_handle); 488 } 489 490 (void) samr_close_handle(&samr_handle); 491 mlsvc_free_user_info(user_info); 492 return (status); 493 } 494 495 /* 496 * sam_lookup_name 497 * 498 * Lookup an account name in the SAM database on the specified domain 499 * controller. Provides the account RID on success. 500 * 501 * Returns NT status codes. 502 */ 503 DWORD 504 sam_lookup_name(char *server, char *domain_name, char *account_name, 505 DWORD *rid_ret) 506 { 507 mlsvc_handle_t samr_handle; 508 mlsvc_handle_t domain_handle; 509 smb_userinfo_t *user_info; 510 struct samr_sid *domain_sid; 511 int rc; 512 DWORD status; 513 char *user = smbrdr_ipc_get_user(); 514 515 *rid_ret = 0; 516 517 if ((user_info = mlsvc_alloc_user_info()) == 0) 518 return (NT_STATUS_NO_MEMORY); 519 520 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 521 &samr_handle); 522 523 if (rc != 0) { 524 mlsvc_free_user_info(user_info); 525 return (NT_STATUS_OPEN_FAILED); 526 } 527 528 rc = samr_lookup_domain(&samr_handle, domain_name, user_info); 529 if (rc != 0) { 530 (void) samr_close_handle(&samr_handle); 531 mlsvc_free_user_info(user_info); 532 return (NT_STATUS_NO_SUCH_DOMAIN); 533 } 534 535 domain_sid = (struct samr_sid *)user_info->domain_sid; 536 537 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, 538 domain_sid, &domain_handle); 539 if (status == 0) { 540 mlsvc_release_user_info(user_info); 541 542 status = samr_lookup_domain_names(&domain_handle, 543 account_name, user_info); 544 if (status == 0) 545 *rid_ret = user_info->rid; 546 547 (void) samr_close_handle(&domain_handle); 548 } 549 550 (void) samr_close_handle(&samr_handle); 551 mlsvc_free_user_info(user_info); 552 return (status); 553 } 554 555 556 /* 557 * sam_get_local_domains 558 * 559 * Query a remote server to get the list of local domains that it 560 * supports. 561 * 562 * Returns NT status codes. 563 */ 564 DWORD 565 sam_get_local_domains(char *server, char *domain_name) 566 { 567 mlsvc_handle_t samr_handle; 568 DWORD status; 569 int rc; 570 char *user = smbrdr_ipc_get_user(); 571 572 rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN, 573 &samr_handle); 574 if (rc != 0) 575 return (NT_STATUS_OPEN_FAILED); 576 577 status = samr_enum_local_domains(&samr_handle); 578 (void) samr_close_handle(&samr_handle); 579 return (status); 580 } 581 582 /* 583 * sam_oem_password 584 * 585 * Generate an OEM password. 586 */ 587 int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password, 588 unsigned char *old_password) 589 { 590 mts_wchar_t *unicode_password; 591 int length; 592 593 #ifdef PBSHORTCUT 594 assert(sizeof (oem_password_t) == SAM_PASSWORD_516); 595 #endif /* PBSHORTCUT */ 596 597 length = strlen((char const *)new_password); 598 unicode_password = alloca((length + 1) * sizeof (mts_wchar_t)); 599 600 length = smb_auth_qnd_unicode((unsigned short *)unicode_password, 601 (char *)new_password, length); 602 oem_password->length = length; 603 604 (void) memcpy(&oem_password->data[512 - length], 605 unicode_password, length); 606 607 rand_hash((unsigned char *)oem_password, sizeof (oem_password_t), 608 old_password, SAM_KEYLEN); 609 610 return (0); 611 } 612