X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Fsmbd%2Fprocess.c;h=c95c1f07ef1cae28ac0e570d35481870d5230e19;hb=8b2b7d1c87b475b61ef5259cee0ae77afe47a667;hp=20569d858c4042781c7fc57c163a11a8fe37f177;hpb=16229e4cefb01c3bdf1cb1cef81f0eab1f1cc0e6;p=ira%2Fwip.git diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 20569d858c4..c95c1f07ef1 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -19,18 +19,30 @@ */ #include "includes.h" +#include "../lib/tsocket/tsocket.h" +#include "system/filesys.h" +#include "smbd/smbd.h" #include "smbd/globals.h" #include "librpc/gen_ndr/netlogon.h" -#include "librpc/gen_ndr/messaging.h" #include "../lib/async_req/async_sock.h" #include "ctdbd_conn.h" #include "../lib/util/select.h" +#include "printing/queue_process.h" +#include "system/select.h" +#include "passdb.h" +#include "auth.h" +#include "messages.h" +#include "smbprofile.h" +#include "rpc_server/spoolss/srv_spoolss_nt.h" +#include "libsmb/libsmb.h" +#include "../lib/util/tevent_ntstatus.h" extern bool global_machine_password_needs_changing; static void construct_reply_common(struct smb_request *req, const char *inbuf, char *outbuf); -static struct pending_message_list *get_deferred_open_message_smb(uint64_t mid); +static struct pending_message_list *get_deferred_open_message_smb( + struct smbd_server_connection *sconn, uint64_t mid); static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn) { @@ -132,7 +144,7 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer, } if (do_encrypt) { - NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out); + NTSTATUS status = srv_encrypt_buffer(sconn, buffer, &buf_out); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("send_smb: SMB encryption failed " "on outgoing packet! Error %s\n", @@ -156,12 +168,12 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer, get_peer_addr(sconn->sock, addr, sizeof(addr)), (int)ret, strerror(errno) )); - srv_free_enc_buffer(buf_out); + srv_free_enc_buffer(sconn, buf_out); goto out; } SMB_PERFCOUNT_SET_MSGLEN_OUT(pcd, len); - srv_free_enc_buffer(buf_out); + srv_free_enc_buffer(sconn, buf_out); out: SMB_PERFCOUNT_END(pcd); @@ -187,9 +199,10 @@ int srv_set_message(char *buf, return (smb_size + num_words*2 + num_bytes); } -static bool valid_smb_header(const uint8_t *inbuf) +static bool valid_smb_header(struct smbd_server_connection *sconn, + const uint8_t *inbuf) { - if (is_encrypted_packet(inbuf)) { + if (is_encrypted_packet(sconn, inbuf)) { return true; } /* @@ -255,6 +268,7 @@ static NTSTATUS read_packet_remainder(int fd, char *buffer, static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, const char lenbuf[4], struct smbd_server_connection *sconn, + int sock, char **buffer, unsigned int timeout, size_t *p_unread, @@ -269,14 +283,16 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, memcpy(writeX_header, lenbuf, 4); status = read_fd_with_timeout( - sconn->sock, writeX_header + 4, + sock, writeX_header + 4, STANDARD_WRITE_AND_X_HEADER_SIZE, STANDARD_WRITE_AND_X_HEADER_SIZE, timeout, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("read_fd_with_timeout failed for client %s read " - "error = %s.\n", sconn->client_id.addr, + "error = %s.\n", + tsocket_address_string(sconn->remote_address, + talloc_tos()), nt_errstr(status))); return status; } @@ -296,7 +312,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) { size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE; - if (drain_socket(sconn->sock, drain) != drain) { + if (drain_socket(sock, drain) != drain) { smb_panic("receive_smb_raw_talloc_partial_read:" " failed to drain pending bytes"); } @@ -310,7 +326,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, /* Copy the header we've written. */ - *buffer = (char *)TALLOC_MEMDUP(mem_ctx, + *buffer = (char *)talloc_memdup(mem_ctx, writeX_header, sizeof(writeX_header)); @@ -335,7 +351,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, * talloc and return. */ - *buffer = TALLOC_ARRAY(mem_ctx, char, len+4); + *buffer = talloc_array(mem_ctx, char, len+4); if (*buffer == NULL) { DEBUG(0, ("Could not allocate inbuf of length %d\n", @@ -351,7 +367,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, if(toread > 0) { status = read_packet_remainder( - sconn->sock, + sock, (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE, timeout, toread); @@ -368,6 +384,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx, static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, struct smbd_server_connection *sconn, + int sock, char **buffer, unsigned int timeout, size_t *p_unread, size_t *plen) { @@ -378,7 +395,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, *p_unread = 0; - status = read_smb_length_return_keepalive(sconn->sock, lenbuf, timeout, + status = read_smb_length_return_keepalive(sock, lenbuf, timeout, &len); if (!NT_STATUS_IS_OK(status)) { return status; @@ -391,7 +408,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, sconn->smb1.echo_handler.trusted_fde == NULL) { return receive_smb_raw_talloc_partial_read( - mem_ctx, lenbuf, sconn, buffer, timeout, + mem_ctx, lenbuf, sconn, sock, buffer, timeout, p_unread, plen); } @@ -403,7 +420,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, * The +4 here can't wrap, we've checked the length above already. */ - *buffer = TALLOC_ARRAY(mem_ctx, char, len+4); + *buffer = talloc_array(mem_ctx, char, len+4); if (*buffer == NULL) { DEBUG(0, ("Could not allocate inbuf of length %d\n", @@ -413,7 +430,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, memcpy(*buffer, lenbuf, sizeof(lenbuf)); - status = read_packet_remainder(sconn->sock, (*buffer)+4, timeout, len); + status = read_packet_remainder(sock, (*buffer)+4, timeout, len); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -424,6 +441,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, struct smbd_server_connection *sconn, + int sock, char **buffer, unsigned int timeout, size_t *p_unread, bool *p_encrypted, size_t *p_len, @@ -435,17 +453,20 @@ static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx, *p_encrypted = false; - status = receive_smb_raw_talloc(mem_ctx, sconn, buffer, timeout, + status = receive_smb_raw_talloc(mem_ctx, sconn, sock, buffer, timeout, p_unread, &len); if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("read_smb_length_return_keepalive failed for " - "client %s read error = %s.\n", - sconn->client_id.addr, nt_errstr(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()), + nt_errstr(status)) ); return status; } - if (is_encrypted_packet((uint8_t *)*buffer)) { - status = srv_decrypt_buffer(*buffer); + if (is_encrypted_packet(sconn, (uint8_t *)*buffer)) { + status = srv_decrypt_buffer(sconn, *buffer); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("receive_smb_talloc: SMB decryption failed on " "incoming packet! Error %s\n", @@ -491,9 +512,9 @@ static bool init_smb_request(struct smb_request *req, req->vuid = SVAL(inbuf, smb_uid); req->tid = SVAL(inbuf, smb_tid); req->wct = CVAL(inbuf, smb_wct); - req->vwv = (uint16_t *)(inbuf+smb_vwv); + req->vwv = discard_const_p(uint16_t, (inbuf+smb_vwv)); req->buflen = smb_buflen(inbuf); - req->buf = (const uint8_t *)smb_buf(inbuf); + req->buf = (const uint8_t *)smb_buf_const(inbuf); req->unread_bytes = unread_bytes; req->encrypted = encrypted; req->sconn = sconn; @@ -512,7 +533,7 @@ static bool init_smb_request(struct smb_request *req, return false; } /* Ensure bcc is correct. */ - if (((uint8 *)smb_buf(inbuf)) + req->buflen > inbuf + req_size) { + if (((const uint8_t *)smb_buf_const(inbuf)) + req->buflen > inbuf + req_size) { DEBUG(0,("init_smb_request: invalid bcc number %u " "(wct = %u, size %u)\n", (unsigned int)req->buflen, @@ -537,6 +558,7 @@ static void smbd_deferred_open_timer(struct event_context *ev, { struct pending_message_list *msg = talloc_get_type(private_data, struct pending_message_list); + struct smbd_server_connection *sconn = msg->sconn; TALLOC_CTX *mem_ctx = talloc_tos(); uint64_t mid = (uint64_t)SVAL(msg->buf.data,smb_mid); uint8_t *inbuf; @@ -557,14 +579,14 @@ static void smbd_deferred_open_timer(struct event_context *ev, * re-processed in error. */ msg->processed = true; - process_smb(smbd_server_conn, inbuf, + process_smb(sconn, 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(mid); + msg = get_deferred_open_message_smb(sconn, mid); if (msg && msg->processed) { - remove_deferred_open_message_smb(mid); + remove_deferred_open_message_smb(sconn, mid); } } @@ -581,12 +603,13 @@ static bool push_queued_message(struct smb_request *req, int msg_len = smb_len(req->inbuf) + 4; struct pending_message_list *msg; - msg = TALLOC_ZERO_P(NULL, struct pending_message_list); + msg = talloc_zero(NULL, struct pending_message_list); if(msg == NULL) { DEBUG(0,("push_message: malloc fail (1)\n")); return False; } + msg->sconn = req->sconn; msg->buf = data_blob_talloc(msg, req->inbuf, msg_len); if(msg->buf.data == NULL) { @@ -611,7 +634,7 @@ static bool push_queued_message(struct smb_request *req, } } - msg->te = event_add_timed(smbd_event_context(), + msg->te = event_add_timed(server_event_context(), msg, end_time, smbd_deferred_open_timer, @@ -622,7 +645,8 @@ static bool push_queued_message(struct smb_request *req, return false; } - DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *); + DLIST_ADD_END(req->sconn->deferred_open_queue, msg, + struct pending_message_list *); DEBUG(10,("push_message: pushed message length %u on " "deferred_open_queue\n", (unsigned int)msg_len)); @@ -634,22 +658,23 @@ static bool push_queued_message(struct smb_request *req, Function to delete a sharing violation open message by mid. ****************************************************************************/ -void remove_deferred_open_message_smb(uint64_t mid) +void remove_deferred_open_message_smb(struct smbd_server_connection *sconn, + uint64_t mid) { struct pending_message_list *pml; - if (smbd_server_conn->using_smb2) { - remove_deferred_open_message_smb2(smbd_server_conn, mid); + if (sconn->using_smb2) { + remove_deferred_open_message_smb2(sconn, mid); return; } - for (pml = deferred_open_queue; pml; pml = pml->next) { + for (pml = sconn->deferred_open_queue; pml; pml = pml->next) { if (mid == (uint64_t)SVAL(pml->buf.data,smb_mid)) { DEBUG(10,("remove_deferred_open_message_smb: " "deleting mid %llu len %u\n", (unsigned long long)mid, (unsigned int)pml->buf.length )); - DLIST_REMOVE(deferred_open_queue, pml); + DLIST_REMOVE(sconn->deferred_open_queue, pml); TALLOC_FREE(pml); return; } @@ -661,17 +686,18 @@ void remove_deferred_open_message_smb(uint64_t mid) schedule it for immediate processing. ****************************************************************************/ -void schedule_deferred_open_message_smb(uint64_t mid) +void schedule_deferred_open_message_smb(struct smbd_server_connection *sconn, + uint64_t mid) { struct pending_message_list *pml; int i = 0; - if (smbd_server_conn->using_smb2) { - schedule_deferred_open_message_smb2(smbd_server_conn, mid); + if (sconn->using_smb2) { + schedule_deferred_open_message_smb2(sconn, mid); return; } - for (pml = deferred_open_queue; pml; pml = pml->next) { + for (pml = sconn->deferred_open_queue; pml; pml = pml->next) { uint64_t msg_mid = (uint64_t)SVAL(pml->buf.data,smb_mid); DEBUG(10,("schedule_deferred_open_message_smb: [%d] " @@ -695,7 +721,7 @@ void schedule_deferred_open_message_smb(uint64_t mid) "scheduling mid %llu\n", (unsigned long long)mid )); - te = event_add_timed(smbd_event_context(), + te = event_add_timed(server_event_context(), pml, timeval_zero(), smbd_deferred_open_timer, @@ -709,7 +735,7 @@ void schedule_deferred_open_message_smb(uint64_t mid) TALLOC_FREE(pml->te); pml->te = te; - DLIST_PROMOTE(deferred_open_queue, pml); + DLIST_PROMOTE(sconn->deferred_open_queue, pml); return; } } @@ -723,15 +749,15 @@ void schedule_deferred_open_message_smb(uint64_t mid) Return true if this mid is on the deferred queue and was not yet processed. ****************************************************************************/ -bool open_was_deferred(uint64_t mid) +bool open_was_deferred(struct smbd_server_connection *sconn, uint64_t mid) { struct pending_message_list *pml; - if (smbd_server_conn->using_smb2) { - return open_was_deferred_smb2(smbd_server_conn, mid); + if (sconn->using_smb2) { + return open_was_deferred_smb2(sconn, mid); } - for (pml = deferred_open_queue; pml; pml = pml->next) { + for (pml = sconn->deferred_open_queue; pml; pml = pml->next) { if (((uint64_t)SVAL(pml->buf.data,smb_mid)) == mid && !pml->processed) { return True; } @@ -743,11 +769,12 @@ bool open_was_deferred(uint64_t mid) Return the message queued by this mid. ****************************************************************************/ -static struct pending_message_list *get_deferred_open_message_smb(uint64_t mid) +static struct pending_message_list *get_deferred_open_message_smb( + struct smbd_server_connection *sconn, uint64_t mid) { struct pending_message_list *pml; - for (pml = deferred_open_queue; pml; pml = pml->next) { + for (pml = sconn->deferred_open_queue; pml; pml = pml->next) { if (((uint64_t)SVAL(pml->buf.data,smb_mid)) == mid) { return pml; } @@ -765,13 +792,13 @@ bool get_deferred_open_message_state(struct smb_request *smbreq, { struct pending_message_list *pml; - if (smbd_server_conn->using_smb2) { + if (smbreq->sconn->using_smb2) { return get_deferred_open_message_state_smb2(smbreq->smb2req, p_request_time, pp_state); } - pml = get_deferred_open_message_smb(smbreq->mid); + pml = get_deferred_open_message_smb(smbreq->sconn, smbreq->mid); if (!pml) { return false; } @@ -827,86 +854,6 @@ bool push_deferred_open_message_smb(struct smb_request *req, private_data, priv_len); } -struct idle_event { - struct timed_event *te; - struct timeval interval; - char *name; - bool (*handler)(const struct timeval *now, void *private_data); - void *private_data; -}; - -static void smbd_idle_event_handler(struct event_context *ctx, - struct timed_event *te, - struct timeval now, - void *private_data) -{ - struct idle_event *event = - talloc_get_type_abort(private_data, struct idle_event); - - TALLOC_FREE(event->te); - - DEBUG(10,("smbd_idle_event_handler: %s %p called\n", - event->name, event->te)); - - if (!event->handler(&now, event->private_data)) { - DEBUG(10,("smbd_idle_event_handler: %s %p stopped\n", - event->name, event->te)); - /* Don't repeat, delete ourselves */ - TALLOC_FREE(event); - return; - } - - DEBUG(10,("smbd_idle_event_handler: %s %p rescheduled\n", - event->name, event->te)); - - event->te = event_add_timed(ctx, event, - timeval_sum(&now, &event->interval), - smbd_idle_event_handler, event); - - /* We can't do much but fail here. */ - SMB_ASSERT(event->te != NULL); -} - -struct idle_event *event_add_idle(struct event_context *event_ctx, - TALLOC_CTX *mem_ctx, - struct timeval interval, - const char *name, - bool (*handler)(const struct timeval *now, - void *private_data), - void *private_data) -{ - struct idle_event *result; - struct timeval now = timeval_current(); - - result = TALLOC_P(mem_ctx, struct idle_event); - if (result == NULL) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - result->interval = interval; - result->handler = handler; - result->private_data = private_data; - - if (!(result->name = talloc_asprintf(result, "idle_evt(%s)", name))) { - DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(result); - return NULL; - } - - result->te = event_add_timed(event_ctx, result, - timeval_sum(&now, &interval), - smbd_idle_event_handler, result); - if (result->te == NULL) { - DEBUG(0, ("event_add_timed failed\n")); - TALLOC_FREE(result); - return NULL; - } - - DEBUG(10,("event_add_idle: %s %p\n", result->name, result->te)); - return result; -} - static void smbd_sig_term_handler(struct tevent_context *ev, struct tevent_signal *se, int signum, @@ -921,8 +868,8 @@ void smbd_setup_sig_term_handler(void) { struct tevent_signal *se; - se = tevent_add_signal(smbd_event_context(), - smbd_event_context(), + se = tevent_add_signal(server_event_context(), + server_event_context(), SIGTERM, 0, smbd_sig_term_handler, NULL); @@ -944,7 +891,7 @@ static void smbd_sig_hup_handler(struct tevent_context *ev, DEBUG(1,("Reloading services after SIGHUP\n")); reload_services(msg_ctx, smbd_server_conn->sock, False); if (am_parent) { - pcap_cache_reload(ev, msg_ctx, &reload_pcap_change_notify); + printing_subsystem_update(ev, msg_ctx, true); } } @@ -960,33 +907,25 @@ void smbd_setup_sig_hup_handler(struct tevent_context *ev, } } -static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *conn) +static NTSTATUS smbd_server_connection_loop_once(struct tevent_context *ev_ctx, + struct smbd_server_connection *conn) { - fd_set r_fds, w_fds; - int selrtn; - struct timeval to; - int maxfd = 0; - - to.tv_sec = SMBD_SELECT_TIMEOUT; - to.tv_usec = 0; - - /* - * Setup the select fd sets. - */ + int timeout; + int num_pfds = 0; + int ret; + bool retry; - FD_ZERO(&r_fds); - FD_ZERO(&w_fds); + timeout = SMBD_SELECT_TIMEOUT * 1000; /* * Are there any timed events waiting ? If so, ensure we don't * select for longer than it would take to wait for them. */ - event_add_to_select_args(smbd_event_context(), - &r_fds, &w_fds, &to, &maxfd); + event_add_to_poll_args(ev_ctx, conn, &conn->pfds, &num_pfds, &timeout); /* Process a signal and timed events now... */ - if (run_events(smbd_event_context(), 0, NULL, NULL)) { + if (run_events_poll(ev_ctx, 0, NULL, 0)) { return NT_STATUS_RETRY; } @@ -994,23 +933,27 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection * int sav; START_PROFILE(smbd_idle); - selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to); + ret = sys_poll(conn->pfds, num_pfds, timeout); sav = errno; END_PROFILE(smbd_idle); errno = sav; } - if (selrtn == -1 && errno != EINTR) { + if (ret == -1) { + if (errno == EINTR) { + return NT_STATUS_RETRY; + } return map_nt_error_from_unix(errno); } - if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) { + retry = run_events_poll(ev_ctx, ret, conn->pfds, num_pfds); + if (retry) { return NT_STATUS_RETRY; } /* Did we timeout ? */ - if (selrtn == 0) { + if (ret == 0) { return NT_STATUS_RETRY; } @@ -1341,12 +1284,12 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, char *msg; if (asprintf(&msg, "num_bytes too large: %u", (unsigned)num_bytes) == -1) { - msg = CONST_DISCARD(char *, "num_bytes too large"); + msg = discard_const_p(char, "num_bytes too large"); } smb_panic(msg); } - *outbuf = TALLOC_ARRAY(mem_ctx, char, + *outbuf = talloc_array(mem_ctx, char, smb_size + num_words*2 + num_bytes); if (*outbuf == NULL) { return false; @@ -1368,7 +1311,7 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes) { char *outbuf; - if (!create_outbuf(req, req, (char *)req->inbuf, &outbuf, num_words, + if (!create_outbuf(req, req, (const char *)req->inbuf, &outbuf, num_words, num_bytes)) { smb_panic("could not allocate output buffer\n"); } @@ -1426,12 +1369,13 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in uint16 session_tag; connection_struct *conn = NULL; struct smbd_server_connection *sconn = req->sconn; + char *raddr; errno = 0; /* Make sure this is an SMB packet. smb_size contains NetBIOS header * so subtract 4 from it. */ - if (!valid_smb_header(req->inbuf) + if (!valid_smb_header(sconn, req->inbuf) || (size < (smb_size - 4))) { DEBUG(2,("Non-SMB packet of length %d. Terminating server\n", smb_len(req->inbuf))); @@ -1440,7 +1384,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in if (smb_messages[type].fn == NULL) { DEBUG(0,("Unknown message type %d!\n",type)); - smb_dump("Unknown", 1, (char *)req->inbuf, size); + smb_dump("Unknown", 1, (const char *)req->inbuf, size); reply_unknown_new(req, type); return NULL; } @@ -1455,10 +1399,10 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n", smb_fn_name(type), (int)sys_getpid(), (unsigned long)conn)); - smb_dump(smb_fn_name(type), 1, (char *)req->inbuf, size); + smb_dump(smb_fn_name(type), 1, (const char *)req->inbuf, size); /* Ensure this value is replaced in the incoming packet. */ - SSVAL(req->inbuf,smb_uid,session_tag); + SSVAL(discard_const_p(uint8_t, req->inbuf),smb_uid,session_tag); /* * Ensure the correct username is in current_user_info. This is a @@ -1477,9 +1421,9 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in vuser = get_valid_user_struct(sconn, session_tag); if (vuser) { set_current_user_info( - vuser->server_info->sanitized_username, - vuser->server_info->unix_name, - vuser->server_info->info3->base.domain.string); + vuser->session_info->unix_info->sanitized_username, + vuser->session_info->unix_info->unix_name, + vuser->session_info->info->domain_name); } } } @@ -1550,12 +1494,19 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in conn->num_smb_operations++; } + raddr = tsocket_address_inet_addr_string(sconn->remote_address, + talloc_tos()); + if (raddr == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return conn; + } + /* does this protocol need to be run as guest? */ if ((flags & AS_GUEST) && (!change_to_guest() || !allow_access(lp_hostsdeny(-1), lp_hostsallow(-1), - sconn->client_id.name, - sconn->client_id.addr))) { + sconn->remote_hostname, + raddr))) { reply_nterror(req, NT_STATUS_ACCESS_DENIED); return conn; } @@ -1650,7 +1601,7 @@ static void process_smb(struct smbd_server_connection *sconn, DEBUG(3, ("Transaction %d of length %d (%u toread)\n", sconn->trans_num, (int)nread, (unsigned int)unread_bytes)); - if (msg_type != 0) { + if (msg_type != NBSSmessage) { /* * NetBIOS session request, keepalive, etc. */ @@ -1664,7 +1615,7 @@ static void process_smb(struct smbd_server_connection *sconn, if (smbd_is_smb2_header(inbuf, nread)) { smbd_smb2_first_negprot(sconn, inbuf, nread); return; - } else if (nread >= smb_size && valid_smb_header(inbuf) + } else if (nread >= smb_size && valid_smb_header(sconn, inbuf) && CVAL(inbuf, smb_com) != 0x72) { /* This is a non-negprot SMB1 packet. Disable SMB2 from now on. */ @@ -1679,7 +1630,7 @@ static void process_smb(struct smbd_server_connection *sconn, sconn->trans_num++; done: - sconn->smb1.num_requests++; + sconn->num_requests++; /* The timeout_processing function isn't run nearly often enough to implement 'max log size' without @@ -1688,7 +1639,7 @@ done: level 10. Checking every 50 SMBs is a nice tradeoff of performance vs log file size overrun. */ - if ((sconn->smb1.num_requests % 50) == 0 && + if ((sconn->num_requests % 50) == 0 && need_to_check_log_size()) { change_to_root_user(); check_log_size(); @@ -1726,15 +1677,21 @@ void remove_from_common_flags2(uint32 v) static void construct_reply_common(struct smb_request *req, const char *inbuf, char *outbuf) { + uint16_t in_flags2 = SVAL(inbuf,smb_flg2); + uint16_t out_flags2 = common_flags2; + + out_flags2 |= in_flags2 & FLAGS2_UNICODE_STRINGS; + out_flags2 |= in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES; + out_flags2 |= in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED; + srv_set_message(outbuf,0,0,false); SCVAL(outbuf, smb_com, req->cmd); SIVAL(outbuf,smb_rcls,0); SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); - SSVAL(outbuf,smb_flg2, - (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) | - common_flags2); + SSVAL(outbuf,smb_flg2, out_flags2); memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh)); + memcpy(outbuf+smb_ss_field, inbuf+smb_ss_field, 8); SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); @@ -1744,7 +1701,7 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf, void construct_reply_common_req(struct smb_request *req, char *outbuf) { - construct_reply_common(req, (char *)req->inbuf, outbuf); + construct_reply_common(req, (const char *)req->inbuf, outbuf); } /* @@ -1884,7 +1841,7 @@ static bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command, return false; } - outbuf = TALLOC_REALLOC_ARRAY(NULL, *poutbuf, uint8_t, new_size); + outbuf = talloc_realloc(NULL, *poutbuf, uint8_t, new_size); if (outbuf == NULL) { DEBUG(0, ("talloc failed\n")); return false; @@ -1898,7 +1855,7 @@ static bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command, if (!find_andx_cmd_ofs(outbuf, &andx_cmd_ofs)) { DEBUG(1, ("invalid command chain\n")); - *poutbuf = TALLOC_REALLOC_ARRAY( + *poutbuf = talloc_realloc( NULL, *poutbuf, uint8_t, old_size); return false; } @@ -1967,9 +1924,9 @@ void chain_reply(struct smb_request *req) uint32_t chain_offset; /* uint32_t to avoid overflow */ uint8_t wct; - uint16_t *vwv; + const uint16_t *vwv; uint16_t buflen; - uint8_t *buf; + const uint8_t *buf; if (IVAL(req->outbuf, smb_rcls) != 0) { fixup_chain_error_packet(req); @@ -1986,7 +1943,7 @@ void chain_reply(struct smb_request *req) if ((req->wct < 2) || (CVAL(req->outbuf, smb_wct) < 2)) { if (req->chain_outbuf == NULL) { - req->chain_outbuf = TALLOC_REALLOC_ARRAY( + req->chain_outbuf = talloc_realloc( req, req->outbuf, uint8_t, smb_len(req->outbuf) + 4); if (req->chain_outbuf == NULL) { @@ -2018,7 +1975,7 @@ void chain_reply(struct smb_request *req) * over-allocated (reply_pipe_read_and_X used to be such an * example). */ - req->chain_outbuf = TALLOC_REALLOC_ARRAY( + req->chain_outbuf = talloc_realloc( req, req->outbuf, uint8_t, smb_len(req->outbuf) + 4); if (req->chain_outbuf == NULL) { smb_panic("talloc failed"); @@ -2078,15 +2035,24 @@ void chain_reply(struct smb_request *req) SMB_PERFCOUNT_SET_MSGLEN_IN(&req->pcd, smblen); /* - * Check if the client tries to fool us. The request so far uses the - * space to the end of the byte buffer in the request just - * processed. The chain_offset can't point into that area. If that was - * the case, we could end up with an endless processing of the chain, - * we would always handle the same request. + * Check if the client tries to fool us. The chain offset + * needs to point beyond the current request in the chain, it + * needs to strictly grow. Otherwise we might be tricked into + * an endless loop always processing the same request over and + * over again. We used to assume that vwv and the byte buffer + * array in a chain are always attached, but OS/2 the + * Write&X/Read&X chain puts the Read&X vwv array right behind + * the Write&X vwv chain. The Write&X bcc array is put behind + * the Read&X vwv array. So now we check whether the chain + * offset points strictly behind the previous vwv + * array. req->buf points right after the vwv array of the + * previous request. See + * https://bugzilla.samba.org/show_bug.cgi?id=8360 for more + * information. */ - already_used = PTR_DIFF(req->buf+req->buflen, smb_base(req->inbuf)); - if (chain_offset < already_used) { + already_used = PTR_DIFF(req->buf, smb_base(req->inbuf)); + if (chain_offset <= already_used) { goto error; } @@ -2118,7 +2084,7 @@ void chain_reply(struct smb_request *req) if (length_needed > smblen) { goto error; } - vwv = (uint16_t *)(smb_base(req->inbuf) + chain_offset + 1); + vwv = (const uint16_t *)(smb_base(req->inbuf) + chain_offset + 1); /* * Now grab the new byte buffer.... @@ -2134,11 +2100,11 @@ void chain_reply(struct smb_request *req) if (length_needed > smblen) { goto error; } - buf = (uint8_t *)(vwv+wct+1); + buf = (const uint8_t *)(vwv+wct+1); req->cmd = chain_cmd; req->wct = wct; - req->vwv = vwv; + req->vwv = discard_const_p(uint16_t, vwv); req->buflen = buflen; req->buf = buf; @@ -2228,27 +2194,22 @@ static void check_reload(struct smbd_server_connection *sconn, time_t t) static bool fd_is_readable(int fd) { - fd_set fds; - struct timeval timeout = {0, }; - int ret; + int ret, revents; - FD_ZERO(&fds); - FD_SET(fd, &fds); + ret = poll_one_fd(fd, POLLIN|POLLHUP, 0, &revents); + + return ((ret > 0) && ((revents & (POLLIN|POLLHUP|POLLERR)) != 0)); - ret = sys_select(fd+1, &fds, NULL, NULL, &timeout); - if (ret == -1) { - return false; - } - return FD_ISSET(fd, &fds); } -static void smbd_server_connection_write_handler(struct smbd_server_connection *conn) +static void smbd_server_connection_write_handler( + struct smbd_server_connection *sconn) { /* TODO: make write nonblocking */ } static void smbd_server_connection_read_handler( - struct smbd_server_connection *conn, int fd) + struct smbd_server_connection *sconn, int fd) { uint8_t *inbuf = NULL; size_t inbuf_len = 0; @@ -2258,35 +2219,41 @@ static void smbd_server_connection_read_handler( NTSTATUS status; uint32_t seqnum; - bool from_client = (conn->sock == fd); + bool from_client; + + 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; + } + + from_client = (sconn->sock == fd); if (from_client) { - smbd_lock_socket(conn); + smbd_lock_socket(sconn); - if (lp_async_smb_echo_handler() && !fd_is_readable(fd)) { + if (!fd_is_readable(fd)) { DEBUG(10,("the echo listener was faster\n")); - smbd_unlock_socket(conn); + smbd_unlock_socket(sconn); return; } + } - /* TODO: make this completely nonblocking */ - status = receive_smb_talloc(mem_ctx, conn, - (char **)(void *)&inbuf, - 0, /* timeout */ - &unread_bytes, - &encrypted, - &inbuf_len, &seqnum, - false /* trusted channel */); - smbd_unlock_socket(conn); - } else { - /* TODO: make this completely nonblocking */ - status = receive_smb_talloc(mem_ctx, conn, - (char **)(void *)&inbuf, - 0, /* timeout */ - &unread_bytes, - &encrypted, - &inbuf_len, &seqnum, - true /* trusted channel */); + /* TODO: make this completely nonblocking */ + status = receive_smb_talloc(mem_ctx, sconn, fd, + (char **)(void *)&inbuf, + 0, /* timeout */ + &unread_bytes, + &encrypted, + &inbuf_len, &seqnum, + false /* trusted channel */); + + if (from_client) { + smbd_unlock_socket(sconn); } if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { @@ -2300,7 +2267,7 @@ static void smbd_server_connection_read_handler( } process: - process_smb(conn, inbuf, inbuf_len, unread_bytes, + process_smb(sconn, inbuf, inbuf_len, unread_bytes, seqnum, encrypted, NULL); } @@ -2341,6 +2308,7 @@ static void smbd_server_echo_handler(struct event_context *ev, } } +#ifdef CLUSTER_SUPPORT /**************************************************************************** received when we should release a specific IP ****************************************************************************/ @@ -2353,6 +2321,9 @@ static void release_ip(const char *ip, void *priv) p = addr + 7; } + DEBUG(10, ("Got release IP message for %s, " + "our address is %s\n", ip, p)); + if ((strcmp(p, ip) == 0) || ((p != addr) && strcmp(addr, ip) == 0)) { /* we can't afford to do a clean exit - that involves database writes, which would potentially mean we @@ -2367,16 +2338,6 @@ static void release_ip(const char *ip, void *priv) } } -static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data, - uint32_t msg_type, struct server_id server_id, DATA_BLOB *data) -{ - struct smbd_server_connection *sconn = talloc_get_type_abort( - private_data, struct smbd_server_connection); - - release_ip((char *)data->data, sconn->client_id.addr); -} - -#ifdef CLUSTER_SUPPORT static int client_get_tcp_info(int sock, struct sockaddr_storage *server, struct sockaddr_storage *client) { @@ -2398,7 +2359,8 @@ static int client_get_tcp_info(int sock, struct sockaddr_storage *server, */ static bool keepalive_fn(const struct timeval *now, void *private_data) { - struct smbd_server_connection *sconn = smbd_server_conn; + struct smbd_server_connection *sconn = talloc_get_type_abort( + private_data, struct smbd_server_connection); bool ret; if (sconn->using_smb2) { @@ -2475,30 +2437,158 @@ static bool housekeeping_fn(const struct timeval *now, void *private_data) return true; } -static int create_unlink_tmp(const char *dir) +/* + * Read an smb packet in the echo handler child, giving the parent + * smbd one second to react once the socket becomes readable. + */ + +struct smbd_echo_read_state { + struct tevent_context *ev; + struct smbd_server_connection *sconn; + + char *buf; + size_t buflen; + uint32_t seqnum; +}; + +static void smbd_echo_read_readable(struct tevent_req *subreq); +static void smbd_echo_read_waited(struct tevent_req *subreq); + +static struct tevent_req *smbd_echo_read_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct smbd_server_connection *sconn) { - char *fname; - int fd; + struct tevent_req *req, *subreq; + struct smbd_echo_read_state *state; - fname = talloc_asprintf(talloc_tos(), "%s/listenerlock_XXXXXX", dir); - if (fname == NULL) { - errno = ENOMEM; - return -1; + req = tevent_req_create(mem_ctx, &state, + struct smbd_echo_read_state); + if (req == NULL) { + return NULL; } - fd = mkstemp(fname); - if (fd == -1) { - TALLOC_FREE(fname); - return -1; + state->ev = ev; + state->sconn = sconn; + + subreq = wait_for_read_send(state, ev, sconn->sock); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - if (unlink(fname) == -1) { - int sys_errno = errno; - close(fd); - TALLOC_FREE(fname); - errno = sys_errno; - return -1; + tevent_req_set_callback(subreq, smbd_echo_read_readable, req); + return req; +} + +static void smbd_echo_read_readable(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct smbd_echo_read_state *state = tevent_req_data( + req, struct smbd_echo_read_state); + bool ok; + int err; + + ok = wait_for_read_recv(subreq, &err); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + + /* + * Give the parent smbd one second to step in + */ + + subreq = tevent_wakeup_send( + state, state->ev, timeval_current_ofs(1, 0)); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, smbd_echo_read_waited, req); +} + +static void smbd_echo_read_waited(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + 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; + bool ok; + NTSTATUS status; + size_t unread = 0; + bool encrypted; + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + ok = smbd_lock_socket_internal(sconn); + 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)) { + DEBUG(10,("echo_handler[%d] the parent smbd was faster\n", + (int)sys_getpid())); + + ok = smbd_unlock_socket_internal(sconn); + if (!ok) { + tevent_req_nterror(req, map_nt_error_from_unix(errno)); + DEBUG(1, ("%s: failed to unlock socket\n", + __location__)); + return; + } + + subreq = wait_for_read_send(state, state->ev, sconn->sock); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, smbd_echo_read_readable, req); + return; + } + + status = receive_smb_talloc(state, sconn, sconn->sock, &state->buf, + 0 /* timeout */, + &unread, + &encrypted, + &state->buflen, + &state->seqnum, + false /* trusted_channel*/); + + if (tevent_req_nterror(req, status)) { + tevent_req_nterror(req, status); + DEBUG(1, ("echo_handler[%d]: receive_smb_raw_talloc failed: %s\n", + (int)sys_getpid(), nt_errstr(status))); + return; + } + + ok = smbd_unlock_socket_internal(sconn); + if (!ok) { + tevent_req_nterror(req, map_nt_error_from_unix(errno)); + DEBUG(1, ("%s: failed to unlock socket\n", __location__)); + return; + } + tevent_req_done(req); +} + +static NTSTATUS smbd_echo_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + char **pbuf, size_t *pbuflen, uint32_t *pseqnum) +{ + struct smbd_echo_read_state *state = tevent_req_data( + req, struct smbd_echo_read_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; } - TALLOC_FREE(fname); - return fd; + *pbuf = talloc_move(mem_ctx, &state->buf); + *pbuflen = state->buflen; + *pseqnum = state->seqnum; + return NT_STATUS_OK; } struct smbd_echo_state { @@ -2509,7 +2599,6 @@ struct smbd_echo_state { struct tevent_fd *parent_fde; - struct tevent_fd *read_fde; struct tevent_req *write_req; }; @@ -2570,7 +2659,7 @@ static bool smbd_echo_reply(uint8_t *inbuf, size_t inbuf_len, char *outbuf; bool ok; - if ((inbuf_len == 4) && (CVAL(inbuf, 0) == SMBkeepalive)) { + if ((inbuf_len == 4) && (CVAL(inbuf, 0) == NBSSkeepalive)) { DEBUG(10, ("Got netbios keepalive\n")); /* * Just swallow it @@ -2582,7 +2671,7 @@ static bool smbd_echo_reply(uint8_t *inbuf, size_t inbuf_len, DEBUG(10, ("Got short packet: %d bytes\n", (int)inbuf_len)); return false; } - if (!valid_smb_header(inbuf)) { + if (!valid_smb_header(smbd_server_conn, inbuf)) { DEBUG(10, ("Got invalid SMB header\n")); return false; } @@ -2610,7 +2699,7 @@ static bool smbd_echo_reply(uint8_t *inbuf, size_t inbuf_len, return false; } - if (!create_outbuf(talloc_tos(), &req, (char *)req.inbuf, &outbuf, + if (!create_outbuf(talloc_tos(), &req, (const char *)req.inbuf, &outbuf, 1, req.buflen)) { DEBUG(10, ("create_outbuf failed\n")); return false; @@ -2645,107 +2734,13 @@ static void smbd_echo_exit(struct tevent_context *ev, exit(0); } -static void smbd_echo_reader(struct tevent_context *ev, - struct tevent_fd *fde, uint16_t flags, - void *private_data) -{ - struct smbd_echo_state *state = talloc_get_type_abort( - private_data, struct smbd_echo_state); - struct smbd_server_connection *sconn = state->sconn; - size_t unread, num_pending; - NTSTATUS status; - struct iovec *tmp; - size_t iov_len; - uint32_t seqnum = 0; - bool reply; - bool ok; - bool encrypted = false; - - smb_msleep(1000); - - ok = smbd_lock_socket_internal(sconn); - if (!ok) { - DEBUG(0, ("%s: failed to lock socket\n", - __location__)); - exit(1); - } - - if (!fd_is_readable(sconn->sock)) { - DEBUG(10,("echo_handler[%d] the parent smbd was faster\n", - (int)sys_getpid())); - ok = smbd_unlock_socket_internal(sconn); - if (!ok) { - DEBUG(1, ("%s: failed to unlock socket in\n", - __location__)); - exit(1); - } - return; - } - - num_pending = talloc_array_length(state->pending); - tmp = talloc_realloc(state, state->pending, struct iovec, - num_pending+1); - if (tmp == NULL) { - DEBUG(1, ("talloc_realloc failed\n")); - exit(1); - } - state->pending = tmp; - - DEBUG(10,("echo_handler[%d]: reading pdu\n", (int)sys_getpid())); - - status = receive_smb_talloc(state->pending, sconn, - (char **)(void *)&state->pending[num_pending].iov_base, - 0 /* timeout */, - &unread, - &encrypted, - &iov_len, - &seqnum, - false /* trusted_channel*/); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("echo_handler[%d]: receive_smb_raw_talloc failed: %s\n", - (int)sys_getpid(), nt_errstr(status))); - exit(1); - } - state->pending[num_pending].iov_len = iov_len; - - ok = smbd_unlock_socket_internal(sconn); - if (!ok) { - DEBUG(1, ("%s: failed to unlock socket in\n", - __location__)); - exit(1); - } - - reply = smbd_echo_reply((uint8_t *)state->pending[num_pending].iov_base, - state->pending[num_pending].iov_len, - seqnum); - if (reply) { - DEBUG(10,("echo_handler[%d]: replied to client\n", (int)sys_getpid())); - /* no check, shrinking by some bytes does not fail */ - state->pending = talloc_realloc(state, state->pending, - struct iovec, - num_pending); - return; - } - - if (state->pending[num_pending].iov_len >= smb_size) { - /* - * place the seqnum in the packet so that the main process - * can reply with signing - */ - SIVAL((uint8_t *)state->pending[num_pending].iov_base, - smb_ss_field, seqnum); - SIVAL((uint8_t *)state->pending[num_pending].iov_base, - smb_ss_field+4, NT_STATUS_V(NT_STATUS_OK)); - } - - DEBUG(10,("echo_handler[%d]: forward to main\n", (int)sys_getpid())); - smbd_echo_activate_writer(state); -} +static void smbd_echo_got_packet(struct tevent_req *req); static void smbd_echo_loop(struct smbd_server_connection *sconn, int parent_pipe) { struct smbd_echo_state *state; + struct tevent_req *read_req; state = talloc_zero(sconn, struct smbd_echo_state); if (state == NULL) { @@ -2768,14 +2763,14 @@ static void smbd_echo_loop(struct smbd_server_connection *sconn, TALLOC_FREE(state); return; } - state->read_fde = tevent_add_fd(state->ev, state, sconn->sock, - TEVENT_FD_READ, smbd_echo_reader, - state); - if (state->read_fde == NULL) { - DEBUG(1, ("tevent_add_fd failed\n")); + + read_req = smbd_echo_read_send(state, state->ev, sconn); + if (read_req == NULL) { + DEBUG(1, ("smbd_echo_read_send failed\n")); TALLOC_FREE(state); return; } + tevent_req_set_callback(read_req, smbd_echo_got_packet, state); while (true) { if (tevent_loop_once(state->ev) == -1) { @@ -2787,10 +2782,70 @@ static void smbd_echo_loop(struct smbd_server_connection *sconn, TALLOC_FREE(state); } +static void smbd_echo_got_packet(struct tevent_req *req) +{ + struct smbd_echo_state *state = tevent_req_callback_data( + req, struct smbd_echo_state); + NTSTATUS status; + char *buf = NULL; + size_t buflen = 0; + uint32_t seqnum = 0; + bool reply; + + status = smbd_echo_read_recv(req, state, &buf, &buflen, &seqnum); + TALLOC_FREE(req); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("smbd_echo_read_recv returned %s\n", + nt_errstr(status))); + exit(1); + } + + reply = smbd_echo_reply((uint8_t *)buf, buflen, seqnum); + if (!reply) { + size_t num_pending; + struct iovec *tmp; + struct iovec *iov; + + num_pending = talloc_array_length(state->pending); + tmp = talloc_realloc(state, state->pending, struct iovec, + num_pending+1); + if (tmp == NULL) { + DEBUG(1, ("talloc_realloc failed\n")); + exit(1); + } + state->pending = tmp; + + if (buflen >= smb_size) { + /* + * place the seqnum in the packet so that the main process + * can reply with signing + */ + SIVAL(buf, smb_ss_field, seqnum); + SIVAL(buf, smb_ss_field+4, NT_STATUS_V(NT_STATUS_OK)); + } + + iov = &state->pending[num_pending]; + iov->iov_base = buf; + iov->iov_len = buflen; + + DEBUG(10,("echo_handler[%d]: forward to main\n", + (int)sys_getpid())); + smbd_echo_activate_writer(state); + } + + req = smbd_echo_read_send(state, state->ev, state->sconn); + if (req == NULL) { + DEBUG(1, ("smbd_echo_read_send failed\n")); + exit(1); + } + tevent_req_set_callback(req, smbd_echo_got_packet, state); +} + + /* * Handle SMBecho requests in a forked child process */ -static bool fork_echo_handler(struct smbd_server_connection *sconn) +bool fork_echo_handler(struct smbd_server_connection *sconn) { int listener_pipe[2]; int res; @@ -2815,7 +2870,7 @@ static bool fork_echo_handler(struct smbd_server_connection *sconn) set_blocking(listener_pipe[1], false); status = reinit_after_fork(sconn->msg_ctx, - smbd_event_context(), + server_event_context(), procid_self(), false); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("reinit_after_fork failed: %s\n", @@ -2835,7 +2890,7 @@ static bool fork_echo_handler(struct smbd_server_connection *sconn) * 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 = event_add_fd(smbd_event_context(), + sconn->smb1.echo_handler.trusted_fde = event_add_fd(server_event_context(), sconn, sconn->smb1.echo_handler.trusted_fd, EVENT_FD_READ, @@ -2893,7 +2948,8 @@ static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn, Process commands from the client ****************************************************************************/ -void smbd_process(struct smbd_server_connection *sconn) +void smbd_process(struct tevent_context *ev_ctx, + struct smbd_server_connection *sconn) { TALLOC_CTX *frame = talloc_stackframe(); struct sockaddr_storage ss; @@ -2901,13 +2957,14 @@ void smbd_process(struct smbd_server_connection *sconn) 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; int ret; - if (lp_maxprotocol() == PROTOCOL_SMB2 && - !lp_async_smb_echo_handler()) { + if (lp_maxprotocol() >= PROTOCOL_SMB2_02) { /* - * We're not making the desion here, + * We're not making the decision here, * we're just allowing the client * to decide between SMB1 and SMB2 * with the first negprot @@ -2959,12 +3016,27 @@ void smbd_process(struct smbd_server_connection *sconn) sconn->local_address = local_address; sconn->remote_address = remote_address; + if (tsocket_address_is_inet(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", + __location__, strerror(errno))); + exit_server_cleanly("tsocket_address_inet_addr_string local failed.\n"); + } + } else { + locaddr = "0.0.0.0"; + } + if (tsocket_address_is_inet(remote_address, "ip")) { remaddr = tsocket_address_inet_addr_string( sconn->remote_address, talloc_tos()); if (remaddr == NULL) { - + DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n", + __location__, strerror(errno))); + exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n"); } } else { remaddr = "0.0.0.0"; @@ -2982,9 +3054,26 @@ void smbd_process(struct smbd_server_connection *sconn) * 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->client_id.name, - sconn->client_id.addr)) { + sconn->remote_hostname, + remaddr)) { /* * send a negative session response "not listening on calling * name" @@ -3026,10 +3115,6 @@ void smbd_process(struct smbd_server_connection *sconn) exit_server("Failed to init smb_signing"); } - if (lp_async_smb_echo_handler() && !fork_echo_handler(sconn)) { - exit_server("Failed to fork echo handler"); - } - /* Setup oplocks */ if (!init_oplocks(sconn->msg_ctx)) exit_server("Failed to init oplocks"); @@ -3037,8 +3122,6 @@ void smbd_process(struct smbd_server_connection *sconn) /* register our message handlers */ messaging_register(sconn->msg_ctx, NULL, MSG_SMB_FORCE_TDIS, msg_force_tdis); - messaging_register(sconn->msg_ctx, sconn, - MSG_SMB_RELEASE_IP, msg_release_ip); messaging_register(sconn->msg_ctx, NULL, MSG_SMB_CLOSE_FILE, msg_close_file); @@ -3052,22 +3135,22 @@ void smbd_process(struct smbd_server_connection *sconn) MSG_DEBUG, debug_message); if ((lp_keepalive() != 0) - && !(event_add_idle(smbd_event_context(), NULL, + && !(event_add_idle(ev_ctx, NULL, timeval_set(lp_keepalive(), 0), "keepalive", keepalive_fn, - NULL))) { + sconn))) { DEBUG(0, ("Could not add keepalive event\n")); exit(1); } - if (!(event_add_idle(smbd_event_context(), NULL, + if (!(event_add_idle(ev_ctx, NULL, timeval_set(IDLE_CLOSED_TIMEOUT, 0), "deadtime", deadtime_fn, sconn))) { DEBUG(0, ("Could not add deadtime event\n")); exit(1); } - if (!(event_add_idle(smbd_event_context(), NULL, + if (!(event_add_idle(ev_ctx, NULL, timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0), "housekeeping", housekeeping_fn, sconn))) { DEBUG(0, ("Could not add housekeeping event\n")); @@ -3124,7 +3207,7 @@ void smbd_process(struct smbd_server_connection *sconn) exit_server("init_dptrs() failed"); } - sconn->smb1.fde = event_add_fd(smbd_event_context(), + sconn->smb1.fde = event_add_fd(ev_ctx, sconn, sconn->sock, EVENT_FD_READ, @@ -3143,7 +3226,7 @@ void smbd_process(struct smbd_server_connection *sconn) errno = 0; - status = smbd_server_connection_loop_once(sconn); + status = smbd_server_connection_loop_once(ev_ctx, sconn); if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY) && !NT_STATUS_IS_OK(status)) { DEBUG(3, ("smbd_server_connection_loop_once failed: %s," @@ -3159,7 +3242,7 @@ void smbd_process(struct smbd_server_connection *sconn) bool req_is_in_chain(struct smb_request *req) { - if (req->vwv != (uint16_t *)(req->inbuf+smb_vwv)) { + if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) { /* * We're right now handling a subsequent request, so we must * be in a chain