r1939: Ensure with my new change we set extended security in flags2 in
[tprouty/samba.git] / source / smbd / trans2.c
index a0e00cfcfe0471a8d17f1ec6f4aebd38f256985b..f3176940c2fc109b6d83e4044bffce32a8b589b6 100644 (file)
@@ -607,7 +607,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        if (IS_IPC(conn))
                return(ERROR_DOS(ERRSRV,ERRaccess));
 
-       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -618,6 +618,9 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        /* XXXX we need to handle passed times, sattr and flags */
 
        unix_convert(fname,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
     
        if (!check_name(fname,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
@@ -627,6 +630,11 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                oplock_request, &rmode,&smb_action);
       
        if (!fsp) {
+               if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+                       /* We have re-scheduled this call. */
+                       clear_cached_errors();
+                       return -1;
+               }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
@@ -1371,7 +1379,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                        return(ERROR_DOS(ERRDOS,ERRunknownlevel));
        }
 
-       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -1379,6 +1387,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
        if(!check_name(directory,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
        }
@@ -1564,7 +1575,7 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
 
        *mask = *directory = *resume_name = 0;
 
-       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -2257,6 +2268,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_QFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2272,11 +2285,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         */
                                                
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
+                       /* We know this name is ok, it's already passed the checks. */
                        
                } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
                        /*
@@ -2284,12 +2293,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         * handle (returned from an NT SMB). NT5.0 seems
                         * to do this call. JRA.
                         */
+                       /* We know this name is ok, it's already passed the checks. */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
                  
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
                                /* Always do lstat for UNIX calls. */
@@ -2297,12 +2302,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
                                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                                }
-                       } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+                       } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
                                DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
 
-                       delete_pending = fsp->directory_delete_on_close;
+                       delete_pending = fsp->is_directory ? fsp->directory_delete_on_close : 0;
                } else {
                        /*
                         * Original code - this is an open file.
@@ -2329,7 +2334,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
 
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
@@ -2337,6 +2342,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
                unix_convert(fname,conn,0,&bad_path,&sbuf);
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
                if (!check_name(fname,conn)) {
                        DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
@@ -2400,7 +2408,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                c_time &= ~1;
                sbuf.st_atime &= ~1;
-               sbuf.st_mtime &= ~1;
+               sbuf.st_ctime &= ~1;
                sbuf.st_mtime &= ~1;
        }
 
@@ -2861,73 +2869,6 @@ NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close)
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- Returns true if this pathname is within the share, and thus safe.
-****************************************************************************/
-
-static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out)
-{
-#ifdef PATH_MAX
-       char resolved_name[PATH_MAX+1];
-#else
-       pstring resolved_name;
-#endif
-       fstring last_component;
-       pstring link_dest;
-       pstring link_test;
-       char *p;
-       BOOL bad_path = False;
-       SMB_STRUCT_STAT sbuf;
-
-       pstrcpy(link_dest, link_dest_in);
-       unix_convert(link_dest,conn,0,&bad_path,&sbuf);
-
-       /* Store the UNIX converted path. */
-       pstrcpy(link_dest_out, link_dest);
-
-       p = strrchr_m(link_dest, '/');
-       if (p) {
-               fstrcpy(last_component, p+1);
-               *p = '\0';
-       } else {
-               fstrcpy(last_component, link_dest);
-               pstrcpy(link_dest, "./");
-       }
-               
-       if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL)
-               return -1;
-
-       DEBUG(10,("ensure_link_is_safe: realpath: link_dest (%s) -> real name (%s)\n",
-                       link_dest, resolved_name ));
-
-       pstrcpy(link_dest, resolved_name);
-       pstrcat(link_dest, "/");
-       pstrcat(link_dest, last_component);
-
-       if (*link_dest != '/') {
-               /* Relative path. */
-               pstrcpy(link_test, conn->connectpath);
-               pstrcat(link_test, "/");
-               pstrcat(link_test, link_dest);
-       } else {
-               pstrcpy(link_test, link_dest);
-       }
-
-       DEBUG(10,("ensure_link_is_safe: connectpath = %s, absolute resolved path = %s\n",
-               conn->connectpath, link_test ));
-
-       /*
-        * Check if the link is within the share.
-        */
-
-       if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) {
-               errno = EACCES;
-               return -1;
-       }
-
-       return 0;
-}
-
 /****************************************************************************
  Set a hard link (called by UNIX extensions and by NT rename with HARD link
  code.
@@ -2938,7 +2879,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
        BOOL bad_path_oldname = False;
        BOOL bad_path_newname = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
-       BOOL rc, rcdest;
        pstring last_component_oldname;
        pstring last_component_newname;
        NTSTATUS status = NT_STATUS_OK;
@@ -2951,8 +2891,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
        }
 
-       rc = unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
-       if (!rc && bad_path_oldname) {
+       unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+       if (bad_path_oldname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2972,8 +2912,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
-       if (!rcdest && bad_path_newname) {
+       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+       if (bad_path_newname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2998,7 +2938,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
-       if (ensure_link_is_safe(conn, oldname, oldname) != 0)
+       /* Ensure this is within the share. */
+       if (!reduce_name(conn, oldname) != 0)
                return NT_STATUS_ACCESS_DENIED;
 
        DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
