s3:smbd: allow status code in smbd_do_qfsinfo() to be set by information class handler
[metze/samba/wip.git] / source3 / smbd / trans2.c
index 682b3c4e4ff4a25e95bef914d020e67357cc693b..76176620800e2fcd06840e7f4ba87a1c77c7740d 100644 (file)
@@ -67,6 +67,7 @@ NTSTATUS check_access(connection_struct *conn,
        } else {
                NTSTATUS status = smbd_check_access_rights(conn,
                                        smb_fname,
+                                       false,
                                        access_mask);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
@@ -312,8 +313,8 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
  Return a linked list of the total EA's. Plus the total size
 ****************************************************************************/
 
-static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
-                                       const char *fname, size_t *pea_total_len)
+static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+                                     const char *fname, size_t *pea_total_len, struct ea_list **ea_list)
 {
        /* Get a list of all xattrs. Max namesize is 64k. */
        size_t i, num_names;
@@ -322,16 +323,18 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str
        NTSTATUS status;
 
        *pea_total_len = 0;
-
-       if (!lp_ea_support(SNUM(conn))) {
-               return NULL;
-       }
+       *ea_list = NULL;
 
        status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
                                        &names, &num_names);
 
-       if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
-               return NULL;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (num_names == 0) {
+               *ea_list = NULL;
+               return NT_STATUS_OK;
        }
 
        for (i=0; i<num_names; i++) {
@@ -342,15 +345,36 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str
                    || samba_private_attr_name(names[i]))
                        continue;
 
+               /*
+                * Filter out any underlying POSIX EA names
+                * that a Windows client can't handle.
+                */
+               if (!lp_posix_pathnames() &&
+                               is_invalid_windows_ea_name(names[i])) {
+                       continue;
+               }
+
                listp = talloc(mem_ctx, struct ea_list);
                if (listp == NULL) {
-                       return NULL;
+                       return NT_STATUS_NO_MEMORY;
                }
 
-               if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
-                                                 fname, names[i],
-                                                 &listp->ea))) {
-                       return NULL;
+               status = get_ea_value(listp, conn, fsp,
+                                     fname, names[i],
+                                     &listp->ea);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(listp);
+                       return status;
+               }
+
+               if (listp->ea.value.length == 0) {
+                       /*
+                        * We can never return a zero length EA.
+                        * Windows reports the EA's as corrupted.
+                        */
+                       TALLOC_FREE(listp);
+                       continue;
                }
 
                push_ascii_fstring(dos_ea_name, listp->ea.name);
@@ -374,7 +398,25 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str
        DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
                   (unsigned int)*pea_total_len));
 
-       return ea_list_head;
+       *ea_list = ea_list_head;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+                                     const struct smb_filename *smb_fname, size_t *pea_total_len, struct ea_list **ea_list)
+{
+       *pea_total_len = 0;
+       *ea_list = NULL;
+
+       if (!lp_ea_support(SNUM(conn))) {
+               return NT_STATUS_OK;
+       }
+
+       if (is_ntfs_stream_smb_fname(smb_fname)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       return get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, pea_total_len, ea_list);
 }
 
 /****************************************************************************
@@ -436,6 +478,7 @@ static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
 {
        uint8_t *p = (uint8_t *)pdata;
        uint8_t *last_start = NULL;
+       bool do_store_data = (pdata != NULL);
 
        *ret_data_size = 0;
 
@@ -447,8 +490,9 @@ static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
                size_t dos_namelen;
                fstring dos_ea_name;
                size_t this_size;
+               size_t pad = 0;
 
-               if (last_start) {
+               if (last_start != NULL && do_store_data) {
                        SIVAL(last_start, 0, PTR_DIFF(p, last_start));
                }
                last_start = p;
@@ -465,23 +509,30 @@ static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
                this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
 
                if (ea_list->next) {
-                       size_t pad = 4 - (this_size % 4);
+                       pad = (4 - (this_size % 4)) % 4;
                        this_size += pad;
                }
 
-               if (this_size > total_data_size) {
-                       return NT_STATUS_INFO_LENGTH_MISMATCH;
+               if (do_store_data) {
+                       if (this_size > total_data_size) {
+                               return NT_STATUS_INFO_LENGTH_MISMATCH;
+                       }
+
+                       /* We know we have room. */
+                       SIVAL(p, 0x00, 0); /* next offset */
+                       SCVAL(p, 0x04, ea_list->ea.flags);
+                       SCVAL(p, 0x05, dos_namelen);
+                       SSVAL(p, 0x06, ea_list->ea.value.length);
+                       strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
+                       memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
+                       if (pad) {
+                               memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
+                                       '\0',
+                                       pad);
+                       }
+                       total_data_size -= this_size;
                }
 
-               /* We know we have room. */
-               SIVAL(p, 0x00, 0); /* next offset */
-               SCVAL(p, 0x04, ea_list->ea.flags);
-               SCVAL(p, 0x05, dos_namelen);
-               SSVAL(p, 0x06, ea_list->ea.value.length);
-               strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
-               memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
-
-               total_data_size -= this_size;
                p += this_size;
        }
 
