s3-auth: Remove security=share (depricated since 3.6).
[kai/samba.git] / source3 / smbd / smb2_tcon.c
index 084ded95a4b40a87729efe92d465721b3c99e1ee..56c42889b6b10ef960bd3ec00c8f8956e0447e04 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
+#include "../libcli/security/security.h"
+#include "auth.h"
+#include "lib/param/loadparm.h"
 
 static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
                                       const char *in_path,
@@ -36,36 +40,29 @@ NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
        int i = req->current_idx;
        uint8_t *outhdr;
        DATA_BLOB outbody;
-       size_t expected_body_size = 0x09;
-       size_t body_size;
        uint16_t in_path_offset;
        uint16_t in_path_length;
        DATA_BLOB in_path_buffer;
        char *in_path_string;
        size_t in_path_string_size;
-       uint8_t out_share_type;
-       uint32_t out_share_flags;
-       uint32_t out_capabilities;
-       uint32_t out_maximal_access;
-       uint32_t out_tree_id;
+       uint8_t out_share_type = 0;
+       uint32_t out_share_flags = 0;
+       uint32_t out_capabilities = 0;
+       uint32_t out_maximal_access = 0;
+       uint32_t out_tree_id = 0;
        NTSTATUS status;
        bool ok;
 
-       if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+       status = smbd_smb2_request_verify_sizes(req, 0x09);
+       if (!NT_STATUS_IS_OK(status)) {
+               return smbd_smb2_request_error(req, status);
        }
-
        inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
 
-       body_size = SVAL(inbody, 0x00);
-       if (body_size != expected_body_size) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
-       }
-
        in_path_offset = SVAL(inbody, 0x04);
        in_path_length = SVAL(inbody, 0x06);
 
-       if (in_path_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
+       if (in_path_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
@@ -80,11 +77,19 @@ NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
                                   in_path_buffer.data,
                                   in_path_buffer.length,
                                   &in_path_string,
-                                  &in_path_string_size, false);
+                                  &in_path_string_size);
        if (!ok) {
                return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
        }
 
+       if (in_path_buffer.length == 0) {
+               in_path_string_size = 0;
+       }
+
+       if (strlen(in_path_string) != in_path_string_size) {
+               return smbd_smb2_request_error(req, NT_STATUS_BAD_NETWORK_NAME);
+       }
+
        status = smbd_smb2_tree_connect(req, in_path_string,
                                        &out_share_type,
                                        &out_share_flags,
@@ -126,6 +131,8 @@ static int smbd_smb2_tcon_destructor(struct smbd_smb2_tcon *tcon)
 
        idr_remove(tcon->session->tcons.idtree, tcon->tid);
        DLIST_REMOVE(tcon->session->tcons.list, tcon);
+       SMB_ASSERT(tcon->session->sconn->num_tcons_open > 0);
+       tcon->session->sconn->num_tcons_open--;
 
        if (tcon->compat_conn) {
                set_current_service(tcon->compat_conn, 0, true);
@@ -148,10 +155,11 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
                                       uint32_t *out_tree_id)
 {
        const char *share = in_path;
-       fstring service;
+       char *service = NULL;
        int snum = -1;
        struct smbd_smb2_tcon *tcon;
        connection_struct *compat_conn = NULL;
+       user_struct *compat_vuser = req->session->compat_vuser;
        int id;
        NTSTATUS status;
 
@@ -165,19 +173,41 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
        DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n",
                  in_path, share));
 
-       fstrcpy(service, share);
+       service = talloc_strdup(talloc_tos(), share);
+       if(!service) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        strlower_m(service);
 
-       snum = find_service(service);
+       /* TODO: do more things... */
+       if (strequal(service,HOMES_NAME)) {
+               if (compat_vuser->homes_snum == -1) {
+                       DEBUG(2, ("[homes] share not available for "
+                               "user %s because it was not found "
+                               "or created at session setup "
+                               "time\n",
+                               compat_vuser->session_info->unix_info->unix_name));
+                       return NT_STATUS_BAD_NETWORK_NAME;
+               }
+               snum = compat_vuser->homes_snum;
+       } else if ((compat_vuser->homes_snum != -1)
+                   && strequal(service,
+                       lp_servicename(compat_vuser->homes_snum))) {
+               snum = compat_vuser->homes_snum;
+       } else {
+               snum = find_service(talloc_tos(), service, &service);
+               if (!service) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
        if (snum < 0) {
                DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n",
                         service));
                return NT_STATUS_BAD_NETWORK_NAME;
        }
 
