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);
}