r1939: Ensure with my new change we set extended security in flags2 in
[tprouty/samba.git] / source / smbd / trans2.c
index 2bf250a980fa81b725283a5fee35fe610cbe41dd..f3176940c2fc109b6d83e4044bffce32a8b589b6 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    SMB transaction2 handling
-   Copyright (C) Jeremy Allison                        1994-2001
+   Copyright (C) Jeremy Allison                        1994-2003
    Copyright (C) Stefan (metze) Metzmacher     2003
 
    Extensively modified by Andrew Tridgell, 1995
@@ -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;
@@ -49,6 +48,363 @@ SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
        return ret;
 }
 
+/****************************************************************************
+ Utility functions for dealing with extended attributes.
+****************************************************************************/
+
+static const char *prohibited_ea_names[] = {
+       SAMBA_POSIX_INHERITANCE_EA_NAME,
+       SAMBA_XATTR_DOS_ATTRIB,
+       NULL
+};
+
+/****************************************************************************
+ Refuse to allow clients to overwrite our private xattrs.
+****************************************************************************/
+
+static BOOL samba_private_attr_name(const char *unix_ea_name)
+{
+       int i;
+
+       for (i = 0; prohibited_ea_names[i]; i++) {
+               if (strequal( prohibited_ea_names[i], unix_ea_name))
+                       return True;
+       }
+       return False;
+}
+
+struct ea_list {
+       struct ea_list *next, *prev;
+       struct ea_struct ea;
+};
+
+/****************************************************************************
+ Get one EA value. Fill in a struct ea_struct.
+****************************************************************************/
+
+static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+                               const char *fname, char *ea_name, struct ea_struct *pea)
+{
+       /* Get the value of this xattr. Max size is 64k. */
+       size_t attr_size = 256;
+       char *val = NULL;
+       ssize_t sizeret;
+
+ again:
+
+       val = talloc_realloc(mem_ctx, val, attr_size);
+       if (!val) {
+               return False;
+       }
+
+       if (fsp && fsp->fd != -1) {
+               sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fd, ea_name, val, attr_size);
+       } else {
+               sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
+       }
+
+       if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
+               attr_size = 65536;
+               goto again;
+       }
+
+       if (sizeret == -1) {
+               return False;
+       }
+
+       DEBUG(10,("get_ea_value: EA %s is of length %d: ", ea_name, sizeret));
+       dump_data(10, val, sizeret);
+
+       pea->flags = 0;
+       if (strnequal(ea_name, "user.", 5)) {
+               pea->name = &ea_name[5];
+       } else {
+               pea->name = ea_name;
+       }
+       pea->value.data = val;
+       pea->value.length = (size_t)sizeret;
+       return True;
+}
+
+/****************************************************************************
+ Return a linked list of the total EA's. Plus the total size
+****************************************************************************/
+
+static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pea_total_len)
+{
+       /* Get a list of all xattrs. Max namesize is 64k. */
+       size_t ea_namelist_size = 1024;
+       char *ea_namelist;
+       char *p;
+       ssize_t sizeret;
+       int i;
+       struct ea_list *ea_list_head = NULL;
+
+       *pea_total_len = 0;
+
+       if (!lp_ea_support(SNUM(conn))) {
+               return NULL;
+       }
+
+       for (i = 0, ea_namelist = talloc(mem_ctx, ea_namelist_size); i < 6;
+                       ea_namelist = talloc_realloc(mem_ctx, ea_namelist, ea_namelist_size), i++) {
+               if (fsp && fsp->fd != -1) {
+                       sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size);
+               } else {
+                       sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size);
+               }
+
+               if (sizeret == -1 && errno == ERANGE) {
+                       ea_namelist_size *= 2;
+               } else {
+                       break;
+               }
+       }
+
+       if (sizeret == -1)
+               return NULL;
+
+       DEBUG(10,("get_ea_list: ea_namelist size = %d\n", sizeret ));
+
+       if (sizeret) {
+               for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {
+                       struct ea_list *listp, *tmp;
+
+                       if (strnequal(p, "system.", 7) || samba_private_attr_name(p))
+                               continue;
+               
+                       listp = talloc(mem_ctx, sizeof(struct ea_list));
+                       if (!listp)
+                               return NULL;
+
+                       if (!get_ea_value(mem_ctx, conn, fsp, fname, p, &listp->ea)) {
+                               return NULL;
+                       }
+
+                       {
+                               fstring dos_ea_name;
+                               push_ascii_fstring(dos_ea_name, listp->ea.name);
+                               *pea_total_len += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
+                               DEBUG(10,("get_ea_list: total_len = %u, %s, val len = %u\n",
+                                       *pea_total_len, dos_ea_name,
+                                       (unsigned int)listp->ea.value.length ));
+                       }
+                       DLIST_ADD_END(ea_list_head, listp, tmp);
+               }
+               /* Add on 4 for total length. */
+               if (*pea_total_len) {
+                       *pea_total_len += 4;
+               }
+       }
+
+       DEBUG(10,("get_ea_list: total_len = %u\n", *pea_total_len));
+       return ea_list_head;
+}
+
+/****************************************************************************
+ Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
+ that was filled.
+****************************************************************************/
+
+static unsigned int fill_ea_buffer(char *pdata, unsigned int total_data_size,
+       connection_struct *conn, files_struct *fsp, const char *fname)
+{
+       unsigned int ret_data_size = 4;
+       char *p = pdata;
+       size_t total_ea_len;
+       TALLOC_CTX *mem_ctx;
+       struct ea_list *ea_list;
+
+       SMB_ASSERT(total_data_size >= 4);
+
+       SIVAL(pdata,0,0);
+       if (!lp_ea_support(SNUM(conn))) {
+               return 4;
+       }
+       mem_ctx = talloc_init("fill_ea_buffer");
+       if (!mem_ctx) {
+               return 4;
+       }
+
+       ea_list = get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
+       if (!ea_list) {
+               talloc_destroy(mem_ctx);
+               return 4;
+       }
+
+       if (total_ea_len > total_data_size) {
+               talloc_destroy(mem_ctx);
+               return 4;
+       }
+
+       for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
+               size_t dos_namelen;
+               fstring dos_ea_name;
+               push_ascii_fstring(dos_ea_name, ea_list->ea.name);
+               dos_namelen = strlen(dos_ea_name);
+               if (dos_namelen > 255 || dos_namelen == 0) {
+                       break;
+               }
+               if (ea_list->ea.value.length > 65535) {
+                       break;
+               }
+               if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
+                       break;
+               }
+
+               /* We know we have room. */
+               SCVAL(p,0,ea_list->ea.flags);
+               SCVAL(p,1,dos_namelen);
+               SSVAL(p,2,ea_list->ea.value.length);
+               fstrcpy(p+4, dos_ea_name);
+               memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
+
+               total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
+               p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
+       }
+
+       ret_data_size = PTR_DIFF(p, pdata);
+       DEBUG(10,("fill_ea_buffer: data_size = %u, total_ea_len = %u\n",
+                       ret_data_size, total_ea_len ));
+       talloc_destroy(mem_ctx);
+       SIVAL(pdata,0,ret_data_size);
+       return ret_data_size;
+}
+
+static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
+{
+       size_t total_ea_len = 0;
+       TALLOC_CTX *mem_ctx = NULL;
+
+       if (!lp_ea_support(SNUM(conn))) {
+               return 0;
+       }
+       mem_ctx = talloc_init("estimate_ea_size");
+       (void)get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
+       talloc_destroy(mem_ctx);
+       return total_ea_len;
+}
+
+/****************************************************************************
+ 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)
+{
+       size_t total_ea_len;
+       TALLOC_CTX *mem_ctx = talloc_init("canonicalize_ea_name");
+       struct ea_list *ea_list = get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
+
+       for (; ea_list; ea_list = ea_list->next) {
+               if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
+                       DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
+                               &unix_ea_name[5], ea_list->ea.name));
+                       safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
+                       break;
+               }
+       }
+       talloc_destroy(mem_ctx);
+}
+
+/****************************************************************************
+ Set or delete an extended attribute.
+****************************************************************************/
+
+static NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname,
+                       char *pdata, int total_data)
+{
+       unsigned int namelen;
+       unsigned int ealen;
+       int ret;
+       fstring unix_ea_name;
+
+       if (!lp_ea_support(SNUM(conn))) {
+               return NT_STATUS_EAS_NOT_SUPPORTED;
+       }
+
+       if (total_data < 8) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (IVAL(pdata,0) > total_data) {
+               DEBUG(10,("set_ea: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       pdata += 4;
+       namelen = CVAL(pdata,1);
+       ealen = SVAL(pdata,2);
+       pdata += 4;
+       if (total_data < 8 + namelen + 1 + ealen) {
+               DEBUG(10,("set_ea: bad total data size (%u) < 8 + namelen (%u) + 1 + ealen (%u)\n",
+                       (unsigned int)total_data, namelen, ealen));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (pdata[namelen] != '\0') {
+               DEBUG(10,("set_ea: ea name not null terminated\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
+       pull_ascii(&unix_ea_name[5], pdata, sizeof(fstring) - 5, -1, STR_TERMINATE);
+       pdata += (namelen + 1);
+
+       canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+
+       DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, ealen));
+       if (ealen) {
+               DEBUG(10,("set_ea: data :\n"));
+               dump_data(10, pdata, ealen);
+       }
+
+       if (samba_private_attr_name(unix_ea_name)) {
+               DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (ealen == 0) {
+               /* Remove the attribute. */
+               if (fsp && (fsp->fd != -1)) {
+                       DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",
+                               unix_ea_name, fsp->fsp_name));
+                       ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, 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);
+               }
+#ifdef ENOATTR
+               /* Removing a non existent attribute always succeeds. */
+               if (ret == -1 && errno == ENOATTR) {
+                       DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n", unix_ea_name));
+                       ret = 0;
+               }
+#endif
+       } else {
+               if (fsp && (fsp->fd != -1)) {
+                       DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",
+                               unix_ea_name, fsp->fsp_name));
+                       ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, unix_ea_name, pdata, ealen, 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, pdata, ealen, 0);
+               }
+       }
+
+       if (ret == -1) {
+#ifdef ENOTSUP
+               if (errno == ENOTSUP) {
+                       return NT_STATUS_EAS_NOT_SUPPORTED;
+               }
+#endif
+               return map_nt_error_from_unix(errno);
+       }
+
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
   Send the required number of replies back.
   We assume all fields other than the data fields are
@@ -220,7 +576,6 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        int32 open_size;
        char *pname;
        pstring fname;
-       mode_t unixmode;
        SMB_OFF_T size=0;
        int fmode=0,mtime=0,rmode;
        SMB_INO_T inode = 0;
@@ -228,6 +583,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        int smb_action = 0;
        BOOL bad_path = False;
        files_struct *fsp;
+       NTSTATUS status;
 
        /*
         * Ensure we have enough parameters to perform the operation.
@@ -248,31 +604,38 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        open_size = IVAL(params,14);
        pname = &params[28];
 
-       srvstr_pull(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE);
+       if (IS_IPC(conn))
+               return(ERROR_DOS(ERRSRV,ERRaccess));
+
+       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
+       }
 
        DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
                fname,open_mode, open_attr, open_ofun, open_size));
 
-       if (IS_IPC(conn))
-               return(ERROR_DOS(ERRSRV,ERRaccess));
-
        /* 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)) {
-               set_bad_path_error(errno, bad_path);
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
-       unixmode = unix_mode(conn,open_attr | aARCH, fname);
-      
-       fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,unixmode,
+       fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr,
                oplock_request, &rmode,&smb_action);
       
        if (!fsp) {
-               set_bad_path_error(errno, bad_path);
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               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);
        }
 
        size = get_file_size(sbuf);
@@ -326,7 +689,13 @@ static BOOL exact_match(char *str,char *mask, BOOL case_sig)
                return False;
        if (case_sig)   
                return strcmp(str,mask)==0;
-       return strcasecmp(str,mask) == 0;
+       if (StrCaseCmp(str,mask) != 0) {
+               return False;
+       }
+       if (ms_has_wild(str)) {
+               return False;
+       }
+       return True;
 }
 
 /****************************************************************************
@@ -435,12 +804,12 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps
 }
 
 /****************************************************************************
-checks for SMB_TIME_NO_CHANGE and if not found
-calls interpret_long_date
+ Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date.
 ****************************************************************************/
+
 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;
@@ -521,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)) {
 
@@ -536,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) {
@@ -614,6 +983,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
        switch (info_level) {
                case SMB_INFO_STANDARD:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
                        if(requires_resume_key) {
                                SIVAL(p,0,reskey);
                                p += 4;
@@ -628,14 +998,24 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        nameptr = p;
                        p += align_string(outbuf, p, 0);
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
-                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
-                               SCVAL(nameptr, -1, len-2);
-                       else
-                               SCVAL(nameptr, -1, len-1);
+                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+                               if (len > 2) {
+                                       SCVAL(nameptr, -1, len - 2);
+                               } else {
+                                       SCVAL(nameptr, -1, 0);
+                               }
+                       } else {
+                               if (len > 1) {
+                                       SCVAL(nameptr, -1, len - 1);
+                               } else {
+                                       SCVAL(nameptr, -1, 0);
+                               }
+                       }
                        p += len;
                        break;
 
                case SMB_INFO_QUERY_EA_SIZE:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
                        if(requires_resume_key) {
                                SIVAL(p,0,reskey);
                                p += 4;
@@ -646,18 +1026,33 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SIVAL(p,l2_cbFile,(uint32)file_size);
                        SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
                        SSVAL(p,l2_attrFile,mode);
-                       SIVAL(p,l2_cbList,0); /* No extended attributes */
+                       {
+                               unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+                               SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
+                       }
                        p += l2_achName;
-                       nameptr = p;
+                       nameptr = p - 1;
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
-                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
-                               SCVAL(nameptr, -1, len-2);
-                       else
-                               SCVAL(nameptr, -1, len-1);
+                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+                               if (len > 2) {
+                                       len -= 2;
+                               } else {
+                                       len = 0;
+                               }
+                       } else {
+                               if (len > 1) {
+                                       len -= 1;
+                               } else {
+                                       len = 0;
+                               }
+                       }
+                       SCVAL(nameptr,0,len);
                        p += len;
+                       SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
                        break;
 
                case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
                        was_8_3 = mangle_is_8_3(fname, True);
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
@@ -665,18 +1060,21 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        put_long_date(p,adate); p += 8;
                        put_long_date(p,mdate); p += 8;
                        put_long_date(p,mdate); p += 8;
-                       SOFF_T(p,0,file_size);
-                       SOFF_T(p,8,allocation_size);
-                       p += 16;
+                       SOFF_T(p,0,file_size); p += 8;
+                       SOFF_T(p,0,allocation_size); p += 8;
                        SIVAL(p,0,nt_extmode); p += 4;
-                       q = p; p += 4;
-                       SIVAL(p,0,0); p += 4;
+                       q = p; p += 4; /* q is placeholder for name length. */
+                       {
+                               unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+                               SIVAL(p,0,ea_size); /* Extended attributes */
+                               p += 4;
+                       }
                        /* Clear the short name buffer. This is
                         * IMPORTANT as not doing so will trigger
                         * a Win2k client bug. JRA.
                         */
                        memset(p,'\0',26);
-                       if (!was_8_3) {
+                       if (!was_8_3 && lp_manglednames(SNUM(conn))) {
                                pstring mangled_name;
                                pstrcpy(mangled_name, fname);
                                mangle_map(mangled_name,True,True,SNUM(conn));
@@ -698,20 +1096,19 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        break;
 
                case SMB_FIND_FILE_DIRECTORY_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
                        put_long_date(p,adate); p += 8;
                        put_long_date(p,mdate); p += 8;
                        put_long_date(p,mdate); p += 8;
-                       SOFF_T(p,0,file_size);
-                       SOFF_T(p,8,allocation_size);
-                       p += 16;
+                       SOFF_T(p,0,file_size); p += 8;
+                       SOFF_T(p,0,allocation_size); p += 8;
                        SIVAL(p,0,nt_extmode); p += 4;
-                       p += 4;
-                       len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-                       SIVAL(p, -4, len);
-                       p += len;
+                       len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
+                       SIVAL(p,0,len);
+                       p += 4 + len;
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -719,22 +1116,25 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        break;
       
                case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
                        put_long_date(p,adate); p += 8;
                        put_long_date(p,mdate); p += 8;
                        put_long_date(p,mdate); p += 8;
-                       SOFF_T(p,0,file_size); 
-                       SOFF_T(p,8,allocation_size);
-                       p += 16;
-                       SIVAL(p,0,nt_extmode);
-                       p += 4;
-
-                       SIVAL(p,4,0); /* ea size */
-                       len = srvstr_push(outbuf, p+8, fname, -1, STR_TERMINATE_ASCII);
-                       SIVAL(p, 0, len);
-                       p += 8 + len;
+                       SOFF_T(p,0,file_size); p += 8;
+                       SOFF_T(p,0,allocation_size); p += 8;
+                       SIVAL(p,0,nt_extmode); p += 4;
+                       q = p; p += 4; /* q is placeholder for name length. */
+                       {
+                               unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+                               SIVAL(p,0,ea_size); /* Extended attributes */
+                               p +=4;
+                       }
+                       len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+                       SIVAL(q, 0, len);
+                       p += len;
 
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
@@ -743,6 +1143,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        break;
 
                case SMB_FIND_FILE_NAMES_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        p += 4;
@@ -757,9 +1158,86 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        p = pdata + len;
                        break;
 
+               case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+                       p += 4;
+                       SIVAL(p,0,reskey); p += 4;
+                       put_long_date(p,cdate); p += 8;
+                       put_long_date(p,adate); p += 8;
+                       put_long_date(p,mdate); p += 8;
+                       put_long_date(p,mdate); 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;
+                       q = p; p += 4; /* q is placeholder for name length. */
+                       {
+                               unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+                               SIVAL(p,0,ea_size); /* Extended attributes */
+                               p +=4;
+                       }
+                       SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
+                       SIVAL(p,0,sbuf.st_dev); p += 4;
+                       SIVAL(p,0,sbuf.st_ino); p += 4;
+                       len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+                       SIVAL(q, 0, len);
+                       p += len; 
+                       len = PTR_DIFF(p, pdata);
+                       len = (len + 3) & ~3;
+                       SIVAL(pdata,0,len);
+                       p = pdata + len;
+                       break;
+
+               case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+                       was_8_3 = mangle_is_8_3(fname, True);
+                       p += 4;
+                       SIVAL(p,0,reskey); p += 4;
+                       put_long_date(p,cdate); p += 8;
+                       put_long_date(p,adate); p += 8;
+                       put_long_date(p,mdate); p += 8;
+                       put_long_date(p,mdate); 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;
+                       q = p; p += 4; /* q is placeholder for name length */
+                       {
+                               unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+                               SIVAL(p,0,ea_size); /* Extended attributes */
+                               p +=4;
+                       }
+                       /* Clear the short name buffer. This is
+                        * IMPORTANT as not doing so will trigger
+                        * a Win2k client bug. JRA.
+                        */
+                       memset(p,'\0',26);
+                       if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+                               pstring mangled_name;
+                               pstrcpy(mangled_name, fname);
+                               mangle_map(mangled_name,True,True,SNUM(conn));
+                               mangled_name[12] = 0;
+                               len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+                               SSVAL(p, 0, len);
+                       } else {
+                               SSVAL(p,0,0);
+                               *(p+2) = 0;
+                       }
+                       p += 26;
+                       SSVAL(p,0,0); p += 2; /* Reserved ? */
+                       SIVAL(p,0,sbuf.st_dev); p += 4;
+                       SIVAL(p,0,sbuf.st_ino); p += 4;
+                       len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+                       SIVAL(q,0,len);
+                       p += len;
+                       len = PTR_DIFF(p, pdata);
+                       len = (len + 3) & ~3;
+                       SIVAL(pdata,0,len);
+                       p = pdata + len;
+                       break;
+
                /* CIFS UNIX Extension. */
 
                case SMB_FIND_FILE_UNIX:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
                        p+= 4;
                        SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
 
@@ -770,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;
@@ -871,6 +1349,7 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
        int space_remaining;
        BOOL bad_path = False;
        SMB_STRUCT_STAT sbuf;
+       NTSTATUS ntstatus = NT_STATUS_OK;
 
        if (total_params < 12)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -878,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));
   
@@ -889,6 +1368,8 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
                case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
                case SMB_FIND_FILE_NAMES_INFO:
                case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+               case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+               case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
                        break;
                case SMB_FIND_FILE_UNIX:
                        if (!lp_unix_extensions())
@@ -898,14 +1379,19 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
                        return(ERROR_DOS(ERRDOS,ERRunknownlevel));
        }
 
-       srvstr_pull(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE);
+       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               return ERROR_NT(ntstatus);
+       }
 
        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)) {
-               set_bad_path_error(errno, bad_path);
-               return(UNIXERROR(ERRDOS,ERRbadpath));
+               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
        }
 
        p = strrchr_m(directory,'/');
@@ -957,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;
@@ -1082,13 +1568,17 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
        BOOL dont_descend = False;
        BOOL out_of_space = False;
        int space_remaining;
+       NTSTATUS ntstatus = NT_STATUS_OK;
 
        if (total_params < 12)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
        *mask = *directory = *resume_name = 0;
 
-       srvstr_pull(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE);
+       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);
+       }
 
        DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
@@ -1153,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;
@@ -1338,17 +1828,34 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
        switch (info_level) {
                case SMB_INFO_ALLOCATION:
                {
-                       SMB_BIG_UINT dfree,dsize,bsize;
+                       SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 18;
                        SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); 
+                       block_size = lp_block_size(snum);
+                       if (bsize < block_size) {
+                               SMB_BIG_UINT factor = block_size/bsize;
+                               bsize = block_size;
+                               dsize /= factor;
+                               dfree /= factor;
+                       }
+                       if (bsize > block_size) {
+                               SMB_BIG_UINT factor = bsize/block_size;
+                               bsize = block_size;
+                               dsize *= factor;
+                               dfree *= factor;
+                       }
+                       bytes_per_sector = 512;
+                       sectors_per_unit = bsize/bytes_per_sector;
+
+                       DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
+cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
+                               (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
+
                        SIVAL(pdata,l1_idFileSystem,st.st_dev);
-                       SIVAL(pdata,l1_cSectorUnit,bsize/512);
+                       SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
                        SIVAL(pdata,l1_cUnit,dsize);
                        SIVAL(pdata,l1_cUnitAvail,dfree);
-                       SSVAL(pdata,l1_cbSector,512);
-                       DEBUG(5,("call_trans2qfsinfo : bsize=%u, id=%x, cSectorUnit=%u, cUnit=%u, cUnitAvail=%u, cbSector=%d\n",
-                               (unsigned int)bsize, (unsigned int)st.st_dev, ((unsigned int)bsize)/512, (unsigned int)dsize,
-                               (unsigned int)dfree, 512));
+                       SSVAL(pdata,l1_cbSector,bytes_per_sector);
                        break;
                }
 
@@ -1359,7 +1866,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                         * the called hostname and the service name.
                         */
                        SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) );
