X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fnttrans.c;h=f70fb36964e0d971f9a45ce635a380e1ba115c18;hb=b4bfcdf921aeee05c4608d7b48618fdfb1f134dc;hp=1d0c9614a9bedfbfc290defe19d61c06dcbb8356;hpb=0ec9a90c29b86435f32c1d47d89df85fa51742f2;p=samba.git diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 1d0c9614a9b..f70fb36964e 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -27,7 +27,6 @@ #include "../librpc/gen_ndr/ndr_security.h" #include "passdb/lookup_sid.h" #include "auth.h" -#include "ntioctl.h" #include "smbprofile.h" #include "libsmb/libsmb.h" @@ -143,11 +142,6 @@ static void send_nt_replies(connection_struct *conn, total_sent_thistime + alignment_offset + data_alignment_offset); - /* - * We might have had SMBnttranss in req->inbuf, fix that. - */ - SCVAL(req->outbuf, smb_com, SMBnttrans); - /* * Set total params and data to be sent. */ @@ -285,15 +279,17 @@ static void send_nt_replies(connection_struct *conn, ****************************************************************************/ static void nt_open_pipe(char *fname, connection_struct *conn, - struct smb_request *req, int *ppnum) + struct smb_request *req, uint16_t *ppnum) { files_struct *fsp; NTSTATUS status; DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname)); - /* Strip \\ off the name. */ - fname++; + /* Strip \\ off the name if present. */ + while (fname[0] == '\\') { + fname++; + } status = open_np_file(req, fname, &fsp); if (!NT_STATUS_IS_OK(status)) { @@ -318,7 +314,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn, struct smb_request *req) { char *fname = NULL; - int pnum = -1; + uint16_t pnum = FNUM_FIELD_INVALID; char *p = NULL; uint32 flags = IVAL(req->vwv+3, 1); TALLOC_CTX *ctx = talloc_tos(); @@ -344,7 +340,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We * return 50 words, but only set - * the wcnt to 42 ? It's definately + * the wcnt to 42 ? It's definitely * what happens on the wire.... */ reply_outbuf(req, 50, 0); @@ -353,6 +349,9 @@ static void do_ntcreate_pipe_open(connection_struct *conn, reply_outbuf(req, 34, 0); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + p = (char *)req->outbuf + smb_vwv2; p++; SSVAL(p,0,pnum); @@ -380,8 +379,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn, } DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname)); - - chain_reply(req); } struct case_semantics_state { @@ -451,7 +448,7 @@ void reply_ntcreate_and_X(struct smb_request *req) /* Breakout the oplock request bits so we can set the reply bits separately. */ uint32 fattr=0; - SMB_OFF_T file_len = 0; + off_t file_len = 0; int info = 0; files_struct *fsp = NULL; char *p = NULL; @@ -584,7 +581,7 @@ void reply_ntcreate_and_X(struct smb_request *req) &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call, no error. */ goto out; } @@ -626,7 +623,7 @@ void reply_ntcreate_and_X(struct smb_request *req) if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We * return 50 words, but only set - * the wcnt to 42 ? It's definately + * the wcnt to 42 ? It's definitely * what happens on the wire.... */ reply_outbuf(req, 50, 0); @@ -635,6 +632,9 @@ void reply_ntcreate_and_X(struct smb_request *req) reply_outbuf(req, 34, 0); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + p = (char *)req->outbuf + smb_vwv2; SCVAL(p, 0, oplock_granted); @@ -693,7 +693,7 @@ void reply_ntcreate_and_X(struct smb_request *req) if (flags & EXTENDED_RESPONSE_REQUIRED) { uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG); size_t num_names = 0; - unsigned int num_streams; + unsigned int num_streams = 0; struct stream_struct *streams = NULL; /* Do we have any EA's ? */ @@ -702,7 +702,7 @@ void reply_ntcreate_and_X(struct smb_request *req) if (NT_STATUS_IS_OK(status) && num_names) { file_status &= ~NO_EAS; } - status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, ctx, + status = vfs_streaminfo(conn, NULL, smb_fname->base_name, ctx, &num_streams, &streams); /* There is always one stream, ::$DATA. */ if (NT_STATUS_IS_OK(status) && num_streams > 1) { @@ -726,10 +726,9 @@ void reply_ntcreate_and_X(struct smb_request *req) SIVAL(p,0,perms); } - DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", - fsp->fnum, smb_fname_str_dbg(smb_fname))); + DEBUG(5,("reply_ntcreate_and_X: %s, open name = %s\n", + fsp_fnum_dbg(fsp), smb_fname_str_dbg(smb_fname))); - chain_reply(req); out: END_PROFILE(SMBntcreateX); return; @@ -747,7 +746,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn, { char *fname = NULL; char *params = *ppparams; - int pnum = -1; + uint16_t pnum = FNUM_FIELD_INVALID; char *p = NULL; NTSTATUS status; size_t param_len; @@ -831,20 +830,48 @@ static void do_nt_transact_create_pipe(connection_struct *conn, return; } +/********************************************************************* + Windows seems to do canonicalization of inheritance bits. Do the + same. +*********************************************************************/ + +static void canonicalize_inheritance_bits(struct security_descriptor *psd) +{ + bool set_auto_inherited = false; + + /* + * We need to filter out the + * SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ + * bits. If both are set we store SEC_DESC_DACL_AUTO_INHERITED + * as this alters whether SEC_ACE_FLAG_INHERITED_ACE is set + * when an ACE is inherited. Otherwise we zero these bits out. + * See: + * + * http://social.msdn.microsoft.com/Forums/eu/os_fileservices/thread/11f77b68-731e-407d-b1b3-064750716531 + * + * for details. + */ + + if ((psd->type & (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ)) + == (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ)) { + set_auto_inherited = true; + } + + psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ); + if (set_auto_inherited) { + psd->type |= SEC_DESC_DACL_AUTO_INHERITED; + } +} + /**************************************************************************** Internal fn to set security descriptors. ****************************************************************************/ -NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len, +NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd, uint32_t security_info_sent) { - struct security_descriptor *psd = NULL; NTSTATUS status; - if (sd_len == 0) { - return NT_STATUS_INVALID_PARAMETER; - } - if (!CAN_WRITE(fsp->conn)) { return NT_STATUS_ACCESS_DENIED; } @@ -853,12 +880,6 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len, return NT_STATUS_OK; } - status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - if (psd->owner_sid == NULL) { security_info_sent &= ~SECINFO_OWNER; } @@ -868,6 +889,12 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len, /* Ensure we have at least one thing set. */ if ((security_info_sent & (SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL)) == 0) { + if (security_info_sent & SECINFO_LABEL) { + /* Only consider SECINFO_LABEL if no other + bits are set. Just like W2K3 we don't + store this. */ + return NT_STATUS_OK; + } return NT_STATUS_INVALID_PARAMETER; } @@ -904,6 +931,8 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len, } } + canonicalize_inheritance_bits(psd); + if (DEBUGLEVEL >= 10) { DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp))); NDR_PRINT_DEBUG(security_descriptor, psd); @@ -916,6 +945,29 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len, return status; } +/**************************************************************************** + Internal fn to set security descriptors from a data blob. +****************************************************************************/ + +NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len, + uint32_t security_info_sent) +{ + struct security_descriptor *psd = NULL; + NTSTATUS status; + + if (sd_len == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return set_sd(fsp, psd, security_info_sent); +} + /**************************************************************************** Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. ****************************************************************************/ @@ -941,7 +993,19 @@ struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t if (next_offset == 0) { break; } + + /* Integer wrap protection for the increment. */ + if (offset + next_offset < offset) { + break; + } + offset += next_offset; + + /* Integer wrap protection for while loop. */ + if (offset + 4 < offset) { + break; + } + } return ea_list_head; @@ -964,7 +1028,7 @@ static void call_nt_transact_create(connection_struct *conn, char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ uint32 fattr=0; - SMB_OFF_T file_len = 0; + off_t file_len = 0; int info = 0; files_struct *fsp = NULL; char *p = NULL; @@ -1159,7 +1223,7 @@ static void call_nt_transact_create(connection_struct *conn, &info); /* pinfo */ if(!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call, no error. */ return; } @@ -1268,7 +1332,7 @@ static void call_nt_transact_create(connection_struct *conn, if (flags & EXTENDED_RESPONSE_REQUIRED) { uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG); size_t num_names = 0; - unsigned int num_streams; + unsigned int num_streams = 0; struct stream_struct *streams = NULL; /* Do we have any EA's ? */ @@ -1277,7 +1341,7 @@ static void call_nt_transact_create(connection_struct *conn, if (NT_STATUS_IS_OK(status) && num_names) { file_status &= ~NO_EAS; } - status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, ctx, + status = vfs_streaminfo(conn, NULL, smb_fname->base_name, ctx, &num_streams, &streams); /* There is always one stream, ::$DATA. */ if (NT_STATUS_IS_OK(status) && num_streams > 1) { @@ -1347,7 +1411,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, files_struct *fsp1,*fsp2; uint32 fattr; int info; - SMB_OFF_T ret=-1; + off_t ret=-1; NTSTATUS status = NT_STATUS_OK; char *parent; @@ -1462,7 +1526,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); TALLOC_FREE(parent); - if (ret < (SMB_OFF_T)smb_fname_src->st.st_ex_size) { + if (ret < (off_t)smb_fname_src->st.st_ex_size) { status = NT_STATUS_DISK_FULL; goto out; } @@ -1642,7 +1706,7 @@ void reply_ntrename(struct smb_request *req) } if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(req->mid)) { + if (open_was_deferred(req->sconn, req->mid)) { /* We have re-scheduled this call. */ goto out; } @@ -1733,7 +1797,7 @@ static void call_nt_transact_notify_change(connection_struct *conn, } } - if (fsp->notify->num_changes != 0) { + if (change_notify_fsp_has_changes(fsp)) { /* * We've got changes pending, respond immediately @@ -1853,6 +1917,7 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, { NTSTATUS status; struct security_descriptor *psd = NULL; + TALLOC_CTX *frame = talloc_stackframe(); /* * Get the permissions to return. @@ -1860,21 +1925,36 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, if ((security_info_wanted & SECINFO_SACL) && !(fsp->access_mask & SEC_FLAG_SYSTEM_SECURITY)) { + DEBUG(10, ("Access to SACL denied.\n")); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } if ((security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) && !(fsp->access_mask & SEC_STD_READ_CONTROL)) { + DEBUG(10, ("Access to DACL, OWNER, or GROUP denied.\n")); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } + if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER| + SECINFO_GROUP|SECINFO_SACL)) { + /* Don't return SECINFO_LABEL if anything else was + requested. See bug #8458. */ + security_info_wanted &= ~SECINFO_LABEL; + } + if (!lp_nt_acl_support(SNUM(conn))) { - status = get_null_nt_acl(mem_ctx, &psd); + status = get_null_nt_acl(frame, &psd); + } else if (security_info_wanted & SECINFO_LABEL) { + /* Like W2K3 return a null object. */ + status = get_null_nt_acl(frame, &psd); } else { status = SMB_VFS_FGET_NT_ACL( - fsp, security_info_wanted, &psd); + fsp, security_info_wanted, frame, &psd); } if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); return status; } @@ -1885,9 +1965,11 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, psd->group_sid = NULL; } if (!(security_info_wanted & SECINFO_DACL)) { + psd->type &= ~SEC_DESC_DACL_PRESENT; psd->dacl = NULL; } if (!(security_info_wanted & SECINFO_SACL)) { + psd->type &= ~SEC_DESC_SACL_PRESENT; psd->sacl = NULL; } @@ -1900,6 +1982,15 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, security_info_wanted & SECINFO_DACL) psd->type |= SEC_DESC_DACL_PRESENT; + if (security_info_wanted & SECINFO_LABEL) { + /* Like W2K3 return a null object. */ + psd->owner_sid = NULL; + psd->group_sid = NULL; + psd->dacl = NULL; + psd->sacl = NULL; + psd->type &= ~(SEC_DESC_DACL_PRESENT|SEC_DESC_SACL_PRESENT); + } + *psd_size = ndr_size_security_descriptor(psd, 0); DEBUG(3,("smbd_do_query_security_desc: sd_size = %lu.\n", @@ -1912,7 +2003,7 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, } if (max_data_count < *psd_size) { - TALLOC_FREE(psd); + TALLOC_FREE(frame); return NT_STATUS_BUFFER_TOO_SMALL; } @@ -1920,11 +2011,11 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, ppmarshalled_sd, psd_size); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(psd); + TALLOC_FREE(frame); return status; } - TALLOC_FREE(psd); + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -2073,7 +2164,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn, return; } - status = set_sd(fsp, (uint8 *)data, data_count, security_info_sent); + status = set_sd_blob(fsp, (uint8 *)data, data_count, security_info_sent); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -2096,12 +2187,16 @@ static void call_nt_transact_ioctl(connection_struct *conn, char **ppdata, uint32 data_count, uint32 max_data_count) { + NTSTATUS status; uint32 function; uint16 fidnum; files_struct *fsp; uint8 isFSctl; uint8 compfilter; + char *out_data = NULL; + uint32 out_data_len = 0; char *pdata = *ppdata; + TALLOC_CTX *ctx = talloc_tos(); if (setup_count != 8) { DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count)); @@ -2114,364 +2209,46 @@ static void call_nt_transact_ioctl(connection_struct *conn, isFSctl = CVAL(*ppsetup, 6); compfilter = CVAL(*ppsetup, 7); - DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", + DEBUG(10, ("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", function, fidnum, isFSctl, compfilter)); fsp=file_fsp(req, fidnum); - /* this check is done in each implemented function case for now - because I don't want to break anything... --metze - FSP_BELONGS_CONN(fsp,conn);*/ - SMB_PERFCOUNT_SET_IOCTL(&req->pcd, function); - - switch (function) { - case FSCTL_SET_SPARSE: - { - bool set_sparse = true; - NTSTATUS status; - - if (data_count >= 1 && pdata[0] == 0) { - set_sparse = false; - } - - DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X]set[%u]\n", - fidnum, set_sparse)); - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - status = file_set_sparse(conn, fsp, set_sparse); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(9,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n", - smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status))); - reply_nterror(req, status); - return; - } - - DEBUG(10,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n", - smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status))); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); + /* + * We don't really implement IOCTLs, especially on files. + */ + if (!isFSctl) { + DEBUG(10, ("isFSctl: 0x%02X indicates IOCTL, not FSCTL!\n", + isFSctl)); + reply_nterror(req, NT_STATUS_NOT_SUPPORTED); return; } - case FSCTL_CREATE_OR_GET_OBJECT_ID: - { - unsigned char objid[16]; - - /* This should return the object-id on this file. - * I think I'll make this be the inode+dev. JRA. - */ - DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum)); - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - data_count = 64; - pdata = nttrans_realloc(ppdata, data_count); - if (pdata == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - /* For backwards compatibility only store the dev/inode. */ - push_file_id_16(pdata, &fsp->file_id); - memcpy(pdata+16,create_volume_objectid(conn,objid),16); - push_file_id_16(pdata+32, &fsp->file_id); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, data_count); + /* Has to be for an open file! */ + if (!check_fsp_open(conn, req, fsp)) { return; } - case FSCTL_GET_REPARSE_POINT: - /* pretend this fail - my winXP does it like this - * --metze - */ - - DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT); - return; - - case FSCTL_SET_REPARSE_POINT: - /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case. - * --metze - */ - - DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum)); - reply_nterror(req, NT_STATUS_NOT_A_REPARSE_POINT); - return; - - case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/ - { - /* - * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots) - * and return their volume names. If max_data_count is 16, then it is just - * asking for the number of volumes and length of the combined names. - * - * pdata is the data allocated by our caller, but that uses - * total_data_count (which is 0 in our case) rather than max_data_count. - * Allocate the correct amount and return the pointer to let - * it be deallocated when we return. - */ - struct shadow_copy_data *shadow_data = NULL; - TALLOC_CTX *shadow_mem_ctx = NULL; - bool labels = False; - uint32 labels_data_count = 0; - uint32 i; - char *cur_pdata; - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (max_data_count < 16) { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n", - max_data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (max_data_count > 16) { - labels = True; - } - - shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA"); - if (shadow_mem_ctx == NULL) { - DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n")); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - shadow_data = TALLOC_ZERO_P(shadow_mem_ctx, - struct shadow_copy_data); - if (shadow_data == NULL) { - DEBUG(0,("TALLOC_ZERO() failed!\n")); - talloc_destroy(shadow_mem_ctx); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - shadow_data->mem_ctx = shadow_mem_ctx; - - /* - * Call the VFS routine to actually do the work. - */ - if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) { - talloc_destroy(shadow_data->mem_ctx); - if (errno == ENOSYS) { - DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", - conn->connectpath)); - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); - return; - } else { - DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", - conn->connectpath)); - reply_nterror(req, NT_STATUS_UNSUCCESSFUL); - return; - } - } - - labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2; - - if (!labels) { - data_count = 16; - } else { - data_count = 12+labels_data_count+4; - } - - if (max_data_countmem_ctx); - reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); - return; - } - - pdata = nttrans_realloc(ppdata, data_count); - if (pdata == NULL) { - talloc_destroy(shadow_data->mem_ctx); - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - cur_pdata = pdata; - - /* num_volumes 4 bytes */ - SIVAL(pdata,0,shadow_data->num_volumes); - - if (labels) { - /* num_labels 4 bytes */ - SIVAL(pdata,4,shadow_data->num_volumes); - } - - /* needed_data_count 4 bytes */ - SIVAL(pdata, 8, labels_data_count+4); - - cur_pdata+=12; - - DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n", - shadow_data->num_volumes, fsp_str_dbg(fsp))); - if (labels && shadow_data->labels) { - for (i=0;inum_volumes;i++) { - srvstr_push(pdata, req->flags2, - cur_pdata, shadow_data->labels[i], - 2*sizeof(SHADOW_COPY_LABEL), - STR_UNICODE|STR_TERMINATE); - cur_pdata+=2*sizeof(SHADOW_COPY_LABEL); - DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i])); - } - } - - talloc_destroy(shadow_data->mem_ctx); - - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, data_count); - - return; - } - - case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */ - { - /* pretend this succeeded - - * - * we have to send back a list with all files owned by this SID - * - * but I have to check that --metze - */ - struct dom_sid sid; - uid_t uid; - size_t sid_len; - - DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum)); - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (data_count < 8) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - sid_len = MIN(data_count-4,SID_MAX_SIZE); - - /* unknown 4 bytes: this is not the length of the sid :-( */ - /*unknown = IVAL(pdata,0);*/ - - if (!sid_parse(pdata+4,sid_len,&sid)) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - DEBUGADD(10, ("for SID: %s\n", sid_string_dbg(&sid))); - - if (!sid_to_uid(&sid, &uid)) { - DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n", - sid_string_dbg(&sid), - (unsigned long)sid_len)); - uid = (-1); - } - - /* we can take a look at the find source :-) - * - * find ./ -uid $uid -name '*' is what we need here - * - * - * and send 4bytes len and then NULL terminated unicode strings - * for each file - * - * but I don't know how to deal with the paged results - * (maybe we can hang the result anywhere in the fsp struct) - * - * we don't send all files at once - * and at the next we should *not* start from the beginning, - * so we have to cache the result - * - * --metze - */ - - /* this works for now... */ - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); - return; - } - case FSCTL_QUERY_ALLOCATED_RANGES: - { - /* FIXME: This is just a dummy reply, telling that all of the - * file is allocated. MKS cp needs that. - * Adding the real allocated ranges via FIEMAP on Linux - * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make - * this FSCTL correct for sparse files. - */ - NTSTATUS status; - uint64_t offset, length; - - if (!check_fsp_open(conn, req, fsp)) { - return; - } - - if (data_count != 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n", - data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (max_data_count < 16) { - DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_data_count(%u) < 16 is invalid!\n", - max_data_count)); - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - offset = BVAL(pdata,0); - length = BVAL(pdata,8); - - if (offset + length < offset) { - /* No 64-bit integer wrap. */ - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - status = vfs_stat_fsp(fsp); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } + SMB_PERFCOUNT_SET_IOCTL(&req->pcd, function); - if (offset > fsp->fsp_name->st.st_ex_size || - fsp->fsp_name->st.st_ex_size == 0 || - length == 0) { - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0); - } else { - uint64_t end = offset + length; - end = MIN(end, fsp->fsp_name->st.st_ex_size); - SBVAL(pdata,0,0); - SBVAL(pdata,8,end); - send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, - pdata, 16); - } - return; - } - case FSCTL_IS_VOLUME_DIRTY: - DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on FID[0x%04X] " - "(but not implemented)\n", (int)fidnum)); - /* - * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx - * says we have to respond with NT_STATUS_INVALID_PARAMETER - */ - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - default: - /* Only print this once... */ - if (!logged_ioctl_message) { - logged_ioctl_message = true; - DEBUG(2,("call_nt_transact_ioctl(0x%x): " - "Currently not implemented.\n", - function)); - } + /* + * out_data might be allocated by the VFS module, but talloc should be + * used, and should be cleaned up when the request ends. + */ + status = SMB_VFS_FSCTL(fsp, + ctx, + function, + req->flags2, + (uint8_t *)pdata, + data_count, + (uint8_t **)&out_data, + max_data_count, + &out_data_len); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + } else { + send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, out_data, out_data_len); } - - reply_nterror(req, NT_STATUS_NOT_SUPPORTED); } @@ -2511,8 +2288,8 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, /* access check */ if (get_current_uid(conn) != 0) { DEBUG(1,("get_user_quota: access_denied service [%s] user " - "[%s]\n", lp_servicename(SNUM(conn)), - conn->session_info->unix_name)); + "[%s]\n", lp_servicename(talloc_tos(), SNUM(conn)), + conn->session_info->unix_info->unix_name)); reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -2744,7 +2521,9 @@ static void call_nt_transact_get_user_quota(connection_struct *conn, break; default: - DEBUG(0,("do_nt_transact_get_user_quota: fnum %d unknown level 0x%04hX\n",fsp->fnum,level)); + DEBUG(0, ("do_nt_transact_get_user_quota: %s: unknown " + "level 0x%04hX\n", + fsp_fnum_dbg(fsp), level)); reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; break; @@ -2781,8 +2560,8 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, /* access check */ if (get_current_uid(conn) != 0) { DEBUG(1,("set_user_quota: access_denied service [%s] user " - "[%s]\n", lp_servicename(SNUM(conn)), - conn->session_info->unix_name)); + "[%s]\n", lp_servicename(talloc_tos(), SNUM(conn)), + conn->session_info->unix_info->unix_name)); reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -3031,7 +2810,7 @@ void reply_nttrans(struct smb_request *req) return; } - if ((state = TALLOC_P(conn, struct trans_state)) == NULL) { + if ((state = talloc(conn, struct trans_state)) == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnttrans); return; @@ -3207,6 +2986,12 @@ void reply_nttranss(struct smb_request *req) show_msg((const char *)req->inbuf); + /* Windows clients expect all replies to + an NT transact secondary (SMBnttranss 0xA1) + to have a command code of NT transact + (SMBnttrans 0xA0). See bug #8989 for details. */ + req->cmd = SMBnttrans; + if (req->wct < 18) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnttranss);