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         int             rc;
 394         bool_t          ok;
 395 
 396         msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK;
 397         msg_hdr.lmh_msglen = 0;
 398 
 399         status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf);
 400         if (status != 0)
 401                 goto errout;
 402 
 403         rlen = msg_hdr.lmh_msglen;
 404         switch (msg_hdr.lmh_msgtype) {
 405 
 406         case LSA_MTYPE_TOKEN:
 407                 status = 0;
 408                 break;
 409 
 410         case LSA_MTYPE_ERROR:
 411                 if (rlen == sizeof (smb_lsa_eresp_t)) {
 412                         smb_lsa_eresp_t *ler = rbuf;
 413                         status = ler->ler_ntstatus;
 414                         goto errout;
 415                 }
 416                 /* FALLTHROUGH */
 417 
 418         default:
 419                 status = NT_STATUS_INTERNAL_ERROR;
 420                 goto errout;
 421         }
 422 
 423         /*
 424          * Authenticated.  Decode the LSA_MTYPE_TOKEN.
 425          */
 426         xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE);
 427         token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
 428         ok = smb_token_xdr(&xdrs, token);
 429         xdr_destroy(&xdrs);
 430         if (!ok) {
 431                 status = RPC_NT_BAD_STUB_DATA;
 432                 goto errout;
 433         }
 434         kmem_free(rbuf, rlen);
 435         rbuf = NULL;
 436 
 437         /*
 438          * Setup the logon object.
 439          */
 440         cr = smb_cred_create(token);
 441         if (cr == NULL)
 442                 goto errout;
 443         privileges = smb_priv_xlate(token);
 444         (void) smb_user_logon(user, cr,
 445             token->tkn_domain_name, token->tkn_account_name,
 446             token->tkn_flags, privileges, token->tkn_audit_sid);
 447         crfree(cr);
 448 
 449         /*
 450          * Save the session key, and (maybe) enable signing,
 451          * but only for real logon (not ANON or GUEST).
 452          */
 453         if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) {
 454                 if (sr->session->dialect >= SMB_VERS_2_BASE) {
 455                         rc = smb2_sign_begin(sr, token);
 456                 } else {
 457                         rc = smb_sign_begin(sr, token);
 458                 }
 459                 if (rc != 0) {
 460                         status = NT_STATUS_INTERNAL_ERROR;
 461                         goto errout;
 462                 }
 463         }
 464 
 465         smb_token_free(token);
 466 
 467         sr->user_cr = user->u_cred;
 468         return (0);
 469 
 470 errout:
 471         if (rbuf != NULL)
 472                 kmem_free(rbuf, rlen);
 473         if (token != NULL)
 474                 smb_token_free(token);
 475         return (status);
 476 }
 477 
 478 /*
 479  * Tokens are allocated in the kernel via XDR.
 480  * Call xdr_free before freeing the token structure.
 481  */
 482 void
 483 smb_token_free(smb_token_t *token)
 484 {
 485         if (token != NULL) {
 486                 xdr_free(smb_token_xdr, (char *)token);
 487                 kmem_free(token, sizeof (smb_token_t));
 488         }
 489 }
 490 
 491 /*
 492  * Convert access token privileges to local definitions.
 493  */
 494 static uint32_t
 495 smb_priv_xlate(smb_token_t *token)
 496 {
 497         uint32_t        privileges = 0;
 498 
 499         if (smb_token_query_privilege(token, SE_BACKUP_LUID))
 500                 privileges |= SMB_USER_PRIV_BACKUP;
 501 
 502         if (smb_token_query_privilege(token, SE_RESTORE_LUID))
 503                 privileges |= SMB_USER_PRIV_RESTORE;
 504 
 505         if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
 506                 privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
 507 
 508         if (smb_token_query_privilege(token, SE_SECURITY_LUID))
 509                 privileges |= SMB_USER_PRIV_SECURITY;
 510 
 511         return (privileges);
 512 }
 513 
 514 /*
 515  * Send/recv a request/reply sequence on the auth socket.
 516  * Returns zero or an NT status.
 517  *
 518  * Errors here mean we can't communicate with the smbd_authsvc.
 519  * With limited authsock instances, this should be rare.
 520  */
 521 static uint32_t
 522 smb_authsock_sendrecv(smb_user_t *user, smb_lsa_msg_hdr_t *hdr,
 523         void *sndbuf, void **recvbuf)
 524 {
 525         ksocket_t so;
 526         uint32_t status;
 527         int rc;
 528 
 529         /*
 530          * Get a hold on the auth socket.
 531          */
 532         mutex_enter(&user->u_mutex);
 533         so = user->u_authsock;
 534         if (so == NULL) {
 535                 mutex_exit(&user->u_mutex);
 536                 return (NT_STATUS_INTERNAL_ERROR);
 537         }
 538         ksocket_hold(so);
 539         mutex_exit(&user->u_mutex);
 540 
 541         rc = smb_authsock_send(so, hdr, sizeof (*hdr));
 542         if (rc == 0 && hdr->lmh_msglen != 0) {
 543                 rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
 544         }
 545         if (rc)
 546                 goto out;
 547 
 548         rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
 549         if (rc == 0 && hdr->lmh_msglen != 0) {
 550                 *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
 551                 rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
 552                 if (rc) {
 553                         kmem_free(*recvbuf, hdr->lmh_msglen);
 554                         *recvbuf = NULL;
 555                 }
 556         }
 557 
 558 out:
 559         ksocket_rele(so);
 560         switch (rc) {
 561         case 0:
 562                 status = 0;
 563                 break;
 564         case EIO:
 565                 status = RPC_NT_COMM_FAILURE;
 566                 break;
 567         case ENOTCONN:
 568                 status = RPC_NT_PIPE_CLOSED;
 569                 break;
 570         default:
 571                 status = RPC_NT_CALL_FAILED;
 572                 break;
 573         }
 574 
 575         return (status);
 576 }
 577 
 578 /*
 579  * Hope this is interpreted per-zone...
 580  */
 581 static struct sockaddr_un smbauth_sockname = {
 582         AF_UNIX, SMB_AUTHSVC_SOCKNAME };
 583 
 584 /*
 585  * Limit how long smb_authsock_sendrecv() will wait for a
 586  * response from the local authentication service.
 587  */
 588 struct timeval smb_auth_recv_tmo = { 45, 0 };
 589 
 590 /*
 591  * Also limit the time smb_authsock_sendrecv() will wait
 592  * trying to send a request to the authentication service.
 593  */
 594 struct timeval smb_auth_send_tmo = { 15, 0 };
 595 
 596 static uint32_t
 597 smb_authsock_open(smb_user_t *user)
 598 {
 599         smb_server_t *sv = user->u_server;
 600         ksocket_t so = NULL;
 601         uint32_t status;
 602         int rc;
 603 
 604         /*
 605          * If the auth. service is busy, wait our turn.
 606          * This may be frequent, so don't log.
 607          */
 608         if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
 609                 return (NT_STATUS_NO_LOGON_SERVERS);
 610 
 611         rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
 612             KSOCKET_SLEEP, CRED());
 613         if (rc != 0) {
 614                 cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
 615                 status = NT_STATUS_INSUFF_SERVER_RESOURCES;
 616                 goto errout;
 617         }
 618 
 619         /*
 620          * Set the send/recv timeouts.
 621          */
 622         (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
 623             &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
 624         (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
 625             &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
 626 
 627         /*
 628          * Connect to the smbd auth. service.
 629          *
 630          * Would like to set the connect timeout too, but there's
 631          * apparently no easy way to do that for AF_UNIX.
 632          */
 633         rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
 634             sizeof (smbauth_sockname), CRED());
 635         if (rc != 0) {
 636                 DTRACE_PROBE1(error, int, rc);
 637                 status = NT_STATUS_NETLOGON_NOT_STARTED;
 638                 goto errout;
 639         }
 640 
 641         /* Note: u_authsock cleanup in smb_authsock_close() */
 642         mutex_enter(&user->u_mutex);
 643         if (user->u_authsock != NULL) {
 644                 mutex_exit(&user->u_mutex);
 645                 status = NT_STATUS_INTERNAL_ERROR;
 646                 goto errout;
 647         }
 648         user->u_authsock = so;
 649         mutex_exit(&user->u_mutex);
 650         return (0);
 651 
 652 errout:
 653         if (so != NULL)
 654                 (void) ksocket_close(so, CRED());
 655         smb_threshold_exit(&sv->sv_ssetup_ct);
 656 
 657         return (status);
 658 }
 659 
 660 static int
 661 smb_authsock_send(ksocket_t so, void *buf, size_t len)
 662 {
 663         int rc;
 664         size_t iocnt = 0;
 665 
 666         rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
 667         if (rc == 0 && iocnt != len) {
 668                 DTRACE_PROBE1(short, size_t, iocnt);
 669                 rc = EIO;
 670         }
 671         if (rc != 0) {
 672                 DTRACE_PROBE1(error, int, rc);
 673         }
 674 
 675         return (rc);
 676 }
 677 
 678 static int
 679 smb_authsock_recv(ksocket_t so, void *buf, size_t len)
 680 {
 681         int rc;
 682         size_t iocnt = 0;
 683 
 684         rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
 685         if (rc == 0) {
 686                 if (iocnt == 0) {
 687                         DTRACE_PROBE1(discon, struct sonode *, so);
 688                         rc = ENOTCONN;
 689                 } else if (iocnt != len) {
 690                         /* Should not happen with MSG_WAITALL */
 691                         DTRACE_PROBE1(short, size_t, iocnt);
 692                         rc = EIO;
 693                 }
 694         }
 695         if (rc != 0) {
 696                 DTRACE_PROBE1(error, int, rc);
 697         }
 698 
 699         return (rc);
 700 }
 701 
 702 void
 703 smb_authsock_close(smb_user_t *user)
 704 {
 705 
 706         ASSERT(MUTEX_HELD(&user->u_mutex));
 707         if (user->u_authsock == NULL)
 708                 return;
 709         (void) ksocket_close(user->u_authsock, CRED());
 710         user->u_authsock = NULL;
 711         smb_threshold_exit(&user->u_server->sv_ssetup_ct);
 712 }