-                       len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, 0);
+                       len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_NOALIGN);
                        SCVAL(pdata,l2_vol_cch,len);
                        data_len = l2_vol_szVolLabel + len;
                        DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
@@ -1515,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);
@@ -1613,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);
@@ -1710,14 +2217,19 @@ static int call_trans2setfsinfo(connection_struct *conn,
  *  Utility function to set bad path error.
  ****************************************************************************/
 
-NTSTATUS set_bad_path_error(int err, BOOL bad_path)
+int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code)
 {
-       if((err == ENOENT) && bad_path) {
-               unix_ERR_class = ERRDOS;
-               unix_ERR_code = ERRbadpath;
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       DEBUG(10,("set_bad_path_error: err = %d bad_path = %d\n",
+                       err, (int)bad_path ));
+
+       if(err == ENOENT) {
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               } else {
+                       return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               }
        }
-       return NT_STATUS_OK;
+       return UNIXERROR(def_class,def_code);
 }
 
 /****************************************************************************
@@ -1739,6 +2251,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        SMB_OFF_T file_size=0;
        SMB_BIG_UINT allocation_size=0;
        unsigned int data_size;
+       unsigned int param_size = 2;
        SMB_STRUCT_STAT sbuf;
        pstring fname, dos_fname;
        char *fullpathname;
@@ -1750,10 +2263,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        int len;
        time_t c_time;
        files_struct *fsp = NULL;
+       uint32 desired_access = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
 
        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));
@@ -1769,12 +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)));
-                               set_bad_path_error(errno, bad_path);
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
-                       }
+                       /* We know this name is ok, it's already passed the checks. */
                        
                } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
                        /*
@@ -1782,28 +2293,21 @@ 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)));
-                               set_bad_path_error(errno, bad_path);
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
-                       }
                  
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
                                /* Always do lstat for UNIX calls. */
                                if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
                                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
