Print this page
NEX-19781 SMB service shutdown hang with threads in smb_authsock_recv
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-16604 Windows 10 SMB client exhausts smbauth sockets
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-9497 SMB should bypass ACL traverse checking
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-10231 SMB logon fails in fksmbd
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-7267 Codenomicon causes panic in smb_authsock_cancel (lint)
NEX-7267 Codenomicon causes panic in smb_authsock_cancel
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6888 Defensics test causes panic due to bad free
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5560 smb2 should use 64-bit server-global uids
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-2522 svcadm disable network/smb/server may hang
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3610 CLONE NEX-3591 SMB3 signing
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3611 CLONE NEX-3550 Replace smb2_enable with max_protocol
Reviewed by: Yuri Pankov <Yuri.Pankov@nexenta.com>
NEX-3080 SMB1 signing problem with Kerberos auth.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2485 SMB authentication flood handled poorly
SUP-866 smbd lwps stuck in libsocket recv() for no apparent reason
SMB-152 mem leak in smb_authenticate_ext/smb_authsock_sendrecv
SMB-55 SMB2 signing
OS-6 mpathadm leads to panic in vhci_mpapi_sync_lu_oid_list
SMB-85 Codenomicon: SMB2 TC: 16193 - Panic in smb_authenticate_ext
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-56 extended security NTLMSSP, inbound