@@ -490,16 +541,46 @@ static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
-static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
+static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname)
 {
        size_t total_ea_len = 0;
-       TALLOC_CTX *mem_ctx = NULL;
+       TALLOC_CTX *mem_ctx;
+       struct ea_list *ea_list = NULL;
 
        if (!lp_ea_support(SNUM(conn))) {
                return 0;
        }
-       mem_ctx = talloc_tos();
-       (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
+       mem_ctx = talloc_stackframe();
+
+       /* If this is a stream fsp, then we need to instead find the
+        * estimated ea len from the main file, not the stream
+        * (streams cannot have EAs), but the estimate isn't just 0 in
+        * this case! */
+       if (is_ntfs_stream_smb_fname(smb_fname)) {
+               fsp = NULL;
+       }
+       (void)get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, &total_ea_len, &ea_list);
+       if(conn->sconn->using_smb2) {
+               NTSTATUS status;
+               unsigned int ret_data_size;
+               /*
+                * We're going to be using fill_ea_chained_buffer() to
+                * marshall EA's - this size is significantly larger
+                * than the SMB1 buffer. Re-calculate the size without
+                * marshalling.
+                */
+               status = fill_ea_chained_buffer(mem_ctx,
+                                               NULL,
+                                               0,
+                                               &ret_data_size,
+                                               conn,
+                                               ea_list);
+               if (!NT_STATUS_IS_OK(status)) {
+                       ret_data_size = 0;
+               }
+               total_ea_len = ret_data_size;
+       }
+       TALLOC_FREE(mem_ctx);
        return total_ea_len;
 }
 
@@ -511,7 +592,11 @@ static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, con
 {
        size_t total_ea_len;
        TALLOC_CTX *mem_ctx = talloc_tos();
-       struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
+       struct ea_list *ea_list;
+       NTSTATUS status = get_ea_list_from_file_path(mem_ctx, conn, fsp, fname, &total_ea_len, &ea_list);
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
 
        for (; ea_list; ea_list = ea_list->next) {
                if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
@@ -542,7 +627,20 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                return status;
        }
 
-       /* For now setting EAs on streams isn't supported. */
+       /* Setting EAs on streams isn't supported. */
+       if (is_ntfs_stream_smb_fname(smb_fname)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /*
+        * Filter out invalid Windows EA names - before
+        * we set *any* of them.
+        */
+
+       if (ea_list_has_invalid_name(ea_list)) {
+               return STATUS_INVALID_EA_NAME;
+       }
+
        fname = smb_fname->base_name;
 
        for (;ea_list; ea_list = ea_list->next) {
@@ -798,6 +896,7 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *
 
 void send_trans2_replies(connection_struct *conn,
                        struct smb_request *req,
+                       NTSTATUS status,
                         const char *params,
                         int paramsize,
                         const char *pdata,
@@ -838,6 +937,14 @@ void send_trans2_replies(connection_struct *conn,
 
        if(params_to_send == 0 && data_to_send == 0) {
                reply_outbuf(req, 10, 0);
+               if (NT_STATUS_V(status)) {
+                       uint8_t eclass;
+                       uint32_t ecode;
+                       ntstatus_to_dos(status, &eclass, &ecode);
+                       error_packet_set((char *)req->outbuf,
+                                       eclass, ecode, status,
+                                       __LINE__,__FILE__);
+               }
                show_msg((char *)req->outbuf);
                if (!srv_send_smb(sconn,
                                (char *)req->outbuf,
@@ -968,6 +1075,13 @@ void send_trans2_replies(connection_struct *conn,
                                         ERRDOS,ERRbufferoverflow,
                                         STATUS_BUFFER_OVERFLOW,
                                         __LINE__,__FILE__);
+               } else if (NT_STATUS_V(status)) {
+                       uint8_t eclass;
+                       uint32_t ecode;
+                       ntstatus_to_dos(status, &eclass, &ecode);
+                       error_packet_set((char *)req->outbuf,
+                                       eclass, ecode, status,
+                                       __LINE__,__FILE__);
                }
 
                /* Send the packet */
@@ -1139,6 +1253,20 @@ static void call_trans2open(connection_struct *conn,
                        reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
                        goto out;
                }
+
+               if (ea_list_has_invalid_name(ea_list)) {
+                       int param_len = 30;
+                       *pparams = (char *)SMB_REALLOC(*pparams, param_len);
+                       if(*pparams == NULL ) {
+                               reply_nterror(req, NT_STATUS_NO_MEMORY);
+                               goto out;
+                       }
+                       params = *pparams;
+                       memset(params, '\0', param_len);
+                       send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
+                               params, param_len, NULL, 0, max_data_bytes);
+                       goto out;
+               }
        }
 
        status = SMB_VFS_CREATE_FILE(
@@ -1207,14 +1335,14 @@ static void call_trans2open(connection_struct *conn,
        SSVAL(params,24,0); /* Padding. */
        if (flags & 8) {
                uint32 ea_size = estimate_ea_size(conn, fsp,
-                                                 fsp->fsp_name->base_name);
+                                                 smb_fname);
                SIVAL(params, 26, ea_size);
        } else {
                SIVAL(params, 26, 0);
        }
 
        /* Send the required number of replies */
-       send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
  out:
        TALLOC_FREE(smb_fname);
 }
@@ -1325,28 +1453,18 @@ static NTSTATUS unix_perms_from_wire( connection_struct *conn,
 
        switch (ptype) {
        case PERM_NEW_FILE:
+       case PERM_EXISTING_FILE:
                /* Apply mode mask */
                ret &= lp_create_mask(SNUM(conn));
                /* Add in force bits */
                ret |= lp_force_create_mode(SNUM(conn));
                break;
        case PERM_NEW_DIR:
+       case PERM_EXISTING_DIR:
                ret &= lp_dir_mask(SNUM(conn));
                /* Add in force bits */
                ret |= lp_force_dir_mode(SNUM(conn));
                break;
-       case PERM_EXISTING_FILE:
-               /* Apply mode mask */
-               ret &= lp_security_mask(SNUM(conn));
-               /* Add in force bits */
-               ret |= lp_force_security_mode(SNUM(conn));
-               break;
-       case PERM_EXISTING_DIR:
-               /* Apply mode mask */
-               ret &= lp_dir_security_mask(SNUM(conn));
-               /* Add in force bits */
-               ret |= lp_force_dir_security_mode(SNUM(conn));
-               break;
        }
 
        *ret_perms = ret;
@@ -1654,7 +1772,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SSVAL(p,20,mode);
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                               smb_fname->base_name);
+                                                               smb_fname);
                        SIVAL(p,22,ea_size); /* Extended attributes */
                }
                p += 27;
@@ -1684,6 +1802,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        {
                struct ea_list *file_list = NULL;
                size_t ea_len = 0;
+               NTSTATUS status;
 
                DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
                if (!name_list) {
@@ -1701,9 +1820,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SSVAL(p,20,mode);
                p += 22; /* p now points to the EA area. */
 
-               file_list = get_ea_list_from_file(ctx, conn, NULL,
-                                                 smb_fname->base_name,
-                                                 &ea_len);
+               status = get_ea_list_from_file(ctx, conn, NULL,
+                                              smb_fname,
+                                              &ea_len, &file_list);
+               if (!NT_STATUS_IS_OK(status)) {
+                       file_list = NULL;
+               }
                name_list = ea_list_union(name_list, file_list, &ea_len);
 
                /* We need to determine if this entry will fit in the space available. */
@@ -1757,7 +1879,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                               smb_fname->base_name);
+                                                               smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
                        p += 4;
                }
@@ -1859,7 +1981,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                               smb_fname->base_name);
+                                                               smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
                        p +=4;
                }
@@ -1934,7 +2056,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                q = p; p += 4; /* q is placeholder for name length. */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                               smb_fname->base_name);
+                                                               smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
                        p +=4;
                }
