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