*** 18,28 **** * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* * Authentication support for SMB session setup */ --- 18,28 ---- * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2019 Nexenta Systems, Inc. All rights reserved. */ /* * Authentication support for SMB session setup */
*** 35,48 **** #include <netinet/in.h> #include <smbsrv/smb_idmap.h> #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_token.h> ! static uint32_t smb_authsock_open(smb_user_t *); static int smb_authsock_send(ksocket_t, void *, size_t); static int smb_authsock_recv(ksocket_t, void *, size_t); ! static uint32_t smb_authsock_sendrecv(smb_user_t *, smb_lsa_msg_hdr_t *hdr, void *sndbuf, void **recvbuf); /* void smb_authsock_close(smb_user_t *); kproto.h */ static uint32_t smb_auth_do_clinfo(smb_request_t *); static uint32_t smb_auth_do_oldreq(smb_request_t *); --- 35,48 ---- #include <netinet/in.h> #include <smbsrv/smb_idmap.h> #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_token.h> ! static uint32_t smb_authsock_open(smb_request_t *); static int smb_authsock_send(ksocket_t, void *, size_t); static int smb_authsock_recv(ksocket_t, void *, size_t); ! static uint32_t smb_authsock_sendrecv(smb_request_t *, smb_lsa_msg_hdr_t *hdr, void *sndbuf, void **recvbuf); /* void smb_authsock_close(smb_user_t *); kproto.h */ static uint32_t smb_auth_do_clinfo(smb_request_t *); static uint32_t smb_auth_do_oldreq(smb_request_t *);
*** 49,58 **** --- 49,59 ---- static uint32_t smb_auth_get_token(smb_request_t *); static uint32_t smb_priv_xlate(smb_token_t *); /* * Handle old-style session setup (non-extended security) + * Note: Used only by SMB1 * * The user information is passed to smbd for authentication. * If smbd can authenticate the user an access token is returned and we * generate a cred and new user based on the token. */
*** 67,83 **** return (NT_STATUS_TOO_MANY_SESSIONS); /* user cleanup in smb_request_free */ sr->uid_user = user; sr->smb_uid = user->u_uid; /* * Open a connection to the local logon service. * If we can't, it may be busy, or not running. * Don't log here - this may be frequent. */ ! if ((status = smb_authsock_open(user)) != 0) goto errout; /* * Tell the auth. svc who this client is. */ --- 68,85 ---- return (NT_STATUS_TOO_MANY_SESSIONS); /* user cleanup in smb_request_free */ sr->uid_user = user; sr->smb_uid = user->u_uid; + sr->smb2_ssnid = 0; /* * Open a connection to the local logon service. * If we can't, it may be busy, or not running. * Don't log here - this may be frequent. */ ! if ((status = smb_authsock_open(sr)) != 0) goto errout; /* * Tell the auth. svc who this client is. */
*** 112,122 **** { smb_lsa_msg_hdr_t msg_hdr; smb_logon_t user_info; XDR xdrs; smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; - smb_user_t *user = sr->uid_user; void *sbuf = NULL; void *rbuf = NULL; uint32_t slen = 0; uint32_t rlen = 0; uint32_t status; --- 114,123 ----
*** 151,161 **** goto out; } msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ; msg_hdr.lmh_msglen = slen; ! status = smb_authsock_sendrecv(user, &msg_hdr, sbuf, &rbuf); if (status != 0) goto out; rlen = msg_hdr.lmh_msglen; kmem_free(sbuf, slen); sbuf = NULL; --- 152,162 ---- goto out; } msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ; msg_hdr.lmh_msglen = slen; ! status = smb_authsock_sendrecv(sr, &msg_hdr, sbuf, &rbuf); if (status != 0) goto out; rlen = msg_hdr.lmh_msglen; kmem_free(sbuf, slen); sbuf = NULL;
*** 230,260 **** uint32_t status; ASSERT(sr->uid_user == NULL); /* ! * On the first request (UID==0) create a USER object. ! * On subsequent requests (UID!=0) find the USER object. * Either way, sr->uid_user is set, so our ref. on the * user object is dropped during normal cleanup work * for the smb_request (sr). Ditto u_authsock. */ ! if (sr->smb_uid == 0) { user = smb_user_new(sr->session); if (user == NULL) return (NT_STATUS_TOO_MANY_SESSIONS); /* user cleanup in smb_request_free */ sr->uid_user = user; sr->smb_uid = user->u_uid; /* * Open a connection to the local logon service. * If we can't, it may be busy, or not running. * Don't log here - this may be frequent. */ ! if ((status = smb_authsock_open(user)) != 0) goto errout; /* * Tell the auth. svc who this client is. */ --- 231,283 ---- uint32_t status; ASSERT(sr->uid_user == NULL); /* ! * Paranoid: While finding/creating the user object, make sure ! * SMB2 ignores smb_uid, and SMB1 ignores smb2_ssnid. The ! * logic below assumes the "other" one is always zero; both ! * the "first request" tests and smb_session_lookup_uid_st. ! */ ! if (sr->session->dialect >= SMB_VERS_2_BASE) { ! /* SMB2+ ignores smb_uid */ ! ASSERT(sr->smb_uid == 0); ! sr->smb_uid = 0; ! } else { ! /* SMB1 ignores smb2_ssnid */ ! ASSERT(sr->smb2_ssnid == 0); ! sr->smb2_ssnid = 0; ! } ! ! /* ! * On the first request (UID/ssnid==0) create a USER object. ! * On subsequent requests (UID/ssnid!=0) find the USER object. * Either way, sr->uid_user is set, so our ref. on the * user object is dropped during normal cleanup work * for the smb_request (sr). Ditto u_authsock. */ ! if (sr->smb2_ssnid == 0 && sr->smb_uid == 0) { user = smb_user_new(sr->session); if (user == NULL) return (NT_STATUS_TOO_MANY_SESSIONS); /* user cleanup in smb_request_free */ sr->uid_user = user; + if (sr->session->dialect >= SMB_VERS_2_BASE) { + /* Intentionally leave smb_uid=0 for SMB2 */ + sr->smb2_ssnid = user->u_ssnid; + } else { + /* Intentionally leave smb2_ssnid=0 for SMB1 */ sr->smb_uid = user->u_uid; + } /* * Open a connection to the local logon service. * If we can't, it may be busy, or not running. * Don't log here - this may be frequent. */ ! if ((status = smb_authsock_open(sr)) != 0) goto errout; /* * Tell the auth. svc who this client is. */
*** 262,272 **** goto errout; msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST; } else { user = smb_session_lookup_uid_st(sr->session, ! sr->smb_uid, SMB_USER_STATE_LOGGING_ON); if (user == NULL) return (NT_STATUS_USER_SESSION_DELETED); /* user cleanup in smb_request_free */ sr->uid_user = user; --- 285,295 ---- goto errout; msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST; } else { user = smb_session_lookup_uid_st(sr->session, ! sr->smb2_ssnid, sr->smb_uid, SMB_USER_STATE_LOGGING_ON); if (user == NULL) return (NT_STATUS_USER_SESSION_DELETED); /* user cleanup in smb_request_free */ sr->uid_user = user;
*** 278,288 **** * Wrap the "security blob" with our header * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT) * and send it up the authsock with either */ msg_hdr.lmh_msglen = sinfo->ssi_iseclen; ! status = smb_authsock_sendrecv(user, &msg_hdr, sinfo->ssi_isecblob, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen; --- 301,311 ---- * Wrap the "security blob" with our header * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT) * and send it up the authsock with either */ msg_hdr.lmh_msglen = sinfo->ssi_iseclen; ! status = smb_authsock_sendrecv(sr, &msg_hdr, sinfo->ssi_isecblob, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen;
*** 348,358 **** static uint32_t smb_auth_do_clinfo(smb_request_t *sr) { smb_lsa_msg_hdr_t msg_hdr; smb_lsa_clinfo_t clinfo; - smb_user_t *user = sr->uid_user; void *rbuf = NULL; uint32_t status; /* * Send a message with info. about the client --- 371,380 ----
*** 362,372 **** msg_hdr.lmh_msglen = sizeof (clinfo); clinfo.lci_clnt_ipaddr = sr->session->ipaddr; (void) memcpy(clinfo.lci_challenge_key, sr->session->challenge_key, sizeof (clinfo.lci_challenge_key)); ! status = smb_authsock_sendrecv(user, &msg_hdr, &clinfo, &rbuf); /* We don't use this response. */ if (rbuf != NULL) { kmem_free(rbuf, msg_hdr.lmh_msglen); rbuf = NULL; } --- 384,394 ---- msg_hdr.lmh_msglen = sizeof (clinfo); clinfo.lci_clnt_ipaddr = sr->session->ipaddr; (void) memcpy(clinfo.lci_challenge_key, sr->session->challenge_key, sizeof (clinfo.lci_challenge_key)); ! status = smb_authsock_sendrecv(sr, &msg_hdr, &clinfo, &rbuf); /* We don't use this response. */ if (rbuf != NULL) { kmem_free(rbuf, msg_hdr.lmh_msglen); rbuf = NULL; }
*** 388,404 **** cred_t *cr = NULL; void *rbuf = NULL; uint32_t rlen = 0; uint32_t privileges; uint32_t status; - int rc; bool_t ok; msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK; msg_hdr.lmh_msglen = 0; ! status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen; switch (msg_hdr.lmh_msgtype) { --- 410,425 ---- cred_t *cr = NULL; void *rbuf = NULL; uint32_t rlen = 0; uint32_t privileges; uint32_t status; bool_t ok; msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK; msg_hdr.lmh_msglen = 0; ! status = smb_authsock_sendrecv(sr, &msg_hdr, NULL, &rbuf); if (status != 0) goto errout; rlen = msg_hdr.lmh_msglen; switch (msg_hdr.lmh_msgtype) {
*** 435,468 **** rbuf = NULL; /* * Setup the logon object. */ ! cr = smb_cred_create(token); if (cr == NULL) goto errout; privileges = smb_priv_xlate(token); (void) smb_user_logon(user, cr, token->tkn_domain_name, token->tkn_account_name, token->tkn_flags, privileges, token->tkn_audit_sid); crfree(cr); /* * Save the session key, and (maybe) enable signing, * but only for real logon (not ANON or GUEST). */ if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) { if (sr->session->dialect >= SMB_VERS_2_BASE) { ! rc = smb2_sign_begin(sr, token); } else { ! rc = smb_sign_begin(sr, token); } - if (rc != 0) { - status = NT_STATUS_INTERNAL_ERROR; - goto errout; } - } smb_token_free(token); sr->user_cr = user->u_cred; return (0); --- 456,501 ---- rbuf = NULL; /* * Setup the logon object. */ ! cr = smb_cred_create(token, sr->session); if (cr == NULL) goto errout; privileges = smb_priv_xlate(token); (void) smb_user_logon(user, cr, token->tkn_domain_name, token->tkn_account_name, token->tkn_flags, privileges, token->tkn_audit_sid); crfree(cr); /* + * Some basic processing for encryption needs to be done, + * even for anonymous/guest sessions. In particular, + * we need to set Session.EncryptData. + * + * Windows handling of anon/guest and encryption is strange. + * It allows these accounts to get through session setup, + * even when they provide no key material. + * Additionally, Windows somehow manages to have key material + * for anonymous accounts under unknown circumstances. + * As such, We set EncryptData on anon/guest to behave like Windows, + * at least through Session Setup. + */ + if (sr->session->dialect >= SMB_VERS_3_0) + smb3_encrypt_begin(sr, token); + + /* * Save the session key, and (maybe) enable signing, * but only for real logon (not ANON or GUEST). */ if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) { if (sr->session->dialect >= SMB_VERS_2_BASE) { ! smb2_sign_begin(sr, token); } else { ! smb_sign_begin(sr, token); } } smb_token_free(token); sr->user_cr = user->u_cred; return (0);
*** 494,529 **** static uint32_t smb_priv_xlate(smb_token_t *token) { uint32_t privileges = 0; if (smb_token_query_privilege(token, SE_BACKUP_LUID)) privileges |= SMB_USER_PRIV_BACKUP; if (smb_token_query_privilege(token, SE_RESTORE_LUID)) privileges |= SMB_USER_PRIV_RESTORE; ! if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) ! privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; - if (smb_token_query_privilege(token, SE_SECURITY_LUID)) - privileges |= SMB_USER_PRIV_SECURITY; - return (privileges); } /* * Send/recv a request/reply sequence on the auth socket. * Returns zero or an NT status. * * Errors here mean we can't communicate with the smbd_authsvc. * With limited authsock instances, this should be rare. */ static uint32_t ! smb_authsock_sendrecv(smb_user_t *user, smb_lsa_msg_hdr_t *hdr, void *sndbuf, void **recvbuf) { ksocket_t so; uint32_t status; int rc; /* --- 527,597 ---- static uint32_t smb_priv_xlate(smb_token_t *token) { uint32_t privileges = 0; + if (smb_token_query_privilege(token, SE_SECURITY_LUID)) + privileges |= SMB_USER_PRIV_SECURITY; + + if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) + privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP; + if (smb_token_query_privilege(token, SE_BACKUP_LUID)) privileges |= SMB_USER_PRIV_BACKUP; if (smb_token_query_privilege(token, SE_RESTORE_LUID)) privileges |= SMB_USER_PRIV_RESTORE; ! if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID)) ! privileges |= SMB_USER_PRIV_CHANGE_NOTIFY; return (privileges); } /* + * Unblock a request that might be blocked reading some + * authentication socket. This can happen when either the + * client cancels a session setup or closes the connection. + */ + static void + smb_authsock_cancel(smb_request_t *sr) + { + smb_user_t *user = sr->cancel_arg2; + ksocket_t authsock = NULL; + + if (user == NULL) + return; + ASSERT(user == sr->uid_user); + + /* + * Check user state, and get a hold on the auth socket. + */ + mutex_enter(&user->u_mutex); + if (user->u_state == SMB_USER_STATE_LOGGING_ON) { + if ((authsock = user->u_authsock) != NULL) + ksocket_hold(authsock); + } + mutex_exit(&user->u_mutex); + + if (authsock != NULL) { + (void) ksocket_shutdown(authsock, SHUT_RDWR, sr->user_cr); + ksocket_rele(authsock); + } + } + + /* * Send/recv a request/reply sequence on the auth socket. * Returns zero or an NT status. * * Errors here mean we can't communicate with the smbd_authsvc. * With limited authsock instances, this should be rare. */ static uint32_t ! smb_authsock_sendrecv(smb_request_t *sr, smb_lsa_msg_hdr_t *hdr, void *sndbuf, void **recvbuf) { + smb_user_t *user = sr->uid_user; ksocket_t so; uint32_t status; int rc; /*
*** 536,564 **** return (NT_STATUS_INTERNAL_ERROR); } ksocket_hold(so); mutex_exit(&user->u_mutex); rc = smb_authsock_send(so, hdr, sizeof (*hdr)); if (rc == 0 && hdr->lmh_msglen != 0) { rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen); } ! if (rc) ! goto out; ! rc = smb_authsock_recv(so, hdr, sizeof (*hdr)); if (rc == 0 && hdr->lmh_msglen != 0) { *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP); rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen); - if (rc) { - kmem_free(*recvbuf, hdr->lmh_msglen); - *recvbuf = NULL; } - } - out: - ksocket_rele(so); switch (rc) { case 0: status = 0; break; case EIO: --- 604,635 ---- return (NT_STATUS_INTERNAL_ERROR); } ksocket_hold(so); mutex_exit(&user->u_mutex); + mutex_enter(&sr->sr_mutex); + if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { + mutex_exit(&sr->sr_mutex); + status = NT_STATUS_CANCELLED; + goto out; + } + sr->sr_state = SMB_REQ_STATE_WAITING_AUTH; + sr->cancel_method = smb_authsock_cancel; + sr->cancel_arg2 = user; + mutex_exit(&sr->sr_mutex); + rc = smb_authsock_send(so, hdr, sizeof (*hdr)); if (rc == 0 && hdr->lmh_msglen != 0) { rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen); } ! if (rc == 0) rc = smb_authsock_recv(so, hdr, sizeof (*hdr)); if (rc == 0 && hdr->lmh_msglen != 0) { *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP); rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen); } switch (rc) { case 0: status = 0; break; case EIO:
*** 570,579 **** --- 641,674 ---- default: status = RPC_NT_CALL_FAILED; break; } + mutex_enter(&sr->sr_mutex); + sr->cancel_method = NULL; + sr->cancel_arg2 = NULL; + switch (sr->sr_state) { + case SMB_REQ_STATE_WAITING_AUTH: + sr->sr_state = SMB_REQ_STATE_ACTIVE; + break; + case SMB_REQ_STATE_CANCEL_PENDING: + sr->sr_state = SMB_REQ_STATE_CANCELLED; + status = NT_STATUS_CANCELLED; + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; + } + mutex_exit(&sr->sr_mutex); + + out: + ksocket_rele(so); + + if (status != 0 && *recvbuf != NULL) { + kmem_free(*recvbuf, hdr->lmh_msglen); + *recvbuf = NULL; + } return (status); } /* * Hope this is interpreted per-zone...
*** 591,624 **** * Also limit the time smb_authsock_sendrecv() will wait * trying to send a request to the authentication service. */ struct timeval smb_auth_send_tmo = { 15, 0 }; static uint32_t ! smb_authsock_open(smb_user_t *user) { ! smb_server_t *sv = user->u_server; ksocket_t so = NULL; ! uint32_t status; int rc; /* ! * If the auth. service is busy, wait our turn. ! * This may be frequent, so don't log. */ if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0) return (NT_STATUS_NO_LOGON_SERVERS); rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0, KSOCKET_SLEEP, CRED()); if (rc != 0) { cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc); status = NT_STATUS_INSUFF_SERVER_RESOURCES; goto errout; } /* * Set the send/recv timeouts. */ (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED()); (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, --- 686,753 ---- * Also limit the time smb_authsock_sendrecv() will wait * trying to send a request to the authentication service. */ struct timeval smb_auth_send_tmo = { 15, 0 }; + /* + * Maximum time a user object may stay in state LOGGING_ON + */ + int smb_auth_total_tmo = 45; /* seconds */ + static uint32_t ! smb_authsock_open(smb_request_t *sr) { ! smb_user_t *user = sr->uid_user; ! smb_server_t *sv = sr->sr_server; ksocket_t so = NULL; ! uint32_t status = 0; int rc; /* ! * If the auth. service is busy, wait our turn. This threshold ! * limits the number of auth sockets we might have trying to ! * communicate with the auth. service up in smbd. Until we've ! * set u_authsock, we need to "exit this threshold" in any ! * error code paths after this "enter". ! * ! * Failure to "enter" may be frequent, so don't log. */ if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0) return (NT_STATUS_NO_LOGON_SERVERS); rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0, KSOCKET_SLEEP, CRED()); if (rc != 0) { cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc); + smb_threshold_exit(&sv->sv_ssetup_ct); status = NT_STATUS_INSUFF_SERVER_RESOURCES; goto errout; } /* + * This (new) user object now gets an authsocket. + * Note: u_authsock cleanup in smb_user_logoff. + * After we've set u_authsock, smb_threshold_exit + * is done in smb_authsock_close(). If we somehow + * already have an authsock, close the new one and + * error out. + */ + mutex_enter(&user->u_mutex); + if (user->u_authsock != NULL) { + mutex_exit(&user->u_mutex); + smb_authsock_close(user, so); + status = NT_STATUS_INTERNAL_ERROR; + goto errout; + } + user->u_authsock = so; + if (smb_auth_total_tmo != 0) { + user->u_auth_tmo = timeout(smb_user_auth_tmo, user, + SEC_TO_TICK(smb_auth_total_tmo)); + } + mutex_exit(&user->u_mutex); + + /* * Set the send/recv timeouts. */ (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED()); (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
*** 628,661 **** * Connect to the smbd auth. service. * * Would like to set the connect timeout too, but there's * apparently no easy way to do that for AF_UNIX. */ rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname, sizeof (smbauth_sockname), CRED()); if (rc != 0) { DTRACE_PROBE1(error, int, rc); status = NT_STATUS_NETLOGON_NOT_STARTED; - goto errout; } ! /* Note: u_authsock cleanup in smb_authsock_close() */ ! mutex_enter(&user->u_mutex); ! if (user->u_authsock != NULL) { ! mutex_exit(&user->u_mutex); status = NT_STATUS_INTERNAL_ERROR; ! goto errout; } ! user->u_authsock = so; ! mutex_exit(&user->u_mutex); ! return (0); errout: - if (so != NULL) - (void) ksocket_close(so, CRED()); - smb_threshold_exit(&sv->sv_ssetup_ct); - return (status); } static int smb_authsock_send(ksocket_t so, void *buf, size_t len) --- 757,802 ---- * Connect to the smbd auth. service. * * Would like to set the connect timeout too, but there's * apparently no easy way to do that for AF_UNIX. */ + mutex_enter(&sr->sr_mutex); + if (sr->sr_state != SMB_REQ_STATE_ACTIVE) { + mutex_exit(&sr->sr_mutex); + status = NT_STATUS_CANCELLED; + goto errout; + } + sr->sr_state = SMB_REQ_STATE_WAITING_AUTH; + sr->cancel_method = smb_authsock_cancel; + sr->cancel_arg2 = user; + mutex_exit(&sr->sr_mutex); + rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname, sizeof (smbauth_sockname), CRED()); if (rc != 0) { DTRACE_PROBE1(error, int, rc); status = NT_STATUS_NETLOGON_NOT_STARTED; } ! mutex_enter(&sr->sr_mutex); ! sr->cancel_method = NULL; ! sr->cancel_arg2 = NULL; ! switch (sr->sr_state) { ! case SMB_REQ_STATE_WAITING_AUTH: ! sr->sr_state = SMB_REQ_STATE_ACTIVE; ! break; ! case SMB_REQ_STATE_CANCEL_PENDING: ! sr->sr_state = SMB_REQ_STATE_CANCELLED; ! status = NT_STATUS_CANCELLED; ! break; ! default: status = NT_STATUS_INTERNAL_ERROR; ! break; } ! mutex_exit(&sr->sr_mutex); errout: return (status); } static int smb_authsock_send(ksocket_t so, void *buf, size_t len)
*** 697,712 **** } return (rc); } void ! smb_authsock_close(smb_user_t *user) { ! ASSERT(MUTEX_HELD(&user->u_mutex)); ! if (user->u_authsock == NULL) ! return; ! (void) ksocket_close(user->u_authsock, CRED()); ! user->u_authsock = NULL; smb_threshold_exit(&user->u_server->sv_ssetup_ct); } --- 838,855 ---- } return (rc); } + /* + * Caller has cleared user->u_authsock, passing the last ref + * as the 2nd arg here. This can block, so it's called + * after exiting u_mutex. + */ void ! smb_authsock_close(smb_user_t *user, ksocket_t so) { ! (void) ksocket_shutdown(so, SHUT_RDWR, CRED()); ! (void) ksocket_close(so, CRED()); smb_threshold_exit(&user->u_server->sv_ssetup_ct); }