-       /* TODO: do more things... */
-
        /* create a new tcon as child of the session */
        tcon = talloc_zero(req->session, struct smbd_smb2_tcon);
        if (tcon == NULL) {
@@ -196,111 +226,72 @@ static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
        DLIST_ADD_END(req->session->tcons.list, tcon,
                      struct smbd_smb2_tcon *);
        tcon->session = req->session;
+       tcon->session->sconn->num_tcons_open++;
        talloc_set_destructor(tcon, smbd_smb2_tcon_destructor);
 
-       compat_conn = make_connection_snum(req->sconn,
-                                       snum, req->session->compat_vuser,
-                                       data_blob_null, "???",
+       compat_conn = make_connection_smb2(req->sconn,
+                                       tcon,
+                                       req->session->compat_vuser,
+                                       "???",
                                        &status);
        if (compat_conn == NULL) {
                TALLOC_FREE(tcon);
                return status;
        }
        tcon->compat_conn = talloc_move(tcon, &compat_conn);
-       tcon->compat_conn->cnum = tcon->tid;
 
        if (IS_PRINT(tcon->compat_conn)) {
-               *out_share_type = 0x03;
+               *out_share_type = SMB2_SHARE_TYPE_PRINT;
        } else if (IS_IPC(tcon->compat_conn)) {
-               *out_share_type = 0x02;
+               *out_share_type = SMB2_SHARE_TYPE_PIPE;
        } else {
-               *out_share_type = 0x01;
+               *out_share_type = SMB2_SHARE_TYPE_DISK;
        }
-       *out_share_flags = SMB2_SHAREFLAG_ALL;
-       *out_capabilities = 0;
-       *out_maximal_access = FILE_GENERIC_ALL;
 
-       *out_tree_id = tcon->tid;
-       return NT_STATUS_OK;
-}
+       *out_share_flags = 0;
 
-NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
-{
-       const uint8_t *inhdr;
-       const uint8_t *outhdr;
-       int i = req->current_idx;
-       uint32_t in_tid;
-       void *p;
-       struct smbd_smb2_tcon *tcon;
-       bool chained_fixup = false;
-
-       inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
-
-       in_tid = IVAL(inhdr, SMB2_HDR_TID);
-
-       if (in_tid == (0xFFFFFFFF)) {
-               if (req->async) {
-                       /*
-                        * async request - fill in tid from
-                        * already setup out.vector[].iov_base.
-                        */
-                       outhdr = (const uint8_t *)req->out.vector[i].iov_base;
-                       in_tid = IVAL(outhdr, SMB2_HDR_TID);
-               } else if (i > 2) {
-                       /*
-                        * Chained request - fill in tid from
-                        * the previous request out.vector[].iov_base.
-                        */
-                       outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
-                       in_tid = IVAL(outhdr, SMB2_HDR_TID);
-                       chained_fixup = true;
-               }
-       }
-
-       /* lookup an existing session */
-       p = idr_find(req->session->tcons.idtree, in_tid);
-       if (p == NULL) {
-               return NT_STATUS_NETWORK_NAME_DELETED;
+       if (lp_msdfs_root(SNUM(tcon->compat_conn)) && lp_host_msdfs()) {
+               *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT);
+               *out_capabilities = SMB2_SHARE_CAP_DFS;
+       } else {
+               *out_capabilities = 0;
        }
-       tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
 
-       if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
-               return NT_STATUS_ACCESS_DENIED;
+       switch(lp_csc_policy(SNUM(tcon->compat_conn))) {
+       case CSC_POLICY_MANUAL:
+               break;
+       case CSC_POLICY_DOCUMENTS:
+               *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING;
+               break;
+       case CSC_POLICY_PROGRAMS:
+               *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING;
+               break;
+       case CSC_POLICY_DISABLE:
+               *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING;
+               break;
+       default:
+               break;
        }
 
-       /* should we pass FLAG_CASELESS_PATHNAMES here? */
-       if (!set_current_service(tcon->compat_conn, 0, true)) {
-               return NT_STATUS_ACCESS_DENIED;
+       if (lp_hideunreadable(SNUM(tcon->compat_conn)) ||
+           lp_hideunwriteable_files(SNUM(tcon->compat_conn))) {
+               *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM;
        }
 
-       req->tcon = tcon;
-
-       if (chained_fixup) {
-               /* Fix up our own outhdr. */
-               outhdr = (const uint8_t *)req->out.vector[i].iov_base;
-               SIVAL(outhdr, SMB2_HDR_TID, in_tid);
-       }
+       *out_maximal_access = tcon->compat_conn->share_access;
 
+       *out_tree_id = tcon->tid;
        return NT_STATUS_OK;
 }
 
 NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req)
 {
-       const uint8_t *inbody;
-       int i = req->current_idx;
+       NTSTATUS status;
        DATA_BLOB outbody;
-       size_t expected_body_size = 0x04;
-       size_t body_size;
-
-       if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
-       }
 
-       inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
-
-       body_size = SVAL(inbody, 0x00);
-       if (body_size != expected_body_size) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+       status = smbd_smb2_request_verify_sizes(req, 0x04);
+       if (!NT_STATUS_IS_OK(status)) {
+               return smbd_smb2_request_error(req, status);
        }
 
        /*