-                                       set_bad_path_error(errno, bad_path);
-                                       return(UNIXERROR(ERRDOS,ERRbadpath));
+                                       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)));
-                               set_bad_path_error(errno, bad_path);
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                               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.
@@ -1815,12 +2319,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
                                return(UNIXERROR(ERRDOS,ERRbadfid));
                        }
-                       if((pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
-
+                       pos = fsp->position_information;
                        delete_pending = fsp->delete_on_close;
+                       desired_access = fsp->desired_access;
                }
        } else {
+               NTSTATUS status = NT_STATUS_OK;
+
                /* qpathinfo */
                if (total_params < 6)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -1829,36 +2334,39 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
 
-               srvstr_pull(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return ERROR_NT(status);
+               }
 
                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)));
-                       set_bad_path_error(errno, bad_path);
-                       return(UNIXERROR(ERRDOS,ERRbadpath));
+                       return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                }
 
                if (INFO_LEVEL_IS_UNIX(info_level)) {
                        /* Always do lstat for UNIX calls. */
                        if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
                                DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
-                               set_bad_path_error(errno, bad_path);
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
-               } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+               } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) {
                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
-                       set_bad_path_error(errno, bad_path);
-                       return(UNIXERROR(ERRDOS,ERRbadpath));
+                       return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                }
        }
 
        if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
                return ERROR_DOS(ERRDOS,ERRunknownlevel);
 
