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