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