s3: smbd: Change canonicalize_ea_name() to take a const smb_filename * parameter...
[sfrench/samba-autobuild/.git] / source3 / smbd / trans2.c
index e518c7b48efb465b102f8d334874b2512bc3910d..2e10bbe79611a914b47848b5b07d2a8456dc0331 100644 (file)
@@ -54,6 +54,43 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
                                files_struct *fsp,
                                const SMB_STRUCT_STAT *psbuf);
 
+/****************************************************************************
+ Check if an open file handle or pathname is a symlink.
+****************************************************************************/
+
+static NTSTATUS refuse_symlink(connection_struct *conn,
+                       const files_struct *fsp,
+                       const char *name)
+{
+       SMB_STRUCT_STAT sbuf;
+       const SMB_STRUCT_STAT *pst = NULL;
+
+       if (fsp) {
+               pst = &fsp->fsp_name->st;
+       } else {
+               int ret = vfs_stat_smb_basename(conn,
+                               name,
+                               &sbuf);
+               if (ret == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+               pst = &sbuf;
+       }
+       if (S_ISLNK(pst->st_ex_mode)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_OK;
+}
+
+NTSTATUS check_access_fsp(const struct files_struct *fsp,
+                         uint32_t access_mask)
+{
+       if (!(fsp->access_mask & access_mask)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_OK;
+}
+
 /********************************************************************
  The canonical "check access" based on object handle or path function.
 ********************************************************************/
@@ -63,20 +100,16 @@ NTSTATUS check_access(connection_struct *conn,
                                const struct smb_filename *smb_fname,
                                uint32_t access_mask)
 {
+       NTSTATUS status;
+
        if (fsp) {
-               if (!(fsp->access_mask & access_mask)) {
-                       return NT_STATUS_ACCESS_DENIED;
-               }
+               status = check_access_fsp(fsp, access_mask);
        } else {
-               NTSTATUS status = smbd_check_access_rights(conn,
-                                       smb_fname,
-                                       false,
-                                       access_mask);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               status = smbd_check_access_rights(conn, smb_fname,
+                                                 false, access_mask);
        }
-       return NT_STATUS_OK;
+
+       return status;
 }
 
 /********************************************************************
@@ -209,12 +242,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
        char **names, **tmp;
        size_t num_names;
        ssize_t sizeret = -1;
+       NTSTATUS status;
+
+       if (pnames) {
+               *pnames = NULL;
+       }
+       *pnum_names = 0;
 
        if (!lp_ea_support(SNUM(conn))) {
-               if (pnames) {
-                       *pnames = NULL;
-               }
-               *pnum_names = 0;
+               return NT_STATUS_OK;
+       }
+
+       status = refuse_symlink(conn, fsp, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * Just return no EA's on a symlink.
+                */
                return NT_STATUS_OK;
        }
 
@@ -264,10 +307,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 
        if (sizeret == 0) {
                TALLOC_FREE(names);
-               if (pnames) {
-                       *pnames = NULL;
-               }
-               *pnum_names = 0;
                return NT_STATUS_OK;
        }
 
@@ -389,7 +428,7 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc
                          "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
                          (unsigned int)listp->ea.value.length));
 
-               DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, listp);
 
        }
 
@@ -591,12 +630,20 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp,
  Ensure the EA name is case insensitive by matching any existing EA name.
 ****************************************************************************/
 
-static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
+static void canonicalize_ea_name(connection_struct *conn,
+                       files_struct *fsp,
+                       const struct smb_filename *smb_fname,
+                       fstring unix_ea_name)
 {
        size_t total_ea_len;
        TALLOC_CTX *mem_ctx = talloc_tos();
        struct ea_list *ea_list;
-       NTSTATUS status = get_ea_list_from_file_path(mem_ctx, conn, fsp, fname, &total_ea_len, &ea_list);
+       NTSTATUS status = get_ea_list_from_file_path(mem_ctx,
+                                       conn,
+                                       fsp,
+                                       smb_fname->base_name,
+                                       &total_ea_len,
+                                       &ea_list);
        if (!NT_STATUS_IS_OK(status)) {
                return;
        }
@@ -619,12 +666,16 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                const struct smb_filename *smb_fname, struct ea_list *ea_list)
 {
        NTSTATUS status;
-       char *fname = NULL;
 
        if (!lp_ea_support(SNUM(conn))) {
                return NT_STATUS_EAS_NOT_SUPPORTED;
        }
 
+       status = refuse_symlink(conn, fsp, smb_fname->base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -644,8 +695,6 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                return STATUS_INVALID_EA_NAME;
        }
 
-       fname = smb_fname->base_name;
-
        for (;ea_list; ea_list = ea_list->next) {
                int ret;
                fstring unix_ea_name;
@@ -653,7 +702,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
                fstrcat(unix_ea_name, ea_list->ea.name);
 
-               canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+               canonicalize_ea_name(conn,
+                               fsp,
+                               smb_fname,
+                               unix_ea_name);
 
                DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
 
@@ -671,8 +723,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                                ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
                        } else {
                                DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
-                                       unix_ea_name, fname));
-                               ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
+                                       unix_ea_name, smb_fname->base_name));
+                               ret = SMB_VFS_REMOVEXATTR(conn,
+                                               smb_fname->base_name,
+                                               unix_ea_name);
                        }
 #ifdef ENOATTR
                        /* Removing a non existent attribute always succeeds. */
