smbd: Remove sconn->using_smb2
[samba.git] / source3 / smbd / filename.c
index e7f5fe29b024b582678329a511703cccf5fdad78..7fafc1718c734f6cfaeaace9fd775e8d0ceccb05 100644 (file)
@@ -43,7 +43,7 @@ uint32_t ucf_flags_from_smb_request(struct smb_request *req)
        if (req->posix_pathnames) {
                ucf_flags |= UCF_POSIX_PATHNAMES;
 
-               if (!req->sconn->using_smb2) {
+               if (!conn_using_smb2(req->sconn)) {
                        ucf_flags |= UCF_LCOMP_LNK_OK;
                }
        }
@@ -659,44 +659,46 @@ static char *symlink_target_path(
        return ret;
 }
 
-static NTSTATUS safe_symlink_target_path(
-       TALLOC_CTX *mem_ctx,
-       const char *connectpath,
-       const char *name_in,
-       const char *substitute,
-       size_t unparsed,
-       char **_name_out)
+NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
+                                 const char *connectpath,
+                                 const char *dir,
+                                 const char *target,
+                                 size_t unparsed,
+                                 char **_relative)
 {
-       char *target = NULL;
        char *abs_target = NULL;
        char *abs_target_canon = NULL;
        const char *relative = NULL;
-       char *name_out = NULL;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
        bool in_share;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
-       if (target == NULL) {
-               goto fail;
-       }
-
-       DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
-                 name_in,
-                 substitute,
-                 unparsed,
-                 target);
+       DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n",
+                 connectpath, target, unparsed);
 
        if (target[0] == '/') {
-               abs_target = target;
+               abs_target = talloc_strdup(mem_ctx, target);
+       } else if (dir == NULL) {
+               abs_target = talloc_asprintf(mem_ctx,
+                                            "%s/%s",
+                                            connectpath,
+                                            target);
+       } else if (dir[0] == '/') {
+               abs_target = talloc_asprintf(mem_ctx,
+                                            "%s/%s",
+                                            dir,
+                                            target);
        } else {
-               abs_target = talloc_asprintf(
-                       target, "%s/%s", connectpath, target);
-               if (abs_target == NULL) {
-                       goto fail;
-               }
+               abs_target = talloc_asprintf(mem_ctx,
+                                            "%s/%s/%s",
+                                            connectpath,
+                                            dir,
+                                            target);
+       }
+       if (abs_target == NULL) {
+               goto fail;
        }
 
-       abs_target_canon = canonicalize_absolute_path(target, abs_target);
+       abs_target_canon = canonicalize_absolute_path(abs_target, abs_target);
        if (abs_target_canon == NULL) {
                goto fail;
        }
@@ -712,15 +714,14 @@ static NTSTATUS safe_symlink_target_path(
                goto fail;
        }
 
-       name_out = talloc_strdup(mem_ctx, relative);
-       if (name_out == NULL) {
+       *_relative = talloc_strdup(mem_ctx, relative);
+       if (*_relative == NULL) {
                goto fail;
        }
 
        status = NT_STATUS_OK;
-       *_name_out = name_out;
 fail:
-       TALLOC_FREE(target);
+       TALLOC_FREE(abs_target);
        return status;
 }
 
@@ -736,12 +737,12 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
        NTTIME twrp,
        struct files_struct **_dirfsp,
        struct smb_filename **_smb_fname,
-       struct open_symlink_err **_symlink_err)
+       struct reparse_data_buffer **_symlink_err)
 {
        struct smb_filename *smb_dirname = NULL;
        struct smb_filename *smb_fname_rel = NULL;
        struct smb_filename *smb_fname = NULL;
-       struct open_symlink_err *symlink_err = NULL;
+       struct reparse_data_buffer *symlink_err = NULL;
        const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
        char *dirname = NULL;
        const char *fname_rel = NULL;
@@ -845,6 +846,9 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
                                                      &symlink_err);
 
                if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+                       struct symlink_reparse_struct
+                               *lnk = &symlink_err->parsed.lnk;
+                       size_t unparsed = lnk->unparsed_path_length;
                        size_t name_in_len, dirname_len;
 
                        name_in_len = strlen(name_in);
@@ -852,7 +856,14 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
 
                        SMB_ASSERT(name_in_len >= dirname_len);
 
-                       symlink_err->unparsed += (name_in_len - dirname_len);
+                       unparsed += (name_in_len - dirname_len);
+
+                       if (unparsed > UINT16_MAX) {
+                               status = NT_STATUS_BUFFER_OVERFLOW;
+                               goto fail;
+                       }
+
+                       lnk->unparsed_path_length = unparsed;
                        *_symlink_err = symlink_err;
 
                        goto fail;
@@ -949,10 +960,10 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
                 * Upper layers might need the link target. Here we
                 * still have the relname around, get the symlink err.
                 */
-               status = create_open_symlink_err(mem_ctx,
-                                                smb_dirname->fsp,
-                                                smb_fname_rel,
-                                                &symlink_err);
+               status = read_symlink_reparse(mem_ctx,
+                                             smb_dirname->fsp,
+                                             smb_fname_rel,
+                                             &symlink_err);
                if (!NT_STATUS_IS_OK(status)) {
                        DBG_DEBUG("Could not read symlink for %s: %s\n",
                                  smb_fname_str_dbg(
@@ -1125,10 +1136,11 @@ NTSTATUS filename_convert_dirfsp(
        struct files_struct **_dirfsp,
        struct smb_filename **_smb_fname)
 {
-       struct open_symlink_err *symlink_err = NULL;
+       struct reparse_data_buffer *symlink_err = NULL;
+       struct symlink_reparse_struct *lnk = NULL;
        NTSTATUS status;
-       char *substitute = NULL;
        char *target = NULL;
+       char *safe_target = NULL;
        size_t symlink_redirects = 0;
 
 next:
@@ -1160,13 +1172,14 @@ next:
        if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
                return status;
        }
+       lnk = &symlink_err->parsed.lnk;
 
        /*
         * If we're on an MSDFS share, see if this is
         * an MSDFS link.
         */
        if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
-           strnequal(symlink_err->reparse->substitute_name, "msdfs:", 6))
+           strnequal(lnk->substitute_name, "msdfs:", 6))
        {
                TALLOC_FREE(*_smb_fname);
                TALLOC_FREE(symlink_err);
@@ -1174,7 +1187,7 @@ next:
        }
 
        if (!lp_follow_symlinks(SNUM(conn))) {
-               status = (symlink_err->unparsed == 0)
+               status = (lnk->unparsed_path_length == 0)
                                 ? NT_STATUS_OBJECT_NAME_NOT_FOUND
                                 : NT_STATUS_OBJECT_PATH_NOT_FOUND;
                TALLOC_FREE(symlink_err);
@@ -1193,19 +1206,25 @@ next:
         * resolve all symlinks locally.
         */
 
-       substitute = symlink_err->reparse->substitute_name;
+       target = symlink_target_path(mem_ctx,
+                                    name_in,
+                                    lnk->substitute_name,
+                                    lnk->unparsed_path_length);
+       if (target == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        status = safe_symlink_target_path(mem_ctx,
                                          conn->connectpath,
-                                         name_in,
-                                         substitute,
-                                         symlink_err->unparsed,
-                                         &target);
+                                         NULL,
+                                         target,
+                                         lnk->unparsed_path_length,
+                                         &safe_target);
        TALLOC_FREE(symlink_err);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       name_in = target;
+       name_in = safe_target;
 
        symlink_redirects += 1;