r1939: Ensure with my new change we set extended security in flags2 in
[tprouty/samba.git] / source / smbd / trans2.c
index 16c2d83aa223f88c86a5fcc9774d748d9e5dc93f..f3176940c2fc109b6d83e4044bffce32a8b589b6 100644 (file)
@@ -24,7 +24,6 @@
 #include "includes.h"
 
 extern int Protocol;
-extern BOOL case_sensitive;
 extern int smb_read_error;
 extern fstring local_machine;
 extern int global_oplock_break;
@@ -395,9 +394,11 @@ static NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *f
        }
 
        if (ret == -1) {
+#ifdef ENOTSUP
                if (errno == ENOTSUP) {
                        return NT_STATUS_EAS_NOT_SUPPORTED;
                }
+#endif
                return map_nt_error_from_unix(errno);
        }
 
@@ -606,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);
        }
@@ -617,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);
@@ -626,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);
        }
 
@@ -800,7 +809,7 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps
 
 time_t interpret_long_unix_date(char *p)
 {
-       DEBUG(1,("interpret_long_unix_date\n"));
+       DEBUG(10,("interpret_long_unix_date\n"));
        if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO &&
           IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) {
                return -1;
@@ -881,8 +890,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                pstrcpy(fname,dname);      
 
-               if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive)))
-                       got_match = mask_match(fname, mask, case_sensitive);
+               if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
+                       got_match = mask_match(fname, mask, conn->case_sensitive);
 
                if(!got_match && !mangle_is_8_3(fname, False)) {
 
@@ -896,8 +905,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        pstring newname;
                        pstrcpy( newname, fname);
                        mangle_map( newname, True, False, SNUM(conn));
-                       if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive)))
-                               got_match = mask_match(newname, mask, case_sensitive);
+                       if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
+                               got_match = mask_match(newname, mask, conn->case_sensitive);
                }
 
                if(got_match) {
@@ -1239,7 +1248,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
                        p+= 8;
 
-                       put_long_date(p,sbuf.st_ctime);       /* Creation Time 64 Bit */
+                       put_long_date(p,sbuf.st_ctime);       /* Inode change Time 64 Bit */
                        put_long_date(p+8,sbuf.st_atime);     /* Last access time 64 Bit */
                        put_long_date(p+16,sbuf.st_mtime);    /* Last modification time 64 Bit */
                        p+= 24;
@@ -1348,7 +1357,7 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
        *directory = *mask = 0;
 
        DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
-close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
+close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
                info_level, max_data_bytes));
   
@@ -1370,7 +1379,7 @@ close_if_end = %d requires_resume_key = %d level = %d, 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);
        }
@@ -1378,6 +1387,9 @@ close_if_end = %d requires_resume_key = %d level = %d, 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);
        }
@@ -1431,7 +1443,7 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
                a different TRANS2 call. */
   
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
-       if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
+       if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
                dont_descend = True;
     
        p = pdata;
@@ -1563,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);
        }
@@ -1631,7 +1643,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn))));
-       if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive))
+       if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
                dont_descend = True;
     
        p = pdata;
@@ -2010,7 +2022,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        fsp.fd = -1;
                        
                        /* access check */
-                       if (conn->admin_user != True) {
+                       if (current_user.uid != 0) {
                                DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
                                        lp_servicename(SNUM(conn)),conn->user));
                                return ERROR_DOS(ERRDOS,ERRnoaccess);
@@ -2108,7 +2120,7 @@ static int call_trans2setfsinfo(connection_struct *conn,
        DEBUG(10,("call_trans2setfsinfo: SET_FS_QUOTA: for service [%s]\n",lp_servicename(SNUM(conn))));
 
        /* access check */
-       if ((conn->admin_user != True)||!CAN_WRITE(conn)) {
+       if ((current_user.uid != 0)||!CAN_WRITE(conn)) {
                DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
                        lp_servicename(SNUM(conn)),conn->user));
                return ERROR_DOS(ERRSRV,ERRaccess);
@@ -2256,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));
@@ -2271,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)) {
                        /*
@@ -2283,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. */
@@ -2296,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.
@@ -2328,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);
                }
@@ -2336,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);
@@ -2399,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;
        }
 
@@ -2860,66 +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(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;
-
-       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);
-       }
-
-       /*
-        * 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.
@@ -2930,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;
@@ -2943,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;
        }
 
@@ -2960,8 +2908,12 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
-       if (!rcdest && bad_path_newname) {
+       if (!check_name(oldname,conn)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+       if (bad_path_newname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2977,12 +2929,17 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
+       if (!check_name(newname,conn)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        /* No links from a directory. */
        if (S_ISDIR(sbuf1.st_mode)) {
                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 ));
@@ -3024,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));
@@ -3038,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);
                        }
@@ -3077,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.
@@ -3255,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));
@@ -3397,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));
@@ -3414,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. */
 
@@ -3423,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);
@@ -3439,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 */
-
                        }
 
                        /*
@@ -3480,7 +3461,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                case SMB_SET_FILE_UNIX_LINK:
                {
-                       pstring oldname;
+                       pstring link_target;
                        char *newname = fname;
 
                        /* Set a symbolic link. */
@@ -3489,18 +3470,37 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if (!lp_symlinks(SNUM(conn)))
                                return(ERROR_DOS(ERRDOS,ERRnoaccess));
 
-                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               return ERROR_NT(status);
-                       }
+                       srvstr_pull(inbuf, link_target, pdata, sizeof(link_target), -1, STR_TERMINATE);
 
-                       if (ensure_link_is_safe(conn, oldname, oldname) != 0)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       /* !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) {
+                                       last_dirp[1] = '\0';
+                               } else {
+                                       pstrcpy(rel_name, "./");
+                               }
+                               pstrcat(rel_name, link_target);
+
+                               if (!check_name(rel_name, conn)) {
+                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               }
+                       }
 
                        DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
-                               fname, oldname ));
+                               fname, link_target ));
 
-                       if (SMB_VFS_SYMLINK(conn,oldname,newname) != 0)
+                       if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0)
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
                        SSVAL(params,0,0);
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
@@ -3513,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);
                        }
@@ -3546,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);
                        }
@@ -3569,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 ));
@@ -3685,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));
@@ -3726,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);
        }
@@ -3734,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));