@@ -691,9 +745,13 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                                                        ea_list->ea.value.data, ea_list->ea.value.length, 0);
                        } else {
                                DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
-                                       unix_ea_name, fname));
-                               ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
-                                                       ea_list->ea.value.data, ea_list->ea.value.length, 0);
+                                       unix_ea_name, smb_fname->base_name));
+                               ret = SMB_VFS_SETXATTR(conn,
+                                               smb_fname->base_name,
+                                               unix_ea_name,
+                                               ea_list->ea.value.data,
+                                               ea_list->ea.value.length,
+                                               0);
                        }
                }
 
@@ -744,7 +802,7 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz
                }
 
                offset += (namelen + 1); /* Go past the name + terminating zero. */
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, eal);
                DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
        }
 
@@ -768,7 +826,7 @@ static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t d
                        return NULL;
                }
 
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, eal);
                offset += bytes_used;
        }
 
@@ -1092,6 +1150,7 @@ static void call_trans2open(connection_struct *conn,
        uint32_t create_disposition;
        uint32_t create_options = 0;
        uint32_t private_flags = 0;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        /*
@@ -1125,9 +1184,25 @@ static void call_trans2open(connection_struct *conn,
                goto out;
        }
 
-       srvstr_get_path(ctx, params, req->flags2, &fname, pname,
-                       total_params - 28, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       pname,
+                       total_params - 28,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       pname,
+                       total_params - 28,
+                       STR_TERMINATE,
                        &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                goto out;
@@ -1141,7 +1216,7 @@ static void call_trans2open(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2469,11 +2544,12 @@ static void call_trans2findfirst(connection_struct *conn,
        struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
        bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
-       TALLOC_CTX *ctx = talloc_tos();
        struct dptr_struct *dirptr = NULL;
        struct smbd_server_connection *sconn = req->sconn;
-       uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
+       uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        bool backup_priv = false;
+       bool as_root = false;
 
        if (total_params < 13) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2529,9 +2605,27 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                        goto out;
        }
 
-       srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
-                             params+12, total_params - 12,
-                             STR_TERMINATE, &ntstatus, &mask_contains_wcard);
+       if (req->posix_pathnames) {
+               srvstr_get_path_wcard_posix(talloc_tos(),
+                               params,
+                               req->flags2,
+                               &directory,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+       } else {
+               srvstr_get_path_wcard(talloc_tos(),
+                               params,
+                               req->flags2,
+                               &directory,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+       }
        if (!NT_STATUS_IS_OK(ntstatus)) {
                reply_nterror(req, ntstatus);
                goto out;
@@ -2539,7 +2633,8 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 
        if (backup_priv) {
                become_root();
-               ntstatus = filename_convert_with_privilege(ctx,
+               as_root = true;
+               ntstatus = filename_convert_with_privilege(talloc_tos(),
                                conn,
                                req,
                                directory,
@@ -2547,7 +2642,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                                &mask_contains_wcard,
                                &smb_dname);
        } else {
-               ntstatus = filename_convert(ctx, conn,
+               ntstatus = filename_convert(talloc_tos(), conn,
                                    req->flags2 & FLAGS2_DFS_PATHNAMES,
                                    directory,
                                    ucf_flags,
@@ -2573,7 +2668,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
        if(p == NULL) {
                /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
                if((directory[0] == '.') && (directory[1] == '\0')) {
-                       mask = talloc_strdup(ctx,"*");
+                       mask = talloc_strdup(talloc_tos(),"*");
                        if (!mask) {
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
                                goto out;
@@ -2591,6 +2686,8 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                        reply_nterror(req, NT_STATUS_NO_MEMORY);
                        goto out;
                }
+               /* Ensure smb_dname->base_name matches. */
+               smb_dname->base_name = directory;
        }
 
        DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
@@ -2617,7 +2714,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
 
                /* Pull out the list of names. */
-               ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
+               ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4);
                if (!ea_list) {
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        goto out;
@@ -2637,7 +2734,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        }
        pdata = *ppdata;
        data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