-       DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
-               fname,info_level,tran_call,total_data));
+       DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
+               fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
 
        p = strrchr_m(fname,'/'); 
        if (!p)
@@ -1867,6 +2375,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                base_name = p+1;
 
        mode = dos_mode(conn,fname,&sbuf);
+       if (!mode)
+               mode = FILE_ATTRIBUTE_NORMAL;
+
        fullpathname = fname;
        file_size = get_file_size(sbuf);
        allocation_size = get_allocation_size(fsp,&sbuf);
@@ -1897,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;
        }
 
@@ -1906,32 +2417,49 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        if (strequal(base_name,".")) {
                pstrcpy(dos_fname, "\\");
        } else {
-               snprintf(dos_fname, sizeof(dos_fname), "\\%s", fname);
+               pstr_sprintf(dos_fname, "\\%s", fname);
                string_replace(dos_fname, '/', '\\');
        }
 
        switch (info_level) {
                case SMB_INFO_STANDARD:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n"));
+                       data_size = 22;
+                       put_dos_date2(pdata,l1_fdateCreation,c_time);
+                       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
+                       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
+                       SIVAL(pdata,l1_cbFile,(uint32)file_size);
+                       SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
+                       SSVAL(pdata,l1_attrFile,mode);
+                       break;
+
                case SMB_INFO_QUERY_EA_SIZE:
-                       data_size = (info_level==1?22:26);
+               {
+                       unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
+                       data_size = 26;
                        put_dos_date2(pdata,l1_fdateCreation,c_time);
                        put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
                        put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
                        SIVAL(pdata,l1_cbFile,(uint32)file_size);
                        SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
                        SSVAL(pdata,l1_attrFile,mode);
-                       SIVAL(pdata,l1_attrFile+2,0); /* this is what win2003 does */
+                       SIVAL(pdata,l1_attrFile+2,ea_size);
                        break;
+               }
 
                case SMB_INFO_IS_NAME_VALID:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
                        if (tran_call == TRANSACT2_QFILEINFO) {
                                /* os/2 needs this ? really ?*/      
                                return ERROR_DOS(ERRDOS,ERRbadfunc); 
                        }
                        data_size = 0;
+                       param_size = 0;
                        break;
                        
                case SMB_INFO_QUERY_EAS_FROM_LIST:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
                        data_size = 24;
                        put_dos_date2(pdata,0,c_time);
                        put_dos_date2(pdata,4,sbuf.st_atime);
@@ -1942,16 +2470,19 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        break;
 
                case SMB_INFO_QUERY_ALL_EAS:
-                       data_size = 4;
-                       SIVAL(pdata,0,0); /* ea size */
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
+                       /* We have data_size bytes to put EA's into. */
+                       data_size = fill_ea_buffer(pdata, data_size, conn, fsp, fname);
                        break;
 
                case SMB_FILE_BASIC_INFORMATION:
                case SMB_QUERY_FILE_BASIC_INFO:
 
-                       if (info_level == SMB_QUERY_FILE_BASIC_INFO)
+                       if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
+                               DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
                                data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
-                       else {
+                       } else {
+                               DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
                                data_size = 40;
                                SIVAL(pdata,36,0);
                        }
@@ -1976,18 +2507,27 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                case SMB_FILE_STANDARD_INFORMATION:
                case SMB_QUERY_FILE_STANDARD_INFO:
 
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
                        data_size = 24;
                        SOFF_T(pdata,0,allocation_size);
                        SOFF_T(pdata,8,file_size);
-                       SIVAL(pdata,16,sbuf.st_nlink);
+                       if (delete_pending & sbuf.st_nlink)
+                               SIVAL(pdata,16,sbuf.st_nlink - 1);
+                       else
+                               SIVAL(pdata,16,sbuf.st_nlink);
                        SCVAL(pdata,20,0);
                        SCVAL(pdata,21,(mode&aDIR)?1:0);
                        break;
 
                case SMB_FILE_EA_INFORMATION:
                case SMB_QUERY_FILE_EA_INFO:
+               {
+                       unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
                        data_size = 4;
+                       SIVAL(pdata,0,ea_size);
                        break;
+               }
 
                /* Get the 8.3 name - used if NT SMB was negotiated. */
                case SMB_QUERY_FILE_ALT_NAME_INFO:
@@ -1995,6 +2535,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                {
                        pstring short_name;
 
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
                        pstrcpy(short_name,base_name);
                        /* Mangle if not already 8.3 */
                        if(!mangle_is_8_3(short_name, True)) {
@@ -2011,24 +2552,30 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                          this must be *exactly* right for ACLs on mapped drives to work
                         */
                        len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_UNICODE);
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
                        data_size = 4 + len;
                        SIVAL(pdata,0,len);
                        break;
 
                case SMB_FILE_ALLOCATION_INFORMATION:
                case SMB_QUERY_FILE_ALLOCATION_INFO:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
                        data_size = 8;
                        SOFF_T(pdata,0,allocation_size);
                        break;
 
                case SMB_FILE_END_OF_FILE_INFORMATION:
                case SMB_QUERY_FILE_END_OF_FILEINFO:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
                        data_size = 8;
                        SOFF_T(pdata,0,file_size);
                        break;
 
                case SMB_QUERY_FILE_ALL_INFO:
                case SMB_FILE_ALL_INFORMATION:
+               {
+                       unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
                        put_long_date(pdata,c_time);
                        put_long_date(pdata+8,sbuf.st_atime);
                        put_long_date(pdata+16,sbuf.st_mtime); /* write time */
@@ -2037,17 +2584,21 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        pdata += 40;
                        SOFF_T(pdata,0,allocation_size);
                        SOFF_T(pdata,8,file_size);
-                       SIVAL(pdata,16,sbuf.st_nlink);
+                       if (delete_pending && sbuf.st_nlink)
+                               SIVAL(pdata,16,sbuf.st_nlink - 1);
+                       else
+                               SIVAL(pdata,16,sbuf.st_nlink);
                        SCVAL(pdata,20,delete_pending);
                        SCVAL(pdata,21,(mode&aDIR)?1:0);
                        pdata += 24;
+                       SIVAL(pdata,0,ea_size);
                        pdata += 4; /* EA info */
                        len = srvstr_push(outbuf, pdata+4, dos_fname, -1, STR_UNICODE);
                        SIVAL(pdata,0,len);
                        pdata += 4 + len;
                        data_size = PTR_DIFF(pdata,(*ppdata));
                        break;
-
+               }
                case SMB_FILE_INTERNAL_INFORMATION:
                        /* This should be an index number - looks like
                           dev/ino to me :-) 
@@ -2055,13 +2606,15 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                           I think this causes us to fail the IFSKIT
                           BasicFileInformationTest. -tpot */
 
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
                        SIVAL(pdata,0,sbuf.st_dev);
                        SIVAL(pdata,4,sbuf.st_ino);
                        data_size = 8;
                        break;
 
                case SMB_FILE_ACCESS_INFORMATION:
-                       SIVAL(pdata,0,0x12019F); /* ??? */
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
+                       SIVAL(pdata,0,desired_access);
                        data_size = 4;
                        break;
 
@@ -2070,27 +2623,32 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        {
                                size_t byte_len;
                                byte_len = dos_PutUniCode(pdata+4,dos_fname,max_data_bytes,False);
+                               DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
                                SIVAL(pdata,0,byte_len);
                                data_size = 4 + byte_len;
                                break;
                        }
 
                case SMB_FILE_DISPOSITION_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
                        data_size = 1;
                        SCVAL(pdata,0,delete_pending);
                        break;
 
                case SMB_FILE_POSITION_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
                        data_size = 8;
                        SOFF_T(pdata,0,pos);
                        break;
 
                case SMB_FILE_MODE_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
                        SIVAL(pdata,0,mode);
                        data_size = 4;
                        break;
 
                case SMB_FILE_ALIGNMENT_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
                        SIVAL(pdata,0,0); /* No alignment needed. */
                        data_size = 4;
                        break;
@@ -2104,6 +2662,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                case SMB_QUERY_FILE_STREAM_INFO:
 #endif
                case SMB_FILE_STREAM_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
                        if (mode & aDIR) {
                                data_size = 0;
                        } else {
@@ -2119,6 +2678,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                case SMB_QUERY_COMPRESSION_INFO:
                case SMB_FILE_COMPRESSION_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
                        SOFF_T(pdata,0,file_size);
                        SIVAL(pdata,8,0); /* ??? */
                        SIVAL(pdata,12,0); /* ??? */
@@ -2126,6 +2686,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        break;
 
                case SMB_FILE_NETWORK_OPEN_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
                        put_long_date(pdata,c_time);
                        put_long_date(pdata+8,sbuf.st_atime);
                        put_long_date(pdata+16,sbuf.st_mtime); /* write time */
@@ -2138,6 +2699,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        break;
 
                case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
                        SIVAL(pdata,0,mode);
                        SIVAL(pdata,4,0);
                        data_size = 8;
@@ -2149,6 +2711,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                case SMB_QUERY_FILE_UNIX_BASIC:
 
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC\n"));
                        DEBUG(4,("call_trans2qfilepathinfo: st_mode=%o\n",(int)sbuf.st_mode));
 
                        SOFF_T(pdata,0,get_file_size(sbuf));             /* File size 64 Bit */
@@ -2208,6 +2771,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        {
                                pstring buffer;
 
+                               DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
 #ifdef S_ISLNK
                                if(!S_ISLNK(sbuf.st_mode))
                                        return(UNIXERROR(ERRSRV,ERRbadlink));
@@ -2229,7 +2793,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
 
-       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, data_size);
+       send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
 
        return(-1);
 }
@@ -2306,63 +2870,87 @@ NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close)
 }
 
 /****************************************************************************
- Returns true if this pathname is within the share, and thus safe.
+ Set a hard link (called by UNIX extensions and by NT rename with HARD link
+ code.
 ****************************************************************************/
 