@@ -1980,7 +2102,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                q = p; p += 4; /* q is placeholder for name length */
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
-                                                               smb_fname->base_name);
+                                                               smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
                        p +=4;
                }
@@ -2442,6 +2564,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto out;
+       }
+
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if(*ppdata == NULL ) {
@@ -2495,8 +2622,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-               directory,lp_dontdescend(SNUM(conn))));
-       if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+                directory,lp_dontdescend(ctx, SNUM(conn))));
+       if (in_list(directory,lp_dontdescend(ctx, SNUM(conn)),conn->case_sensitive))
                dont_descend = True;
 
        p = pdata;
@@ -2584,7 +2711,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        SSVAL(params,6,0); /* Never an EA error */
        SSVAL(params,8,last_entry_off);
 
-       send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
                            max_data_bytes);
 
        if ((! *directory) && dptr_path(sconn, dptr_num)) {
@@ -2771,6 +2898,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if(*ppdata == NULL) {
@@ -2824,8 +2956,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                directory,lp_dontdescend(SNUM(conn))));
-       if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+                directory,lp_dontdescend(ctx, SNUM(conn))));
+       if (in_list(directory,lp_dontdescend(ctx, SNUM(conn)),conn->case_sensitive))
                dont_descend = True;
 
        p = pdata;
@@ -2935,7 +3067,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        SSVAL(params,4,0); /* Never an EA error */
        SSVAL(params,6,last_entry_off);
 
-       send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata),
                            max_data_bytes);
 
        return;
@@ -2943,7 +3075,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
 {
-       E_md4hash(lp_servicename(SNUM(conn)),objid);
+       E_md4hash(lp_servicename(talloc_tos(), SNUM(conn)),objid);
        return objid;
 }
 
@@ -2987,17 +3119,26 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                         uint16_t info_level,
                         uint16_t flags2,
                         unsigned int max_data_bytes,