@@ -3040,6 +2981,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_SETFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -3054,8 +2997,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                         * to do this call. JRA.
                         */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+                       if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
                                DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
@@ -3093,11 +3035,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
                info_level = SVAL(params,0);    
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
                unix_convert(fname,conn,0,&bad_path,&sbuf);
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
 
                /*
                 * For CIFS UNIX extensions the target name may not exist.
@@ -3271,7 +3216,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                                                        SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                                        (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                                                                        FILE_ATTRIBUTE_NORMAL,
-                                                                       0, &access_mode, &action);
+                                                                       INTERNAL_OPEN_ONLY, &access_mode, &action);
  
                                        if (new_fsp == NULL)
                                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3413,16 +3358,15 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                 * a new info level should be used for mknod. JRA.
                                 */
 
-#if !defined(HAVE_MAKEDEV_FN)
-                               return(ERROR_DOS(ERRDOS,ERRnoaccess));
-#else /* HAVE_MAKEDEV_FN */
                                uint32 file_type = IVAL(pdata,0);
+#if defined(HAVE_MAKEDEV)
                                uint32 dev_major = IVAL(pdata,4);
                                uint32 dev_minor = IVAL(pdata,12);
+#endif
 
                                uid_t myuid = geteuid();
                                gid_t mygid = getegid();
-                               SMB_DEV_T dev;
+                               SMB_DEV_T dev = (SMB_DEV_T)0;
 
                                if (tran_call == TRANSACT2_SETFILEINFO)
                                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
@@ -3430,7 +3374,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                if (raw_unixmode == SMB_MODE_NO_CHANGE)
                                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
+#if defined(HAVE_MAKEDEV)
                                dev = makedev(dev_major, dev_minor);
+#endif
 
                                /* We can only create as the owner/group we are. */
 
@@ -3439,15 +3385,36 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE))
                                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
 
-                               if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV &&
-                                               file_type != UNIX_TYPE_FIFO)
-                                       return(ERROR_DOS(ERRDOS,ERRnoaccess));
+                               switch (file_type) {
+#if defined(S_IFIFO)
+                                       case UNIX_TYPE_FIFO:
+                                               unixmode |= S_IFIFO;
+                                               break;
+#endif
+#if defined(S_IFSOCK)
+                                       case UNIX_TYPE_SOCKET:
+                                               unixmode |= S_IFSOCK;
+                                               break;
+#endif
+#if defined(S_IFCHR)
+                                       case UNIX_TYPE_CHARDEV:
+                                               unixmode |= S_IFCHR;
+                                               break;
+#endif
+#if defined(S_IFBLK)
+                                       case UNIX_TYPE_BLKDEV:
+                                               unixmode |= S_IFBLK;
+                                               break;
+#endif
+                                       default:
+                                               return(ERROR_DOS(ERRDOS,ERRnoaccess));
+                               }
 
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
 0%o for file %s\n", (double)dev, unixmode, fname ));
 
                                /* Ok - do the mknod. */
-                               if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
+                               if (SMB_VFS_MKNOD(conn,fname, unixmode, dev) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
 
                                inherit_access_acl(conn, fname, unixmode);
@@ -3455,8 +3422,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                SSVAL(params,0,0);
                                send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
                                return(-1);
-#endif /* HAVE_MAKEDEV_FN */
-
                        }
 
                        /*
@@ -3508,12 +3473,16 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        srvstr_pull(inbuf, link_target, pdata, sizeof(link_target), -1, STR_TERMINATE);
 
                        /* !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))) {
                                pstring rel_name;
                                char *last_dirp = NULL;
 
                                unix_format(link_target);
-
+                               if (*link_target == '/') {
+                                       /* No absolute paths allowed. */
+                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               }
                                pstrcpy(rel_name, newname);
                                last_dirp = strrchr_m(rel_name, '/');
                                if (last_dirp) {
@@ -3522,11 +3491,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                        pstrcpy(rel_name, "./");
                                }
                                pstrcat(rel_name, link_target);
-                               if (ensure_link_is_safe(conn, rel_name, rel_name) != 0) {
-                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
-                               }
 
-                               if (check_name(link_target, conn)) {
+                               if (!check_name(rel_name, conn)) {
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                                }
                        }
@@ -3547,7 +3513,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        char *newname = fname;
 
                        /* Set a hard link. */
-                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3580,7 +3546,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        overwrite = (CVAL(pdata,0) ? True : False);
                        root_fid = IVAL(pdata,4);
                        len = IVAL(pdata,8);
-                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
+                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3603,7 +3569,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if (fsp) {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
                                        fsp->fnum, fsp->fsp_name, base_name ));
-                               status = rename_internals_fsp(conn, fsp, base_name, overwrite);
+                               status = rename_internals_fsp(conn, fsp, base_name, 0, overwrite);
                        } else {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
                                        fname, newname ));
@@ -3719,7 +3685,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                                SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                                                FILE_ATTRIBUTE_NORMAL,
-                                               0, &access_mode, &action);
+                                               INTERNAL_OPEN_ONLY, &access_mode, &action);
        
                        if (new_fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3760,7 +3726,7 @@ static int call_trans2mkdir(connection_struct *conn,
        if (total_params < 4)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
-       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -3768,6 +3734,9 @@ static int call_trans2mkdir(connection_struct *conn,
        DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
        if (check_name(directory,conn))
                ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));