-static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out)
+NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newname)
 {
-#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;
+       BOOL bad_path_oldname = False;
+       BOOL bad_path_newname = False;
+       SMB_STRUCT_STAT sbuf1, sbuf2;
+       pstring last_component_oldname;
+       pstring last_component_newname;
+       NTSTATUS status = NT_STATUS_OK;
+
+       ZERO_STRUCT(sbuf1);
+       ZERO_STRUCT(sbuf2);
+
+       /* No wildcards. */
+       if (ms_has_wild(newname) || ms_has_wild(oldname)) {
+               return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+       }
 
-       pstrcpy(link_dest, link_dest_in);
-       unix_convert(link_dest,conn,0,&bad_path,&sbuf);
+       unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+       if (bad_path_oldname) {
+               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       }
 
-       /* Store the UNIX converted path. */
-       pstrcpy(link_dest_out, link_dest);
+       /* Quick check for "." and ".." */
+       if (last_component_oldname[0] == '.') {
+               if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) {
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+       }
 
-       p = strrchr(link_dest, '/');
-       if (p) {
-               fstrcpy(last_component, p+1);
-               *p = '\0';
-       } else {
-               fstrcpy(last_component, link_dest);
-               pstrcpy(link_dest, "./");
+       /* source must already exist. */
+       if (!VALID_STAT(sbuf1)) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
-               
-       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 (!check_name(oldname,conn)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
 
-       if (*link_dest != '/') {
-               /* Relative path. */
-               pstrcpy(link_test, conn->connectpath);
-               pstrcat(link_test, "/");
-               pstrcat(link_test, link_dest);
-       } else {
-               pstrcpy(link_test, link_dest);
+       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+       if (bad_path_newname) {
+               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
-       /*
-        * Check if the link is within the share.
-        */
+       /* Quick check for "." and ".." */
+       if (last_component_newname[0] == '.') {
+               if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) {
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+       }
 
-       if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) {
-               errno = EACCES;
-               return -1;
+       /* Disallow if newname already exists. */
+       if (VALID_STAT(sbuf2)) {
+               return NT_STATUS_OBJECT_NAME_COLLISION;
        }
-       return 0;
+
+       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;
+       }
+
+       /* 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 ));
+
+       if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
+               status = map_nt_error_from_unix(errno);
+               DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
+                                nt_errstr(status), newname, oldname));
+       }
+
+       return status;
 }
 
 /****************************************************************************
@@ -2388,10 +2976,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
        gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
        mode_t unixmode = 0;
+       NTSTATUS status = NT_STATUS_OK;
 
        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));
@@ -2406,11 +2997,9 @@ 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)));
-                               set_bad_path_error(errno, bad_path);
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
                } else if (fsp && fsp->print_file) {
                        /*
@@ -2446,11 +3035,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
                info_level = SVAL(params,0);    
-               srvstr_pull(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE);
+               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(!check_name(fname, conn)) {
-                       set_bad_path_error(errno, bad_path);
-                       return(UNIXERROR(ERRDOS,ERRbadpath));
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
                }
 
                /*
@@ -2459,9 +3050,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 
                if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) {
                        DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno)));
-                       set_bad_path_error(errno, bad_path);
-                       return(UNIXERROR(ERRDOS,ERRbadpath));
+                       return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                }    
+
+               if(!check_name(fname, conn)) {
+                       return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+               }
+
        }
 
        if (!CAN_WRITE(conn))
@@ -2473,8 +3068,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        if (VALID_STAT(sbuf))
                unixmode = sbuf.st_mode;
 
-       DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
-               tran_call,fname,info_level,total_data));
+       DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
+               tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
 
        /* Realloc the parameter and data sizes */
        params = Realloc(*pparams,2);
@@ -2501,23 +3096,21 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        switch (info_level) {
                case SMB_INFO_STANDARD:
                {
-                       if (total_data < l1_cbFile+4)
+                       if (total_data < 12)
                                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
                        /* access time */
                        tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
-
                        /* write time */
                        tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
-
-                       dosmode = SVAL(pdata,l1_attrFile);
-                       size = IVAL(pdata,l1_cbFile);
-
                        break;
                }
 
                case SMB_INFO_SET_EA:
-                       return(ERROR_DOS(ERRDOS,ERReasnotsupported));
+                       status = set_ea(conn, fsp, fname, pdata, total_data);
+                       if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
+                               return ERROR_NT(status);
+                       break;
 
                /* XXXX um, i don't think this is right.
                        it's also not in the cifs6.txt spec.
@@ -2622,7 +3215,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                        new_fsp = open_file_shared1(conn, fname, &sbuf,FILE_WRITE_DATA,
                                                                        SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                                        (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                                                                       0, 0, &access_mode, &action);
+                                                                       FILE_ATTRIBUTE_NORMAL,
+                                                                       INTERNAL_OPEN_ONLY, &access_mode, &action);
  
                                        if (new_fsp == NULL)
                                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -2671,14 +3265,16 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                case SMB_FILE_DISPOSITION_INFORMATION:
                case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
                {
-                       BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
-                       NTSTATUS status;
+                       BOOL delete_on_close;
 
                        if (total_data < 1)
                                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
+                       delete_on_close = (CVAL(pdata,0) ? True : False);
+
+                       /* Just ignore this set on a path. */
                        if (tran_call != TRANSACT2_SETFILEINFO)
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                               break;
 
                        if (fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadfid));
@@ -2696,6 +3292,27 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        break;
                }
 
+               case SMB_FILE_POSITION_INFORMATION:
+               {
+                       SMB_BIG_UINT position_information;
+
+                       if (total_data < 8)
+                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+                       position_information = (SMB_BIG_UINT)IVAL(pdata,0);
+#ifdef LARGE_SMB_OFF_T
+                       position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
+#else /* LARGE_SMB_OFF_T */
+                       if (IVAL(pdata,4) != 0) /* more than 32 bits? */
+                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+#endif /* LARGE_SMB_OFF_T */
+                       DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n",
+                                       fname, (double)position_information ));
+                       if (fsp)
+                               fsp->position_information = position_information;
+                       break;
+               }
+
                /*
                 * CIFS UNIX extensions.
                 */
@@ -2741,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));
@@ -2758,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. */
 
