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