#include "../libcli/security/dom_sid.h"
#include "../libcli/security/security_token.h"
#include "lib/id_cache.h"
+#include "lib/util/sys_rw_data.h"
#include "serverid.h"
+#include "system/threads.h"
/* Internal message queue for deferred opens. */
struct pending_message_list {
struct pending_message_list *next, *prev;
struct timeval request_time; /* When was this first issued? */
struct smbd_server_connection *sconn;
+ struct smbXsrv_connection *xconn;
struct tevent_timer *te;
struct smb_perfcount_data pcd;
uint32_t seqnum;
bool encrypted;
bool processed;
DATA_BLOB buf;
- DATA_BLOB private_data;
+ struct deferred_open_record *open_rec;
};
-static void construct_reply_common(struct smb_request *req, const char *inbuf,
+static void construct_reply_common(uint8_t cmd, const uint8_t *inbuf,
char *outbuf);
static struct pending_message_list *get_deferred_open_message_smb(
struct smbd_server_connection *sconn, uint64_t mid);
static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf);
-static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn)
+static void smbd_echo_init(struct smbXsrv_connection *xconn)
{
- bool ok;
+ xconn->smb1.echo_handler.trusted_fd = -1;
+ xconn->smb1.echo_handler.socket_lock_fd = -1;
+#ifdef HAVE_ROBUST_MUTEXES
+ xconn->smb1.echo_handler.socket_mutex = NULL;
+#endif
+}
+
+static bool smbd_echo_active(struct smbXsrv_connection *xconn)
+{
+ if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
+ return true;
+ }
- if (sconn->smb1.echo_handler.socket_lock_fd == -1) {
+#ifdef HAVE_ROBUST_MUTEXES
+ if (xconn->smb1.echo_handler.socket_mutex != NULL) {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+static bool smbd_lock_socket_internal(struct smbXsrv_connection *xconn)
+{
+ if (!smbd_echo_active(xconn)) {
return true;
}
- sconn->smb1.echo_handler.ref_count++;
+ xconn->smb1.echo_handler.ref_count++;
- if (sconn->smb1.echo_handler.ref_count > 1) {
+ if (xconn->smb1.echo_handler.ref_count > 1) {
return true;
}
DEBUG(10,("pid[%d] wait for socket lock\n", (int)getpid()));
- do {
- ok = fcntl_lock(
- sconn->smb1.echo_handler.socket_lock_fd,
- F_SETLKW, 0, 0, F_WRLCK);
- } while (!ok && (errno == EINTR));
+#ifdef HAVE_ROBUST_MUTEXES
+ if (xconn->smb1.echo_handler.socket_mutex != NULL) {
+ int ret = EINTR;
- if (!ok) {
- DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
- return false;
+ while (ret == EINTR) {
+ ret = pthread_mutex_lock(
+ xconn->smb1.echo_handler.socket_mutex);
+ if (ret == 0) {
+ break;
+ }
+ }
+ if (ret != 0) {
+ DEBUG(1, ("pthread_mutex_lock failed: %s\n",
+ strerror(ret)));
+ return false;
+ }
+ }
+#endif
+
+ if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
+ bool ok;
+
+ do {
+ ok = fcntl_lock(
+ xconn->smb1.echo_handler.socket_lock_fd,
+ F_SETLKW, 0, 0, F_WRLCK);
+ } while (!ok && (errno == EINTR));
+
+ if (!ok) {
+ DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
+ return false;
+ }
}
DEBUG(10,("pid[%d] got socket lock\n", (int)getpid()));
return true;
}
-void smbd_lock_socket(struct smbd_server_connection *sconn)
+void smbd_lock_socket(struct smbXsrv_connection *xconn)
{
- if (!smbd_lock_socket_internal(sconn)) {
+ if (!smbd_lock_socket_internal(xconn)) {
exit_server_cleanly("failed to lock socket");
}
}
-static bool smbd_unlock_socket_internal(struct smbd_server_connection *sconn)
+static bool smbd_unlock_socket_internal(struct smbXsrv_connection *xconn)
{
- bool ok;
-
- if (sconn->smb1.echo_handler.socket_lock_fd == -1) {
+ if (!smbd_echo_active(xconn)) {
return true;
}
- sconn->smb1.echo_handler.ref_count--;
+ xconn->smb1.echo_handler.ref_count--;
- if (sconn->smb1.echo_handler.ref_count > 0) {
+ if (xconn->smb1.echo_handler.ref_count > 0) {
return true;
}
- do {
- ok = fcntl_lock(
- sconn->smb1.echo_handler.socket_lock_fd,
- F_SETLKW, 0, 0, F_UNLCK);
- } while (!ok && (errno == EINTR));
+#ifdef HAVE_ROBUST_MUTEXES
+ if (xconn->smb1.echo_handler.socket_mutex != NULL) {
+ int ret = EINTR;
- if (!ok) {
- DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
- return false;
+ while (ret == EINTR) {
+ ret = pthread_mutex_unlock(
+ xconn->smb1.echo_handler.socket_mutex);
+ if (ret == 0) {
+ break;
+ }
+ }
+ if (ret != 0) {
+ DEBUG(1, ("pthread_mutex_unlock failed: %s\n",
+ strerror(ret)));
+ return false;
+ }
+ }
+#endif
+
+ if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
+ bool ok;
+
+ do {
+ ok = fcntl_lock(
+ xconn->smb1.echo_handler.socket_lock_fd,
+ F_SETLKW, 0, 0, F_UNLCK);
+ } while (!ok && (errno == EINTR));
+
+ if (!ok) {
+ DEBUG(1, ("fcntl_lock failed: %s\n", strerror(errno)));
+ return false;
+ }
}
DEBUG(10,("pid[%d] unlocked socket\n", (int)getpid()));
return true;
}
-void smbd_unlock_socket(struct smbd_server_connection *sconn)
+void smbd_unlock_socket(struct smbXsrv_connection *xconn)
{
- if (!smbd_unlock_socket_internal(sconn)) {
+ if (!smbd_unlock_socket_internal(xconn)) {
exit_server_cleanly("failed to unlock socket");
}
}
Send an smb to a fd.
****************************************************************************/
-bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer,
+bool srv_send_smb(struct smbXsrv_connection *xconn, char *buffer,
bool do_signing, uint32_t seqnum,
bool do_encrypt,
struct smb_perfcount_data *pcd)
ssize_t ret;
char *buf_out = buffer;
- smbd_lock_socket(sconn);
+ if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+ /*
+ * we're not supposed to do any io
+ */
+ return true;
+ }
+
+ smbd_lock_socket(xconn);
if (do_signing) {
/* Sign the outgoing packet if required. */
- srv_calculate_sign_mac(sconn, buf_out, seqnum);
+ srv_calculate_sign_mac(xconn, buf_out, seqnum);
}
if (do_encrypt) {
- NTSTATUS status = srv_encrypt_buffer(sconn, buffer, &buf_out);
+ NTSTATUS status = srv_encrypt_buffer(xconn, buffer, &buf_out);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("send_smb: SMB encryption failed "
"on outgoing packet! Error %s\n",
nt_errstr(status) ));
+ ret = -1;
goto out;
}
}
len = smb_len_large(buf_out) + 4;
- ret = write_data(sconn->sock, buf_out, len);
+ ret = write_data(xconn->transport.sock, buf_out, len);
if (ret <= 0) {
-
- char addr[INET6_ADDRSTRLEN];
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
DEBUG(1,("pid[%d] Error writing %d bytes to client %s. %d. (%s)\n",
(int)getpid(), (int)len,
- get_peer_addr(sconn->sock, addr, sizeof(addr)),
- (int)ret, strerror(errno) ));
+ smbXsrv_connection_dbg(xconn),
+ (int)ret, strerror(saved_errno)));
+ errno = saved_errno;
- srv_free_enc_buffer(sconn, buf_out);
+ srv_free_enc_buffer(xconn, buf_out);
goto out;
}
SMB_PERFCOUNT_SET_MSGLEN_OUT(pcd, len);
- srv_free_enc_buffer(sconn, buf_out);
+ srv_free_enc_buffer(xconn, buf_out);
out:
SMB_PERFCOUNT_END(pcd);
- smbd_unlock_socket(sconn);
+ smbd_unlock_socket(xconn);
return (ret > 0);
}
return (smb_size + num_words*2 + num_bytes);
}
-static bool valid_smb_header(struct smbd_server_connection *sconn,
- const uint8_t *inbuf)
+static bool valid_smb_header(const uint8_t *inbuf)
{
- if (is_encrypted_packet(sconn, inbuf)) {
+ if (is_encrypted_packet(inbuf)) {
return true;
}
/*
* of header. Don't print the error if this fits.... JRA.
*/
- if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ if (len > (LARGE_WRITEX_BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
DEBUG(0,("Invalid packet length! (%lu bytes).\n",
(unsigned long)len));
return false;
static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
const char lenbuf[4],
- struct smbd_server_connection *sconn,
+ struct smbXsrv_connection *xconn,
int sock,
char **buffer,
unsigned int timeout,
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("read_fd_with_timeout failed for client %s read "
"error = %s.\n",
- tsocket_address_string(sconn->remote_address,
- talloc_tos()),
+ smbXsrv_connection_dbg(xconn),
nt_errstr(status)));
return status;
}
* valid writeX call.
*/
- if (is_valid_writeX_buffer(sconn, (uint8_t *)writeX_header)) {
+ if (is_valid_writeX_buffer(xconn, (uint8_t *)writeX_header)) {
/*
* If the data offset is beyond what
* we've read, drain the extra bytes.
}
static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
- struct smbd_server_connection *sconn,
+ struct smbXsrv_connection *xconn,
int sock,
char **buffer, unsigned int timeout,
size_t *p_unread, size_t *plen)
if (CVAL(lenbuf,0) == 0 && min_recv_size &&
(smb_len_large(lenbuf) > /* Could be a UNIX large writeX. */
(min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE)) &&
- !srv_is_signing_active(sconn) &&
- sconn->smb1.echo_handler.trusted_fde == NULL) {
+ !srv_is_signing_active(xconn) &&
+ xconn->smb1.echo_handler.trusted_fde == NULL) {
return receive_smb_raw_talloc_partial_read(
- mem_ctx, lenbuf, sconn, sock, buffer, timeout,
+ mem_ctx, lenbuf, xconn, sock, buffer, timeout,
p_unread, plen);
}
}
static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx,
- struct smbd_server_connection *sconn,
+ struct smbXsrv_connection *xconn,
int sock,
char **buffer, unsigned int timeout,
size_t *p_unread, bool *p_encrypted,
*p_encrypted = false;
- status = receive_smb_raw_talloc(mem_ctx, sconn, sock, buffer, timeout,
+ status = receive_smb_raw_talloc(mem_ctx, xconn, sock, buffer, timeout,
p_unread, &len);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)?5:1,
("receive_smb_raw_talloc failed for client %s "
"read error = %s.\n",
- tsocket_address_string(sconn->remote_address,
- talloc_tos()),
+ smbXsrv_connection_dbg(xconn),
nt_errstr(status)) );
return status;
}
- if (is_encrypted_packet(sconn, (uint8_t *)*buffer)) {
- status = srv_decrypt_buffer(sconn, *buffer);
+ if (is_encrypted_packet((uint8_t *)*buffer)) {
+ status = srv_decrypt_buffer(xconn, *buffer);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
"incoming packet! Error %s\n",
}
/* Check the incoming SMB signature. */
- if (!srv_check_sign_mac(sconn, *buffer, seqnum, trusted_channel)) {
+ if (!srv_check_sign_mac(xconn, *buffer, seqnum, trusted_channel)) {
DEBUG(0, ("receive_smb: SMB Signature verification failed on "
"incoming packet!\n"));
return NT_STATUS_INVALID_NETWORK_RESPONSE;
static bool init_smb_request(struct smb_request *req,
struct smbd_server_connection *sconn,
- const uint8 *inbuf,
+ struct smbXsrv_connection *xconn,
+ const uint8_t *inbuf,
size_t unread_bytes, bool encrypted,
uint32_t seqnum)
{
req->unread_bytes = unread_bytes;
req->encrypted = encrypted;
req->sconn = sconn;
- status = smb1srv_tcon_lookup(sconn->conn, req->tid, now, &tcon);
- if (NT_STATUS_IS_OK(status)) {
- req->conn = tcon->compat;
- } else {
- req->conn = NULL;
+ req->xconn = xconn;
+ req->conn = NULL;
+ if (xconn != NULL) {
+ status = smb1srv_tcon_lookup(xconn, req->tid, now, &tcon);
+ if (NT_STATUS_IS_OK(status)) {
+ req->conn = tcon->compat;
+ }
}
req->chain_fsp = NULL;
req->smb2req = NULL;
req->priv_paths = NULL;
req->chain = NULL;
+ req->posix_pathnames = lp_posix_pathnames();
smb_init_perfcount_data(&req->pcd);
/* Ensure we have at least wct words and 2 bytes of bcc. */
return true;
}
-static void process_smb(struct smbd_server_connection *conn,
+static void process_smb(struct smbXsrv_connection *xconn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
uint32_t seqnum, bool encrypted,
struct smb_perfcount_data *deferred_pcd);
struct pending_message_list *msg = talloc_get_type(private_data,
struct pending_message_list);
struct smbd_server_connection *sconn = msg->sconn;
+ struct smbXsrv_connection *xconn = msg->xconn;
TALLOC_CTX *mem_ctx = talloc_tos();
uint64_t mid = (uint64_t)SVAL(msg->buf.data,smb_mid);
uint8_t *inbuf;
* re-processed in error. */
msg->processed = true;
- process_smb(sconn, inbuf,
+ process_smb(xconn, inbuf,
msg->buf.length, 0,
msg->seqnum, msg->encrypted, &msg->pcd);
/* If it's still there and was processed, remove it. */
msg = get_deferred_open_message_smb(sconn, mid);
if (msg && msg->processed) {
- remove_deferred_open_message_smb(sconn, mid);
+ remove_deferred_open_message_smb(xconn, mid);
}
}
static bool push_queued_message(struct smb_request *req,
struct timeval request_time,
struct timeval end_time,
- char *private_data, size_t private_len)
+ struct deferred_open_record *open_rec)
{
int msg_len = smb_len(req->inbuf) + 4;
struct pending_message_list *msg;
return False;
}
msg->sconn = req->sconn;
+ msg->xconn = req->xconn;
msg->buf = data_blob_talloc(msg, req->inbuf, msg_len);
if(msg->buf.data == NULL) {
msg->processed = false;
SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd);
- if (private_data) {
- msg->private_data = data_blob_talloc(msg, private_data,
- private_len);
- if (msg->private_data.data == NULL) {
- DEBUG(0,("push_message: malloc fail (3)\n"));
- TALLOC_FREE(msg);
- return False;
- }
+ if (open_rec) {
+ msg->open_rec = talloc_move(msg, &open_rec);
}
#if 0
}
#endif
- DLIST_ADD_END(req->sconn->deferred_open_queue, msg,
- struct pending_message_list *);
+ DLIST_ADD_END(req->sconn->deferred_open_queue, msg);
DEBUG(10,("push_message: pushed message length %u on "
"deferred_open_queue\n", (unsigned int)msg_len));
Function to delete a sharing violation open message by mid.
****************************************************************************/
-void remove_deferred_open_message_smb(struct smbd_server_connection *sconn,
+void remove_deferred_open_message_smb(struct smbXsrv_connection *xconn,
uint64_t mid)
{
+ struct smbd_server_connection *sconn = xconn->client->sconn;
struct pending_message_list *pml;
if (sconn->using_smb2) {
- remove_deferred_open_message_smb2(sconn, mid);
+ remove_deferred_open_message_smb2(xconn, mid);
return;
}
schedule it for immediate processing.
****************************************************************************/
-bool schedule_deferred_open_message_smb(struct smbd_server_connection *sconn,
+bool schedule_deferred_open_message_smb(struct smbXsrv_connection *xconn,
uint64_t mid)
{
+ struct smbd_server_connection *sconn = xconn->client->sconn;
struct pending_message_list *pml;
int i = 0;
if (sconn->using_smb2) {
- return schedule_deferred_open_message_smb2(sconn, mid);
+ return schedule_deferred_open_message_smb2(xconn, mid);
}
for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
Return true if this mid is on the deferred queue and was not yet processed.
****************************************************************************/
-bool open_was_deferred(struct smbd_server_connection *sconn, uint64_t mid)
+bool open_was_deferred(struct smbXsrv_connection *xconn, uint64_t mid)
{
+ struct smbd_server_connection *sconn = xconn->client->sconn;
struct pending_message_list *pml;
if (sconn->using_smb2) {
- return open_was_deferred_smb2(sconn, mid);
+ return open_was_deferred_smb2(xconn, mid);
}
for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
bool get_deferred_open_message_state(struct smb_request *smbreq,
struct timeval *p_request_time,
- void **pp_state)
+ struct deferred_open_record **open_rec)
{
struct pending_message_list *pml;
if (smbreq->sconn->using_smb2) {
return get_deferred_open_message_state_smb2(smbreq->smb2req,
p_request_time,
- pp_state);
+ open_rec);
}
pml = get_deferred_open_message_smb(smbreq->sconn, smbreq->mid);
if (p_request_time) {
*p_request_time = pml->request_time;
}
- if (pp_state) {
- *pp_state = (void *)pml->private_data.data;
+ if (open_rec != NULL) {
+ *open_rec = pml->open_rec;
}
return true;
}
struct timeval request_time,
struct timeval timeout,
struct file_id id,
- char *private_data, size_t priv_len)
+ struct deferred_open_record *open_rec)
{
struct timeval end_time;
request_time,
timeout,
id,
- private_data,
- priv_len);
+ open_rec);
}
if (req->unread_bytes) {
(unsigned int)end_time.tv_sec,
(unsigned int)end_time.tv_usec));
- return push_queued_message(req, request_time, end_time,
- private_data, priv_len);
+ return push_queued_message(req, request_time, end_time, open_rec);
}
static void smbd_sig_term_handler(struct tevent_context *ev,
********************************************************************/
static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req,
- const char *inbuf, char **outbuf, uint8_t num_words,
- uint32_t num_bytes)
+ const uint8_t *inbuf, char **outbuf,
+ uint8_t num_words, uint32_t num_bytes)
{
size_t smb_len = MIN_SMB_SIZE + VWV(num_words) + num_bytes;
return false;
}
- construct_reply_common(req, inbuf, *outbuf);
+ construct_reply_common(req->cmd, inbuf, *outbuf);
srv_set_message(*outbuf, num_words, num_bytes, false);
/*
* Zero out the word area, the caller has to take care of the bcc area
return true;
}
-void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
+void reply_outbuf(struct smb_request *req, uint8_t num_words, uint32_t num_bytes)
{
char *outbuf;
- if (!create_outbuf(req, req, (const char *)req->inbuf, &outbuf, num_words,
+ if (!create_outbuf(req, req, req->inbuf, &outbuf, num_words,
num_bytes)) {
smb_panic("could not allocate output buffer\n");
}
TALLOC_FREE(fname);
}
+static void smb1srv_update_crypto_flags(struct smbXsrv_session *session,
+ struct smb_request *req,
+ uint8_t type,
+ bool *update_session_globalp,
+ bool *update_tcon_globalp)
+{
+ connection_struct *conn = req->conn;
+ struct smbXsrv_tcon *tcon = conn ? conn->tcon : NULL;
+ uint8_t encrypt_flag = SMBXSRV_PROCESSED_UNENCRYPTED_PACKET;
+ uint8_t sign_flag = SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+ bool update_session = false;
+ bool update_tcon = false;
+
+ if (req->encrypted) {
+ encrypt_flag = SMBXSRV_PROCESSED_ENCRYPTED_PACKET;
+ }
+
+ if (srv_is_signing_active(req->xconn)) {
+ sign_flag = SMBXSRV_PROCESSED_SIGNED_PACKET;
+ } else if ((type == SMBecho) || (type == SMBsesssetupX)) {
+ /*
+ * echo can be unsigned. Sesssion setup except final
+ * session setup response too
+ */
+ sign_flag &= ~SMBXSRV_PROCESSED_UNSIGNED_PACKET;
+ }
+
+ update_session |= smbXsrv_set_crypto_flag(
+ &session->global->encryption_flags, encrypt_flag);
+ update_session |= smbXsrv_set_crypto_flag(
+ &session->global->signing_flags, sign_flag);
+
+ if (tcon) {
+ update_tcon |= smbXsrv_set_crypto_flag(
+ &tcon->global->encryption_flags, encrypt_flag);
+ update_tcon |= smbXsrv_set_crypto_flag(
+ &tcon->global->signing_flags, sign_flag);
+ }
+
+ if (update_session) {
+ session->global->channels[0].encryption_cipher = SMB_ENCRYPTION_GSSAPI;
+ }
+
+ *update_session_globalp = update_session;
+ *update_tcon_globalp = update_tcon;
+ return;
+}
+
/****************************************************************************
Prepare everything for calling the actual request function, and potentially
call the request function via the "new" interface.
find.
****************************************************************************/
-static connection_struct *switch_message(uint8 type, struct smb_request *req)
+static connection_struct *switch_message(uint8_t type, struct smb_request *req)
{
int flags;
uint64_t session_tag;
connection_struct *conn = NULL;
- struct smbd_server_connection *sconn = req->sconn;
+ struct smbXsrv_connection *xconn = req->xconn;
NTTIME now = timeval_to_nttime(&req->request_time);
struct smbXsrv_session *session = NULL;
NTSTATUS status;
errno = 0;
+ if (!xconn->smb1.negprot.done) {
+ switch (type) {
+ /*
+ * Without a negprot the request must
+ * either be a negprot, or one of the
+ * evil old SMB mailslot messaging types.
+ */
+ case SMBnegprot:
+ case SMBsendstrt:
+ case SMBsendend:
+ case SMBsendtxt:
+ break;
+ default:
+ exit_server_cleanly("The first request "
+ "should be a negprot");
+ }
+ }
+
if (smb_messages[type].fn == NULL) {
DEBUG(0,("Unknown message type %d!\n",type));
smb_dump("Unknown", 1, (const char *)req->inbuf);
* Note: for now we only check for NT_STATUS_NETWORK_SESSION_EXPIRED
* here, the main check is still in change_to_user()
*/
- status = smb1srv_session_lookup(sconn->conn,
+ status = smb1srv_session_lookup(xconn,
session_tag,
now,
&session);
}
}
- if (session_tag != sconn->smb1.sessions.last_session_tag) {
+ if (session_tag != xconn->client->last_session_id) {
struct user_struct *vuser = NULL;
- sconn->smb1.sessions.last_session_tag = session_tag;
+ xconn->client->last_session_id = session_tag;
if (session) {
vuser = session->compat;
}
return conn;
}
- raddr = tsocket_address_inet_addr_string(sconn->remote_address,
+ raddr = tsocket_address_inet_addr_string(xconn->remote_address,
talloc_tos());
if (raddr == NULL) {
reply_nterror(req, NT_STATUS_NO_MEMORY);
* Haven't we checked this in smbd_process already???
*/
- ok = allow_access(lp_hostsdeny(-1), lp_hostsallow(-1),
- sconn->remote_hostname, raddr);
+ ok = allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1),
+ xconn->remote_hostname, raddr);
TALLOC_FREE(raddr);
if (!ok) {
}
}
+ /*
+ * Update encryption and signing state tracking flags that are
+ * used by smbstatus to display signing and encryption status.
+ */
+ if (session != NULL) {
+ bool update_session_global = false;
+ bool update_tcon_global = false;
+
+ smb1srv_update_crypto_flags(session, req, type,
+ &update_session_global,
+ &update_tcon_global);
+
+ if (update_session_global) {
+ status = smbXsrv_session_update(session);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return conn;
+ }
+ }
+
+ if (update_tcon_global) {
+ status = smbXsrv_tcon_update(req->conn->tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ reply_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return conn;
+ }
+ }
+ }
+
smb_messages[type].fn(req);
return req->conn;
}
Construct a reply to the incoming packet.
****************************************************************************/
-static void construct_reply(struct smbd_server_connection *sconn,
+static void construct_reply(struct smbXsrv_connection *xconn,
char *inbuf, int size, size_t unread_bytes,
uint32_t seqnum, bool encrypted,
struct smb_perfcount_data *deferred_pcd)
{
- connection_struct *conn;
+ struct smbd_server_connection *sconn = xconn->client->sconn;
struct smb_request *req;
if (!(req = talloc(talloc_tos(), struct smb_request))) {
smb_panic("could not allocate smb_request");
}
- if (!init_smb_request(req, sconn, (uint8 *)inbuf, unread_bytes,
+ if (!init_smb_request(req, sconn, xconn, (uint8_t *)inbuf, unread_bytes,
encrypted, seqnum)) {
exit_server_cleanly("Invalid SMB request");
}
SMB_PERFCOUNT_SET_MSGLEN_IN(&req->pcd, size);
}
- conn = switch_message(req->cmd, req);
+ req->conn = switch_message(req->cmd, req);
if (req->outbuf == NULL) {
+ /*
+ * Request has suspended itself, will come
+ * back here.
+ */
return;
}
-
if (CVAL(req->outbuf,0) == 0) {
show_msg((char *)req->outbuf);
}
-
- if (!srv_send_smb(req->sconn,
- (char *)req->outbuf,
- true, req->seqnum+1,
- IS_CONN_ENCRYPTED(conn)||req->encrypted,
- &req->pcd)) {
- exit_server_cleanly("construct_reply: srv_send_smb failed.");
- }
-
- TALLOC_FREE(req);
-
- return;
+ smb_request_done(req);
}
-static void construct_reply_chain(struct smbd_server_connection *sconn,
+static void construct_reply_chain(struct smbXsrv_connection *xconn,
char *inbuf, int size, uint32_t seqnum,
bool encrypted,
struct smb_perfcount_data *deferred_pcd)
unsigned num_reqs;
bool ok;
- ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, sconn, encrypted,
+ ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, xconn, encrypted,
seqnum, &reqs, &num_reqs);
if (!ok) {
char errbuf[smb_size];
error_packet(errbuf, 0, 0, NT_STATUS_INVALID_PARAMETER,
__LINE__, __FILE__);
- if (!srv_send_smb(sconn, errbuf, true, seqnum, encrypted,
+ if (!srv_send_smb(xconn, errbuf, true, seqnum, encrypted,
NULL)) {
exit_server_cleanly("construct_reply_chain: "
"srv_send_smb failed.");
next->vuid = SVAL(req->outbuf, smb_uid);
next->tid = SVAL(req->outbuf, smb_tid);
- status = smb1srv_tcon_lookup(req->sconn->conn, req->tid,
+ status = smb1srv_tcon_lookup(req->xconn, req->tid,
now, &tcon);
if (NT_STATUS_IS_OK(status)) {
req->conn = tcon->compat;
first_req->outbuf, talloc_get_size(first_req->outbuf) - 4);
shipit:
- if (!srv_send_smb(first_req->sconn,
+ if (!srv_send_smb(first_req->xconn,
(char *)first_req->outbuf,
true, first_req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)||first_req->encrypted,
{
char errbuf[smb_size];
error_packet(errbuf, 0, 0, status, __LINE__, __FILE__);
- if (!srv_send_smb(req->sconn, errbuf, true,
+ if (!srv_send_smb(req->xconn, errbuf, true,
req->seqnum+1, req->encrypted,
NULL)) {
exit_server_cleanly("construct_reply_chain: "
/****************************************************************************
Process an smb from the client
****************************************************************************/
-static void process_smb(struct smbd_server_connection *sconn,
+static void process_smb(struct smbXsrv_connection *xconn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
uint32_t seqnum, bool encrypted,
struct smb_perfcount_data *deferred_pcd)
{
+ struct smbd_server_connection *sconn = xconn->client->sconn;
int msg_type = CVAL(inbuf,0);
- DO_PROFILE_INC(smb_count);
+ DO_PROFILE_INC(request);
DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type,
smb_len(inbuf) ) );
/*
* NetBIOS session request, keepalive, etc.
*/
- reply_special(sconn, (char *)inbuf, nread);
+ reply_special(xconn, (char *)inbuf, nread);
goto done;
}
/* At this point we're not really using smb2,
* we make the decision here.. */
if (smbd_is_smb2_header(inbuf, nread)) {
- smbd_smb2_first_negprot(sconn, inbuf, nread);
+ const uint8_t *inpdu = inbuf + NBT_HDR_SIZE;
+ size_t pdulen = nread - NBT_HDR_SIZE;
+ smbd_smb2_process_negprot(xconn, 0, inpdu, pdulen);
return;
- } else if (nread >= smb_size && valid_smb_header(sconn, inbuf)
+ } else if (nread >= smb_size && valid_smb_header(inbuf)
&& CVAL(inbuf, smb_com) != 0x72) {
/* This is a non-negprot SMB1 packet.
Disable SMB2 from now on. */
/* Make sure this is an SMB packet. smb_size contains NetBIOS header
* so subtract 4 from it. */
- if ((nread < (smb_size - 4)) || !valid_smb_header(sconn, inbuf)) {
+ if ((nread < (smb_size - 4)) || !valid_smb_header(inbuf)) {
DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
smb_len(inbuf)));
show_msg((char *)inbuf);
if ((unread_bytes == 0) && smb1_is_chain(inbuf)) {
- construct_reply_chain(sconn, (char *)inbuf, nread,
+ construct_reply_chain(xconn, (char *)inbuf, nread,
seqnum, encrypted, deferred_pcd);
} else {
- construct_reply(sconn, (char *)inbuf, nread, unread_bytes,
+ construct_reply(xconn, (char *)inbuf, nread, unread_bytes,
seqnum, encrypted, deferred_pcd);
}
Helper functions for contruct_reply.
****************************************************************************/
-void add_to_common_flags2(uint32 v)
+void add_to_common_flags2(uint32_t v)
{
common_flags2 |= v;
}
-void remove_from_common_flags2(uint32 v)
+void remove_from_common_flags2(uint32_t v)
{
common_flags2 &= ~v;
}
-static void construct_reply_common(struct smb_request *req, const char *inbuf,
+static void construct_reply_common(uint8_t cmd, const uint8_t *inbuf,
char *outbuf)
{
uint16_t in_flags2 = SVAL(inbuf,smb_flg2);
srv_set_message(outbuf,0,0,false);
- SCVAL(outbuf, smb_com, req->cmd);
+ SCVAL(outbuf, smb_com, cmd);
SIVAL(outbuf,smb_rcls,0);
SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES));
SSVAL(outbuf,smb_flg2, out_flags2);
void construct_reply_common_req(struct smb_request *req, char *outbuf)
{
- construct_reply_common(req, (const char *)req->inbuf, outbuf);
+ construct_reply_common(req->cmd, req->inbuf, outbuf);
}
/**
bytes_addr = outbuf + ofs /* vwv start */
+ sizeof(uint16_t) * wct /* vwv array */
- + sizeof(uint16_t); /* bcc */
+ + sizeof(uint16_t) /* bcc */
+ + 1; /* padding byte */
SSVAL(outbuf + ofs, 6 * sizeof(uint16_t),
bytes_addr - outbuf - 4);
TALLOC_CTX *mem_ctx;
const uint8_t *buf;
struct smbd_server_connection *sconn;
+ struct smbXsrv_connection *xconn;
bool encrypted;
uint32_t seqnum;
return false;
}
- ok = init_smb_request(req, state->sconn, state->buf, 0,
+ ok = init_smb_request(req, state->sconn, state->xconn, state->buf, 0,
state->encrypted, state->seqnum);
if (!ok) {
return false;
}
bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
- struct smbd_server_connection *sconn,
+ struct smbXsrv_connection *xconn,
bool encrypted, uint32_t seqnum,
struct smb_request ***reqs, unsigned *num_reqs)
{
+ struct smbd_server_connection *sconn = NULL;
struct smb1_parse_chain_state state;
unsigned i;
+ if (xconn != NULL) {
+ sconn = xconn->client->sconn;
+ }
+
state.mem_ctx = mem_ctx;
state.buf = buf;
state.sconn = sconn;
+ state.xconn = xconn;
state.encrypted = encrypted;
state.seqnum = seqnum;
state.reqs = NULL;
}
static void smbd_server_connection_write_handler(
- struct smbd_server_connection *sconn)
+ struct smbXsrv_connection *xconn)
{
/* TODO: make write nonblocking */
}
static void smbd_server_connection_read_handler(
- struct smbd_server_connection *sconn, int fd)
+ struct smbXsrv_connection *xconn, int fd)
{
uint8_t *inbuf = NULL;
size_t inbuf_len = 0;
NTSTATUS status;
uint32_t seqnum;
- bool from_client;
+ bool async_echo = lp_async_smb_echo_handler();
+ bool from_client = false;
- if (lp_async_smb_echo_handler()
- && fd_is_readable(sconn->smb1.echo_handler.trusted_fd)) {
- /*
- * This is the super-ugly hack to prefer the packets
- * forwarded by the echo handler over the ones by the
- * client directly
- */
- fd = sconn->smb1.echo_handler.trusted_fd;
+ if (async_echo) {
+ if (fd_is_readable(xconn->smb1.echo_handler.trusted_fd)) {
+ /*
+ * This is the super-ugly hack to prefer the packets
+ * forwarded by the echo handler over the ones by the
+ * client directly
+ */
+ fd = xconn->smb1.echo_handler.trusted_fd;
+ }
}
- from_client = (sconn->sock == fd);
+ from_client = (xconn->transport.sock == fd);
- if (from_client) {
- smbd_lock_socket(sconn);
+ if (async_echo && from_client) {
+ smbd_lock_socket(xconn);
if (!fd_is_readable(fd)) {
DEBUG(10,("the echo listener was faster\n"));
- smbd_unlock_socket(sconn);
+ smbd_unlock_socket(xconn);
return;
}
}
/* TODO: make this completely nonblocking */
- status = receive_smb_talloc(mem_ctx, sconn, fd,
+ status = receive_smb_talloc(mem_ctx, xconn, fd,
(char **)(void *)&inbuf,
0, /* timeout */
&unread_bytes,
&inbuf_len, &seqnum,
!from_client /* trusted channel */);
- if (from_client) {
- smbd_unlock_socket(sconn);
+ if (async_echo && from_client) {
+ smbd_unlock_socket(xconn);
}
if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
}
process:
- process_smb(sconn, inbuf, inbuf_len, unread_bytes,
+ process_smb(xconn, inbuf, inbuf_len, unread_bytes,
seqnum, encrypted, NULL);
}
uint16_t flags,
void *private_data)
{
- struct smbd_server_connection *conn = talloc_get_type(private_data,
- struct smbd_server_connection);
+ struct smbXsrv_connection *xconn =
+ talloc_get_type_abort(private_data,
+ struct smbXsrv_connection);
+
+ if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+ /*
+ * we're not supposed to do any io
+ */
+ TEVENT_FD_NOT_READABLE(xconn->transport.fde);
+ TEVENT_FD_NOT_WRITEABLE(xconn->transport.fde);
+ return;
+ }
if (flags & TEVENT_FD_WRITE) {
- smbd_server_connection_write_handler(conn);
+ smbd_server_connection_write_handler(xconn);
return;
}
if (flags & TEVENT_FD_READ) {
- smbd_server_connection_read_handler(conn, conn->sock);
+ smbd_server_connection_read_handler(xconn, xconn->transport.sock);
return;
}
}
uint16_t flags,
void *private_data)
{
- struct smbd_server_connection *conn = talloc_get_type(private_data,
- struct smbd_server_connection);
+ struct smbXsrv_connection *xconn =
+ talloc_get_type_abort(private_data,
+ struct smbXsrv_connection);
+
+ if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+ /*
+ * we're not supposed to do any io
+ */
+ TEVENT_FD_NOT_READABLE(xconn->smb1.echo_handler.trusted_fde);
+ TEVENT_FD_NOT_WRITEABLE(xconn->smb1.echo_handler.trusted_fde);
+ return;
+ }
if (flags & TEVENT_FD_WRITE) {
- smbd_server_connection_write_handler(conn);
+ smbd_server_connection_write_handler(xconn);
return;
}
if (flags & TEVENT_FD_READ) {
smbd_server_connection_read_handler(
- conn, conn->smb1.echo_handler.trusted_fd);
+ xconn, xconn->smb1.echo_handler.trusted_fd);
return;
}
}
-#ifdef CLUSTER_SUPPORT
-
struct smbd_release_ip_state {
- struct smbd_server_connection *sconn;
+ struct smbXsrv_connection *xconn;
+ struct tevent_immediate *im;
char addr[INET6_ADDRSTRLEN];
};
+static void smbd_release_ip_immediate(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct smbd_release_ip_state *state =
+ talloc_get_type_abort(private_data,
+ struct smbd_release_ip_state);
+ struct smbXsrv_connection *xconn = state->xconn;
+
+ if (!NT_STATUS_EQUAL(xconn->transport.status, NT_STATUS_ADDRESS_CLOSED)) {
+ /*
+ * smbd_server_connection_terminate() already triggered ?
+ */
+ return;
+ }
+
+ smbd_server_connection_terminate(xconn, "CTDB_SRVID_RELEASE_IP");
+}
+
/****************************************************************************
received when we should release a specific IP
****************************************************************************/
-static void release_ip(const char *ip, void *priv)
+static int release_ip(uint32_t src_vnn, uint32_t dst_vnn,
+ uint64_t dst_srvid,
+ const uint8_t *msg, size_t msglen,
+ void *private_data)
{
struct smbd_release_ip_state *state =
- talloc_get_type_abort(priv,
+ talloc_get_type_abort(private_data,
struct smbd_release_ip_state);
+ struct smbXsrv_connection *xconn = state->xconn;
+ const char *ip;
const char *addr = state->addr;
const char *p = addr;
+ if (msglen == 0) {
+ return 0;
+ }
+ if (msg[msglen-1] != '\0') {
+ return 0;
+ }
+
+ ip = (const char *)msg;
+
+ if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+ /* avoid recursion */
+ return 0;
+ }
+
if (strncmp("::ffff:", addr, 7) == 0) {
p = addr + 7;
}
* triggered and has implication on our process model,
* we can just use smbd_server_connection_terminate()
* (also for SMB1).
+ *
+ * We don't call smbd_server_connection_terminate() directly
+ * as we might be called from within ctdbd_migrate(),
+ * we need to defer our action to the next event loop
*/
- smbd_server_connection_terminate(state->sconn,
- "CTDB_SRVID_RELEASE_IP");
- return;
+ tevent_schedule_immediate(state->im, xconn->ev_ctx,
+ smbd_release_ip_immediate, state);
+
+ /*
+ * Make sure we don't get any io on the connection.
+ */
+ xconn->transport.status = NT_STATUS_ADDRESS_CLOSED;
+ return EADDRNOTAVAIL;
}
+
+ return 0;
}
-static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn,
+static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
struct sockaddr_storage *srv,
struct sockaddr_storage *clnt)
{
struct smbd_release_ip_state *state;
struct ctdbd_connection *cconn;
+ int ret;
cconn = messaging_ctdbd_connection();
if (cconn == NULL) {
return NT_STATUS_NO_MEMORY;
}
- state = talloc_zero(sconn, struct smbd_release_ip_state);
+ state = talloc_zero(xconn, struct smbd_release_ip_state);
if (state == NULL) {
return NT_STATUS_NO_MEMORY;
}
- state->sconn = sconn;
+ state->xconn = xconn;
+ state->im = tevent_create_immediate(state);
+ if (state->im == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
if (print_sockaddr(state->addr, sizeof(state->addr), srv) == NULL) {
return NT_STATUS_NO_MEMORY;
}
- return ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
+ ret = ctdbd_register_ips(cconn, srv, clnt, release_ip, state);
+ if (ret != 0) {
+ return map_nt_error_from_unix(ret);
+ }
+ return NT_STATUS_OK;
}
-static int client_get_tcp_info(int sock, struct sockaddr_storage *server,
- struct sockaddr_storage *client)
+static void msg_kill_client_ip(struct messaging_context *msg_ctx,
+ void *private_data, uint32_t msg_type,
+ struct server_id server_id, DATA_BLOB *data)
{
- socklen_t length;
- length = sizeof(*server);
- if (getsockname(sock, (struct sockaddr *)server, &length) != 0) {
- return -1;
+ struct smbd_server_connection *sconn = talloc_get_type_abort(
+ private_data, struct smbd_server_connection);
+ const char *ip = (char *) data->data;
+ char *client_ip;
+
+ DBG_DEBUG("Got kill request for client IP %s\n", ip);
+
+ client_ip = tsocket_address_inet_addr_string(sconn->remote_address,
+ talloc_tos());
+ if (client_ip == NULL) {
+ return;
}
- length = sizeof(*client);
- if (getpeername(sock, (struct sockaddr *)client, &length) != 0) {
- return -1;
+
+ if (strequal(ip, client_ip)) {
+ DBG_WARNING("Got kill client message for %s - "
+ "exiting immediately\n", ip);
+ exit_server_cleanly("Forced disconnect for client");
}
- return 0;
+
+ TALLOC_FREE(client_ip);
}
-#endif
/*
* Send keepalive packets to our client
{
struct smbd_server_connection *sconn = talloc_get_type_abort(
private_data, struct smbd_server_connection);
+ struct smbXsrv_connection *xconn = NULL;
bool ret;
if (sconn->using_smb2) {
return false;
}
- smbd_lock_socket(sconn);
- ret = send_keepalive(sconn->sock);
- smbd_unlock_socket(sconn);
+ /*
+ * With SMB1 we only have 1 connection
+ */
+ xconn = sconn->client->connections;
+ smbd_lock_socket(xconn);
+ ret = send_keepalive(xconn->transport.sock);
+ smbd_unlock_socket(xconn);
if (!ret) {
- char addr[INET6_ADDRSTRLEN];
+ int saved_errno = errno;
/*
* Try and give an error message saying what
* client failed.
*/
DEBUG(0, ("send_keepalive failed for client %s. "
"Error %s - exiting\n",
- get_peer_addr(sconn->sock, addr, sizeof(addr)),
- strerror(errno)));
+ smbXsrv_connection_dbg(xconn),
+ strerror(saved_errno)));
+ errno = saved_errno;
return False;
}
return True;
struct smbd_echo_read_state {
struct tevent_context *ev;
- struct smbd_server_connection *sconn;
+ struct smbXsrv_connection *xconn;
char *buf;
size_t buflen;
static struct tevent_req *smbd_echo_read_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct smbd_server_connection *sconn)
+ struct smbXsrv_connection *xconn)
{
struct tevent_req *req, *subreq;
struct smbd_echo_read_state *state;
return NULL;
}
state->ev = ev;
- state->sconn = sconn;
+ state->xconn = xconn;
- subreq = wait_for_read_send(state, ev, sconn->sock);
+ subreq = wait_for_read_send(state, ev, xconn->transport.sock, false);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
subreq, struct tevent_req);
struct smbd_echo_read_state *state = tevent_req_data(
req, struct smbd_echo_read_state);
- struct smbd_server_connection *sconn = state->sconn;
+ struct smbXsrv_connection *xconn = state->xconn;
bool ok;
NTSTATUS status;
size_t unread = 0;
return;
}
- ok = smbd_lock_socket_internal(sconn);
+ ok = smbd_lock_socket_internal(xconn);
if (!ok) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
DEBUG(0, ("%s: failed to lock socket\n", __location__));
return;
}
- if (!fd_is_readable(sconn->sock)) {
+ if (!fd_is_readable(xconn->transport.sock)) {
DEBUG(10,("echo_handler[%d] the parent smbd was faster\n",
(int)getpid()));
- ok = smbd_unlock_socket_internal(sconn);
+ ok = smbd_unlock_socket_internal(xconn);
if (!ok) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
DEBUG(1, ("%s: failed to unlock socket\n",
return;
}
- subreq = wait_for_read_send(state, state->ev, sconn->sock);
+ subreq = wait_for_read_send(state, state->ev,
+ xconn->transport.sock, false);
if (tevent_req_nomem(subreq, req)) {
return;
}
return;
}
- status = receive_smb_talloc(state, sconn, sconn->sock, &state->buf,
+ status = receive_smb_talloc(state, xconn,
+ xconn->transport.sock,
+ &state->buf,
0 /* timeout */,
&unread,
&encrypted,
return;
}
- ok = smbd_unlock_socket_internal(sconn);
+ ok = smbd_unlock_socket_internal(xconn);
if (!ok) {
tevent_req_nterror(req, map_nt_error_from_unix(errno));
DEBUG(1, ("%s: failed to unlock socket\n", __location__));
struct tevent_context *ev;
struct iovec *pending;
struct smbd_server_connection *sconn;
+ struct smbXsrv_connection *xconn;
int parent_pipe;
struct tevent_fd *parent_fde;
DEBUG(10, ("Got short packet: %d bytes\n", (int)inbuf_len));
return false;
}
- if (!valid_smb_header(state->sconn, inbuf)) {
+ if (!valid_smb_header(inbuf)) {
DEBUG(10, ("Got invalid SMB header\n"));
return false;
}
- if (!init_smb_request(&req, state->sconn, inbuf, 0, false,
+ if (!init_smb_request(&req, state->sconn, state->xconn, inbuf, 0, false,
seqnum)) {
return false;
}
return false;
}
- if (!create_outbuf(talloc_tos(), &req, (const char *)req.inbuf, &outbuf,
+ if (!create_outbuf(talloc_tos(), &req, req.inbuf, &outbuf,
1, req.buflen)) {
DEBUG(10, ("create_outbuf failed\n"));
return false;
memcpy(smb_buf(req.outbuf), req.buf, req.buflen);
}
- ok = srv_send_smb(req.sconn,
+ ok = srv_send_smb(req.xconn,
(char *)outbuf,
true, seqnum+1,
false, &req.pcd);
static void smbd_echo_got_packet(struct tevent_req *req);
-static void smbd_echo_loop(struct smbd_server_connection *sconn,
+static void smbd_echo_loop(struct smbXsrv_connection *xconn,
int parent_pipe)
{
struct smbd_echo_state *state;
struct tevent_req *read_req;
- state = talloc_zero(sconn, struct smbd_echo_state);
+ state = talloc_zero(xconn, struct smbd_echo_state);
if (state == NULL) {
DEBUG(1, ("talloc failed\n"));
return;
}
- state->sconn = sconn;
+ state->xconn = xconn;
state->parent_pipe = parent_pipe;
state->ev = s3_tevent_context_init(state);
if (state->ev == NULL) {
return;
}
- read_req = smbd_echo_read_send(state, state->ev, sconn);
+ read_req = smbd_echo_read_send(state, state->ev, xconn);
if (read_req == NULL) {
DEBUG(1, ("smbd_echo_read_send failed\n"));
TALLOC_FREE(state);
smbd_echo_activate_writer(state);
}
- req = smbd_echo_read_send(state, state->ev, state->sconn);
+ req = smbd_echo_read_send(state, state->ev, state->xconn);
if (req == NULL) {
DEBUG(1, ("smbd_echo_read_send failed\n"));
exit(1);
/*
* Handle SMBecho requests in a forked child process
*/
-bool fork_echo_handler(struct smbd_server_connection *sconn)
+bool fork_echo_handler(struct smbXsrv_connection *xconn)
{
int listener_pipe[2];
int res;
pid_t child;
+ bool use_mutex = false;
res = pipe(listener_pipe);
if (res == -1) {
DEBUG(1, ("pipe() failed: %s\n", strerror(errno)));
return false;
}
- sconn->smb1.echo_handler.socket_lock_fd = create_unlink_tmp(lp_lockdir());
- if (sconn->smb1.echo_handler.socket_lock_fd == -1) {
- DEBUG(1, ("Could not create lock fd: %s\n", strerror(errno)));
- goto fail;
+
+#ifdef HAVE_ROBUST_MUTEXES
+ use_mutex = tdb_runtime_check_for_robust_mutexes();
+
+ if (use_mutex) {
+ pthread_mutexattr_t a;
+
+ xconn->smb1.echo_handler.socket_mutex =
+ anonymous_shared_allocate(sizeof(pthread_mutex_t));
+ if (xconn->smb1.echo_handler.socket_mutex == NULL) {
+ DEBUG(1, ("Could not create mutex shared memory: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
+
+ res = pthread_mutexattr_init(&a);
+ if (res != 0) {
+ DEBUG(1, ("pthread_mutexattr_init failed: %s\n",
+ strerror(res)));
+ goto fail;
+ }
+ res = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_ERRORCHECK);
+ if (res != 0) {
+ DEBUG(1, ("pthread_mutexattr_settype failed: %s\n",
+ strerror(res)));
+ pthread_mutexattr_destroy(&a);
+ goto fail;
+ }
+ res = pthread_mutexattr_setpshared(&a, PTHREAD_PROCESS_SHARED);
+ if (res != 0) {
+ DEBUG(1, ("pthread_mutexattr_setpshared failed: %s\n",
+ strerror(res)));
+ pthread_mutexattr_destroy(&a);
+ goto fail;
+ }
+ res = pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
+ if (res != 0) {
+ DEBUG(1, ("pthread_mutexattr_setrobust failed: "
+ "%s\n", strerror(res)));
+ pthread_mutexattr_destroy(&a);
+ goto fail;
+ }
+ res = pthread_mutex_init(xconn->smb1.echo_handler.socket_mutex,
+ &a);
+ pthread_mutexattr_destroy(&a);
+ if (res != 0) {
+ DEBUG(1, ("pthread_mutex_init failed: %s\n",
+ strerror(res)));
+ goto fail;
+ }
+ }
+#endif
+
+ if (!use_mutex) {
+ xconn->smb1.echo_handler.socket_lock_fd =
+ create_unlink_tmp(lp_lock_directory());
+ if (xconn->smb1.echo_handler.socket_lock_fd == -1) {
+ DEBUG(1, ("Could not create lock fd: %s\n",
+ strerror(errno)));
+ goto fail;
+ }
}
child = fork();
close(listener_pipe[0]);
set_blocking(listener_pipe[1], false);
- status = reinit_after_fork(sconn->msg_ctx,
- sconn->ev_ctx,
- true);
+ status = smbd_reinit_after_fork(xconn->msg_ctx, xconn->ev_ctx,
+ true, "smbd-echo");
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("reinit_after_fork failed: %s\n",
nt_errstr(status)));
exit(1);
}
- smbd_echo_loop(sconn, listener_pipe[1]);
+ smbd_echo_loop(xconn, listener_pipe[1]);
exit(0);
}
close(listener_pipe[1]);
listener_pipe[1] = -1;
- sconn->smb1.echo_handler.trusted_fd = listener_pipe[0];
+ xconn->smb1.echo_handler.trusted_fd = listener_pipe[0];
DEBUG(10,("fork_echo_handler: main[%d] echo_child[%d]\n", (int)getpid(), (int)child));
* Without smb signing this is the same as the normal smbd
* listener. This needs to change once signing comes in.
*/
- sconn->smb1.echo_handler.trusted_fde = tevent_add_fd(sconn->ev_ctx,
- sconn,
- sconn->smb1.echo_handler.trusted_fd,
+ xconn->smb1.echo_handler.trusted_fde = tevent_add_fd(xconn->ev_ctx,
+ xconn,
+ xconn->smb1.echo_handler.trusted_fd,
TEVENT_FD_READ,
smbd_server_echo_handler,
- sconn);
- if (sconn->smb1.echo_handler.trusted_fde == NULL) {
+ xconn);
+ if (xconn->smb1.echo_handler.trusted_fde == NULL) {
DEBUG(1, ("event_add_fd failed\n"));
goto fail;
}
if (listener_pipe[1] != -1) {
close(listener_pipe[1]);
}
- sconn->smb1.echo_handler.trusted_fd = -1;
- if (sconn->smb1.echo_handler.socket_lock_fd != -1) {
- close(sconn->smb1.echo_handler.socket_lock_fd);
+ if (xconn->smb1.echo_handler.socket_lock_fd != -1) {
+ close(xconn->smb1.echo_handler.socket_lock_fd);
+ }
+#ifdef HAVE_ROBUST_MUTEXES
+ if (xconn->smb1.echo_handler.socket_mutex != NULL) {
+ pthread_mutex_destroy(xconn->smb1.echo_handler.socket_mutex);
+ anonymous_shared_free(xconn->smb1.echo_handler.socket_mutex);
}
- sconn->smb1.echo_handler.trusted_fd = -1;
- sconn->smb1.echo_handler.socket_lock_fd = -1;
+#endif
+ smbd_echo_init(xconn);
+
return false;
}
{
NTSTATUS status;
- set_Protocol(protocol);
conn->protocol = protocol;
+ if (conn->client->session_table != NULL) {
+ return NT_STATUS_OK;
+ }
+
if (protocol >= PROTOCOL_SMB2_02) {
status = smb2srv_session_table_init(conn);
if (!NT_STATUS_IS_OK(status)) {
+ conn->protocol = PROTOCOL_NONE;
return status;
}
status = smb2srv_open_table_init(conn);
if (!NT_STATUS_IS_OK(status)) {
+ conn->protocol = PROTOCOL_NONE;
return status;
}
} else {
status = smb1srv_session_table_init(conn);
if (!NT_STATUS_IS_OK(status)) {
+ conn->protocol = PROTOCOL_NONE;
return status;
}
status = smb1srv_tcon_table_init(conn);
if (!NT_STATUS_IS_OK(status)) {
+ conn->protocol = PROTOCOL_NONE;
return status;
}
status = smb1srv_open_table_init(conn);
if (!NT_STATUS_IS_OK(status)) {
+ conn->protocol = PROTOCOL_NONE;
return status;
}
}
+ set_Protocol(protocol);
return NT_STATUS_OK;
}
+struct smbd_tevent_trace_state {
+ struct tevent_context *ev;
+ TALLOC_CTX *frame;
+ SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
+};
+
static void smbd_tevent_trace_callback(enum tevent_trace_point point,
void *private_data)
{
- struct smbXsrv_connection *conn =
- talloc_get_type_abort(private_data,
- struct smbXsrv_connection);
+ struct smbd_tevent_trace_state *state =
+ (struct smbd_tevent_trace_state *)private_data;
switch (point) {
case TEVENT_TRACE_BEFORE_WAIT:
- /*
- * This just removes compiler warning
- * without profile support
- */
- conn->smbd_idle_profstamp = 0;
- START_PROFILE_STAMP(smbd_idle, conn->smbd_idle_profstamp);
+ if (!smbprofile_dump_pending()) {
+ /*
+ * If there's no dump pending
+ * we don't want to schedule a new 1 sec timer.
+ *
+ * Instead we want to sleep as long as nothing happens.
+ */
+ smbprofile_dump_setup(NULL);
+ }
+ SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
break;
case TEVENT_TRACE_AFTER_WAIT:
- END_PROFILE_STAMP(smbd_idle, conn->smbd_idle_profstamp);
+ SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
+ if (!smbprofile_dump_pending()) {
+ /*
+ * We need to flush our state after sleeping
+ * (hopefully a long time).
+ */
+ smbprofile_dump();
+ /*
+ * future profiling events should trigger timers
+ * on our main event context.
+ */
+ smbprofile_dump_setup(state->ev);
+ }
+ break;
+ case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+ TALLOC_FREE(state->frame);
+ state->frame = talloc_stackframe_pool(8192);
+ break;
+ case TEVENT_TRACE_AFTER_LOOP_ONCE:
+ TALLOC_FREE(state->frame);
break;
}
+
+ errno = 0;
}
-/****************************************************************************
- Process commands from the client
-****************************************************************************/
+/**
+ * Create a debug string for the connection
+ *
+ * This is allocated to talloc_tos() or a string constant
+ * in certain corner cases. The returned string should
+ * hence not be free'd directly but only via the talloc stack.
+ */
+const char *smbXsrv_connection_dbg(const struct smbXsrv_connection *xconn)
+{
+ const char *ret;
-void smbd_process(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- int sock_fd,
- bool interactive)
+ /*
+ * TODO: this can be improved later
+ * maybe including the client guid or more
+ */
+ ret = tsocket_address_string(xconn->remote_address, talloc_tos());
+ if (ret == NULL) {
+ return "<tsocket_address_string() failed>";
+ }
+
+ return ret;
+}
+
+NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
+ struct smbXsrv_connection **_xconn)
{
TALLOC_CTX *frame = talloc_stackframe();
- struct smbXsrv_connection *conn;
- struct smbd_server_connection *sconn;
- struct sockaddr_storage ss;
- struct sockaddr *sa = NULL;
+ struct smbXsrv_connection *xconn;
+ struct sockaddr_storage ss_srv;
+ void *sp_srv = (void *)&ss_srv;
+ struct sockaddr *sa_srv = (struct sockaddr *)sp_srv;
+ struct sockaddr_storage ss_clnt;
+ void *sp_clnt = (void *)&ss_clnt;
+ struct sockaddr *sa_clnt = (struct sockaddr *)sp_clnt;
socklen_t sa_socklen;
struct tsocket_address *local_address = NULL;
struct tsocket_address *remote_address = NULL;
- const char *locaddr = NULL;
const char *remaddr = NULL;
- char *rhost;
+ char *p;
+ const char *rhost = NULL;
int ret;
+ int tmp;
+
+ *_xconn = NULL;
- conn = talloc_zero(ev_ctx, struct smbXsrv_connection);
- if (conn == NULL) {
+ DO_PROFILE_INC(connect);
+
+ xconn = talloc_zero(client, struct smbXsrv_connection);
+ if (xconn == NULL) {
DEBUG(0,("talloc_zero(struct smbXsrv_connection)\n"));
- exit_server_cleanly("talloc_zero(struct smbXsrv_connection).\n");
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
}
+ talloc_steal(frame, xconn);
- conn->ev_ctx = ev_ctx;
- conn->msg_ctx = msg_ctx;
+ xconn->ev_ctx = client->ev_ctx;
+ xconn->msg_ctx = client->msg_ctx;
+ xconn->transport.sock = sock_fd;
+ smbd_echo_init(xconn);
+ xconn->protocol = PROTOCOL_NONE;
- sconn = talloc_zero(conn, struct smbd_server_connection);
- if (!sconn) {
- exit_server("failed to create smbd_server_connection");
+ /* Ensure child is set to blocking mode */
+ set_blocking(sock_fd,True);
+
+ set_socket_options(sock_fd, "SO_KEEPALIVE");
+ set_socket_options(sock_fd, lp_socket_options());
+
+ sa_socklen = sizeof(ss_clnt);
+ ret = getpeername(sock_fd, sa_clnt, &sa_socklen);
+ if (ret != 0) {
+ int saved_errno = errno;
+ int level = (errno == ENOTCONN)?2:0;
+ DEBUG(level,("getpeername() failed - %s\n",
+ strerror(saved_errno)));
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+ ret = tsocket_address_bsd_from_sockaddr(xconn,
+ sa_clnt, sa_socklen,
+ &remote_address);
+ if (ret != 0) {
+ int saved_errno = errno;
+ DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
+ __location__, strerror(saved_errno)));
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+
+ sa_socklen = sizeof(ss_srv);
+ ret = getsockname(sock_fd, sa_srv, &sa_socklen);
+ if (ret != 0) {
+ int saved_errno = errno;
+ int level = (errno == ENOTCONN)?2:0;
+ DEBUG(level,("getsockname() failed - %s\n",
+ strerror(saved_errno)));
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+ ret = tsocket_address_bsd_from_sockaddr(xconn,
+ sa_srv, sa_socklen,
+ &local_address);
+ if (ret != 0) {
+ int saved_errno = errno;
+ DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
+ __location__, strerror(saved_errno)));
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix_common(saved_errno);
}
- conn->sconn = sconn;
- sconn->conn = conn;
+ if (tsocket_address_is_inet(remote_address, "ip")) {
+ remaddr = tsocket_address_inet_addr_string(remote_address,
+ talloc_tos());
+ if (remaddr == NULL) {
+ DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
+ __location__, strerror(errno)));
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ remaddr = "0.0.0.0";
+ }
+
+ /*
+ * Before the first packet, check the global hosts allow/ hosts deny
+ * parameters before doing any parsing of packets passed to us by the
+ * client. This prevents attacks on our parsing code from hosts not in
+ * the hosts allow list.
+ */
+
+ ret = get_remote_hostname(remote_address,
+ &p, talloc_tos());
+ if (ret < 0) {
+ int saved_errno = errno;
+ DEBUG(0,("%s: get_remote_hostname failed - %s\n",
+ __location__, strerror(saved_errno)));
+ TALLOC_FREE(frame);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+ rhost = p;
+ if (strequal(rhost, "UNKNOWN")) {
+ rhost = remaddr;
+ }
+
+ xconn->local_address = local_address;
+ xconn->remote_address = remote_address;
+ xconn->remote_hostname = talloc_strdup(xconn, rhost);
+ if (xconn->remote_hostname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!srv_init_signing(xconn)) {
+ DEBUG(0, ("Failed to init smb_signing\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (!allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1),
+ xconn->remote_hostname,
+ remaddr)) {
+ DEBUG( 1, ("Connection denied from %s to %s\n",
+ tsocket_address_string(remote_address, talloc_tos()),
+ tsocket_address_string(local_address, talloc_tos())));
+
+ /*
+ * We return a valid xconn
+ * so that the caller can return an error message
+ * to the client
+ */
+ client->connections = xconn;
+ xconn->client = client;
+ talloc_steal(client, xconn);
+
+ *_xconn = xconn;
+ TALLOC_FREE(frame);
+ return NT_STATUS_NETWORK_ACCESS_DENIED;
+ }
+
+ DEBUG(10, ("Connection allowed from %s to %s\n",
+ tsocket_address_string(remote_address, talloc_tos()),
+ tsocket_address_string(local_address, talloc_tos())));
+
+ if (lp_clustering()) {
+ /*
+ * We need to tell ctdb about our client's TCP
+ * connection, so that for failover ctdbd can send
+ * tickle acks, triggering a reconnection by the
+ * client.
+ */
+ NTSTATUS status;
+
+ status = smbd_register_ips(xconn, &ss_srv, &ss_clnt);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ctdbd_register_ips failed: %s\n",
+ nt_errstr(status)));
+ }
+ }
+
+ tmp = lp_max_xmit();
+ tmp = MAX(tmp, SMB_BUFFER_SIZE_MIN);
+ tmp = MIN(tmp, SMB_BUFFER_SIZE_MAX);
+
+ xconn->smb1.negprot.max_recv = tmp;
+
+ xconn->smb1.sessions.done_sesssetup = false;
+ xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
+
+ xconn->transport.fde = tevent_add_fd(client->ev_ctx,
+ xconn,
+ sock_fd,
+ TEVENT_FD_READ,
+ smbd_server_connection_handler,
+ xconn);
+ if (!xconn->transport.fde) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* for now we only have one connection */
+ DLIST_ADD_END(client->connections, xconn);
+ xconn->client = client;
+ talloc_steal(client, xconn);
+
+ *_xconn = xconn;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Process commands from the client
+****************************************************************************/
+
+void smbd_process(struct tevent_context *ev_ctx,
+ struct messaging_context *msg_ctx,
+ int sock_fd,
+ bool interactive)
+{
+ struct smbd_tevent_trace_state trace_state = {
+ .ev = ev_ctx,
+ .frame = talloc_stackframe(),
+ };
+ struct smbXsrv_client *client = NULL;
+ struct smbd_server_connection *sconn = NULL;
+ struct smbXsrv_connection *xconn = NULL;
+ const char *locaddr = NULL;
+ const char *remaddr = NULL;
+ int ret;
+ NTSTATUS status;
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+ char *chroot_dir = NULL;
+ int rc;
+
+ status = smbXsrv_client_create(ev_ctx, ev_ctx, msg_ctx, now, &client);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smbXsrv_client_create(): %s\n", nt_errstr(status));
+ exit_server_cleanly("talloc_zero(struct smbXsrv_client).\n");
+ }
/*
* TODO: remove this...:-)
*/
- global_smbXsrv_connection = conn;
+ global_smbXsrv_client = client;
+
+ sconn = talloc_zero(client, struct smbd_server_connection);
+ if (sconn == NULL) {
+ exit_server("failed to create smbd_server_connection");
+ }
+
+ client->sconn = sconn;
+ sconn->client = client;
sconn->ev_ctx = ev_ctx;
sconn->msg_ctx = msg_ctx;
- sconn->sock = sock_fd;
- sconn->smb1.echo_handler.trusted_fd = -1;
- sconn->smb1.echo_handler.socket_lock_fd = -1;
+
+ if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
+ /*
+ * We're not making the decision here,
+ * we're just allowing the client
+ * to decide between SMB1 and SMB2
+ * with the first negprot
+ * packet.
+ */
+ sconn->using_smb2 = true;
+ }
if (!interactive) {
smbd_setup_sig_term_handler(sconn);
}
}
- if (lp_srv_maxprotocol() >= PROTOCOL_SMB2_02) {
+ status = smbd_add_connection(client, sock_fd, &xconn);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
/*
- * We're not making the decision here,
- * we're just allowing the client
- * to decide between SMB1 and SMB2
- * with the first negprot
- * packet.
+ * send a negative session response "not listening on calling
+ * name"
*/
- sconn->using_smb2 = true;
+ unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+ (void)srv_send_smb(xconn,(char *)buf, false,
+ 0, false, NULL);
+ exit_server_cleanly("connection denied");
+ } else if (!NT_STATUS_IS_OK(status)) {
+ exit_server_cleanly(nt_errstr(status));
}
- /* Ensure child is set to blocking mode */
- set_blocking(sconn->sock,True);
-
- set_socket_options(sconn->sock, "SO_KEEPALIVE");
- set_socket_options(sconn->sock, lp_socket_options());
-
- sa = (struct sockaddr *)(void *)&ss;
- sa_socklen = sizeof(ss);
- ret = getpeername(sconn->sock, sa, &sa_socklen);
- if (ret != 0) {
- int level = (errno == ENOTCONN)?2:0;
- DEBUG(level,("getpeername() failed - %s\n", strerror(errno)));
- exit_server_cleanly("getpeername() failed.\n");
+ sconn->local_address =
+ tsocket_address_copy(xconn->local_address, sconn);
+ if (sconn->local_address == NULL) {
+ exit_server_cleanly("tsocket_address_copy() failed");
}
- ret = tsocket_address_bsd_from_sockaddr(sconn,
- sa, sa_socklen,
- &remote_address);
- if (ret != 0) {
- DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
- __location__, strerror(errno)));
- exit_server_cleanly("tsocket_address_bsd_from_sockaddr remote failed.\n");
+ sconn->remote_address =
+ tsocket_address_copy(xconn->remote_address, sconn);
+ if (sconn->remote_address == NULL) {
+ exit_server_cleanly("tsocket_address_copy() failed");
}
-
- sa = (struct sockaddr *)(void *)&ss;
- sa_socklen = sizeof(ss);
- ret = getsockname(sconn->sock, sa, &sa_socklen);
- if (ret != 0) {
- int level = (errno == ENOTCONN)?2:0;
- DEBUG(level,("getsockname() failed - %s\n", strerror(errno)));
- exit_server_cleanly("getsockname() failed.\n");
+ sconn->remote_hostname =
+ talloc_strdup(sconn, xconn->remote_hostname);
+ if (sconn->remote_hostname == NULL) {
+ exit_server_cleanly("tsocket_strdup() failed");
}
- ret = tsocket_address_bsd_from_sockaddr(sconn,
- sa, sa_socklen,
- &local_address);
- if (ret != 0) {
- DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
- __location__, strerror(errno)));
- exit_server_cleanly("tsocket_address_bsd_from_sockaddr remote failed.\n");
- }
-
- sconn->local_address = local_address;
- sconn->remote_address = remote_address;
- if (tsocket_address_is_inet(local_address, "ip")) {
+ if (tsocket_address_is_inet(sconn->local_address, "ip")) {
locaddr = tsocket_address_inet_addr_string(
sconn->local_address,
talloc_tos());
if (locaddr == NULL) {
- DEBUG(0,("%s: tsocket_address_inet_addr_string local failed - %s\n",
+ DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
__location__, strerror(errno)));
- exit_server_cleanly("tsocket_address_inet_addr_string local failed.\n");
+ exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
}
} else {
locaddr = "0.0.0.0";
}
- if (tsocket_address_is_inet(remote_address, "ip")) {
+ if (tsocket_address_is_inet(sconn->remote_address, "ip")) {
remaddr = tsocket_address_inet_addr_string(
sconn->remote_address,
talloc_tos());
in smbstatus for port 445 connects */
set_remote_machine_name(remaddr, false);
reload_services(sconn, conn_snum_used, true);
-
- /*
- * Before the first packet, check the global hosts allow/ hosts deny
- * parameters before doing any parsing of packets passed to us by the
- * client. This prevents attacks on our parsing code from hosts not in
- * the hosts allow list.
- */
-
- ret = get_remote_hostname(remote_address,
- &rhost,
- talloc_tos());
- if (ret < 0) {
- DEBUG(0,("%s: get_remote_hostname failed - %s\n",
- __location__, strerror(errno)));
- exit_server_cleanly("get_remote_hostname failed.\n");
- }
- if (strequal(rhost, "UNKNOWN")) {
- rhost = talloc_strdup(talloc_tos(), remaddr);
- }
- sconn->remote_hostname = talloc_move(sconn, &rhost);
-
sub_set_socket_ids(remaddr,
sconn->remote_hostname,
locaddr);
- if (!allow_access(lp_hostsdeny(-1), lp_hostsallow(-1),
- sconn->remote_hostname,
- remaddr)) {
- /*
- * send a negative session response "not listening on calling
- * name"
- */
- unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
- DEBUG( 1, ("Connection denied from %s to %s\n",
- tsocket_address_string(remote_address, talloc_tos()),
- tsocket_address_string(local_address, talloc_tos())));
- (void)srv_send_smb(sconn,(char *)buf, false,
- 0, false, NULL);
- exit_server_cleanly("connection denied");
- }
-
- DEBUG(10, ("Connection allowed from %s to %s\n",
- tsocket_address_string(remote_address, talloc_tos()),
- tsocket_address_string(local_address, talloc_tos())));
-
if (lp_preload_modules()) {
smb_load_modules(lp_preload_modules());
}
exit_server("Could not open account policy tdb.\n");
}
- if (*lp_rootdir(talloc_tos())) {
- if (chroot(lp_rootdir(talloc_tos())) != 0) {
- DEBUG(0,("Failed to change root to %s\n",
- lp_rootdir(talloc_tos())));
- exit_server("Failed to chroot()");
+ chroot_dir = lp_root_directory(talloc_tos());
+ if (chroot_dir[0] != '\0') {
+ rc = chdir(chroot_dir);
+ if (rc != 0) {
+ DBG_ERR("Failed to chdir to %s\n", chroot_dir);
+ exit_server("Failed to chdir()");
}
- if (chdir("/") == -1) {
- DEBUG(0,("Failed to chdir to / on chroot to %s\n", lp_rootdir(talloc_tos())));
+
+ rc = chroot(chroot_dir);
+ if (rc != 0) {
+ DBG_ERR("Failed to change root to %s\n", chroot_dir);
exit_server("Failed to chroot()");
}
- DEBUG(0,("Changed root to %s\n", lp_rootdir(talloc_tos())));
- }
+ DBG_WARNING("Changed root to %s\n", chroot_dir);
- if (!srv_init_signing(sconn)) {
- exit_server("Failed to init smb_signing");
+ TALLOC_FREE(chroot_dir);
}
if (!file_init(sconn)) {
messaging_register(sconn->msg_ctx, sconn,
MSG_SMB_CONF_UPDATED, smbd_conf_updated);
+ messaging_deregister(sconn->msg_ctx, MSG_SMB_KILL_CLIENT_IP,
+ NULL);
+ messaging_register(sconn->msg_ctx, sconn,
+ MSG_SMB_KILL_CLIENT_IP,
+ msg_kill_client_ip);
+
+ messaging_deregister(sconn->msg_ctx, MSG_SMB_TELL_NUM_CHILDREN, NULL);
+
/*
* Use the default MSG_DEBUG handler to avoid rebroadcasting
* MSGs to all child processes
exit(1);
}
-#ifdef CLUSTER_SUPPORT
-
- if (lp_clustering()) {
- /*
- * We need to tell ctdb about our client's TCP
- * connection, so that for failover ctdbd can send
- * tickle acks, triggering a reconnection by the
- * client.
- */
-
- struct sockaddr_storage srv, clnt;
-
- if (client_get_tcp_info(sconn->sock, &srv, &clnt) == 0) {
- NTSTATUS status;
- status = smbd_register_ips(sconn, &srv, &clnt);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("ctdbd_register_ips failed: %s\n",
- nt_errstr(status)));
- }
- } else {
- int level = (errno == ENOTCONN)?2:0;
- DEBUG(level,("Unable to get tcp info for "
- "smbd_register_ips: %s\n",
- strerror(errno)));
- exit_server_cleanly("client_get_tcp_info() failed.\n");
- }
- }
-
-#endif
-
- sconn->nbt.got_session = false;
-
- sconn->smb1.negprot.max_recv = MIN(lp_max_xmit(),BUFFER_SIZE);
-
- sconn->smb1.sessions.done_sesssetup = false;
- sconn->smb1.sessions.max_send = BUFFER_SIZE;
- sconn->smb1.sessions.last_session_tag = UID_FIELD_INVALID;
+ smbprofile_dump_setup(ev_ctx);
if (!init_dptrs(sconn)) {
exit_server("init_dptrs() failed");
}
- sconn->smb1.fde = tevent_add_fd(ev_ctx,
- sconn,
- sconn->sock,
- TEVENT_FD_READ,
- smbd_server_connection_handler,
- sconn);
- if (!sconn->smb1.fde) {
- exit_server("failed to create smbd_server_connection fde");
- }
-
- sconn->conn->local_address = sconn->local_address;
- sconn->conn->remote_address = sconn->remote_address;
- sconn->conn->remote_hostname = sconn->remote_hostname;
- sconn->conn->protocol = PROTOCOL_NONE;
-
- TALLOC_FREE(frame);
-
- tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback, conn);
+ TALLOC_FREE(trace_state.frame);
- while (True) {
- frame = talloc_stackframe_pool(8192);
+ tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback,
+ &trace_state);
- errno = 0;
- if (tevent_loop_once(ev_ctx) == -1) {
- if (errno != EINTR) {
- DEBUG(3, ("tevent_loop_once failed: %s,"
- " exiting\n", strerror(errno) ));
- break;
- }
- }
-
- TALLOC_FREE(frame);
+ ret = tevent_loop_wait(ev_ctx);
+ if (ret != 0) {
+ DEBUG(1, ("tevent_loop_wait failed: %d, %s,"
+ " exiting\n", ret, strerror(errno)));
}
+ TALLOC_FREE(trace_state.frame);
+
exit_server_cleanly(NULL);
}