Fix bug 7104 - "wide links" and "unix extensions" are incompatible.
[samba.git] / source3 / smbd / trans2.c
index 2892e26c772e9b392bf760c3b25bf99053c0f881..28862d1f4e8d78de92d71543895c192437117071 100644 (file)
@@ -70,8 +70,8 @@ static bool samba_private_attr_name(const char *unix_ea_name)
        static const char * const prohibited_ea_names[] = {
                SAMBA_POSIX_INHERITANCE_EA_NAME,
                SAMBA_XATTR_DOS_ATTRIB,
-               SAMBA_XATTR_DOSTIMESTAMPS,
                SAMBA_XATTR_MARKER,
+               XATTR_NTACL_NAME,
                NULL
        };
 
@@ -1012,7 +1012,7 @@ static void call_trans2open(connection_struct *conn,
        pname = &params[28];
 
        if (IS_IPC(conn)) {
-               reply_doserror(req, ERRSRV, ERRaccess);
+               reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
                goto out;
        }
 
@@ -1055,7 +1055,7 @@ static void call_trans2open(connection_struct *conn,
                                         &access_mask, &share_mode,
                                         &create_disposition,
                                         &create_options)) {
-               reply_doserror(req, ERRDOS, ERRbadaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                goto out;
        }
 
@@ -1121,7 +1121,7 @@ static void call_trans2open(connection_struct *conn,
        inode = smb_fname->st.st_ex_ino;
        if (fattr & aDIR) {
                close_file(req, fsp, ERROR_CLOSE);
-               reply_doserror(req, ERRDOS,ERRnoaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                goto out;
        }
 
@@ -1484,7 +1484,6 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        char *nameptr;
        char *last_entry_ptr;
        bool was_8_3;
-       uint32_t nt_extmode; /* Used for NT connections instead of mode */
        off_t off;
        off_t pad = 0;
 
@@ -1535,8 +1534,6 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        pad = 0;
        off = 0;
 
-       nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
-
        switch (info_level) {
        case SMB_FIND_INFO_STANDARD:
                DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
@@ -1684,7 +1681,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
-               SIVAL(p,0,nt_extmode); p += 4;
+               SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
@@ -1750,7 +1747,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
-               SIVAL(p,0,nt_extmode); p += 4;
+               SIVAL(p,0,mode); p += 4;
                len = srvstr_push(base_data, flags2,
                                  p + 4, fname, PTR_DIFF(end_data, p+4),
                                  STR_TERMINATE_ASCII);
@@ -1786,7 +1783,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
-               SIVAL(p,0,nt_extmode); p += 4;
+               SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
@@ -1861,7 +1858,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
-               SIVAL(p,0,nt_extmode); p += 4;
+               SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
@@ -1908,7 +1905,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
-               SIVAL(p,0,nt_extmode); p += 4;
+               SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
@@ -2337,7 +2334,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
 
                if (!lp_ea_support(SNUM(conn))) {
-                       reply_doserror(req, ERRDOS, ERReasnotsupported);
+                       reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
                        goto out;
                }
 
@@ -2465,7 +2462,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        if(numentries == 0) {
                dptr_close(sconn, &dptr_num);
                if (get_Protocol() < PROTOCOL_NT1) {
-                       reply_doserror(req, ERRDOS, ERRnofiles);
+                       reply_force_doserror(req, ERRDOS, ERRnofiles);
                        goto out;
                } else {
                        reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
@@ -2652,7 +2649,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
 
                if (!lp_ea_support(SNUM(conn))) {
-                       reply_doserror(req, ERRDOS, ERReasnotsupported);
+                       reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
                        return;
                }
 
@@ -2685,7 +2682,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
        /* Check that the dptr is valid */
        if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
-               reply_doserror(req, ERRDOS, ERRnofiles);
+               reply_nterror(req, STATUS_NO_MORE_FILES);
                return;
        }
 
@@ -2694,7 +2691,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        /* Get the wildcard mask from the dptr */
        if((p = dptr_wcard(sconn, dptr_num))== NULL) {
                DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
-               reply_doserror(req, ERRDOS, ERRnofiles);
+               reply_nterror(req, STATUS_NO_MORE_FILES);
                return;
        }
 
@@ -4187,8 +4184,6 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
        } else {
                mode = dos_mode(conn, smb_fname);
        }
-       if (!mode)
-               mode = FILE_ATTRIBUTE_NORMAL;
 
        nlink = psbuf->st_ex_nlink;
 
@@ -5236,8 +5231,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        }
 
                        if (!lp_ea_support(SNUM(conn))) {
-                               reply_doserror(req, ERRDOS,
-                                              ERReasnotsupported);
+                               reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
                                return;
                        }
 
@@ -5538,7 +5532,8 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                                  files_struct *fsp,
                                  const struct smb_filename *smb_fname,
                                  const SMB_STRUCT_STAT *psbuf,
-                                 SMB_OFF_T size)
+                                 SMB_OFF_T size,
+                                 bool fail_after_createfile)
 {
        NTSTATUS status = NT_STATUS_OK;
        struct smb_filename *smb_fname_tmp = NULL;
@@ -5598,6 +5593,12 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                return status;
        }
 
+       /* See RAW-SFILEINFO-END-OF-FILE */
+       if (fail_after_createfile) {
+               close_file(req, new_fsp,NORMAL_CLOSE);
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
        if (vfs_set_filelen(new_fsp, size) == -1) {
                status = map_nt_error_from_unix(errno);
                close_file(req, new_fsp,NORMAL_CLOSE);
@@ -5730,10 +5731,11 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
                (unsigned int)dosmode,
                (unsigned int)delete_on_close ));
 
-       status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (delete_on_close) {
+               status = can_set_delete_on_close(fsp, dosmode);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
        }
 
        /* The set is across all open files on this dev/inode pair. */
@@ -5834,42 +5836,6 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       /* !widelinks forces the target path to be within the share. */
-       /* This means we can interpret the target as a pathname. */
-       if (!lp_widelinks(SNUM(conn))) {
-               char *rel_name = NULL;
-               char *last_dirp = NULL;
-
-               if (*link_target == '/') {
-                       /* No absolute paths allowed. */
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-               rel_name = talloc_strdup(ctx,newname);
-               if (!rel_name) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-               last_dirp = strrchr_m(rel_name, '/');
-               if (last_dirp) {
-                       last_dirp[1] = '\0';
-               } else {
-                       rel_name = talloc_strdup(ctx,"./");
-                       if (!rel_name) {
-                               return NT_STATUS_NO_MEMORY;
-                       }
-               }
-               rel_name = talloc_asprintf_append(rel_name,
-                               "%s",
-                               link_target);
-               if (!rel_name) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               status = check_name(conn, rel_name);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-       }
-
        DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
                        newname, link_target ));
 