-
+       /*
+        * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
+        * error.
+        */
+       memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
        /* Realloc the params space */
        *pparams = (char *)SMB_REALLOC(*pparams, 10);
        if (*pparams == NULL) {
@@ -2652,7 +2753,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        ntstatus = dptr_create(conn,
                                req,
                                NULL, /* fsp */
-                               directory,
+                               smb_dname,
                                False,
                                True,
                                req->smbpid,
@@ -2682,9 +2783,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                directory,lp_dont_descend(ctx, SNUM(conn))));
-       if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive))
+                directory,lp_dont_descend(talloc_tos(), SNUM(conn))));
+       if (in_list(directory,
+                       lp_dont_descend(talloc_tos(), SNUM(conn)),
+                       conn->case_sensitive)) {
                dont_descend = True;
+       }
 
        p = pdata;
        space_remaining = max_data_bytes;
@@ -2699,7 +2803,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        out_of_space = True;
                        finished = False;
                } else {
-                       ntstatus = get_lanman2_dir_entry(ctx,
+                       ntstatus = get_lanman2_dir_entry(talloc_tos(),
                                        conn,
                                        dirptr,
                                        req->flags2,
@@ -2809,7 +2913,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        }
  out:
 
-       if (backup_priv) {
+       if (as_root) {
                unbecome_root();
        }
 
@@ -2863,6 +2967,7 @@ static void call_trans2findnext(connection_struct *conn,
        struct dptr_struct *dirptr;
        struct smbd_server_connection *sconn = req->sconn;
        bool backup_priv = false; 
+       bool as_root = false;
 
        if (total_params < 13) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2881,10 +2986,27 @@ static void call_trans2findnext(connection_struct *conn,
 
        if (!continue_bit) {
                /* We only need resume_name if continue_bit is zero. */
-               srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
-                             params+12,
-                             total_params - 12, STR_TERMINATE, &ntstatus,
-                             &mask_contains_wcard);
+               if (req->posix_pathnames) {
+                       srvstr_get_path_wcard_posix(ctx,
+                               params,
+                               req->flags2,
+                               &resume_name,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+               } else {
+                       srvstr_get_path_wcard(ctx,
+                               params,
+                               req->flags2,
+                               &resume_name,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+               }
                if (!NT_STATUS_IS_OK(ntstatus)) {
                        /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
                           complain (it thinks we're asking for the directory above the shared
@@ -2983,6 +3105,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        pdata = *ppdata;
        data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
 
+       /*
+        * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
+        * error.
+        */
+       memset(pdata + total_data, 0, (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data);
        /* Realloc the params space */
        *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
        if(*pparams == NULL ) {
@@ -3036,6 +3163,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
        if (backup_priv) {
                become_root();
+               as_root = true;
        }
 
        /*
@@ -3137,7 +3265,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
        }
 
-       if (backup_priv) {
+       if (as_root) {
                unbecome_root();
        }
 
@@ -3635,6 +3763,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        case SMB_SIGNING_OFF:
                                encrypt_caps = 0;
                                break;
+                       case SMB_SIGNING_DESIRED:
                        case SMB_SIGNING_IF_REQUIRED:
                        case SMB_SIGNING_DEFAULT:
                                encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
@@ -3791,7 +3920,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                        &conn->session_info->security_token->sids[i],
                                        0);
 
-                               sid_linearize(pdata + data_len, sid_len,
+                               sid_linearize((uint8_t *)(pdata + data_len),
+                                             sid_len,
                                    &conn->session_info->security_token->sids[i]);
                                data_len += sid_len;
                        }
@@ -5103,8 +5233,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                return NT_STATUS_INVALID_PARAMETER;
                        }
 
-                       status = vfs_streaminfo(conn, fsp, smb_fname->base_name,
-                                               talloc_tos(), &num_streams, &streams);
+                       status = vfs_streaminfo(conn,
+                                               fsp,
+                                               smb_fname,
+                                               talloc_tos(),
+                                               &num_streams,
+                                               &streams);
 
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(10, ("could not get stream info: %s\n",
@@ -5237,6 +5371,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                uint16_t num_file_acls = 0;
                                uint16_t num_def_acls = 0;
 
+                               status = refuse_symlink(conn,
+                                               fsp,
+                                               smb_fname->base_name);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       return status;
+                               }
+
                                if (fsp && fsp->fh->fd != -1) {
                                        file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
                                                talloc_tos());
@@ -5522,7 +5663,8 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
        } else {
                uint32_t name_hash;
                char *fname = NULL;
-               uint32_t ucf_flags = 0;
+               uint32_t ucf_flags = (req->posix_pathnames ?
+                               UCF_POSIX_PATHNAMES : 0);
 
                /* qpathinfo */
                if (total_params < 7) {
@@ -5546,9 +5688,25 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        }
                }
 
-               srvstr_get_path(req, params, req->flags2, &fname, &params[6],
+               if (req->posix_pathnames) {
+                       srvstr_get_path_posix(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
                                total_params - 6,
-                               STR_TERMINATE, &status);
+                               STR_TERMINATE,
+                               &status);
+               } else {
+                       srvstr_get_path(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
+                               &status);
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -6352,6 +6510,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
 {
        char *oldname = NULL;
        struct smb_filename *smb_fname_old = NULL;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
        NTSTATUS status = NT_STATUS_OK;
 
@@ -6360,8 +6519,25 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
-                       total_data, STR_TERMINATE, &status);
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       pdata,
+                       req->flags2,
+                       &oldname,
+                       pdata,
+                       total_data,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       pdata,
+                       req->flags2,
+                       &oldname,
+                       pdata,
+                       total_data,
+                       STR_TERMINATE,
+                       &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6373,7 +6549,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                oldname,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_fname_old);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6399,6 +6575,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
        uint32_t len;
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
+       uint32_t ucf_flags = UCF_SAVE_LCOMP |
+               (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        NTSTATUS status = NT_STATUS_OK;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -6417,9 +6595,25 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &newname,
-                               &pdata[20], len, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
                                &status);
+       } else {
+               srvstr_get_path(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6431,7 +6625,7 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                newname,
-                               UCF_SAVE_LCOMP,
+                               ucf_flags,
                                NULL,
                                &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6491,6 +6685,8 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
        NTSTATUS status = NT_STATUS_OK;
+       uint32_t ucf_flags = UCF_SAVE_LCOMP |
+               (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!fsp) {
@@ -6508,9 +6704,25 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &newname,
-                               &pdata[20], len, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+       } else {
+               srvstr_get_path(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
                                &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6522,7 +6734,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                newname,
-                               UCF_SAVE_LCOMP,
+                               ucf_flags,
                                NULL,
                                &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6582,9 +6794,27 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
-                             len, 0, &status,
-                             &dest_has_wcard);
+       if (req->posix_pathnames) {
+               srvstr_get_path_wcard_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[12],
+                               len,
+                               0,
+                               &status,
+                               &dest_has_wcard);
+       } else {
+               srvstr_get_path_wcard(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[12],
+                               len,
+                               0,
+                               &status,
+                               &dest_has_wcard);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6734,6 +6964,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
        uint16_t num_def_acls;
        bool valid_file_acls = True;
        bool valid_def_acls = True;
+       NTSTATUS status;
 
        if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -6761,6 +6992,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       status = refuse_symlink(conn, fsp, smb_fname->base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
                smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
                (unsigned int)num_file_acls,
@@ -7348,7 +7584,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                if (fsp && fsp->fh->fd != -1) {
                        ret = SMB_VFS_FCHMOD(fsp, unixmode);
                } else {
-                       ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
+                       ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
                }
                if (ret != 0) {
                        return map_nt_error_from_unix(errno);
@@ -7375,7 +7611,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                         * UNIX extensions calls must always operate
                         * on symlinks.
                         */
-                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
+                       ret = SMB_VFS_LCHOWN(conn, smb_fname,
                                             set_owner, (gid_t)-1);
                }
 
@@ -7407,7 +7643,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                         * UNIX extensions calls must always operate
                         * on symlinks.
                         */
-                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, (uid_t)-1,
+                       ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
                                  set_grp);
                }
                if (ret != 0) {
@@ -8402,7 +8638,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
        } else {
                char *fname = NULL;
-               uint32_t ucf_flags = 0;
+               uint32_t ucf_flags = (req->posix_pathnames ?
+                       UCF_POSIX_PATHNAMES : 0);
 
                /* set path info */
                if (total_params < 7) {
@@ -8411,9 +8648,25 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
 
                info_level = SVAL(params,0);
-               srvstr_get_path(req, params, req->flags2, &fname, &params[6],
-                               total_params - 6, STR_TERMINATE,
+               if (req->posix_pathnames) {
+                       srvstr_get_path_posix(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
+                               &status);
+               } else {
+                       srvstr_get_path(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
                                &status);
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -8536,6 +8789,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
        char *directory = NULL;
        NTSTATUS status = NT_STATUS_OK;
        struct ea_list *ea_list = NULL;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!CAN_WRITE(conn)) {
@@ -8548,9 +8802,25 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                return;
        }
 
-       srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
-                       total_params - 4, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &directory,
+                       &params[4],
+                       total_params - 4,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &directory,
+                       &params[4],
+                       total_params - 4,
+                       STR_TERMINATE,
                        &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
@@ -8562,7 +8832,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                directory,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_dname);