@@ -2767,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);
@@ -2783,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 */
-
                        }
 
                        /*
@@ -2824,26 +3461,46 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                case SMB_SET_FILE_UNIX_LINK:
                {
-                       pstring link_dest;
+                       pstring link_target;
+                       char *newname = fname;
+
                        /* Set a symbolic link. */
                        /* Don't allow this if follow links is false. */
 
                        if (!lp_symlinks(SNUM(conn)))
                                return(ERROR_DOS(ERRDOS,ERRnoaccess));
 
-                       /* Disallow if already exists. */
-                       if (VALID_STAT(sbuf))
-                               return(ERROR_DOS(ERRDOS,ERRbadpath));
+                       srvstr_pull(inbuf, link_target, pdata, sizeof(link_target), -1, STR_TERMINATE);
 
-                       srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -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;
 
-                       if (ensure_link_is_safe(conn, link_dest, link_dest) != 0)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               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, link_dest ));
+                               fname, link_target ));
 
-                       if (SMB_VFS_SYMLINK(conn,link_dest,fname) != 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);
@@ -2852,29 +3509,80 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                case SMB_SET_FILE_UNIX_HLINK:
                {
-                       pstring link_dest;
+                       pstring oldname;
+                       char *newname = fname;
 
                        /* Set a hard link. */
+                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
 
-                       /* Disallow if already exists. */
-                       if (VALID_STAT(sbuf))
-                               return(ERROR_DOS(ERRDOS,ERRbadpath));
+                       DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
+                               fname, oldname));
 
-                       srvstr_pull(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE);
+                       status = hardlink_internals(conn, oldname, newname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
 
-                       if (ensure_link_is_safe(conn, link_dest, link_dest) != 0)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
 
-                       DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
-                               fname, link_dest ));
+               case SMB_FILE_RENAME_INFORMATION:
+               {
+                       BOOL overwrite;
+                       uint32 root_fid;
+                       uint32 len;
+                       pstring newname;
+                       pstring base_name;
+                       char *p;
 
-                       if (SMB_VFS_LINK(conn,link_dest,fname) != 0)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       if (total_data < 12)
+                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+                       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, False);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
+
+                       /* Check the new name has no '/' characters. */
+                       if (strchr_m(newname, '/'))
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+
+                       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+                       /* Create the base directory. */
+                       pstrcpy(base_name, fname);
+                       p = strrchr_m(base_name, '/');
+                       if (p)
+                               *p = '\0';
+                       /* Append the new name. */
+                       pstrcat(base_name, "/");
+                       pstrcat(base_name, newname);
+
+                       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, 0, overwrite);
+                       } else {
+                               DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
+                                       fname, newname ));
+                               status = rename_internals(conn, fname, base_name, 0, overwrite);
+                       }
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
+                       process_pending_change_notify_queue((time_t)0);
                        SSVAL(params,0,0);
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
                        return(-1);
                }
-
                default:
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
@@ -2890,10 +3598,12 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
        DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
        DEBUG(6,("size: %.0f ", (double)size));
 