+                        struct smb_filename *fname,
                         char **ppdata,
                         int *ret_data_len)
 {
        char *pdata, *end_data;
        int data_len = 0, len;
-       const char *vname = volume_label(SNUM(conn));
+       const char *vname = volume_label(talloc_tos(), SNUM(conn));
        int snum = SNUM(conn);
-       char *fstype = lp_fstype(SNUM(conn));
+       char *fstype = lp_fstype(talloc_tos(), SNUM(conn));
+       char *filename = NULL;
        uint32 additional_flags = 0;
-       struct smb_filename smb_fname_dot;
+       struct smb_filename smb_fname;
        SMB_STRUCT_STAT st;
+       NTSTATUS status = NT_STATUS_OK;
+
+       if (fname == NULL || fname->base_name == NULL) {
+               filename = ".";
+       } else {
+               filename = fname->base_name;
+       }
 
        if (IS_IPC(conn)) {
                if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
@@ -3010,15 +3151,19 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 
        DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
 
-       ZERO_STRUCT(smb_fname_dot);
-       smb_fname_dot.base_name = discard_const_p(char, ".");
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, filename);
 
-       if(SMB_VFS_STAT(conn, &smb_fname_dot) != 0) {
+       if(SMB_VFS_STAT(conn, &smb_fname) != 0) {
                DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
                return map_nt_error_from_unix(errno);
        }
 
-       st = smb_fname_dot.st;
+       st = smb_fname.st;
+
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
@@ -3035,7 +3180,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 18;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
 
@@ -3073,7 +3218,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                         * Add volume serial number - hash of a combination of
                         * the called hostname and the service name.
                         */
-                       SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
+                       SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), snum)) ^ (str_checksum(get_local_machine_name())<<16) );
                        /*
                         * Win2k3 and previous mess this up by sending a name length
                         * one byte short. I believe only older clients (OS/2 Win9x) use
@@ -3139,7 +3284,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                         * Add volume serial number - hash of a combination of
                         * the called hostname and the service name.
                         */
-                       SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ 
+                       SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), snum)) ^
                                (str_checksum(get_local_machine_name())<<16));
 
                        /* Max label len is 32 characters. */
@@ -3150,7 +3295,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                        data_len = 18+len;
 
                        DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
-                               (int)strlen(vname),vname, lp_servicename(snum)));
+                               (int)strlen(vname),vname,
+                               lp_servicename(talloc_tos(), snum)));
                        break;
 
                case SMB_QUERY_FS_SIZE_INFO:
@@ -3158,7 +3304,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 24;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3190,7 +3336,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 32;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3271,20 +3417,20 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        if (get_current_uid(conn) != 0) {
                                DEBUG(0,("set_user_quota: access_denied "
                                         "service [%s] user [%s]\n",
-                                        lp_servicename(SNUM(conn)),
+                                        lp_servicename(talloc_tos(), SNUM(conn)),
                                         conn->session_info->unix_info->unix_name));
                                return NT_STATUS_ACCESS_DENIED;
                        }
 
                        if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
-                               DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+                               DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
                                return map_nt_error_from_unix(errno);
                        }
 
                        data_len = 48;
 
                        DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
-                                 lp_servicename(SNUM(conn))));
+                                 lp_servicename(talloc_tos(), SNUM(conn))));
 
                        /* Unknown1 24 NULL bytes*/
                        SBIG_UINT(pdata,0,(uint64_t)0);
@@ -3339,14 +3485,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        }
 
                        switch (conn->encrypt_level) {
-                       case 0:
+                       case SMB_SIGNING_OFF:
                                encrypt_caps = 0;
                                break;
-                       case 1:
-                       case Auto:
+                       case SMB_SIGNING_IF_REQUIRED:
+                       case SMB_SIGNING_DEFAULT:
                                encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
                                break;
-                       case Required:
+                       case SMB_SIGNING_REQUIRED:
                                encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
                                                CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
                                large_write = false;
@@ -3383,7 +3529,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                return NT_STATUS_INVALID_LEVEL;
                        }
 
-                       rc = SMB_VFS_STATVFS(conn, ".", &svfs);
+                       rc = SMB_VFS_STATVFS(conn, filename, &svfs);
 
                        if (!rc) {
                                data_len = 56;
@@ -3401,7 +3547,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                return NT_STATUS_INVALID_LEVEL;
 #endif /* EOPNOTSUPP */
                        } else {
-                               DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+                               DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
                                return NT_STATUS_DOS(ERRSRV, ERRerror);
                        }
                        break;
@@ -3511,7 +3657,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                         * Thursby MAC extension... ONLY on NTFS filesystems
                         * once we do streams then we don't need this
                         */
-                       if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
+                       if (strequal(lp_fstype(talloc_tos(), SNUM(conn)),"NTFS")) {
                                data_len = 88;
                                SIVAL(pdata,84,0x100); /* Don't support mac... */
                                break;
@@ -3522,7 +3668,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
        }
 
        *ret_data_len = data_len;
