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 2008 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 54 /* 55 * sam_create_trust_account 56 * 57 * Create a trust account for this system. 58 * 59 * SAMR_AF_WORKSTATION_TRUST_ACCOUNT: servers and workstations. 60 * SAMR_AF_SERVER_TRUST_ACCOUNT: domain controllers. 61 * 62 * Returns NT status codes. 63 */ 64 DWORD 65 sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth) 66 { 67 char account_name[MAXHOSTNAMELEN]; 68 DWORD status; 69 70 if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0) 71 return (NT_STATUS_NO_MEMORY); 72 73 (void) strlcat(account_name, "$", MAXHOSTNAMELEN); 74 75 /* 76 * The trust account value here should match 77 * the value that will be used when the user 78 * information is set on this account. 79 */ 80 status = sam_create_account(server, domain, account_name, 81 auth, SAMR_AF_WORKSTATION_TRUST_ACCOUNT); 82 83 /* 84 * Based on network traces, a Windows 2000 client will 85 * always try to create the computer account first. 86 * If it existed, then check the user permission to join 87 * the domain. 88 */ 89 90 if (status == NT_STATUS_USER_EXISTS) 91 status = sam_check_user(server, domain, account_name); 92 93 return (status); 94 } 95 96 97 /* 98 * sam_create_account 99 * 100 * Create the specified domain account in the SAM database on the 101 * domain controller. 102 * 103 * Account flags: 104 * SAMR_AF_NORMAL_ACCOUNT 105 * SAMR_AF_WORKSTATION_TRUST_ACCOUNT 106 * SAMR_AF_SERVER_TRUST_ACCOUNT 107 * 108 * Returns NT status codes. 109 */ 110 DWORD 111 sam_create_account(char *server, char *domain_name, char *account_name, 112 smb_auth_info_t *auth, DWORD account_flags) 113 { 114 mlsvc_handle_t samr_handle; 115 mlsvc_handle_t domain_handle; 116 mlsvc_handle_t user_handle; 117 smb_userinfo_t *user_info; 118 union samr_user_info sui; 119 struct samr_sid *sid; 120 DWORD rid; 121 DWORD status; 122 int rc; 123 char *user = smbrdr_ipc_get_user(); 124 125 if ((user_info = mlsvc_alloc_user_info()) == 0) 126 return (NT_STATUS_NO_MEMORY); 127 128 rc = samr_open(server, domain_name, user, SAM_CONNECT_CREATE_ACCOUNT, 129 &samr_handle); 130 131 if (rc != 0) { 132 status = NT_STATUS_OPEN_FAILED; 133 smb_tracef("SamCreateAccount[%s\\%s]: %s", 134 domain_name, account_name, xlate_nt_status(status)); 135 mlsvc_free_user_info(user_info); 136 return (status); 137 } 138 139 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 140 nt_domain_t *ntdp; 141 142 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 143 (void) lsa_query_account_domain_info(); 144 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 145 (void) samr_close_handle(&samr_handle); 146 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 147 smb_tracef("SamCreateAccount[%s\\%s]: %s", 148 domain_name, account_name, 149 xlate_nt_status(status)); 150 mlsvc_free_user_info(user_info); 151 return (status); 152 } 153 } 154 155 sid = (struct samr_sid *)ntdp->sid; 156 } else { 157 if (samr_lookup_domain(&samr_handle, 158 domain_name, user_info) != 0) { 159 (void) samr_close_handle(&samr_handle); 160 smb_tracef("SamCreateAccount[%s]: lookup failed", 161 account_name); 162 163 mlsvc_free_user_info(user_info); 164 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 165 } 166 167 sid = (struct samr_sid *)user_info->domain_sid; 168 } 169 170 status = samr_open_domain(&samr_handle, 171 SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle); 172 173 if (status == NT_STATUS_SUCCESS) { 174 status = samr_create_user(&domain_handle, account_name, 175 account_flags, &rid, &user_handle); 176 177 if (status == NT_STATUS_SUCCESS) { 178 (void) samr_query_user_info(&user_handle, 179 SAMR_QUERY_USER_UNKNOWN16, &sui); 180 181 (void) samr_get_user_pwinfo(&user_handle); 182 (void) samr_set_user_info(&user_handle, auth); 183 (void) samr_close_handle(&user_handle); 184 } else if (status != NT_STATUS_USER_EXISTS) { 185 smb_tracef("SamCreateAccount[%s]: %s", 186 account_name, xlate_nt_status(status)); 187 } 188 189 (void) samr_close_handle(&domain_handle); 190 } else { 191 smb_tracef("SamCreateAccount[%s]: open domain failed", 192 account_name); 193 status = (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 194 } 195 196 (void) samr_close_handle(&samr_handle); 197 mlsvc_free_user_info(user_info); 198 return (status); 199 } 200 201 202 /* 203 * sam_remove_trust_account 204 * 205 * Attempt to remove the workstation trust account for this system. 206 * Administrator access is required to perform this operation. 207 * 208 * Returns NT status codes. 209 */ 210 DWORD 211 sam_remove_trust_account(char *server, char *domain) 212 { 213 char account_name[MAXHOSTNAMELEN]; 214 215 if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0) 216 return (NT_STATUS_NO_MEMORY); 217 218 (void) strcat(account_name, "$"); 219 220 return (sam_delete_account(server, domain, account_name)); 221 } 222 223 224 /* 225 * sam_delete_account 226 * 227 * Attempt to remove an account from the SAM database on the specified 228 * server. 229 * 230 * Returns NT status codes. 231 */ 232 DWORD 233 sam_delete_account(char *server, char *domain_name, char *account_name) 234 { 235 mlsvc_handle_t samr_handle; 236 mlsvc_handle_t domain_handle; 237 mlsvc_handle_t user_handle; 238 smb_userinfo_t *user_info; 239 struct samr_sid *sid; 240 DWORD rid; 241 DWORD access_mask; 242 DWORD status; 243 int rc; 244 char *user = smbrdr_ipc_get_user(); 245 246 if ((user_info = mlsvc_alloc_user_info()) == 0) 247 return (NT_STATUS_NO_MEMORY); 248 249 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 250 &samr_handle); 251 252 if (rc != 0) { 253 mlsvc_free_user_info(user_info); 254 return (NT_STATUS_OPEN_FAILED); 255 } 256 257 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 258 nt_domain_t *ntdp; 259 260 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 261 (void) lsa_query_account_domain_info(); 262 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 263 264 (void) samr_close_handle(&samr_handle); 265 return (NT_STATUS_NO_SUCH_DOMAIN); 266 } 267 } 268 269 sid = (struct samr_sid *)ntdp->sid; 270 } else { 271 if (samr_lookup_domain( 272 &samr_handle, domain_name, user_info) != 0) { 273 (void) samr_close_handle(&samr_handle); 274 mlsvc_free_user_info(user_info); 275 return (NT_STATUS_NO_SUCH_DOMAIN); 276 } 277 278 sid = (struct samr_sid *)user_info->domain_sid; 279 } 280 281 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, 282 sid, &domain_handle); 283 if (status == 0) { 284 mlsvc_release_user_info(user_info); 285 status = samr_lookup_domain_names(&domain_handle, 286 account_name, user_info); 287 288 if (status == 0) { 289 rid = user_info->rid; 290 access_mask = STANDARD_RIGHTS_EXECUTE | DELETE; 291 292 status = samr_open_user(&domain_handle, access_mask, 293 rid, &user_handle); 294 if (status == NT_STATUS_SUCCESS) { 295 if (samr_delete_user(&user_handle) != 0) 296 (void) samr_close_handle(&user_handle); 297 } 298 } 299 300 (void) samr_close_handle(&domain_handle); 301 } 302 303 (void) samr_close_handle(&samr_handle); 304 mlsvc_free_user_info(user_info); 305 return (status); 306 } 307 308 /* 309 * sam_check_user 310 * 311 * Check to see if user have permission to access computer account. 312 * The user being checked is the specified user for joining the Solaris 313 * host to the domain. 314 */ 315 DWORD 316 sam_check_user(char *server, char *domain_name, char *account_name) 317 { 318 mlsvc_handle_t samr_handle; 319 mlsvc_handle_t domain_handle; 320 mlsvc_handle_t user_handle; 321 smb_userinfo_t *user_info; 322 struct samr_sid *sid; 323 DWORD rid; 324 DWORD access_mask; 325 DWORD status; 326 int rc; 327 char *user = smbrdr_ipc_get_user(); 328 329 if ((user_info = mlsvc_alloc_user_info()) == 0) 330 return (NT_STATUS_NO_MEMORY); 331 332 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 333 &samr_handle); 334 335 if (rc != 0) { 336 mlsvc_free_user_info(user_info); 337 return (NT_STATUS_OPEN_FAILED); 338 } 339 340 if (samr_handle.context->server_os == NATIVE_OS_WIN2000) { 341 nt_domain_t *ntdp; 342 343 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 344 (void) lsa_query_account_domain_info(); 345 if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) { 346 (void) samr_close_handle(&samr_handle); 347 return (NT_STATUS_NO_SUCH_DOMAIN); 348 } 349 } 350 351 sid = (struct samr_sid *)ntdp->sid; 352 } else { 353 if (samr_lookup_domain(&samr_handle, domain_name, user_info) 354 != 0) { 355 (void) samr_close_handle(&samr_handle); 356 mlsvc_free_user_info(user_info); 357 return (NT_STATUS_NO_SUCH_DOMAIN); 358 } 359 360 sid = (struct samr_sid *)user_info->domain_sid; 361 } 362 363 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid, 364 &domain_handle); 365 if (status == 0) { 366 mlsvc_release_user_info(user_info); 367 status = samr_lookup_domain_names(&domain_handle, account_name, 368 user_info); 369 370 if (status == 0) { 371 rid = user_info->rid; 372 373 /* 374 * Win2000 client uses this access mask. The 375 * following SAMR user specific rights bits are 376 * set: set password, set attributes, and get 377 * attributes. 378 */ 379 380 access_mask = 0xb0; 381 382 status = samr_open_user(&domain_handle, 383 access_mask, rid, &user_handle); 384 if (status == NT_STATUS_SUCCESS) 385 (void) samr_close_handle(&user_handle); 386 } 387 388 (void) samr_close_handle(&domain_handle); 389 } 390 391 (void) samr_close_handle(&samr_handle); 392 mlsvc_free_user_info(user_info); 393 return (status); 394 } 395 396 /* 397 * sam_lookup_name 398 * 399 * Lookup an account name in the SAM database on the specified domain 400 * controller. Provides the account RID on success. 401 * 402 * Returns NT status codes. 403 */ 404 DWORD 405 sam_lookup_name(char *server, char *domain_name, char *account_name, 406 DWORD *rid_ret) 407 { 408 mlsvc_handle_t samr_handle; 409 mlsvc_handle_t domain_handle; 410 smb_userinfo_t *user_info; 411 struct samr_sid *domain_sid; 412 int rc; 413 DWORD status; 414 char *user = smbrdr_ipc_get_user(); 415 416 *rid_ret = 0; 417 418 if ((user_info = mlsvc_alloc_user_info()) == 0) 419 return (NT_STATUS_NO_MEMORY); 420 421 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, 422 &samr_handle); 423 424 if (rc != 0) { 425 mlsvc_free_user_info(user_info); 426 return (NT_STATUS_OPEN_FAILED); 427 } 428 429 rc = samr_lookup_domain(&samr_handle, domain_name, user_info); 430 if (rc != 0) { 431 (void) samr_close_handle(&samr_handle); 432 mlsvc_free_user_info(user_info); 433 return (NT_STATUS_NO_SUCH_DOMAIN); 434 } 435 436 domain_sid = (struct samr_sid *)user_info->domain_sid; 437 438 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, 439 domain_sid, &domain_handle); 440 if (status == 0) { 441 mlsvc_release_user_info(user_info); 442 443 status = samr_lookup_domain_names(&domain_handle, 444 account_name, user_info); 445 if (status == 0) 446 *rid_ret = user_info->rid; 447 448 (void) samr_close_handle(&domain_handle); 449 } 450 451 (void) samr_close_handle(&samr_handle); 452 mlsvc_free_user_info(user_info); 453 return (status); 454 } 455 456 457 /* 458 * sam_get_local_domains 459 * 460 * Query a remote server to get the list of local domains that it 461 * supports. 462 * 463 * Returns NT status codes. 464 */ 465 DWORD 466 sam_get_local_domains(char *server, char *domain_name) 467 { 468 mlsvc_handle_t samr_handle; 469 DWORD status; 470 int rc; 471 char *user = smbrdr_ipc_get_user(); 472 473 rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN, 474 &samr_handle); 475 if (rc != 0) 476 return (NT_STATUS_OPEN_FAILED); 477 478 status = samr_enum_local_domains(&samr_handle); 479 (void) samr_close_handle(&samr_handle); 480 return (status); 481 } 482 483 /* 484 * sam_oem_password 485 * 486 * Generate an OEM password. 487 */ 488 int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password, 489 unsigned char *old_password) 490 { 491 mts_wchar_t *unicode_password; 492 int length; 493 494 #ifdef PBSHORTCUT 495 assert(sizeof (oem_password_t) == SAM_PASSWORD_516); 496 #endif /* PBSHORTCUT */ 497 498 length = strlen((char const *)new_password); 499 unicode_password = alloca((length + 1) * sizeof (mts_wchar_t)); 500 501 length = smb_auth_qnd_unicode((unsigned short *)unicode_password, 502 (char *)new_password, length); 503 oem_password->length = length; 504 505 (void) memcpy(&oem_password->data[512 - length], 506 unicode_password, length); 507 508 rand_hash((unsigned char *)oem_password, sizeof (oem_password_t), 509 old_password, SAM_KEYLEN); 510 511 return (0); 512 } 513