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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Authentication support for SMB session setup 28 */ 29 30 #include <sys/types.h> 31 #include <sys/sid.h> 32 #include <sys/priv_names.h> 33 #include <sys/socket.h> 34 #include <sys/un.h> 35 #include <netinet/in.h> 36 #include <smbsrv/smb_idmap.h> 37 #include <smbsrv/smb_kproto.h> 38 #include <smbsrv/smb_token.h> 39 40 static uint32_t smb_authsock_open(smb_user_t *); 41 static int smb_authsock_send(ksocket_t, void *, size_t); 42 static int smb_authsock_recv(ksocket_t, void *, size_t); 43 static uint32_t smb_authsock_sendrecv(smb_user_t *, smb_lsa_msg_hdr_t *hdr, 44 void *sndbuf, void **recvbuf); 45 /* void smb_authsock_close(smb_user_t *); kproto.h */ 46 47 static uint32_t smb_auth_do_clinfo(smb_request_t *); 48 static uint32_t smb_auth_do_oldreq(smb_request_t *); 49 static uint32_t smb_auth_get_token(smb_request_t *); 50 static uint32_t smb_priv_xlate(smb_token_t *); 51 52 /* 53 * Handle old-style session setup (non-extended security) 54 * 55 * The user information is passed to smbd for authentication. 56 * If smbd can authenticate the user an access token is returned and we 57 * generate a cred and new user based on the token. 58 */ 59 int 60 smb_authenticate_old(smb_request_t *sr) 61 { 62 smb_user_t *user = NULL; 63 uint32_t status; 64 65 user = smb_user_new(sr->session); 66 if (user == NULL) 67 return (NT_STATUS_TOO_MANY_SESSIONS); 68 69 /* user cleanup in smb_request_free */ 70 sr->uid_user = user; 71 sr->smb_uid = user->u_uid; 72 73 /* 74 * Open a connection to the local logon service. 75 * If we can't, it may be busy, or not running. 76 * Don't log here - this may be frequent. 77 */ 78 if ((status = smb_authsock_open(user)) != 0) 79 goto errout; 80 81 /* 82 * Tell the auth. svc who this client is. 83 */ 84 if ((status = smb_auth_do_clinfo(sr)) != 0) 85 goto errout; 86 87 /* 88 * Authentication proper 89 */ 90 if ((status = smb_auth_do_oldreq(sr)) != 0) 91 goto errout; 92 93 /* 94 * Get the final auth. token. 95 */ 96 if ((status = smb_auth_get_token(sr)) != 0) 97 goto errout; 98 99 return (0); 100 101 errout: 102 smb_user_logoff(user); 103 return (status); 104 } 105 106 /* 107 * Build an authentication request message and 108 * send it to the local logon service. 109 */ 110 static uint32_t 111 smb_auth_do_oldreq(smb_request_t *sr) 112 { 113 smb_lsa_msg_hdr_t msg_hdr; 114 smb_logon_t user_info; 115 XDR xdrs; 116 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; 117 smb_user_t *user = sr->uid_user; 118 void *sbuf = NULL; 119 void *rbuf = NULL; 120 uint32_t slen = 0; 121 uint32_t rlen = 0; 122 uint32_t status; 123 bool_t ok; 124 125 bzero(&user_info, sizeof (smb_logon_t)); 126 127 user_info.lg_level = NETR_NETWORK_LOGON; 128 user_info.lg_username = sinfo->ssi_user; 129 user_info.lg_domain = sinfo->ssi_domain; 130 user_info.lg_workstation = sr->session->workstation; 131 user_info.lg_clnt_ipaddr = sr->session->ipaddr; 132 user_info.lg_local_ipaddr = sr->session->local_ipaddr; 133 user_info.lg_local_port = sr->session->s_local_port; 134 user_info.lg_challenge_key.val = sr->session->challenge_key; 135 user_info.lg_challenge_key.len = sr->session->challenge_len; 136 user_info.lg_nt_password.val = sinfo->ssi_ntpwd; 137 user_info.lg_nt_password.len = sinfo->ssi_ntpwlen; 138 user_info.lg_lm_password.val = sinfo->ssi_lmpwd; 139 user_info.lg_lm_password.len = sinfo->ssi_lmpwlen; 140 user_info.lg_native_os = sr->session->native_os; 141 user_info.lg_native_lm = sr->session->native_lm; 142 /* lg_flags? */ 143 144 slen = xdr_sizeof(smb_logon_xdr, &user_info); 145 sbuf = kmem_alloc(slen, KM_SLEEP); 146 xdrmem_create(&xdrs, sbuf, slen, XDR_ENCODE); 147 ok = smb_logon_xdr(&xdrs, &user_info); 148 xdr_destroy(&xdrs); 149 if (!ok) { 150 status = RPC_NT_BAD_STUB_DATA; 151 goto out; 152 } 153 154 msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ; 155 msg_hdr.lmh_msglen = slen; 156 status = smb_authsock_sendrecv(user, &msg_hdr, sbuf, &rbuf); 157 if (status != 0) 158 goto out; 159 rlen = msg_hdr.lmh_msglen; 160 kmem_free(sbuf, slen); 161 sbuf = NULL; 162 163 /* 164 * Decode the response message. 165 */ 166 switch (msg_hdr.lmh_msgtype) { 167 168 case LSA_MTYPE_OK: 169 status = 0; 170 break; 171 172 case LSA_MTYPE_ERROR: 173 if (rlen == sizeof (smb_lsa_eresp_t)) { 174 smb_lsa_eresp_t *ler = rbuf; 175 status = ler->ler_ntstatus; 176 break; 177 } 178 /* FALLTHROUGH */ 179 180 default: /* Bogus message type */ 181 status = NT_STATUS_INTERNAL_ERROR; 182 break; 183 } 184 185 out: 186 if (rbuf != NULL) 187 kmem_free(rbuf, rlen); 188 if (sbuf != NULL) 189 kmem_free(sbuf, slen); 190 191 return (status); 192 } 193 194 /* 195 * Handle new-style (extended security) session setup. 196 * Returns zero: success, non-zero: error (value not used) 197 * 198 * Note that this style uses a sequence of session setup requests, 199 * where the first has SMB UID=0, and subsequent requests in the 200 * same authentication sequence have the SMB UID returned for that 201 * first request. We allocate a USER object when the first request 202 * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that 203 * to maintain state between requests in this sequence. The state 204 * for one sequence includes an AF_UNIX "authsock" connection to the 205 * user-space smbd. The neat part of this is: in smbd, the handler 206 * for the server-side of one authsock gets only request specific to 207 * one authentication sequence, simplifying it's work immensely. 208 * When the authentication sequence is finished, with either success 209 * or failure, the local side of the authsock is closed. 210 * 211 * As with the old-style authentication, if we succeed, then the 212 * last message from smbd will be an smb_token_t encoding the 213 * information about the new user. 214 * 215 * Outline: 216 * (a) On the first request (UID==0) create a USER object, 217 * and on subsequent requests, find USER by SMB UID. 218 * (b) Send message / recv. response as above, 219 * (c) If response says "we're done", close authsock 220 * (both success and failure must close authsock) 221 */ 222 int 223 smb_authenticate_ext(smb_request_t *sr) 224 { 225 smb_lsa_msg_hdr_t msg_hdr; 226 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; 227 smb_user_t *user = NULL; 228 void *rbuf = NULL; 229 uint32_t rlen = 0; 230 uint32_t status; 231 232 ASSERT(sr->uid_user == NULL); 233 234 /* 235 * On the first request (UID==0) create a USER object. 236 * On subsequent requests (UID!=0) find the USER object. 237 * Either way, sr->uid_user is set, so our ref. on the 238 * user object is dropped during normal cleanup work 239 * for the smb_request (sr). Ditto u_authsock. 240 */ 241 if (sr->smb_uid == 0) { 242 user = smb_user_new(sr->session); 243 if (user == NULL) 244 return (NT_STATUS_TOO_MANY_SESSIONS); 245 246 /* user cleanup in smb_request_free */ 247 sr->uid_user = user; 248 sr->smb_uid = user->u_uid; 249 250 /* 251 * Open a connection to the local logon service. 252 * If we can't, it may be busy, or not running. 253 * Don't log here - this may be frequent. 254 */ 255 if ((status = smb_authsock_open(user)) != 0) 256 goto errout; 257 258 /* 259 * Tell the auth. svc who this client is. 260 */ 261 if ((status = smb_auth_do_clinfo(sr)) != 0) 262 goto errout; 263 264 msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST; 265 } else { 266 user = smb_session_lookup_uid_st(sr->session, 267 sr->smb_uid, SMB_USER_STATE_LOGGING_ON); 268 if (user == NULL) 269 return (NT_STATUS_USER_SESSION_DELETED); 270 271 /* user cleanup in smb_request_free */ 272 sr->uid_user = user; 273 274 msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT; 275 } 276 277 /* 278 * Wrap the "security blob" with our header 279 * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT) 280 * and send it up the authsock with either 281 */ 282 msg_hdr.lmh_msglen = sinfo->ssi_iseclen; 283 status = smb_authsock_sendrecv(user, &msg_hdr, 284 sinfo->ssi_isecblob, &rbuf); 285 if (status != 0) 286 goto errout; 287 rlen = msg_hdr.lmh_msglen; 288 289 /* 290 * Decode the response message. 291 * Note: allocated rbuf 292 */ 293 switch (msg_hdr.lmh_msgtype) { 294 295 case LSA_MTYPE_ES_CONT: 296 sinfo->ssi_oseclen = (uint16_t)rlen; 297 sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen); 298 bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen); 299 /* 300 * This is not really an error, but tells the client 301 * it should send another session setup request. 302 */ 303 status = NT_STATUS_MORE_PROCESSING_REQUIRED; 304 break; 305 306 case LSA_MTYPE_ES_DONE: 307 sinfo->ssi_oseclen = (uint16_t)rlen; 308 sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen); 309 bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen); 310 sinfo->ssi_ntpwlen = 0; 311 /* 312 * Get the final auth. token. 313 */ 314 status = smb_auth_get_token(sr); 315 break; 316 317 case LSA_MTYPE_ERROR: 318 /* 319 * Authentication failed. Return the error 320 * provided in the reply message. 321 */ 322 if (rlen == sizeof (smb_lsa_eresp_t)) { 323 smb_lsa_eresp_t *ler = rbuf; 324 status = ler->ler_ntstatus; 325 goto errout; 326 } 327 /* FALLTHROUGH */ 328 329 default: /* Bogus message type */ 330 status = NT_STATUS_INTERNAL_ERROR; 331 goto errout; 332 } 333 334 if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) { 335 errout: 336 smb_user_logoff(user); 337 } 338 339 if (rbuf != NULL) 340 kmem_free(rbuf, rlen); 341 342 return (status); 343 } 344 345 /* 346 * Send the "client info" up to the auth service. 347 */ 348 static uint32_t 349 smb_auth_do_clinfo(smb_request_t *sr) 350 { 351 smb_lsa_msg_hdr_t msg_hdr; 352 smb_lsa_clinfo_t clinfo; 353 smb_user_t *user = sr->uid_user; 354 void *rbuf = NULL; 355 uint32_t status; 356 357 /* 358 * Send a message with info. about the client 359 * (IP address, etc) and wait for an ACK. 360 */ 361 msg_hdr.lmh_msgtype = LSA_MTYPE_CLINFO; 362 msg_hdr.lmh_msglen = sizeof (clinfo); 363 clinfo.lci_clnt_ipaddr = sr->session->ipaddr; 364 (void) memcpy(clinfo.lci_challenge_key, 365 sr->session->challenge_key, 366 sizeof (clinfo.lci_challenge_key)); 367 status = smb_authsock_sendrecv(user, &msg_hdr, &clinfo, &rbuf); 368 /* We don't use this response. */ 369 if (rbuf != NULL) { 370 kmem_free(rbuf, msg_hdr.lmh_msglen); 371 rbuf = NULL; 372 } 373 374 return (status); 375 } 376 377 /* 378 * After a successful authentication, ask the authsvc to 379 * send us the authentication token. 380 */ 381 static uint32_t 382 smb_auth_get_token(smb_request_t *sr) 383 { 384 smb_lsa_msg_hdr_t msg_hdr; 385 XDR xdrs; 386 smb_user_t *user = sr->uid_user; 387 smb_token_t *token = NULL; 388 cred_t *cr = NULL; 389 void *rbuf = NULL; 390 uint32_t rlen = 0; 391 uint32_t privileges; 392 uint32_t status; 393 bool_t ok; 394 395 msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK; 396 msg_hdr.lmh_msglen = 0; 397 398 status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf); 399 if (status != 0) 400 goto errout; 401 402 rlen = msg_hdr.lmh_msglen; 403 switch (msg_hdr.lmh_msgtype) { 404 405 case LSA_MTYPE_TOKEN: 406 status = 0; 407 break; 408 409 case LSA_MTYPE_ERROR: 410 if (rlen == sizeof (smb_lsa_eresp_t)) { 411 smb_lsa_eresp_t *ler = rbuf; 412 status = ler->ler_ntstatus; 413 goto errout; 414 } 415 /* FALLTHROUGH */ 416 417 default: 418 status = NT_STATUS_INTERNAL_ERROR; 419 goto errout; 420 } 421 422 /* 423 * Authenticated. Decode the LSA_MTYPE_TOKEN. 424 */ 425 xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE); 426 token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP); 427 ok = smb_token_xdr(&xdrs, token); 428 xdr_destroy(&xdrs); 429 if (!ok) { 430 status = RPC_NT_BAD_STUB_DATA; 431 goto errout; 432 } 433 kmem_free(rbuf, rlen); 434 rbuf = NULL; 435 436 /* 437 * Setup the logon object. 438 */ 439 cr = smb_cred_create(token); 440 if (cr == NULL) 441 goto errout; 442 privileges = smb_priv_xlate(token); 443 (void) smb_user_logon(user, cr, 444 token->tkn_domain_name, token->tkn_account_name, 445 token->tkn_flags, privileges, token->tkn_audit_sid); 446 crfree(cr); 447 448 /* 449 * Save the session key, and (maybe) enable signing, 450 * but only for real logon (not ANON or GUEST). 451 */ 452 if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) { 453 if (smb_sign_begin(sr, token) != 0) { 454 status = NT_STATUS_INTERNAL_ERROR; 455 goto errout; 456 } 457 } 458 459 smb_token_free(token); 460 461 sr->user_cr = user->u_cred; 462 return (0); 463 464 errout: 465 if (rbuf != NULL) 466 kmem_free(rbuf, rlen); 467 if (token != NULL) 468 smb_token_free(token); 469 return (status); 470 } 471 472 /* 473 * Tokens are allocated in the kernel via XDR. 474 * Call xdr_free before freeing the token structure. 475 */ 476 void 477 smb_token_free(smb_token_t *token) 478 { 479 if (token != NULL) { 480 xdr_free(smb_token_xdr, (char *)token); 481 kmem_free(token, sizeof (smb_token_t)); 482 } 483 } 484 485 /* 486 * Convert access token privileges to local definitions. 487 */ 488 static uint32_t 489 smb_priv_xlate(smb_token_t *token) 490 { 491 uint32_t privileges = 0; 492 493 if (smb_token_query_privilege(token, SE_BACKUP_LUID)) 494 privileges |= SMB_USER_PRIV_BACKUP; 495 496 if (smb_token_query_privilege(token, SE_RESTORE_LUID)) 497 privileges |= SMB_USER_PRIV_RESTORE; 498 499 if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) 500 privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; 501 502 if (smb_token_query_privilege(token, SE_SECURITY_LUID)) 503 privileges |= SMB_USER_PRIV_SECURITY; 504 505 return (privileges); 506 } 507 508 /* 509 * Send/recv a request/reply sequence on the auth socket. 510 * Returns zero or an NT status. 511 * 512 * Errors here mean we can't communicate with the smbd_authsvc. 513 * With limited authsock instances, this should be rare. 514 */ 515 static uint32_t 516 smb_authsock_sendrecv(smb_user_t *user, smb_lsa_msg_hdr_t *hdr, 517 void *sndbuf, void **recvbuf) 518 { 519 ksocket_t so; 520 uint32_t status; 521 int rc; 522 523 /* 524 * Get a hold on the auth socket. 525 */ 526 mutex_enter(&user->u_mutex); 527 so = user->u_authsock; 528 if (so == NULL) { 529 mutex_exit(&user->u_mutex); 530 return (NT_STATUS_INTERNAL_ERROR); 531 } 532 ksocket_hold(so); 533 mutex_exit(&user->u_mutex); 534 535 rc = smb_authsock_send(so, hdr, sizeof (*hdr)); 536 if (rc == 0 && hdr->lmh_msglen != 0) { 537 rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen); 538 } 539 if (rc) 540 goto out; 541 542 rc = smb_authsock_recv(so, hdr, sizeof (*hdr)); 543 if (rc == 0 && hdr->lmh_msglen != 0) { 544 *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP); 545 rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen); 546 if (rc) { 547 kmem_free(*recvbuf, hdr->lmh_msglen); 548 *recvbuf = NULL; 549 } 550 } 551 552 out: 553 ksocket_rele(so); 554 switch (rc) { 555 case 0: 556 status = 0; 557 break; 558 case EIO: 559 status = RPC_NT_COMM_FAILURE; 560 break; 561 case ENOTCONN: 562 status = RPC_NT_PIPE_CLOSED; 563 break; 564 default: 565 status = RPC_NT_CALL_FAILED; 566 break; 567 } 568 569 return (status); 570 } 571 572 /* 573 * Hope this is interpreted per-zone... 574 */ 575 static struct sockaddr_un smbauth_sockname = { 576 AF_UNIX, SMB_AUTHSVC_SOCKNAME }; 577 578 /* 579 * Limit how long smb_authsock_sendrecv() will wait for a 580 * response from the local authentication service. 581 */ 582 struct timeval smb_auth_recv_tmo = { 45, 0 }; 583 584 /* 585 * Also limit the time smb_authsock_sendrecv() will wait 586 * trying to send a request to the authentication service. 587 */ 588 struct timeval smb_auth_send_tmo = { 15, 0 }; 589 590 static uint32_t 591 smb_authsock_open(smb_user_t *user) 592 { 593 smb_server_t *sv = user->u_server; 594 ksocket_t so = NULL; 595 uint32_t status; 596 int rc; 597 598 /* 599 * If the auth. service is busy, wait our turn. 600 * This may be frequent, so don't log. 601 */ 602 if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0) 603 return (NT_STATUS_NO_LOGON_SERVERS); 604 605 rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0, 606 KSOCKET_SLEEP, CRED()); 607 if (rc != 0) { 608 cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc); 609 status = NT_STATUS_INSUFF_SERVER_RESOURCES; 610 goto errout; 611 } 612 613 /* 614 * Set the send/recv timeouts. 615 */ 616 (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, 617 &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED()); 618 (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, 619 &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED()); 620 621 /* 622 * Connect to the smbd auth. service. 623 * 624 * Would like to set the connect timeout too, but there's 625 * apparently no easy way to do that for AF_UNIX. 626 */ 627 rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname, 628 sizeof (smbauth_sockname), CRED()); 629 if (rc != 0) { 630 DTRACE_PROBE1(error, int, rc); 631 status = NT_STATUS_NETLOGON_NOT_STARTED; 632 goto errout; 633 } 634 635 /* Note: u_authsock cleanup in smb_authsock_close() */ 636 mutex_enter(&user->u_mutex); 637 if (user->u_authsock != NULL) { 638 mutex_exit(&user->u_mutex); 639 status = NT_STATUS_INTERNAL_ERROR; 640 goto errout; 641 } 642 user->u_authsock = so; 643 mutex_exit(&user->u_mutex); 644 return (0); 645 646 errout: 647 if (so != NULL) 648 (void) ksocket_close(so, CRED()); 649 smb_threshold_exit(&sv->sv_ssetup_ct); 650 651 return (status); 652 } 653 654 static int 655 smb_authsock_send(ksocket_t so, void *buf, size_t len) 656 { 657 int rc; 658 size_t iocnt = 0; 659 660 rc = ksocket_send(so, buf, len, 0, &iocnt, CRED()); 661 if (rc == 0 && iocnt != len) { 662 DTRACE_PROBE1(short, size_t, iocnt); 663 rc = EIO; 664 } 665 if (rc != 0) { 666 DTRACE_PROBE1(error, int, rc); 667 } 668 669 return (rc); 670 } 671 672 static int 673 smb_authsock_recv(ksocket_t so, void *buf, size_t len) 674 { 675 int rc; 676 size_t iocnt = 0; 677 678 rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED()); 679 if (rc == 0) { 680 if (iocnt == 0) { 681 DTRACE_PROBE1(discon, struct sonode *, so); 682 rc = ENOTCONN; 683 } else if (iocnt != len) { 684 /* Should not happen with MSG_WAITALL */ 685 DTRACE_PROBE1(short, size_t, iocnt); 686 rc = EIO; 687 } 688 } 689 if (rc != 0) { 690 DTRACE_PROBE1(error, int, rc); 691 } 692 693 return (rc); 694 } 695 696 void 697 smb_authsock_close(smb_user_t *user) 698 { 699 700 ASSERT(MUTEX_HELD(&user->u_mutex)); 701 if (user->u_authsock == NULL) 702 return; 703 (void) ksocket_close(user->u_authsock, CRED()); 704 user->u_authsock = NULL; 705 smb_threshold_exit(&user->u_server->sv_ssetup_ct); 706 } 707