-       return NT_STATUS_OK;
+       return status;
 }
 
 /****************************************************************************
@@ -3552,8 +3698,7 @@ static void call_trans2qfsinfo(connection_struct *conn,
                        DEBUG(0,("call_trans2qfsinfo: encryption required "
                                "and info level 0x%x sent.\n",
                                (unsigned int)info_level));
-                       exit_server_cleanly("encryption required "
-                               "on connection");
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        return;
                }
        }
@@ -3564,13 +3709,14 @@ static void call_trans2qfsinfo(connection_struct *conn,
                                 info_level,
                                 req->flags2,
                                 max_data_bytes,
+                                NULL,
                                 ppdata, &data_len);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
        }
 
-       send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
                            max_data_bytes);
 
        DEBUG( 4, ( "%s info_level = %d\n",
@@ -3594,7 +3740,8 @@ static void call_trans2setfsinfo(connection_struct *conn,
        char *params = *pparams;
        uint16 info_level;
 
-       DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
+       DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
+                 lp_servicename(talloc_tos(), SNUM(conn))));
 
        /*  */
        if (total_params < 4) {
@@ -3622,8 +3769,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                        DEBUG(0,("call_trans2setfsinfo: encryption required "
                                "and info level 0x%x sent.\n",
                                (unsigned int)info_level));
-                       exit_server_cleanly("encryption required "
-                               "on connection");
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                        return;
                }
        }
@@ -3693,7 +3839,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                        return;
                                }
 
-                               if (lp_smb_encrypt(SNUM(conn)) == false) {
+                               if (lp_smb_encrypt(SNUM(conn)) == SMB_SIGNING_OFF) {
                                        reply_nterror(
                                                req,
                                                NT_STATUS_NOT_SUPPORTED);
@@ -3726,6 +3872,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                }
 
                                send_trans2_replies(conn, req,
+                                               NT_STATUS_OK,
                                                *pparams,
                                                param_len,
                                                *ppdata,
@@ -3757,7 +3904,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                /* access check */
                                if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
                                        DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
-                                                lp_servicename(SNUM(conn)),
+                                                lp_servicename(talloc_tos(), SNUM(conn)),
                                                 conn->session_info->unix_info->unix_name));
                                        reply_nterror(req, NT_STATUS_ACCESS_DENIED);
                                        return;
@@ -3801,7 +3948,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
 
                                /* now set the quotas */
                                if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
-                                       DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+                                       DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
                                        reply_nterror(req, map_nt_error_from_unix(errno));
                                        return;
                                }
@@ -3836,7 +3983,7 @@ static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_a
        int entry_id = SMB_ACL_FIRST_ENTRY;
        SMB_ACL_ENTRY_T entry;
 
-       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+       while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
                /* get_next... */
                if (entry_id == SMB_ACL_FIRST_ENTRY) {
                        entry_id = SMB_ACL_NEXT_ENTRY;
@@ -3855,7 +4002,7 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
        int entry_id = SMB_ACL_FIRST_ENTRY;
        SMB_ACL_ENTRY_T entry;
 
-       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+       while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
                SMB_ACL_TAG_T tagtype;
                SMB_ACL_PERMSET_T permset;
                unsigned char perms = 0;
@@ -3866,19 +4013,19 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
                        entry_id = SMB_ACL_NEXT_ENTRY;
                }
 
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+               if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
                        DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
                        return False;
                }
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+               if (sys_acl_get_permset(entry, &permset) == -1) {
                        DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
                        return False;
                }
 
-               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
-               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
-               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
+               perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
+               perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
+               perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
 
                SCVAL(pdata,1,perms);
 