-       if (S_ISDIR(sbuf.st_mode))
-               dosmode |= aDIR;
-       else
-               dosmode &= ~aDIR;
+       if (dosmode) {
+               if (S_ISDIR(sbuf.st_mode))
+                       dosmode |= aDIR;
+               else
+                       dosmode &= ~aDIR;
+       }
 
        DEBUG(6,("dosmode: %x\n"  , dosmode));
 
@@ -2943,8 +3653,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode ));
 
-               if(file_chmod(conn, fname, dosmode, NULL)) {
-                       DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
+               if(file_set_dosmode(conn, fname, dosmode, NULL)) {
+                       DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno)));
                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                }
        }
@@ -2974,7 +3684,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        new_fsp = open_file_shared(conn, fname, &sbuf,
                                                SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
-                                               0, 0, &access_mode, &action);
+                                               FILE_ATTRIBUTE_NORMAL,
+                                               INTERNAL_OPEN_ONLY, &access_mode, &action);
        
                        if (new_fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3007,6 +3718,7 @@ static int call_trans2mkdir(connection_struct *conn,
        int ret = -1;
        SMB_STRUCT_STAT sbuf;
        BOOL bad_path = False;
+       NTSTATUS status = NT_STATUS_OK;
 
        if (!CAN_WRITE(conn))
                return ERROR_DOS(ERRSRV,ERRaccess);
@@ -3014,18 +3726,23 @@ static int call_trans2mkdir(connection_struct *conn,
        if (total_params < 4)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
-       srvstr_pull(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE);
+       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
+       }
 
        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));
   
        if(ret < 0) {
                DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
-               set_bad_path_error(errno, bad_path);
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
+               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
        /* Realloc the parameter and data sizes */
@@ -3139,9 +3856,8 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
                return ERROR_DOS(ERRDOS,ERRbadfunc);
 
        srvstr_pull(inbuf, pathname, &params[2], sizeof(pathname), -1, STR_TERMINATE);
-
-       if((reply_size = setup_dfs_referral(pathname,max_referral_level,ppdata)) < 0)
-               return ERROR_DOS(ERRDOS,ERRbadfile);
+       if((reply_size = setup_dfs_referral(conn, pathname,max_referral_level,ppdata)) < 0)
+               return UNIXERROR(ERRDOS,ERRbadfile);
     
        SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
        send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size);
@@ -3162,7 +3878,12 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf,
 {
        char *pdata = *ppdata;
        files_struct *fsp = file_fsp(inbuf,smb_vwv15);
+
+       /* check for an invalid fid before proceeding */
        
+       if (!fsp)                                
+               return(ERROR_DOS(ERRDOS,ERRbadfid));  
+
        if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
                        (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
                pdata = Realloc(*ppdata, 32);
@@ -3340,7 +4061,8 @@ int reply_trans2(connection_struct *conn,
                unsigned int psoff = SVAL(inbuf, smb_psoff);
                if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
                        goto bad_param;
-               if (smb_base(inbuf) + psoff + num_params > inbuf + length)
+               if ((smb_base(inbuf) + psoff + num_params > inbuf + length) ||
+                               (smb_base(inbuf) + psoff + num_params < smb_base(inbuf)))
                        goto bad_param;
                memcpy( params, smb_base(inbuf) + psoff, num_params);
        }
@@ -3348,15 +4070,19 @@ int reply_trans2(connection_struct *conn,
                unsigned int dsoff = SVAL(inbuf, smb_dsoff);
                if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
                        goto bad_param;
-               if (smb_base(inbuf) + dsoff + num_data > inbuf + length)
+               if ((smb_base(inbuf) + dsoff + num_data > inbuf + length) ||
+                               (smb_base(inbuf) + dsoff + num_data < smb_base(inbuf)))
                        goto bad_param;
                memcpy( data, smb_base(inbuf) + dsoff, num_data);
        }
 
+       srv_signing_trans_start(SVAL(inbuf,smb_mid));
+
        if(num_data_sofar < total_data || num_params_sofar < total_params)  {
                /* We need to send an interim response then receive the rest
                   of the parameter/data bytes */
                outsize = set_message(outbuf,0,0,True);
+               srv_signing_trans_stop();
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server("reply_trans2: send_smb failed.");
 
@@ -3370,6 +4096,13 @@ int reply_trans2(connection_struct *conn,
 
                        ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
                        
+                       /*
+                        * The sequence number for the trans reply is always
+                        * based on the last secondary received.
+                        */
+
+                       srv_signing_trans_start(SVAL(inbuf,smb_mid));
+
                        if ((ret && 
                             (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) {
                                outsize = set_message(outbuf,0,0,True);
@@ -3407,7 +4140,10 @@ int reply_trans2(connection_struct *conn,
                                if ((param_disp + num_params < param_disp) ||
                                                (param_disp + num_params < num_params))
                                        goto bad_param;
-                               if (smb_base(inbuf) + param_off + num_params >= inbuf + bufsize)
+                               if (param_disp > total_params)
+                                       goto bad_param;
+                               if ((smb_base(inbuf) + param_off + num_params >= inbuf + bufsize) ||
+                                               (smb_base(inbuf) + param_off + num_params < smb_base(inbuf)))
                                        goto bad_param;
                                if (params + param_disp < params)
                                        goto bad_param;
@@ -3420,7 +4156,10 @@ int reply_trans2(connection_struct *conn,
                                if ((data_disp + num_data < data_disp) ||
                                                (data_disp + num_data < num_data))
                                        goto bad_param;
-                               if (smb_base(inbuf) + data_off + num_data >= inbuf + bufsize)
+                               if (data_disp > total_data)
+                                       goto bad_param;
+                               if ((smb_base(inbuf) + data_off + num_data >= inbuf + bufsize) ||
+                                               (smb_base(inbuf) + data_off + num_data < smb_base(inbuf)))
                                        goto bad_param;
                                if (data + data_disp < data)
                                        goto bad_param;
@@ -3525,6 +4264,7 @@ int reply_trans2(connection_struct *conn,
                SAFE_FREE(params);
                SAFE_FREE(data);
                END_PROFILE(SMBtrans2);
+               srv_signing_trans_stop();
                return ERROR_DOS(ERRSRV,ERRerror);
        }
        
@@ -3535,6 +4275,8 @@ int reply_trans2(connection_struct *conn,
           an error packet. 
        */
        
+       srv_signing_trans_stop();
+
        SAFE_FREE(params);
        SAFE_FREE(data);
        END_PROFILE(SMBtrans2);
@@ -3544,6 +4286,7 @@ int reply_trans2(connection_struct *conn,
 
   bad_param:
 
+       srv_signing_trans_stop();
        SAFE_FREE(params);
        SAFE_FREE(data);
        END_PROFILE(SMBtrans2);