s3: smbd: Remove one more use of lp_posix_pathnames().
[obnox/samba/samba-obnox.git] / source3 / smbd / dir.c
index aa81a38b362ea526c1ccf7fe4e56716b99d111f2..380591521068b088ee0477083cef2ba81f9d3aea 100644 (file)
@@ -64,12 +64,12 @@ struct smb_Dir {
 struct dptr_struct {
        struct dptr_struct *next, *prev;
        int dnum;
-       uint16 spid;
+       uint16_t spid;
        struct connection_struct *conn;
        struct smb_Dir *dir_hnd;
        bool expect_close;
        char *wcard;
-       uint32 attr;
+       uint32_t attr;
        char *path;
        bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
        bool did_stat; /* Optimisation for non-wcard searches. */
@@ -81,7 +81,7 @@ struct dptr_struct {
 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        files_struct *fsp,
                        const char *mask,
-                       uint32 attr);
+                       uint32_t attr);
 
 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset);
 
@@ -209,7 +209,7 @@ const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
  Get the dir attrib for a dir index.
 ****************************************************************************/
 
-uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
+uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
 {
        struct dptr_struct *dptr = dptr_get(sconn, key, false);
        if (dptr)
@@ -334,7 +334,7 @@ void dptr_idlecnum(connection_struct *conn)
 ****************************************************************************/
 
 void dptr_closepath(struct smbd_server_connection *sconn,
-                   char *path,uint16 spid)
+                   char *path,uint16_t spid)
 {
        struct dptr_struct *dptr, *next;
        for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
@@ -444,8 +444,8 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn,
 NTSTATUS dptr_create(connection_struct *conn,
                struct smb_request *req,
                files_struct *fsp,
-               const char *path, bool old_handle, bool expect_close,uint16 spid,
-               const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
+               const char *path, bool old_handle, bool expect_close,uint16_t spid,
+               const char *wcard, bool wcard_has_wild, uint32_t attr, struct dptr_struct **dptr_ret)
 {
        struct smbd_server_connection *sconn = conn->sconn;
        struct dptr_struct *dptr = NULL;
@@ -485,7 +485,7 @@ NTSTATUS dptr_create(connection_struct *conn,
                if (smb_dname == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
-               if (lp_posix_pathnames()) {
+               if (req != NULL && req->posix_pathnames) {
                        ret = SMB_VFS_LSTAT(conn, smb_dname);
                } else {
                        ret = SMB_VFS_STAT(conn, smb_dname);
@@ -545,7 +545,8 @@ NTSTATUS dptr_create(connection_struct *conn,
                TALLOC_FREE(dir_hnd);
                return NT_STATUS_NO_MEMORY;
        }
-       if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
+       if ((req != NULL && req->posix_pathnames) ||
+                       (wcard[0] == '.' && wcard[1] == 0)) {
                dptr->has_wild = True;
        } else {
                dptr->has_wild = wcard_has_wild;
@@ -1068,6 +1069,7 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
        connection_struct *conn = dirptr->conn;
        size_t slashlen;
        size_t pathlen;
+       bool dirptr_path_is_dot = ISDOT(dirptr->path);
 
        *_smb_fname = NULL;
        *_mode = 0;
@@ -1132,10 +1134,18 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
                        return false;
                }
 
-               memcpy(pathreal, dirptr->path, pathlen);
-               pathreal[pathlen] = '/';
-               memcpy(pathreal + slashlen + pathlen, dname,
-                      talloc_get_size(dname));
+               /*
+                * We don't want to pass ./xxx to modules below us so don't
+                * add the path if it is just . by itself.
+                */
+               if (dirptr_path_is_dot) {
+                       memcpy(pathreal, dname, talloc_get_size(dname));
+               } else {
+                       memcpy(pathreal, dirptr->path, pathlen);
+                       pathreal[pathlen] = '/';
+                       memcpy(pathreal + slashlen + pathlen, dname,
+                              talloc_get_size(dname));
+               }
 
                /* Create smb_fname with NULL stream_name. */
                smb_fname = (struct smb_filename) {
@@ -1221,7 +1231,7 @@ static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
                size_t ret_len = 0;
                size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
                uint8_t *tmp = talloc_array(talloc_tos(),
-                                       uint8,
+                                       uint8_t,
                                        len);
 
                status = srvstr_push(NULL,
@@ -1334,6 +1344,15 @@ bool get_dir_entry(TALLOC_CTX *ctx,
 static bool user_can_read_file(connection_struct *conn,
                               struct smb_filename *smb_fname)
 {
+       NTSTATUS status;
+       uint32_t rejected_share_access = 0;
+       uint32_t rejected_mask = 0;
+       struct security_descriptor *sd = NULL;
+       uint32_t access_mask = FILE_READ_DATA|
+                               FILE_READ_EA|
+                               FILE_READ_ATTRIBUTES|
+                               SEC_STD_READ_CONTROL;
+
        /*
         * Never hide files from the root user.
         * We use (uid_t)0 here not sec_initial_uid()
@@ -1344,10 +1363,59 @@ static bool user_can_read_file(connection_struct *conn,
                return True;
        }
 
-       return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
-                               smb_fname,
+       /*
+        * We can't directly use smbd_check_access_rights()
+        * here, as this implicitly grants FILE_READ_ATTRIBUTES
+        * which the Windows access-based-enumeration code
+        * explicitly checks for on the file security descriptor.
+        * See bug:
+        *
+        * https://bugzilla.samba.org/show_bug.cgi?id=10252
+        *
+        * and the smb2.acl2.ACCESSBASED test for details.
+        */
+
+       rejected_share_access = access_mask & ~(conn->share_access);
+       if (rejected_share_access) {
+               DEBUG(10, ("rejected share access 0x%x "
+                       "on %s (0x%x)\n",
+                       (unsigned int)access_mask,
+                       smb_fname_str_dbg(smb_fname),
+                       (unsigned int)rejected_share_access ));
+               return false;
+        }
+
+       status = SMB_VFS_GET_NT_ACL(conn,
+                       smb_fname->base_name,
+                       (SECINFO_OWNER |
+                        SECINFO_GROUP |
+                        SECINFO_DACL),
+                       talloc_tos(),
+                       &sd);
+
+       if (!NT_STATUS_IS_OK(status)) {
+                DEBUG(10, ("Could not get acl "
+                       "on %s: %s\n",
+                       smb_fname_str_dbg(smb_fname),
+                       nt_errstr(status)));
+               return false;
+        }
+
+       status = se_file_access_check(sd,
+                               get_current_nttok(conn),
                                false,
-                               FILE_READ_DATA));
+                               access_mask,
+                               &rejected_mask);
+
+        TALLOC_FREE(sd);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+               DEBUG(10,("rejected bits 0x%x read access for %s\n",
+                       (unsigned int)rejected_mask,
+                       smb_fname_str_dbg(smb_fname) ));
+               return false;
+        }
+       return true;
 }
 
 /*******************************************************************
@@ -1456,9 +1524,8 @@ bool is_visible_file(connection_struct *conn, const char *dir_path,
                        if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
                                ret = true;
                                goto out;
-                       } else {
-                               *pst = smb_fname_base->st;
                        }
+                       *pst = smb_fname_base->st;
                }
 
                /* Honour _hide unreadable_ option */
@@ -1524,7 +1591,7 @@ static int smb_Dir_destructor(struct smb_Dir *dirp)
 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        const char *name,
                        const char *mask,
-                       uint32 attr)
+                       uint32_t attr)
 {
        struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
        struct smbd_server_connection *sconn = conn->sconn;
@@ -1568,7 +1635,7 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        files_struct *fsp,
                        const char *mask,
-                       uint32 attr)
+                       uint32_t attr)
 {
        struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
        struct smbd_server_connection *sconn = conn->sconn;
@@ -1652,14 +1719,16 @@ const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
                dirp->file_number++;
                *ptalloced = NULL;
                return n;
-       } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
+       }
+
+       if (*poffset == END_OF_DIRECTORY_OFFSET) {
                *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
                return NULL;
-       } else {
-               /* A real offset, seek to it. */
-               SeekDir(dirp, *poffset);
        }
 
+       /* A real offset, seek to it. */
+       SeekDir(dirp, *poffset);
+
        while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
                /* Ignore . and .. - we've already returned them. */
                if (*n == '.') {
@@ -1844,14 +1913,14 @@ static int files_below_forall_fn(struct file_id fid,
                return 0;
        }
 
-       if (memcmp(state->dirpath, fullpath, len) != 0) {
+       if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
                /*
                 * Not a parent
                 */
                return 0;
        }
 
-       return state->fn(fid, data, private_data);
+       return state->fn(fid, data, state->private_data);
 }
 
 static int files_below_forall(connection_struct *conn,
@@ -1861,7 +1930,10 @@ static int files_below_forall(connection_struct *conn,
                                        void *private_data),
                              void *private_data)
 {
-       struct files_below_forall_state state = {};
+       struct files_below_forall_state state = {
+                       .fn = fn,
+                       .private_data = private_data,
+       };
        int ret;
        char tmpbuf[PATH_MAX];
        char *to_free;
@@ -1872,7 +1944,6 @@ static int files_below_forall(connection_struct *conn,
                                          &state.dirpath, &to_free);
        if (state.dirpath_len == -1) {
                return -1;
-
        }
 
        ret = share_mode_forall(files_below_forall_fn, &state);
@@ -1893,10 +1964,12 @@ static int have_file_open_below_fn(struct file_id fid,
        return 1;
 }
 
-static bool have_file_open_below(connection_struct *conn,
+bool have_file_open_below(connection_struct *conn,
                                 const struct smb_filename *name)
 {
-       struct have_file_open_below_state state = {};
+       struct have_file_open_below_state state = {
+               .found_one = false,
+       };
        int ret;
 
        if (!VALID_STAT(name->st)) {
@@ -1963,7 +2036,7 @@ NTSTATUS can_delete_directory_fsp(files_struct *fsp)
                return status;
        }
 
-       if (!lp_posix_pathnames() &&
+       if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
            lp_strict_rename(SNUM(conn)) &&
            have_file_open_below(fsp->conn, fsp->fsp_name))
        {