@@ -3891,13 +4038,12 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
                                break;
                        case SMB_ACL_USER:
                                {
-                                       uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
                                        if (!puid) {
                                                DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
                                                return False;
                                        }
                                        own_grp = (unsigned int)*puid;
-                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
                                        SCVAL(pdata,0,SMB_POSIX_ACL_USER);
                                        SIVAL(pdata,2,own_grp);
                                        SIVAL(pdata,6,0);
@@ -3911,13 +4057,12 @@ static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
                                break;
                        case SMB_ACL_GROUP:
                                {
-                                       gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
                                        if (!pgid) {
                                                DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
                                                return False;
                                        }
                                        own_grp = (unsigned int)*pgid;
-                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
                                        SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
                                        SIVAL(pdata,2,own_grp);
                                        SIVAL(pdata,6,0);
@@ -4127,7 +4272,7 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
        unsigned int i;
        unsigned int ofs = 0;
 
-       for (i = 0; i < num_streams && ofs <= max_data_bytes; i++) {
+       for (i = 0; i < num_streams; i++) {
                unsigned int next_offset;
                size_t namelen;
                smb_ucs2_t *namebuf;
@@ -4146,6 +4291,16 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
 
                namelen -= 2;
 
+               /*
+                * We cannot overflow ...
+                */
+               if ((ofs + 24 + namelen) > max_data_bytes) {
+                       DEBUG(10, ("refusing to overflow reply at stream %u\n",
+                               i));
+                       TALLOC_FREE(namebuf);
+                       return STATUS_BUFFER_OVERFLOW;
+               }
+
                SIVAL(data, ofs+4, namelen);
                SOFF_T(data, ofs+8, streams[i].size);
                SOFF_T(data, ofs+16, streams[i].alloc_size);
@@ -4160,6 +4315,14 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
                else {
                        unsigned int align = ndr_align_size(next_offset, 8);
 
+                       if ((next_offset + align) > max_data_bytes) {
+                               DEBUG(10, ("refusing to overflow align "
+                                       "reply at stream %u\n",
+                                       i));
+                               TALLOC_FREE(namebuf);
+                               return STATUS_BUFFER_OVERFLOW;
+                       }
+
                        memset(data+next_offset, 0, align);
                        next_offset += align;
 
@@ -4170,6 +4333,8 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
                ofs = next_offset;
        }
 
+       DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));
+
        *data_size = ofs;
 
        return NT_STATUS_OK;
@@ -4218,6 +4383,10 @@ static void call_trans2qpipeinfo(connection_struct *conn,
        }
        params = *pparams;
        SSVAL(params,0,0);
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
        *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
        if (*ppdata == NULL ) {
@@ -4240,7 +4409,7 @@ static void call_trans2qpipeinfo(connection_struct *conn,
                        return;
        }
 
-       send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
                            max_data_bytes);
 
        return;
@@ -4299,6 +4468,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                nlink -= 1;
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
        *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
        if (*ppdata == NULL) {
@@ -4410,7 +4583,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                {
                        unsigned int ea_size =
                            estimate_ea_size(conn, fsp,
-                                            smb_fname->base_name);
+                                            smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
                        data_size = 26;
                        srv_put_dos_date2(pdata,0,create_time);
@@ -4437,13 +4610,16 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                {
                        size_t total_ea_len = 0;
                        struct ea_list *ea_file_list = NULL;
-
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
 
-                       ea_file_list =
+                       status =
                            get_ea_list_from_file(mem_ctx, conn, fsp,
-                                                 smb_fname->base_name,
-                                                 &total_ea_len);
+                                                 smb_fname,
+                                                 &total_ea_len, &ea_file_list);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
+
                        ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
 
                        if (!ea_list || (total_ea_len > data_size)) {
@@ -4460,12 +4636,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                {
                        /* We have data_size bytes to put EA's into. */
                        size_t total_ea_len = 0;
-
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
 
-                       ea_list = get_ea_list_from_file(mem_ctx, conn, fsp,
-                                                       smb_fname->base_name,
-                                                       &total_ea_len);
+                       status = get_ea_list_from_file(mem_ctx, conn, fsp,
+                                                       smb_fname,
+                                                       &total_ea_len, &ea_list);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
+
                        if (!ea_list || (total_ea_len > data_size)) {
                                data_size = 4;
                                SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
@@ -4489,10 +4668,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                        /*TODO: add filtering and index handling */
 
-                       ea_file_list =
-                           get_ea_list_from_file(mem_ctx, conn, fsp,
-                                                 smb_fname->base_name,
-                                                 &total_ea_len);
+                       status  =
+                               get_ea_list_from_file(mem_ctx, conn, fsp,
+                                                 smb_fname,
+                                                 &total_ea_len, &ea_file_list);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        if (!ea_file_list) {
                                return NT_STATUS_NO_EAS_ON_FILE;
                        }
@@ -4550,7 +4732,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                case SMB_QUERY_FILE_EA_INFO:
                {
                        unsigned int ea_size =
-                           estimate_ea_size(conn, fsp, smb_fname->base_name);
+                           estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
                        data_size = 4;
                        SIVAL(pdata,0,ea_size);
@@ -4612,7 +4794,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                {
                        int len;
                        unsigned int ea_size =
-                           estimate_ea_size(conn, fsp, smb_fname->base_name);
+                           estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
                        put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
                        put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
@@ -4644,7 +4826,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                {
                        int len;
                        unsigned int ea_size =
-                           estimate_ea_size(conn, fsp, smb_fname->base_name);
+                           estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
                        put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
                        put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
@@ -4760,6 +4942,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(10, ("marshall_stream_info failed: %s\n",
                                           nt_errstr(status)));
+                               TALLOC_FREE(streams);
                                return status;
                        }
 
@@ -4870,12 +5053,14 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                uint16 num_def_acls = 0;
 
                                if (fsp && fsp->fh->fd != -1) {
-                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
+                                               talloc_tos());
                                } else {
                                        file_acl =
                                            SMB_VFS_SYS_ACL_GET_FILE(conn,
                                                smb_fname->base_name,
-                                               SMB_ACL_TYPE_ACCESS);
+                                               SMB_ACL_TYPE_ACCESS,
+                                               talloc_tos());
                                }
 
                                if (file_acl == NULL && no_acl_syscall_error(errno)) {
@@ -4892,13 +5077,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                                    SMB_VFS_SYS_ACL_GET_FILE(
                                                            conn,
                                                            fsp->fsp_name->base_name,
-                                                           SMB_ACL_TYPE_DEFAULT);
+                                                           SMB_ACL_TYPE_DEFAULT,
+                                                           talloc_tos());
                                        } else {
                                                def_acl =
                                                    SMB_VFS_SYS_ACL_GET_FILE(
                                                            conn,
                                                            smb_fname->base_name,
-                                                           SMB_ACL_TYPE_DEFAULT);
+                                                           SMB_ACL_TYPE_DEFAULT,
+                                                           talloc_tos());
                                        }
                                        def_acl = free_empty_sys_acl(conn, def_acl);
                                }
@@ -4912,10 +5099,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                                (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
                                                        SMB_POSIX_ACL_HEADER_SIZE) ));
                                        if (file_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                               TALLOC_FREE(file_acl);
                                        }
                                        if (def_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                               TALLOC_FREE(def_acl);
                                        }
                                        return NT_STATUS_BUFFER_TOO_SMALL;
                                }
@@ -4925,28 +5112,28 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                SSVAL(pdata,4,num_def_acls);
                                if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
                                        if (file_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                               TALLOC_FREE(file_acl);
                                        }
                                        if (def_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                               TALLOC_FREE(def_acl);
                                        }
                                        return NT_STATUS_INTERNAL_ERROR;
                                }
                                if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
                                        if (file_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                               TALLOC_FREE(file_acl);
                                        }
                                        if (def_acl) {
-                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                               TALLOC_FREE(def_acl);
                                        }
                                        return NT_STATUS_INTERNAL_ERROR;
                                }
 
                                if (file_acl) {
-                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       TALLOC_FREE(file_acl);
                                }
                                if (def_acl) {
-                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       TALLOC_FREE(def_acl);
                                }
                                data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
                                break;
