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