@@ -6474,7 +6440,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
                                        const char *pdata,
                                        int total_data,
                                        files_struct *fsp,
-                                       const struct smb_filename *smb_fname)
+                                       const struct smb_filename *smb_fname,
+                                       bool fail_after_createfile)
 {
        SMB_OFF_T size;
 
@@ -6499,7 +6466,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
                                fsp,
                                smb_fname,
                                &smb_fname->st,
-                               size);
+                               size,
+                               fail_after_createfile);
 }
 
 /****************************************************************************
@@ -6785,7 +6753,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                                   fsp,
                                   smb_fname,
                                   &sbuf,
-                                  size);
+                                  size,
+                                  false);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -7381,11 +7350,22 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
                case SMB_FILE_END_OF_FILE_INFORMATION:
                case SMB_SET_FILE_END_OF_FILE_INFO:
                {
+                       /*
+                        * XP/Win7 both fail after the createfile with
+                        * SMB_SET_FILE_END_OF_FILE_INFO but not
+                        * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
+                        * The level is known here, so pass it down
+                        * appropriately.
+                        */
+                       bool should_fail =
+                           (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
+
                        status = smb_set_file_end_of_file_info(conn, req,
                                                                pdata,
                                                                total_data,
                                                                fsp,
-                                                               smb_fname);
+                                                               smb_fname,
+                                                               should_fail);
                        break;
                }
 
@@ -7647,7 +7627,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                                                    max_data_bytes);
                                return;
                        } else {
-                               reply_doserror(req, ERRDOS, ERRbadpath);
+                               reply_nterror(req,
+                                       NT_STATUS_OBJECT_PATH_NOT_FOUND);
                                return;
                        }
                } else {
@@ -7787,7 +7768,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!CAN_WRITE(conn)) {
-               reply_doserror(req, ERRSRV, ERRaccess);
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                return;
        }
 
@@ -8006,7 +7987,7 @@ static void call_trans2getdfsreferral(connection_struct *conn,
        max_referral_level = SVAL(params,0);
 
        if(!lp_host_msdfs()) {
-               reply_doserror(req, ERRDOS, ERRbadfunc);
+               reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
                return;
        }
 
@@ -8048,7 +8029,7 @@ static void call_trans2ioctl(connection_struct *conn,
        /* check for an invalid fid before proceeding */
 
        if (!fsp) {
-               reply_doserror(req, ERRDOS, ERRbadfid);
+               reply_nterror(req, NT_STATUS_INVALID_HANDLE);
                return;
        }
 
@@ -8077,7 +8058,7 @@ static void call_trans2ioctl(connection_struct *conn,
        }
 
        DEBUG(2,("Unknown TRANS2_IOCTL\n"));
-       reply_doserror(req, ERRSRV, ERRerror);
+       reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
 }
 
 /****************************************************************************
@@ -8303,7 +8284,7 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
        default:
                /* Error in request */
                DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
-               reply_doserror(req, ERRSRV,ERRerror);
+               reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
        }
 }
 
@@ -8355,7 +8336,7 @@ void reply_trans2(struct smb_request *req)
                case TRANSACT2_SETFSINFO:
                        break;
                default:
-                       reply_doserror(req, ERRSRV, ERRaccess);
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        END_PROFILE(SMBtrans2);
                        return;
                }