@@ -5101,10 +5288,9 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
-                                          &smb_fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       reply_nterror(req, status);
+               smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
+               if (smb_fname == NULL) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
                        return;
                }
 
@@ -5217,16 +5403,14 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                /* If this is a stream, check if there is a delete_pending. */
                if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
                    && is_ntfs_stream_smb_fname(smb_fname)) {
-                       struct smb_filename *smb_fname_base = NULL;
+                       struct smb_filename *smb_fname_base;
 
                        /* Create an smb_filename with stream_name == NULL. */
-                       status =
-                           create_synthetic_smb_fname(talloc_tos(),
-                                                      smb_fname->base_name,
-                                                      NULL, NULL,
-                                                      &smb_fname_base);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               reply_nterror(req, status);
+                       smb_fname_base = synthetic_smb_fname(
+                               talloc_tos(), smb_fname->base_name,
+                               NULL, NULL);
+                       if (smb_fname_base == NULL) {
+                               reply_nterror(req, NT_STATUS_NO_MEMORY);
                                return;
                        }
 
@@ -5431,7 +5615,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                return;
        }
 
-       send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
                            max_data_bytes);
 
        return;
@@ -5609,7 +5793,7 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
                                     const struct smb_filename *smb_fname,
                                     uint32 dosmode)
 {
-       struct smb_filename *smb_fname_base = NULL;
+       struct smb_filename *smb_fname_base;
        NTSTATUS status;
 
        if (!VALID_STAT(smb_fname->st)) {
@@ -5617,11 +5801,10 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
        }
 
        /* Always operate on the base_name, even if a stream was passed in. */
-       status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
-                                           NULL, &smb_fname->st,
-                                           &smb_fname_base);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       smb_fname_base = synthetic_smb_fname(
+               talloc_tos(), smb_fname->base_name, NULL, &smb_fname->st);
+       if (smb_fname_base == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
        if (dosmode) {
@@ -5698,9 +5881,9 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+       if (smb_fname_tmp == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
        smb_fname_tmp->st = *psbuf;
@@ -6083,10 +6266,11 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                }
 
                /* Create an smb_fname to call rename_internals_fsp() with. */
-               status = create_synthetic_smb_fname(talloc_tos(),
-                   fsp->base_fsp->fsp_name->base_name, newname, NULL,
-                   &smb_fname_dst);
-               if (!NT_STATUS_IS_OK(status)) {
+               smb_fname_dst = synthetic_smb_fname(
+                       talloc_tos(), fsp->base_fsp->fsp_name->base_name,
+                       newname, NULL);
+               if (smb_fname_dst == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
                        goto out;
                }
 
@@ -6252,10 +6436,11 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                }
 
                /* Create an smb_fname to call rename_internals_fsp() with. */
-               status = create_synthetic_smb_fname(talloc_tos(),
-                   fsp->base_fsp->fsp_name->base_name, newname, NULL,
-                   &smb_fname_dst);
-               if (!NT_STATUS_IS_OK(status)) {
+               smb_fname_dst = synthetic_smb_fname(
+                       talloc_tos(), fsp->base_fsp->fsp_name->base_name,
+                       newname, NULL);
+               if (smb_fname_dst == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
                        goto out;
                }
 
@@ -6323,11 +6508,10 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                                goto out;
                        }
                        /* Create an smb_fname to call rename_internals_fsp() */
-                       status = create_synthetic_smb_fname(ctx,
-                                                           base_name, NULL,
-                                                           NULL,
-                                                           &smb_fname_dst);
-                       if (!NT_STATUS_IS_OK(status)) {
+                       smb_fname_dst = synthetic_smb_fname(
+                               ctx, base_name, NULL, NULL);
+                       if (smb_fname_dst == NULL) {
+                               status = NT_STATUS_NO_MEMORY;
                                goto out;
                        }
                }
@@ -6939,10 +7123,9 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                        return status;
                }
 
-               status = copy_smb_filename(talloc_tos(), smb_fname,
-                                          &smb_fname_tmp);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
+               smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+               if (smb_fname_tmp == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
 
                if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
@@ -7337,12 +7520,19 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                        /* File exists open. File not exist create. */
                        create_disp = FILE_OPEN_IF;
                        break;
+               case SMB_O_EXCL:
+                       /* O_EXCL on its own without O_CREAT is undefined.
+                          We deliberately ignore it as some versions of
+                          Linux CIFSFS can send a bare O_EXCL on the
+                          wire which other filesystems in the kernel
+                          ignore. See bug 9519 for details. */
+
+                       /* Fallthrough. */
+
                case 0:
                        /* File exists open. File not exist fail. */
                        create_disp = FILE_OPEN;
                        break;
-               case SMB_O_EXCL:
-                       /* O_EXCL on its own without O_CREAT is undefined. */
                default:
                        DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
                                (unsigned int)wire_open_mode ));
