s3:smbd: Fix converity warning with _smb_setlen_large()
[metze/samba/wip.git] / source3 / smbd / process.c
index aa7f419a1b2a9e475cdd986e81205da762724b79..936b5351de7cf6b917677c8d618cca9085355841 100644 (file)
@@ -32,6 +32,7 @@
 #include "passdb.h"
 #include "auth.h"
 #include "messages.h"
+#include "lib/messages_ctdb.h"
 #include "smbprofile.h"
 #include "rpc_server/spoolss/srv_spoolss_nt.h"
 #include "libsmb/libsmb.h"
 #include "../libcli/security/dom_sid.h"
 #include "../libcli/security/security_token.h"
 #include "lib/id_cache.h"
-#include "lib/sys_rw_data.h"
-#include "serverid.h"
+#include "lib/util/sys_rw_data.h"
 #include "system/threads.h"
+#include "lib/pthreadpool/pthreadpool_tevent.h"
+#include "util_event.h"
 
 /* Internal message queue for deferred opens. */
 struct pending_message_list {
@@ -162,15 +164,9 @@ static bool smbd_unlock_socket_internal(struct smbXsrv_connection *xconn)
 
 #ifdef HAVE_ROBUST_MUTEXES
        if (xconn->smb1.echo_handler.socket_mutex != NULL) {
-               int ret = EINTR;
-
-               while (ret == EINTR) {
-                       ret = pthread_mutex_unlock(
-                               xconn->smb1.echo_handler.socket_mutex);
-                       if (ret == 0) {
-                               break;
-                       }
-               }
+               int ret;
+               ret = pthread_mutex_unlock(
+                       xconn->smb1.echo_handler.socket_mutex);
                if (ret != 0) {
                        DEBUG(1, ("pthread_mutex_unlock failed: %s\n",
                                  strerror(ret)));
@@ -278,10 +274,10 @@ out:
  Setup the word count and byte count for a smb message.
 ********************************************************************/
 
-int srv_set_message(char *buf,
-                        int num_words,
-                        int num_bytes,
-                        bool zero)
+size_t srv_set_message(char *buf,
+                      size_t num_words,
+                      size_t num_bytes,
+                      bool zero)
 {
        if (zero && (num_words || num_bytes)) {
                memset(buf + smb_size,'\0',num_words*2 + num_bytes);
@@ -584,7 +580,7 @@ static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx,
 static bool init_smb_request(struct smb_request *req,
                             struct smbd_server_connection *sconn,
                             struct smbXsrv_connection *xconn,
-                            const uint8 *inbuf,
+                            const uint8_t *inbuf,
                             size_t unread_bytes, bool encrypted,
                             uint32_t seqnum)
 {
@@ -629,6 +625,7 @@ static bool init_smb_request(struct smb_request *req,
        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. */
@@ -749,8 +746,7 @@ static bool push_queued_message(struct smb_request *req,
        }
 #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));
@@ -1382,7 +1378,7 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req,
        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, req->inbuf, &outbuf, num_words,
@@ -1430,6 +1426,54 @@ static void smb_dump(const char *name, int type, const char *data)
        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.
@@ -1443,7 +1487,7 @@ static void smb_dump(const char *name, int type, const char *data)
  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;
@@ -1646,6 +1690,35 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req)
                }
        }
 
+       /*
+        * 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;
 }
@@ -1666,7 +1739,7 @@ static void construct_reply(struct smbXsrv_connection *xconn,
                smb_panic("could not allocate smb_request");
        }
 
-       if (!init_smb_request(req, sconn, xconn, (uint8 *)inbuf, unread_bytes,
+       if (!init_smb_request(req, sconn, xconn, (uint8_t *)inbuf, unread_bytes,
                              encrypted, seqnum)) {
                exit_server_cleanly("Invalid SMB request");
        }
@@ -1707,7 +1780,7 @@ static void construct_reply_chain(struct smbXsrv_connection *xconn,
        unsigned num_reqs;
        bool ok;
 
-       ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, xconn, encrypted,
+       ok = smb1_parse_chain(xconn, (uint8_t *)inbuf, xconn, encrypted,
                              seqnum, &reqs, &num_reqs);
        if (!ok) {
                char errbuf[smb_size];
@@ -1777,12 +1850,13 @@ void smb_request_done(struct smb_request *req)
 
                next->vuid = SVAL(req->outbuf, smb_uid);
                next->tid  = SVAL(req->outbuf, smb_tid);
-               status = smb1srv_tcon_lookup(req->xconn, req->tid,
+               status = smb1srv_tcon_lookup(req->xconn, next->tid,
                                             now, &tcon);
+
                if (NT_STATUS_IS_OK(status)) {
-                       req->conn = tcon->compat;
+                       next->conn = tcon->compat;
                } else {
-                       req->conn = NULL;
+                       next->conn = NULL;
                }
                next->chain_fsp = req->chain_fsp;
                next->inbuf = req->inbuf;
@@ -1893,9 +1967,10 @@ static void process_smb(struct smbXsrv_connection *xconn,
                if (smbd_is_smb2_header(inbuf, nread)) {
                        const uint8_t *inpdu = inbuf + NBT_HDR_SIZE;
                        size_t pdulen = nread - NBT_HDR_SIZE;
-                       smbd_smb2_first_negprot(xconn, inpdu, pdulen);
+                       smbd_smb2_process_negprot(xconn, 0, inpdu, pdulen);
                        return;
-               } else if (nread >= smb_size && valid_smb_header(inbuf)
+               }
+               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. */
@@ -1969,12 +2044,12 @@ const char *smb_fn_name(int type)
  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;
 }
@@ -2000,6 +2075,7 @@ static void construct_reply_common(uint8_t cmd, const uint8_t *inbuf,
 
        SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
        SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
+       SSVAL(outbuf,smb_pidhigh,SVAL(inbuf,smb_pidhigh));
        SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
        SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
 }
@@ -2616,18 +2692,32 @@ static void smbd_release_ip_immediate(struct tevent_context *ctx,
 /****************************************************************************
 received when we should release a specific IP
 ****************************************************************************/
-static bool release_ip(const char *ip, void *priv)
+static int release_ip(struct tevent_context *ev,
+                     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 false;
+               return 0;
        }
 
        if (strncmp("::ffff:", addr, 7) == 0) {
@@ -2668,10 +2758,10 @@ static bool release_ip(const char *ip, void *priv)
                 * Make sure we don't get any io on the connection.
                 */
                xconn->transport.status = NT_STATUS_ADDRESS_CLOSED;
-               return true;
+               return EADDRNOTAVAIL;
        }
 
-       return false;
+       return 0;
 }
 
 static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
@@ -2680,8 +2770,9 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
 {
        struct smbd_release_ip_state *state;
        struct ctdbd_connection *cconn;
+       int ret;
 
-       cconn = messaging_ctdbd_connection();
+       cconn = messaging_ctdb_connection();
        if (cconn == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2699,7 +2790,11 @@ static NTSTATUS smbd_register_ips(struct smbXsrv_connection *xconn,
                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 void msg_kill_client_ip(struct messaging_context *msg_ctx,
@@ -2711,7 +2806,7 @@ static void msg_kill_client_ip(struct messaging_context *msg_ctx,
        const char *ip = (char *) data->data;
        char *client_ip;
 
-       DEBUG(10, ("Got kill request for client IP %s\n", ip));
+       DBG_DEBUG("Got kill request for client IP %s\n", ip);
 
        client_ip = tsocket_address_inet_addr_string(sconn->remote_address,
                                                     talloc_tos());
@@ -2720,8 +2815,8 @@ static void msg_kill_client_ip(struct messaging_context *msg_ctx,
        }
 
        if (strequal(ip, client_ip)) {
-               DEBUG(1, ("Got kill client message for %s - "
-                         "exiting immediately\n", ip));
+               DBG_WARNING("Got kill client message for %s - "
+                           "exiting immediately\n", ip);
                exit_server_cleanly("Forced disconnect for client");
        }
 
@@ -2846,7 +2941,7 @@ static struct tevent_req *smbd_echo_read_send(
        state->ev = ev;
        state->xconn = xconn;
 
-       subreq = wait_for_read_send(state, ev, xconn->transport.sock);
+       subreq = wait_for_read_send(state, ev, xconn->transport.sock, false);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -2921,7 +3016,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                }
 
                subreq = wait_for_read_send(state, state->ev,
-                                           xconn->transport.sock);
+                                           xconn->transport.sock, false);
                if (tevent_req_nomem(subreq, req)) {
                        return;
                }
@@ -3128,9 +3223,9 @@ static void smbd_echo_loop(struct smbXsrv_connection *xconn,
        }
        state->xconn = xconn;
        state->parent_pipe = parent_pipe;
-       state->ev = s3_tevent_context_init(state);
+       state->ev = samba_tevent_context_init(state);
        if (state->ev == NULL) {
-               DEBUG(1, ("tevent_context_init failed\n"));
+               DEBUG(1, ("samba_tevent_context_init failed\n"));
                TALLOC_FREE(state);
                return;
        }
@@ -3306,12 +3401,14 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn)
                close(listener_pipe[0]);
                set_blocking(listener_pipe[1], false);
 
-               status = smbd_reinit_after_fork(xconn->msg_ctx, xconn->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);
                }
+               initialize_password_db(true, xconn->ev_ctx);
                smbd_echo_loop(xconn, listener_pipe[1]);
                exit(0);
        }
@@ -3464,36 +3561,45 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
 {
        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;
 }
 
@@ -3767,7 +3873,7 @@ NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
        }
 
        /* for now we only have one connection */
-       DLIST_ADD_END(client->connections, xconn, NULL);
+       DLIST_ADD_END(client->connections, xconn);
        xconn->client = client;
        talloc_steal(client, xconn);
 
@@ -3796,10 +3902,14 @@ void smbd_process(struct tevent_context *ev_ctx,
        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;
 
-       client = talloc_zero(ev_ctx, struct smbXsrv_client);
-       if (client == NULL) {
-               DEBUG(0,("talloc_zero(struct smbXsrv_client)\n"));
+       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");
        }
 
@@ -3808,9 +3918,6 @@ void smbd_process(struct tevent_context *ev_ctx,
         */
        global_smbXsrv_client = client;
 
-       client->ev_ctx = ev_ctx;
-       client->msg_ctx = msg_ctx;
-
        sconn = talloc_zero(client, struct smbd_server_connection);
        if (sconn == NULL) {
                exit_server("failed to create smbd_server_connection");
@@ -3822,6 +3929,12 @@ void smbd_process(struct tevent_context *ev_ctx,
        sconn->ev_ctx = ev_ctx;
        sconn->msg_ctx = msg_ctx;
 
+       ret = pthreadpool_tevent_init(sconn, lp_aio_max_threads(),
+                                     &sconn->pool);
+       if (ret != 0) {
+               exit_server("pthreadpool_tevent_init() failed.");
+       }
+
        if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
                /*
                 * We're not making the decision here,
@@ -3836,14 +3949,6 @@ void smbd_process(struct tevent_context *ev_ctx,
        if (!interactive) {
                smbd_setup_sig_term_handler(sconn);
                smbd_setup_sig_hup_handler(sconn);
-
-               if (!serverid_register(messaging_server_id(msg_ctx),
-                                      FLAG_MSG_GENERAL|FLAG_MSG_SMBD
-                                      |FLAG_MSG_DBWRAP
-                                      |FLAG_MSG_PRINT_GENERAL)) {
-                       exit_server_cleanly("Could not register myself in "
-                                           "serverid.tdb");
-               }
        }
 
        status = smbd_add_connection(client, sock_fd, &xconn);
@@ -3911,7 +4016,7 @@ void smbd_process(struct tevent_context *ev_ctx,
                           locaddr);
 
        if (lp_preload_modules()) {
-               smb_load_modules(lp_preload_modules());
+               smb_load_all_modules_absoute_path(lp_preload_modules());
        }
 
        smb_perfcount_init();
@@ -3920,17 +4025,22 @@ void smbd_process(struct tevent_context *ev_ctx,
                exit_server("Could not open account policy tdb.\n");
        }
 
-       if (*lp_root_directory(talloc_tos())) {
-               if (chroot(lp_root_directory(talloc_tos())) != 0) {
-                       DEBUG(0,("Failed to change root to %s\n",
-                                lp_root_directory(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_root_directory(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_root_directory(talloc_tos())));
+               DBG_WARNING("Changed root to %s\n", chroot_dir);
+
+               TALLOC_FREE(chroot_dir);
        }
 
        if (!file_init(sconn)) {