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