@@ -7597,8 +7787,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                                continue;
                        }
                        /* Fail with sharing violation. */
-                       close_file(req, fsp, NORMAL_CLOSE);
                        TALLOC_FREE(lck);
+                       close_file(req, fsp, NORMAL_CLOSE);
                        return NT_STATUS_SHARING_VIOLATION;
                }
        }
@@ -7612,12 +7802,12 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                                                fsp,
                                                smb_fname);
 
+       TALLOC_FREE(lck);
+
        if (!NT_STATUS_IS_OK(status)) {
                close_file(req, fsp, NORMAL_CLOSE);
-               TALLOC_FREE(lck);
                return status;
        }
-       TALLOC_FREE(lck);
        return close_file(req, fsp, NORMAL_CLOSE);
 }
 
@@ -7943,10 +8133,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
                info_level = SVAL(params,2);
 
-               status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
-                                          &smb_fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       reply_nterror(req, status);
+               smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
+               if (smb_fname == NULL) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
                        return;
                }
 
@@ -7989,7 +8178,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                                         fsp_str_dbg(fsp)));
 
                                SSVAL(params,0,0);
-                               send_trans2_replies(conn, req, params, 2,
+                               send_trans2_replies(conn, req, NT_STATUS_OK, params, 2,
                                                    *ppdata, 0,
                                                    max_data_bytes);
                                return;
@@ -8112,11 +8301,20 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               reply_nterror(req, status);
+               /*
+                * Invalid EA name needs to return 2 param bytes,
+                * not a zero-length error packet.
+                */
+               if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
+                       send_trans2_replies(conn, req, status, params, 2, NULL, 0,
+                                       max_data_bytes);
+               } else {
+                       reply_nterror(req, status);
+               }
                return;
        }
 
-       send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, data_return_size,
                            max_data_bytes);
 
        return;
@@ -8241,7 +8439,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 
        SSVAL(params,0,0);
 
-       send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
 
  out:
        TALLOC_FREE(smb_dname);
@@ -8296,7 +8494,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn,
        if(fnf_handle == 0)
                fnf_handle = 257;
 
-       send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
 
        return;
 }
@@ -8327,7 +8525,7 @@ static void call_trans2findnotifynext(connection_struct *conn,
        SSVAL(params,0,0); /* No changes */
        SSVAL(params,2,0); /* No EA errors */
 
-       send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
+       send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
 
        return;
 }
@@ -8377,7 +8575,7 @@ static void call_trans2getdfsreferral(connection_struct *conn,
 
        SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
              SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
-       send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
+       send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
 
        return;
 }
@@ -8424,9 +8622,9 @@ static void call_trans2ioctl(connection_struct *conn,
                            lp_netbios_name(), 15,
                            STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
                srvstr_push(pdata, req->flags2, pdata+18,
-                           lp_servicename(SNUM(conn)), 13,
+                           lp_servicename(talloc_tos(), SNUM(conn)), 13,
                            STR_ASCII|STR_TERMINATE); /* Service name */
-               send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
+               send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
                                    max_data_bytes);
                return;
        }
@@ -8506,9 +8704,9 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
                SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
        }
 
-       if (conn->encrypt_level == Required && !req->encrypted) {
+       if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
                if (state->call != TRANSACT2_QFSINFO &&
-                               state->call != TRANSACT2_SETFSINFO) {
+                   state->call != TRANSACT2_SETFSINFO) {
                        DEBUG(0,("handle_trans2: encryption required "
                                "with call 0x%x\n",
                                (unsigned int)state->call));