From a9d5f9d7643f1d1830f680eafa0baee67fd25579 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Feb 2013 10:18:57 +0100 Subject: [PATCH 1/5] s3:smbd: s/EVENT_FD/TEVENT_FD Signed-off-by: Stefan Metzmacher Reviewed-by: Michael Adam (cherry picked from commit 2672c37a8fbc9ff4e5b74e9a5ae55a3e08beed43) --- source3/smbd/process.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 78a5909..8156896 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2443,11 +2443,11 @@ static void smbd_server_connection_handler(struct event_context *ev, struct smbd_server_connection *conn = talloc_get_type(private_data, struct smbd_server_connection); - if (flags & EVENT_FD_WRITE) { + if (flags & TEVENT_FD_WRITE) { smbd_server_connection_write_handler(conn); return; } - if (flags & EVENT_FD_READ) { + if (flags & TEVENT_FD_READ) { smbd_server_connection_read_handler(conn, conn->sock); return; } @@ -2461,11 +2461,11 @@ static void smbd_server_echo_handler(struct event_context *ev, struct smbd_server_connection *conn = talloc_get_type(private_data, struct smbd_server_connection); - if (flags & EVENT_FD_WRITE) { + if (flags & TEVENT_FD_WRITE) { smbd_server_connection_write_handler(conn); return; } - if (flags & EVENT_FD_READ) { + if (flags & TEVENT_FD_READ) { smbd_server_connection_read_handler( conn, conn->smb1.echo_handler.trusted_fd); return; -- 1.7.9.5 From 4e1a461096f64b23b620ae16ef134bd95ee0e749 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 17 Feb 2014 12:05:42 +0100 Subject: [PATCH 2/5] s3:smbd: simplify exit_server_common() Signed-off-by: Stefan Metzmacher --- source3/smbd/server_exit.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c index fa28374..aac738c 100644 --- a/source3/smbd/server_exit.c +++ b/source3/smbd/server_exit.c @@ -99,13 +99,11 @@ static void exit_server_common(enum server_exit_reason how, change_to_root_user(); - if (sconn && sconn->smb1.negprot.auth_context) { - TALLOC_FREE(sconn->smb1.negprot.auth_context); - } - if (sconn) { NTSTATUS status; + TALLOC_FREE(sconn->smb1.negprot.auth_context); + if (lp_log_writeable_files_on_exit()) { bool found = false; files_forall(sconn, log_writeable_file_fn, &found); -- 1.7.9.5 From ee813ac700d067d7f842da8a0d54db2cf9572ef5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 17 Feb 2014 12:01:12 +0100 Subject: [PATCH 3/5] 4.0.13: s3:smbd: maintain smbd_server_connection->status If this isn't NT_STATUS_OK, we skip any io on the socket. This avoids possible problems during shutdown. Signed-off-by: Stefan Metzmacher --- source3/smbd/globals.h | 1 + source3/smbd/process.c | 25 +++++++++++++++++++++++++ source3/smbd/server_exit.c | 11 +++++++++++ source3/smbd/smb2_server.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 82bae4a..17fdcc8 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -620,6 +620,7 @@ struct user_struct { }; struct smbd_server_connection { + NTSTATUS status; int sock; const struct tsocket_address *local_address; const struct tsocket_address *remote_address; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 8156896..57da9ae 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -155,6 +155,13 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer, ssize_t ret; char *buf_out = buffer; + if (!NT_STATUS_IS_OK(sconn->status)) { + /* + * we're not supposed to do any io + */ + return true; + } + smbd_lock_socket(sconn); if (do_signing) { @@ -2443,6 +2450,15 @@ static void smbd_server_connection_handler(struct event_context *ev, struct smbd_server_connection *conn = talloc_get_type(private_data, struct smbd_server_connection); + if (!NT_STATUS_IS_OK(conn->status)) { + /* + * we're not supposed to do any io + */ + TEVENT_FD_NOT_READABLE(conn->smb1.fde); + TEVENT_FD_NOT_WRITEABLE(conn->smb1.fde); + return; + } + if (flags & TEVENT_FD_WRITE) { smbd_server_connection_write_handler(conn); return; @@ -2461,6 +2477,15 @@ static void smbd_server_echo_handler(struct event_context *ev, struct smbd_server_connection *conn = talloc_get_type(private_data, struct smbd_server_connection); + if (!NT_STATUS_IS_OK(conn->status)) { + /* + * we're not supposed to do any io + */ + TEVENT_FD_NOT_READABLE(conn->smb1.echo_handler.trusted_fde); + TEVENT_FD_NOT_WRITEABLE(conn->smb1.echo_handler.trusted_fde); + return; + } + if (flags & TEVENT_FD_WRITE) { smbd_server_connection_write_handler(conn); return; diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c index aac738c..0bd6f5c 100644 --- a/source3/smbd/server_exit.c +++ b/source3/smbd/server_exit.c @@ -102,6 +102,17 @@ static void exit_server_common(enum server_exit_reason how, if (sconn) { NTSTATUS status; + if (NT_STATUS_IS_OK(sconn->status)) { + switch (how) { + case SERVER_EXIT_ABNORMAL: + sconn->status = NT_STATUS_INTERNAL_ERROR; + break; + case SERVER_EXIT_NORMAL: + sconn->status = NT_STATUS_LOCAL_DISCONNECT; + break; + } + } + TALLOC_FREE(sconn->smb1.negprot.auth_context); if (lp_log_writeable_files_on_exit()) { diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 525b81b..c239c1c 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -1163,6 +1163,10 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request struct smbd_smb2_request *nreq = NULL; NTSTATUS status; + if (!NT_STATUS_IS_OK(req->sconn->status)) { + return NT_STATUS_OK; + } + /* Create a new smb2 request we'll use for the interim return. */ nreq = dup_smb2_req(req); @@ -1411,6 +1415,10 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, TALLOC_FREE(req->async_te); + if (!NT_STATUS_IS_OK(req->sconn->status)) { + return; + } + /* Ensure our final reply matches the interim one. */ inhdr = SMBD_SMB2_IN_HDR_PTR(req); outhdr = SMBD_SMB2_OUT_HDR_PTR(req); @@ -2287,6 +2295,10 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) req->subreq = NULL; TALLOC_FREE(req->async_te); + if (!NT_STATUS_IS_OK(req->sconn->status)) { + return NT_STATUS_OK; + } + if (req->do_encryption && (firsttf->iov_len == 0) && (req->first_key.length == 0) && @@ -2711,6 +2723,10 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn, uint64_t nonce_high = 0; uint64_t nonce_low = 0; + if (!NT_STATUS_IS_OK(sconn->status)) { + return NT_STATUS_OK; + } + if (tcon->global->encryption_required) { do_encryption = true; } @@ -3158,6 +3174,13 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *s size_t cur_send_queue_len; struct tevent_req *subreq; + if (!NT_STATUS_IS_OK(sconn->status)) { + /* + * we're not supposed to do any io + */ + return NT_STATUS_OK; + } + if (tevent_queue_length(sconn->smb2.recv_queue) > 0) { /* * if there is already a smbd_smb2_request_read @@ -3243,6 +3266,11 @@ static void smbd_smb2_request_incoming(struct tevent_req *subreq) NTSTATUS status; struct smbd_smb2_request *req = NULL; + if (!NT_STATUS_IS_OK(sconn->status)) { + TALLOC_FREE(subreq); + return; + } + status = smbd_smb2_request_read_recv(subreq, sconn, &req); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { -- 1.7.9.5 From 6a1e4f8c26ab245ce6519f580c81ba8a30d451cc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 17 Feb 2014 11:57:52 +0100 Subject: [PATCH 4/5] s3:lib/ctdbd_conn: let release_ip_handler return bool If it returns true the passed ip address matched and we let a nested ctdb operation fail with NT_STATUS_ADDRESS_CLOSED. Signed-off-by: Stefan Metzmacher --- source3/include/ctdbd_conn.h | 2 +- source3/lib/ctdbd_conn.c | 36 ++++++++++++++++++++++++++++++------ source3/smbd/process.c | 6 ++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index c481f1e..b5627c3 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -91,7 +91,7 @@ NTSTATUS ctdbd_traverse(uint32_t db_id, NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, const struct sockaddr_storage *server, const struct sockaddr_storage *client, - void (*release_ip_handler)(const char *ip_addr, + bool (*release_ip_handler)(const char *ip_addr, void *private_data), void *private_data); diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 13cb698..30f351d 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -60,7 +60,7 @@ struct ctdbd_connection { struct ctdb_packet_context *pkt; struct fd_event *fde; - void (*release_ip_handler)(const char *ip_addr, void *private_data); + bool (*release_ip_handler)(const char *ip_addr, void *private_data); void *release_ip_priv; }; @@ -441,10 +441,23 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32_t reqid, if ((conn->release_ip_handler != NULL) && (msg->srvid == CTDB_SRVID_RELEASE_IP)) { + bool ret; + /* must be dispatched immediately */ DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n")); - conn->release_ip_handler((const char *)msg->data, - conn->release_ip_priv); + ret = conn->release_ip_handler((const char *)msg->data, + conn->release_ip_priv); + if (ret) { + /* + * We need to release the ip, + * so return an error to the upper layers. + * + * We make sure we don't trigger this again. + */ + conn->release_ip_handler = NULL; + conn->release_ip_priv = NULL; + return NT_STATUS_ADDRESS_CLOSED; + } TALLOC_FREE(hdr); goto next_pkt; } @@ -643,10 +656,21 @@ static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length, if ((conn->release_ip_handler != NULL) && (msg->srvid == CTDB_SRVID_RELEASE_IP)) { + bool ret; + /* must be dispatched immediately */ DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n")); - conn->release_ip_handler((const char *)msg->data, - conn->release_ip_priv); + ret = conn->release_ip_handler((const char *)msg->data, + conn->release_ip_priv); + if (ret) { + /* + * We need to release the ip. + * + * We make sure we don't trigger this again. + */ + conn->release_ip_handler = NULL; + conn->release_ip_priv = NULL; + } TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -1812,7 +1836,7 @@ static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in, NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, const struct sockaddr_storage *_server, const struct sockaddr_storage *_client, - void (*release_ip_handler)(const char *ip_addr, + bool (*release_ip_handler)(const char *ip_addr, void *private_data), void *private_data) { diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 57da9ae..bc16df7 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2507,7 +2507,7 @@ struct smbd_release_ip_state { /**************************************************************************** received when we should release a specific IP ****************************************************************************/ -static void release_ip(const char *ip, void *priv) +static bool release_ip(const char *ip, void *priv) { struct smbd_release_ip_state *state = talloc_get_type_abort(priv, @@ -2544,8 +2544,10 @@ static void release_ip(const char *ip, void *priv) */ smbd_server_connection_terminate(state->sconn, "CTDB_SRVID_RELEASE_IP"); - return; + return true; } + + return false; } static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn, -- 1.7.9.5 From bf7fd31544e72b1b5437a3316f33833c4468639e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 13 Feb 2014 15:36:27 +0100 Subject: [PATCH 5/5] s3:smbd: avoid invalid lock_order panic triggered by "CTDB_SRVID_RELEASE_IP" If smbd_server_connection_terminate("CTDB_SRVID_RELEASE_IP") is triggered from within ctdbd_migrate(), we got a smb_panic complaining about invalid lock_order, as ctdbd_migrate is called from dbwrap_fetch_locked(). Bug: https://bugzilla.samba.org/show_bug.cgi?id=10444 Signed-off-by: Stefan Metzmacher --- source3/smbd/process.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/source3/smbd/process.c b/source3/smbd/process.c index bc16df7..4b9c4a4 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2501,9 +2501,28 @@ static void smbd_server_echo_handler(struct event_context *ev, struct smbd_release_ip_state { struct smbd_server_connection *sconn; + 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); + + if (!NT_STATUS_EQUAL(state->sconn->status, NT_STATUS_ADDRESS_CLOSED)) { + /* + * smbd_server_connection_terminate() already triggered ? + */ + return; + } + + smbd_server_connection_terminate(state->sconn, "CTDB_SRVID_RELEASE_IP"); +} + /**************************************************************************** received when we should release a specific IP ****************************************************************************/ @@ -2515,6 +2534,11 @@ static bool release_ip(const char *ip, void *priv) const char *addr = state->addr; const char *p = addr; + if (!NT_STATUS_IS_OK(state->sconn->status)) { + /* avoid recursion */ + return false; + } + if (strncmp("::ffff:", addr, 7) == 0) { p = addr + 7; } @@ -2541,9 +2565,18 @@ static bool release_ip(const char *ip, void *priv) * 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"); + tevent_schedule_immediate(state->im, state->sconn->ev_ctx, + smbd_release_ip_immediate, state); + + /* + * Make sure we don't get any io on the connection. + */ + state->sconn->status = NT_STATUS_ADDRESS_CLOSED; return true; } @@ -2567,6 +2600,10 @@ static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn, return NT_STATUS_NO_MEMORY; } state->sconn = sconn; + 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; } -- 1.7.9.5