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 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * NETR SamLogon and SamLogoff RPC client functions. 29 */ 30 31 #include <stdio.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <time.h> 35 #include <alloca.h> 36 #include <unistd.h> 37 #include <netdb.h> 38 #include <thread.h> 39 40 #include <libmlrpc/libmlrpc.h> 41 #include <smbsrv/libsmb.h> 42 #include <smbsrv/libmlsvc.h> 43 #include <smbsrv/ndl/netlogon.ndl> 44 #include <smbsrv/netrauth.h> 45 #include <smbsrv/smbinfo.h> 46 #include <smbsrv/smb_token.h> 47 #include <mlsvc.h> 48 49 #define NETLOGON_ATTEMPTS 2 50 51 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *); 52 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *, 53 smb_logon_t *, smb_token_t *); 54 static void netr_invalidate_chain(void); 55 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *, 56 struct netr_logon_info1 *); 57 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *, 58 smb_logon_t *, struct netr_logon_info2 *); 59 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *, 60 netr_logon_id_t *); 61 static boolean_t netr_isadmin(struct netr_validation_info3 *); 62 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *, 63 smb_ids_t *); 64 static uint32_t netr_setup_token_info3(struct netr_validation_info3 *, 65 smb_token_t *); 66 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *, 67 smb_token_t *); 68 69 /* 70 * Shared with netr_auth.c 71 */ 72 extern netr_info_t netr_global_info; 73 74 static mutex_t netlogon_mutex; 75 static cond_t netlogon_cv; 76 static boolean_t netlogon_busy = B_FALSE; 77 static boolean_t netlogon_abort = B_FALSE; 78 79 /* 80 * Helper for Kerberos authentication 81 */ 82 uint32_t 83 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len) 84 { 85 struct krb5_validation_info info; 86 ndr_buf_t *nbuf; 87 uint32_t status = NT_STATUS_NO_MEMORY; 88 int rc; 89 90 bzero(&info, sizeof (info)); 91 92 /* Need to keep this until we're done with &info */ 93 nbuf = ndr_buf_init(&TYPEINFO(netr_interface)); 94 if (nbuf == NULL) 95 goto out; 96 97 rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC, 98 NETR_OPNUM_decode_krb5_pac, data, len, &info); 99 if (rc != NDR_DRC_OK) { 100 status = RPC_NT_PROTOCOL_ERROR; 101 goto out; 102 } 103 104 status = netr_setup_token_info3(&info.info3, token); 105 106 /* Deal with the "resource groups"? */ 107 108 109 out: 110 if (nbuf != NULL) 111 ndr_buf_fini(nbuf); 112 113 return (status); 114 } 115 116 /* 117 * Code factored out of netr_setup_token() 118 */ 119 static uint32_t 120 netr_setup_token_info3(struct netr_validation_info3 *info3, 121 smb_token_t *token) 122 { 123 smb_sid_t *domsid; 124 125 domsid = (smb_sid_t *)info3->LogonDomainId; 126 127 token->tkn_user.i_sid = smb_sid_splice(domsid, 128 info3->UserId); 129 if (token->tkn_user.i_sid == NULL) 130 goto errout; 131 132 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, 133 info3->PrimaryGroupId); 134 if (token->tkn_primary_grp.i_sid == NULL) 135 goto errout; 136 137 if (info3->EffectiveName.str) { 138 token->tkn_account_name = 139 strdup((char *)info3->EffectiveName.str); 140 if (token->tkn_account_name == NULL) 141 goto errout; 142 } 143 144 if (info3->LogonDomainName.str) { 145 token->tkn_domain_name = 146 strdup((char *)info3->LogonDomainName.str); 147 if (token->tkn_domain_name == NULL) 148 goto errout; 149 } 150 151 return (netr_setup_token_wingrps(info3, token)); 152 errout: 153 return (NT_STATUS_INSUFF_SERVER_RESOURCES); 154 } 155 156 /* 157 * Abort impending domain logon requests. 158 */ 159 void 160 smb_logon_abort(void) 161 { 162 (void) mutex_lock(&netlogon_mutex); 163 if (netlogon_busy && !netlogon_abort) 164 syslog(LOG_DEBUG, "logon abort"); 165 netlogon_abort = B_TRUE; 166 (void) cond_broadcast(&netlogon_cv); 167 (void) mutex_unlock(&netlogon_mutex); 168 } 169 170 /* 171 * This is the entry point for authenticating domain users. 172 * 173 * If we are not going to attempt to authenticate the user, 174 * this function must return without updating the status. 175 * 176 * If the user is successfully authenticated, we build an 177 * access token and the status will be NT_STATUS_SUCCESS. 178 * Otherwise, the token contents are invalid. 179 */ 180 void 181 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token) 182 { 183 uint32_t status; 184 int i; 185 186 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN) 187 return; 188 189 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL) 190 return; 191 192 for (i = 0; i < NETLOGON_ATTEMPTS; ++i) { 193 (void) mutex_lock(&netlogon_mutex); 194 while (netlogon_busy && !netlogon_abort) 195 (void) cond_wait(&netlogon_cv, &netlogon_mutex); 196 197 if (netlogon_abort) { 198 (void) mutex_unlock(&netlogon_mutex); 199 user_info->lg_status = NT_STATUS_REQUEST_ABORTED; 200 return; 201 } 202 203 netlogon_busy = B_TRUE; 204 (void) mutex_unlock(&netlogon_mutex); 205 206 status = netlogon_logon(user_info, token); 207 208 (void) mutex_lock(&netlogon_mutex); 209 netlogon_busy = B_FALSE; 210 if (netlogon_abort) 211 status = NT_STATUS_REQUEST_ABORTED; 212 (void) cond_signal(&netlogon_cv); 213 (void) mutex_unlock(&netlogon_mutex); 214 215 if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO) 216 break; 217 } 218 219 if (status != NT_STATUS_SUCCESS) 220 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain, 221 user_info->lg_e_username, xlate_nt_status(status)); 222 223 user_info->lg_status = status; 224 } 225 226 static uint32_t 227 netlogon_logon(smb_logon_t *user_info, smb_token_t *token) 228 { 229 char resource_domain[SMB_PI_MAX_DOMAIN]; 230 char server[MAXHOSTNAMELEN]; 231 mlsvc_handle_t netr_handle; 232 smb_domainex_t di; 233 uint32_t status; 234 int retries = 0; 235 236 (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN); 237 238 /* Avoid interfering with DC discovery. */ 239 if (smb_ddiscover_wait() != 0 || 240 !smb_domain_getinfo(&di)) { 241 netr_invalidate_chain(); 242 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 243 } 244 245 do { 246 if (netr_open(di.d_dci.dc_name, di.d_primary.di_nbname, 247 &netr_handle) != 0) 248 return (NT_STATUS_OPEN_FAILED); 249 250 if (di.d_dci.dc_name[0] != '\0' && 251 (*netr_global_info.server != '\0')) { 252 (void) snprintf(server, sizeof (server), 253 "\\\\%s", di.d_dci.dc_name); 254 if (strncasecmp(netr_global_info.server, 255 server, strlen(server)) != 0) 256 netr_invalidate_chain(); 257 } 258 259 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 || 260 !smb_match_netlogon_seqnum()) { 261 status = netlogon_auth(di.d_dci.dc_name, &netr_handle, 262 NETR_FLG_NULL); 263 264 if (status != 0) { 265 (void) netr_close(&netr_handle); 266 return (NT_STATUS_LOGON_FAILURE); 267 } 268 269 netr_global_info.flags |= NETR_FLG_VALID; 270 } 271 272 status = netr_server_samlogon(&netr_handle, 273 &netr_global_info, di.d_dci.dc_name, user_info, token); 274 275 (void) netr_close(&netr_handle); 276 } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3); 277 278 if (retries >= 3) 279 status = NT_STATUS_LOGON_FAILURE; 280 281 return (status); 282 } 283 284 static uint32_t 285 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info, 286 netr_info_t *netr_info, smb_token_t *token) 287 { 288 char *username, *domain; 289 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ]; 290 smb_sid_t *domsid; 291 uint32_t status; 292 char nbdomain[NETBIOS_NAME_SZ]; 293 294 domsid = (smb_sid_t *)info3->LogonDomainId; 295 296 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId); 297 if (token->tkn_user.i_sid == NULL) 298 return (NT_STATUS_NO_MEMORY); 299 300 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, 301 info3->PrimaryGroupId); 302 if (token->tkn_primary_grp.i_sid == NULL) 303 return (NT_STATUS_NO_MEMORY); 304 305 username = (info3->EffectiveName.str) 306 ? (char *)info3->EffectiveName.str : user_info->lg_e_username; 307 308 if (info3->LogonDomainName.str) { 309 domain = (char *)info3->LogonDomainName.str; 310 } else if (*user_info->lg_e_domain != '\0') { 311 domain = user_info->lg_e_domain; 312 } else { 313 (void) smb_getdomainname(nbdomain, sizeof (nbdomain)); 314 domain = nbdomain; 315 } 316 317 if (username) 318 token->tkn_account_name = strdup(username); 319 if (domain) 320 token->tkn_domain_name = strdup(domain); 321 322 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL) 323 return (NT_STATUS_NO_MEMORY); 324 325 status = netr_setup_token_wingrps(info3, token); 326 if (status != NT_STATUS_SUCCESS) 327 return (status); 328 329 /* 330 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the 331 * session key obtained in the NETLOGON credential chain. 332 * An 8 byte session key is zero extended to 16 bytes. This 16 byte 333 * key is the key to the RC4 algorithm. The RC4 byte stream is 334 * exclusively ored with the 16 byte UserSessionKey to recover 335 * the the clear form. 336 */ 337 if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) 338 return (NT_STATUS_NO_MEMORY); 339 token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ; 340 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ); 341 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len); 342 bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val, 343 SMBAUTH_SESSION_KEY_SZ); 344 rand_hash((unsigned char *)token->tkn_ssnkey.val, 345 SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ); 346 347 return (NT_STATUS_SUCCESS); 348 } 349 350 /* 351 * netr_server_samlogon 352 * 353 * NetrServerSamLogon RPC: interactive or network. It is assumed that 354 * we have already authenticated with the PDC. If everything works, 355 * we build a user info structure and return it, where the caller will 356 * probably build an access token. 357 * 358 * Returns an NT status. There are numerous possibilities here. 359 * For example: 360 * NT_STATUS_INVALID_INFO_CLASS 361 * NT_STATUS_INVALID_PARAMETER 362 * NT_STATUS_ACCESS_DENIED 363 * NT_STATUS_PASSWORD_MUST_CHANGE 364 * NT_STATUS_NO_SUCH_USER 365 * NT_STATUS_WRONG_PASSWORD 366 * NT_STATUS_LOGON_FAILURE 367 * NT_STATUS_ACCOUNT_RESTRICTION 368 * NT_STATUS_INVALID_LOGON_HOURS 369 * NT_STATUS_INVALID_WORKSTATION 370 * NT_STATUS_INTERNAL_ERROR 371 * NT_STATUS_PASSWORD_EXPIRED 372 * NT_STATUS_ACCOUNT_DISABLED 373 */ 374 uint32_t 375 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, 376 char *server, smb_logon_t *user_info, smb_token_t *token) 377 { 378 struct netr_SamLogon arg; 379 struct netr_authenticator auth; 380 struct netr_authenticator ret_auth; 381 struct netr_logon_info1 info1; 382 struct netr_logon_info2 info2; 383 struct netr_validation_info3 *info3; 384 ndr_heap_t *heap; 385 int opnum; 386 int rc, len; 387 uint32_t status; 388 389 bzero(&arg, sizeof (struct netr_SamLogon)); 390 opnum = NETR_OPNUM_SamLogon; 391 392 /* 393 * Should we get the server and hostname from netr_info? 394 */ 395 396 len = strlen(server) + 4; 397 arg.servername = ndr_rpc_malloc(netr_handle, len); 398 arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ); 399 if (arg.servername == NULL || arg.hostname == NULL) { 400 ndr_rpc_release(netr_handle); 401 return (NT_STATUS_INTERNAL_ERROR); 402 } 403 404 (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 405 if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) { 406 ndr_rpc_release(netr_handle); 407 return (NT_STATUS_INTERNAL_ERROR); 408 } 409 410 rc = netr_setup_authenticator(netr_info, &auth, &ret_auth); 411 if (rc != SMBAUTH_SUCCESS) { 412 ndr_rpc_release(netr_handle); 413 return (NT_STATUS_INTERNAL_ERROR); 414 } 415 416 arg.auth = &auth; 417 arg.ret_auth = &ret_auth; 418 arg.validation_level = NETR_VALIDATION_LEVEL3; 419 arg.logon_info.logon_level = user_info->lg_level; 420 arg.logon_info.switch_value = user_info->lg_level; 421 422 heap = ndr_rpc_get_heap(netr_handle); 423 424 switch (user_info->lg_level) { 425 case NETR_INTERACTIVE_LOGON: 426 netr_setup_identity(heap, user_info, &info1.identity); 427 netr_interactive_samlogon(netr_info, user_info, &info1); 428 arg.logon_info.ru.info1 = &info1; 429 break; 430 431 case NETR_NETWORK_LOGON: 432 if (user_info->lg_challenge_key.len < 8 || 433 user_info->lg_challenge_key.val == NULL) { 434 ndr_rpc_release(netr_handle); 435 return (NT_STATUS_INVALID_PARAMETER); 436 } 437 netr_setup_identity(heap, user_info, &info2.identity); 438 netr_network_samlogon(heap, netr_info, user_info, &info2); 439 arg.logon_info.ru.info2 = &info2; 440 break; 441 442 default: 443 ndr_rpc_release(netr_handle); 444 return (NT_STATUS_INVALID_PARAMETER); 445 } 446 447 rc = ndr_rpc_call(netr_handle, opnum, &arg); 448 if (rc != 0) { 449 bzero(netr_info, sizeof (netr_info_t)); 450 status = NT_STATUS_INVALID_PARAMETER; 451 } else if (arg.status != 0) { 452 status = NT_SC_VALUE(arg.status); 453 454 /* 455 * We need to validate the chain even though we have 456 * a non-zero status. If the status is ACCESS_DENIED 457 * this will trigger a new credential chain. However, 458 * a valid credential is returned with some status 459 * codes; for example, WRONG_PASSWORD. 460 */ 461 (void) netr_validate_chain(netr_info, arg.ret_auth); 462 } else { 463 status = netr_validate_chain(netr_info, arg.ret_auth); 464 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) { 465 ndr_rpc_release(netr_handle); 466 return (status); 467 } 468 469 info3 = arg.ru.info3; 470 status = netr_setup_token(info3, user_info, netr_info, token); 471 } 472 473 ndr_rpc_release(netr_handle); 474 return (status); 475 } 476 477 /* 478 * netr_interactive_samlogon 479 * 480 * Set things up for an interactive SamLogon. Copy the NT and LM 481 * passwords to the logon structure and hash them with the session 482 * key. 483 */ 484 static void 485 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info, 486 struct netr_logon_info1 *info1) 487 { 488 BYTE key[NETR_OWF_PASSWORD_SZ]; 489 490 (void) memcpy(&info1->lm_owf_password, 491 user_info->lg_lm_password.val, sizeof (netr_owf_password_t)); 492 493 (void) memcpy(&info1->nt_owf_password, 494 user_info->lg_nt_password.val, sizeof (netr_owf_password_t)); 495 496 (void) memset(key, 0, NETR_OWF_PASSWORD_SZ); 497 (void) memcpy(key, netr_info->session_key.key, 498 netr_info->session_key.len); 499 500 rand_hash((unsigned char *)&info1->lm_owf_password, 501 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 502 503 rand_hash((unsigned char *)&info1->nt_owf_password, 504 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ); 505 } 506 507 /* 508 * netr_network_samlogon 509 * 510 * Set things up for a network SamLogon. We provide a copy of the random 511 * challenge, that we sent to the client, to the domain controller. This 512 * is the key that the client will have used to encrypt the NT and LM 513 * passwords. Note that Windows 9x clients may not provide both passwords. 514 */ 515 /*ARGSUSED*/ 516 static void 517 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info, 518 smb_logon_t *user_info, struct netr_logon_info2 *info2) 519 { 520 uint32_t len; 521 522 if (user_info->lg_challenge_key.len >= 8 && 523 user_info->lg_challenge_key.val != 0) { 524 bcopy(user_info->lg_challenge_key.val, 525 info2->lm_challenge.data, 8); 526 } else { 527 bzero(info2->lm_challenge.data, 8); 528 } 529 530 if ((len = user_info->lg_nt_password.len) != 0) { 531 ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len, 532 (ndr_vcbuf_t *)&info2->nt_response); 533 } else { 534 bzero(&info2->nt_response, sizeof (netr_vcbuf_t)); 535 } 536 537 if ((len = user_info->lg_lm_password.len) != 0) { 538 ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len, 539 (ndr_vcbuf_t *)&info2->lm_response); 540 } else { 541 bzero(&info2->lm_response, sizeof (netr_vcbuf_t)); 542 } 543 } 544 545 /* 546 * netr_setup_authenticator 547 * 548 * Set up the request and return authenticators. A new credential is 549 * generated from the session key, the current client credential and 550 * the current time, i.e. 551 * 552 * NewCredential = Cred(SessionKey, OldCredential, time); 553 * 554 * The timestamp, which is used as a random seed, is stored in both 555 * the request and return authenticators. 556 * 557 * If any difficulties occur using the cryptographic framework, the 558 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 559 * returned. 560 */ 561 int 562 netr_setup_authenticator(netr_info_t *netr_info, 563 struct netr_authenticator *auth, struct netr_authenticator *ret_auth) 564 { 565 bzero(auth, sizeof (struct netr_authenticator)); 566 567 netr_info->timestamp = time(0); 568 auth->timestamp = netr_info->timestamp; 569 570 if (netr_gen_credentials(netr_info->session_key.key, 571 &netr_info->client_credential, 572 netr_info->timestamp, 573 (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS) 574 return (SMBAUTH_FAILURE); 575 576 if (ret_auth) { 577 bzero(ret_auth, sizeof (struct netr_authenticator)); 578 ret_auth->timestamp = netr_info->timestamp; 579 } 580 581 return (SMBAUTH_SUCCESS); 582 } 583 584 /* 585 * Validate the returned credentials and update the credential chain. 586 * The server returns an updated client credential rather than a new 587 * server credential. The server uses (timestamp + 1) when generating 588 * the credential. 589 * 590 * Generate the new seed for the credential chain. The new seed is 591 * formed by adding (timestamp + 1) to the current client credential. 592 * The only quirk is the uint32_t style addition. 593 * 594 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a 595 * NULL pointer. The Authenticator field of the SamLogon response packet 596 * sent by the Samba 3 PDC always return NULL pointer if the received 597 * SamLogon request is not immediately followed by the ServerReqChallenge 598 * and ServerAuthenticate2 requests. 599 * 600 * Returns NT_STATUS_SUCCESS if the server returned a valid credential. 601 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL. 602 */ 603 uint32_t 604 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth) 605 { 606 netr_cred_t cred; 607 uint32_t result = NT_STATUS_SUCCESS; 608 uint32_t *dwp; 609 610 ++netr_info->timestamp; 611 612 if (netr_gen_credentials(netr_info->session_key.key, 613 &netr_info->client_credential, 614 netr_info->timestamp, &cred) != SMBAUTH_SUCCESS) 615 return (NT_STATUS_INTERNAL_ERROR); 616 617 if (&auth->credential == 0) { 618 /* 619 * If the validation fails, destroy the credential chain. 620 * This should trigger a new authentication chain. 621 */ 622 bzero(netr_info, sizeof (netr_info_t)); 623 return (NT_STATUS_INSUFFICIENT_LOGON_INFO); 624 } 625 626 result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t)); 627 if (result != 0) { 628 /* 629 * If the validation fails, destroy the credential chain. 630 * This should trigger a new authentication chain. 631 */ 632 bzero(netr_info, sizeof (netr_info_t)); 633 result = NT_STATUS_UNSUCCESSFUL; 634 } else { 635 /* 636 * Otherwise generate the next step in the chain. 637 */ 638 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 639 dwp = (uint32_t *)&netr_info->client_credential; 640 dwp[0] += netr_info->timestamp; 641 642 netr_info->flags |= NETR_FLG_VALID; 643 } 644 645 return (result); 646 } 647 648 /* 649 * netr_invalidate_chain 650 * 651 * Mark the credential chain as invalid so that it will be recreated 652 * on the next attempt. 653 */ 654 static void 655 netr_invalidate_chain(void) 656 { 657 netr_global_info.flags &= ~NETR_FLG_VALID; 658 } 659 660 /* 661 * netr_setup_identity 662 * 663 * Set up the client identity information. All of this information is 664 * specifically related to the client user and workstation attempting 665 * to access this system. It may not be in our primary domain. 666 * 667 * I don't know what logon_id is, it seems to be a unique identifier. 668 * Increment it before each use. 669 */ 670 static void 671 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info, 672 netr_logon_id_t *identity) 673 { 674 static mutex_t logon_id_mutex; 675 static uint32_t logon_id; 676 677 (void) mutex_lock(&logon_id_mutex); 678 679 if (logon_id == 0) 680 logon_id = 0xDCD0; 681 682 ++logon_id; 683 user_info->lg_logon_id = logon_id; 684 685 (void) mutex_unlock(&logon_id_mutex); 686 687 /* 688 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set 689 * ParameterControl to the 'E' + 'K' bits. Those are: 690 * (1 << 5) | (1 << 11), a.k.a 691 */ 692 identity->parameter_control = 693 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | 694 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; 695 identity->logon_id.LowPart = logon_id; 696 identity->logon_id.HighPart = 0; 697 698 ndr_heap_mkvcs(heap, user_info->lg_domain, 699 (ndr_vcstr_t *)&identity->domain_name); 700 701 ndr_heap_mkvcs(heap, user_info->lg_username, 702 (ndr_vcstr_t *)&identity->username); 703 704 /* 705 * Some systems prefix the client workstation name with \\. 706 * It doesn't seem to make any difference whether it's there 707 * or not. 708 */ 709 ndr_heap_mkvcs(heap, user_info->lg_workstation, 710 (ndr_vcstr_t *)&identity->workstation); 711 } 712 713 /* 714 * Sets up domain, local and well-known group membership for the given 715 * token. Two assumptions have been made here: 716 * 717 * a) token already contains a valid user SID so that group 718 * memberships can be established 719 * 720 * b) token belongs to a domain user 721 */ 722 static uint32_t 723 netr_setup_token_wingrps(struct netr_validation_info3 *info3, 724 smb_token_t *token) 725 { 726 smb_ids_t tkn_grps; 727 uint32_t status; 728 729 tkn_grps.i_cnt = 0; 730 tkn_grps.i_ids = NULL; 731 732 status = netr_setup_domain_groups(info3, &tkn_grps); 733 if (status != NT_STATUS_SUCCESS) { 734 smb_ids_free(&tkn_grps); 735 return (status); 736 } 737 738 status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps); 739 if (status != NT_STATUS_SUCCESS) { 740 smb_ids_free(&tkn_grps); 741 return (status); 742 } 743 744 if (netr_isadmin(info3)) 745 token->tkn_flags |= SMB_ATF_ADMIN; 746 747 status = smb_wka_token_groups(token->tkn_flags, &tkn_grps); 748 if (status == NT_STATUS_SUCCESS) 749 token->tkn_win_grps = tkn_grps; 750 else 751 smb_ids_free(&tkn_grps); 752 753 return (status); 754 } 755 756 /* 757 * Converts groups information in the returned structure by domain controller 758 * (info3) to an internal representation (gids) 759 */ 760 static uint32_t 761 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids) 762 { 763 smb_sid_t *domain_sid; 764 smb_id_t *ids; 765 int i, total_cnt; 766 767 if ((i = info3->GroupCount) == 0) 768 i++; 769 i += info3->SidCount; 770 771 total_cnt = gids->i_cnt + i; 772 773 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); 774 if (gids->i_ids == NULL) 775 return (NT_STATUS_NO_MEMORY); 776 777 domain_sid = (smb_sid_t *)info3->LogonDomainId; 778 779 ids = gids->i_ids + gids->i_cnt; 780 for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) { 781 ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid); 782 if (ids->i_sid == NULL) 783 return (NT_STATUS_NO_MEMORY); 784 785 ids->i_attrs = info3->GroupIds[i].attributes; 786 } 787 788 if (info3->GroupCount == 0) { 789 /* 790 * if there's no global group should add the primary group. 791 */ 792 ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId); 793 if (ids->i_sid == NULL) 794 return (NT_STATUS_NO_MEMORY); 795 796 ids->i_attrs = 0x7; 797 gids->i_cnt++; 798 ids++; 799 } 800 801 /* Add the extra SIDs */ 802 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) { 803 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid); 804 if (ids->i_sid == NULL) 805 return (NT_STATUS_NO_MEMORY); 806 807 ids->i_attrs = info3->ExtraSids[i].attributes; 808 } 809 810 return (NT_STATUS_SUCCESS); 811 } 812 813 /* 814 * Determines if the given user is the domain Administrator or a 815 * member of Domain Admins 816 */ 817 static boolean_t 818 netr_isadmin(struct netr_validation_info3 *info3) 819 { 820 smb_domain_t di; 821 int i; 822 823 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di)) 824 return (B_FALSE); 825 826 if (di.di_type != SMB_DOMAIN_PRIMARY) 827 return (B_FALSE); 828 829 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) || 830 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS)) 831 return (B_TRUE); 832 833 for (i = 0; i < info3->GroupCount; i++) 834 if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS) 835 return (B_TRUE); 836 837 return (B_FALSE); 838 } 839