diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/dosmode.c | 244 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 18 | ||||
-rw-r--r-- | source3/smbd/open.c | 20 | ||||
-rw-r--r-- | source3/smbd/reply.c | 3 | ||||
-rw-r--r-- | source3/smbd/smb2_create.c | 40 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 2 |
6 files changed, 188 insertions, 139 deletions
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index e10f23918d..0f31973675 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -19,6 +19,7 @@ */ #include "includes.h" +#include "librpc/gen_ndr/ndr_xattr.h" static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf) { @@ -205,15 +206,19 @@ static uint32 dos_mode_from_sbuf(connection_struct *conn, /**************************************************************************** Get DOS attributes from an EA. + This can also pull the create time into the stat struct inside smb_fname. ****************************************************************************/ static bool get_ea_dos_attribute(connection_struct *conn, - const struct smb_filename *smb_fname, + struct smb_filename *smb_fname, uint32 *pattr) { + struct xattr_DOSATTRIB dosattrib; + enum ndr_err_code ndr_err; + DATA_BLOB blob; ssize_t sizeret; fstring attrstr; - unsigned int dosattr; + uint32_t dosattr; if (!lp_store_dos_attributes(SNUM(conn))) { return False; @@ -240,18 +245,65 @@ static bool get_ea_dos_attribute(connection_struct *conn, } return False; } - /* Null terminate string. */ - attrstr[sizeret] = 0; - DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", - smb_fname_str_dbg(smb_fname), attrstr)); - if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' || - sscanf(attrstr, "%x", &dosattr) != 1) { - DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on " - "file %s - %s\n", smb_fname_str_dbg(smb_fname), - attrstr)); - return False; - } + blob.data = (uint8_t *)attrstr; + blob.length = sizeret; + + ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib, + (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB); + + DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n", + smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex)); + + switch (dosattrib.version) { + case 0xFFFF: + dosattr = dosattrib.info.compatinfoFFFF.attrib; + break; + case 1: + dosattr = dosattrib.info.info1.attrib; + if (!null_nttime(dosattrib.info.info1.create_time)) { + struct timespec create_time = + nt_time_to_unix_timespec( + &dosattrib.info.info1.create_time); + + update_stat_ex_create_time(&smb_fname->st, + create_time); + + DEBUG(10,("get_ea_dos_attributes: file %s case 1 " + "set btime %s\n", + smb_fname_str_dbg(smb_fname), + time_to_asc(convert_timespec_to_time_t( + create_time)) )); + } + break; + case 2: + dosattr = dosattrib.info.oldinfo2.attrib; + /* Don't know what flags to check for this case. */ + break; + case 3: + dosattr = dosattrib.info.info3.attrib; + if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) && + !null_nttime(dosattrib.info.info3.create_time)) { + struct timespec create_time = + nt_time_to_unix_timespec( + &dosattrib.info.info3.create_time); + + update_stat_ex_create_time(&smb_fname->st, + create_time); + + DEBUG(10,("get_ea_dos_attributes: file %s case 3 " + "set btime %s\n", + smb_fname_str_dbg(smb_fname), + time_to_asc(convert_timespec_to_time_t( + create_time)) )); + } + break; + default: + DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on " + "file %s - %s\n", smb_fname_str_dbg(smb_fname), + attrstr)); + return false; + } if (S_ISDIR(smb_fname->st.st_ex_mode)) { dosattr |= aDIR; @@ -273,23 +325,49 @@ static bool get_ea_dos_attribute(connection_struct *conn, /**************************************************************************** Set DOS attributes in an EA. + Also sets the create time. ****************************************************************************/ static bool set_ea_dos_attribute(connection_struct *conn, struct smb_filename *smb_fname, uint32 dosmode) { - fstring attrstr; + struct xattr_DOSATTRIB dosattrib; + enum ndr_err_code ndr_err; + DATA_BLOB blob; files_struct *fsp = NULL; - bool ret = False; + bool ret = false; if (!lp_store_dos_attributes(SNUM(conn))) { return False; } - snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK); + ZERO_STRUCT(dosattrib); + ZERO_STRUCT(blob); + + dosattrib.version = 3; + dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB| + XATTR_DOSINFO_CREATE_TIME; + dosattrib.info.info3.attrib = dosmode; + unix_timespec_to_nt_time(&dosattrib.info.info3.create_time, + smb_fname->st.st_ex_btime); + + ndr_err = ndr_push_struct_blob( + &blob, talloc_tos(), NULL, &dosattrib, + (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n", + ndr_errstr(ndr_err))); + return false; + } + + if (blob.data == NULL || blob.length == 0) { + return false; + } + if (SMB_VFS_SETXATTR(conn, smb_fname->base_name, - SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), + SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length, 0) == -1) { if((errno != EPERM) && (errno != EACCES)) { if (errno == ENOSYS @@ -304,7 +382,7 @@ static bool set_ea_dos_attribute(connection_struct *conn, strerror(errno) )); set_store_dos_attributes(SNUM(conn), False); } - return False; + return false; } /* We want DOS semantics, ie allow non owner with write permission to change the @@ -313,7 +391,7 @@ static bool set_ea_dos_attribute(connection_struct *conn, /* Check if we have write access. */ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) - return False; + return false; /* * We need to open the file with write access whilst @@ -326,17 +404,18 @@ static bool set_ea_dos_attribute(connection_struct *conn, return ret; become_root(); if (SMB_VFS_SETXATTR(conn, smb_fname->base_name, - SAMBA_XATTR_DOS_ATTRIB, attrstr, - strlen(attrstr), 0) == 0) { - ret = True; + SAMBA_XATTR_DOS_ATTRIB, blob.data, + blob.length, 0) == 0) { + ret = true; } unbecome_root(); close_file_fchmod(NULL, fsp); return ret; } - DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, - smb_fname_str_dbg(smb_fname))); - return True; + DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n", + (unsigned int)dosmode, + smb_fname_str_dbg(smb_fname))); + return true; } /**************************************************************************** @@ -510,11 +589,12 @@ static bool set_stat_dos_flags(connection_struct *conn, /**************************************************************************** Change a unix mode to a dos mode. + May also read the create timespec into the stat struct in smb_fname + if "store dos attributes" is true. ****************************************************************************/ -uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname) +uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) { - SMB_STRUCT_STAT sbuf; uint32 result = 0; bool offline, used_stat_dos_flags = false; @@ -553,9 +633,8 @@ uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname) } } - sbuf = smb_fname->st; - offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &sbuf); - if (S_ISREG(sbuf.st_ex_mode) && offline) { + offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st); + if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { result |= FILE_ATTRIBUTE_OFFLINE; } @@ -588,6 +667,9 @@ uint32 dos_mode(connection_struct *conn, const struct smb_filename *smb_fname) /******************************************************************* chmod a file - but preserve some bits. + If "store dos attributes" is also set it will store the create time + from the stat struct in smb_fname (in NTTIME format) in the EA + attribute also. ********************************************************************/ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, @@ -598,6 +680,7 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, mode_t unixmode; int ret = -1, lret = -1; uint32_t old_mode; + struct timespec new_create_timespec; /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */ dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE); @@ -605,11 +688,6 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, smb_fname_str_dbg(smb_fname))); - if (!VALID_STAT(smb_fname->st)) { - if (SMB_VFS_STAT(conn, smb_fname)) - return(-1); - } - unixmode = smb_fname->st.st_ex_mode; get_acl_group_bits(conn, smb_fname->base_name, @@ -620,6 +698,8 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, else dosmode &= ~aDIR; + new_create_timespec = smb_fname->st.st_ex_btime; + old_mode = dos_mode(conn, smb_fname); if (dosmode & FILE_ATTRIBUTE_OFFLINE) { @@ -639,11 +719,15 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, dosmode &= ~FILE_ATTRIBUTE_OFFLINE; old_mode &= ~FILE_ATTRIBUTE_OFFLINE; - if (old_mode == dosmode) { + if (old_mode == dosmode && + (timespec_compare(&new_create_timespec, + &smb_fname->st.st_ex_btime) == 0)) { smb_fname->st.st_ex_mode = unixmode; return(0); } + smb_fname->st.st_ex_btime = new_create_timespec; + #ifdef HAVE_STAT_DOS_FLAGS { bool attributes_changed; @@ -842,6 +926,10 @@ bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime) bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime) { + if (null_timespec(mtime)) { + return true; + } + fsp->write_time_forced = true; TALLOC_FREE(fsp->update_write_time_event); @@ -853,93 +941,51 @@ bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime) ******************************************************************/ NTSTATUS set_create_timespec_ea(connection_struct *conn, - struct files_struct *fsp, - const struct smb_filename *smb_fname, + const struct smb_filename *psmb_fname, struct timespec create_time) { + NTSTATUS status; + struct smb_filename *smb_fname = NULL; + uint32_t dosmode; int ret; - char buf[8]; - if (!lp_store_create_time(SNUM(conn))) { + if (!lp_store_dos_attributes(SNUM(conn))) { return NT_STATUS_OK; } - put_long_date_timespec(conn->ts_res, buf, create_time); - if (fsp && fsp->fh->fd != -1) { - ret = SMB_VFS_FSETXATTR(fsp, - SAMBA_XATTR_DOSTIMESTAMPS, - buf, - sizeof(buf), - 0); - } else { - ret = SMB_VFS_SETXATTR(conn, - smb_fname->base_name, - SAMBA_XATTR_DOSTIMESTAMPS, - buf, - sizeof(buf), - 0); + status = create_synthetic_smb_fname(talloc_tos(), + psmb_fname->base_name, + NULL, &psmb_fname->st, + &smb_fname); + + if (!NT_STATUS_IS_OK(status)) { + return status; } + dosmode = dos_mode(conn, smb_fname); + + smb_fname->st.st_ex_btime = create_time; + + ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false); if (ret == -1) { map_nt_error_from_unix(errno); } + DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n", smb_fname_str_dbg(smb_fname))); - return NT_STATUS_OK; -} -/****************************************************************** - Returns an EA create timespec, or a zero timespec if fail. -******************************************************************/ - -static struct timespec get_create_timespec_ea(connection_struct *conn, - struct files_struct *fsp, - const struct smb_filename *smb_fname) -{ - ssize_t ret; - char buf[8]; - struct timespec ts; - - ZERO_STRUCT(ts); - - if (!lp_store_create_time(SNUM(conn))) { - return ts; - } - - if (fsp && fsp->fh->fd != -1) { - ret = SMB_VFS_FGETXATTR(fsp, - SAMBA_XATTR_DOSTIMESTAMPS, - buf, - sizeof(buf)); - } else { - ret = SMB_VFS_GETXATTR(conn, - smb_fname->base_name, - SAMBA_XATTR_DOSTIMESTAMPS, - buf, - sizeof(buf)); - } - if (ret == sizeof(buf)) { - return interpret_long_date(buf); - } else { - return ts; - } + return NT_STATUS_OK; } /****************************************************************** - Return a create time - looks at EA. + Return a create time. ******************************************************************/ struct timespec get_create_timespec(connection_struct *conn, struct files_struct *fsp, const struct smb_filename *smb_fname) { - struct timespec ts = get_create_timespec_ea(conn, fsp, smb_fname); - - if (!null_timespec(ts)) { - return ts; - } else { - return smb_fname->st.st_ex_btime; - } + return smb_fname->st.st_ex_btime; } /****************************************************************** diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 66102fa96c..bacb9cb0b2 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -554,10 +554,6 @@ void reply_ntcreate_and_X(struct smb_request *req) } file_len = smb_fname->st.st_ex_size; - fattr = dos_mode(conn, smb_fname); - if (fattr == 0) { - fattr = FILE_ATTRIBUTE_NORMAL; - } if (flags & EXTENDED_RESPONSE_REQUIRED) { /* This is very strange. We @@ -586,6 +582,11 @@ void reply_ntcreate_and_X(struct smb_request *req) } p += 4; + fattr = dos_mode(conn, smb_fname); + if (fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; + } + /* Deal with other possible opens having a modified write time. JRA. */ ZERO_STRUCT(write_time_ts); @@ -1070,10 +1071,6 @@ static void call_nt_transact_create(connection_struct *conn, } file_len = smb_fname->st.st_ex_size; - fattr = dos_mode(conn, smb_fname); - if (fattr == 0) { - fattr = FILE_ATTRIBUTE_NORMAL; - } /* Realloc the size of parameters and data we will return */ if (flags & EXTENDED_RESPONSE_REQUIRED) { @@ -1102,6 +1099,11 @@ static void call_nt_transact_create(connection_struct *conn, } p += 8; + fattr = dos_mode(conn, smb_fname); + if (fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; + } + /* Deal with other possible opens having a modified write time. JRA. */ ZERO_STRUCT(write_time_ts); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 85b7d9106d..1f48daf904 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1495,7 +1495,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } return print_fsp_open(req, conn, smb_fname->base_name, - req->vuid, fsp, &smb_fname->st); + req->vuid, fsp); } if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir, @@ -3243,7 +3243,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } } - if (!fsp->is_directory && S_ISDIR(smb_fname->st.st_ex_mode)) { + if (!fsp->is_directory && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) { status = NT_STATUS_ACCESS_DENIED; goto fail; } @@ -3251,7 +3251,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, /* Save the requested allocation size. */ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { if (allocation_size - && (allocation_size > smb_fname->st.st_ex_size)) { + && (allocation_size > fsp->fsp_name->st.st_ex_size)) { fsp->initial_allocation_size = smb_roundup( fsp->conn, allocation_size); if (fsp->is_directory) { @@ -3266,7 +3266,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } } else { fsp->initial_allocation_size = smb_roundup( - fsp->conn, (uint64_t)smb_fname->st.st_ex_size); + fsp->conn, (uint64_t)fsp->fsp_name->st.st_ex_size); } } @@ -3276,18 +3276,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, if (pinfo != NULL) { *pinfo = info; } - if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) { - SMB_VFS_FSTAT(fsp, &smb_fname->st); - fsp->fsp_name->st = smb_fname->st; - } - /* Try and make a create timestamp, if required. */ - if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { - if (lp_store_create_time(SNUM(conn))) { - set_create_timespec_ea(conn, fsp, - smb_fname, smb_fname->st.st_ex_btime); - } - } + smb_fname->st = fsp->fsp_name->st; return NT_STATUS_OK; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index d39edc56db..caa80f9ade 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -4980,7 +4980,6 @@ void reply_printopen(struct smb_request *req) { connection_struct *conn = req->conn; files_struct *fsp; - SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBsplopen); @@ -5005,7 +5004,7 @@ void reply_printopen(struct smb_request *req) } /* Open for exclusive use, write only. */ - status = print_fsp_open(req, conn, NULL, req->vuid, fsp, &sbuf); + status = print_fsp_open(req, conn, NULL, req->vuid, fsp); if (!NT_STATUS_IS_OK(status)) { file_free(req, fsp); diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index e0815049a4..3cf8b185b0 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -347,7 +347,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, struct smb_request *smbreq; files_struct *result; int info; - SMB_STRUCT_STAT sbuf; + struct timespec write_time_ts; struct smb2_create_blobs out_context_blobs; ZERO_STRUCT(out_context_blobs); @@ -386,7 +386,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } info = FILE_WAS_OPENED; - ZERO_STRUCT(sbuf); } else if (CAN_PRINT(smbreq->conn)) { status = file_new(smbreq, smbreq->conn, &result); if(!NT_STATUS_IS_OK(status)) { @@ -398,8 +397,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, smbreq->conn, in_name, smbreq->vuid, - result, - &sbuf); + result); if (!NT_STATUS_IS_OK(status)) { file_free(smbreq, result); tevent_req_nterror(req, status); @@ -669,8 +667,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } } - - sbuf = result->fsp_name->st; } smb2req->compat_chain_fsp = smbreq->chain_fsp; @@ -682,14 +678,30 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, } else { state->out_create_action = info; } - unix_timespec_to_nt_time(&state->out_creation_time, sbuf.st_ex_btime); - unix_timespec_to_nt_time(&state->out_last_access_time, sbuf.st_ex_atime); - unix_timespec_to_nt_time(&state->out_last_write_time,sbuf.st_ex_mtime); - unix_timespec_to_nt_time(&state->out_change_time, sbuf.st_ex_ctime); - state->out_allocation_size = sbuf.st_ex_blksize * sbuf.st_ex_blocks; - state->out_end_of_file = sbuf.st_ex_size; - state->out_file_attributes = dos_mode(result->conn, - result->fsp_name); + state->out_file_attributes = dos_mode(result->conn, + result->fsp_name); + /* Deal with other possible opens having a modified + write time. JRA. */ + ZERO_STRUCT(write_time_ts); + get_file_infos(result->file_id, NULL, &write_time_ts); + if (!null_timespec(write_time_ts)) { + update_stat_ex_mtime(&result->fsp_name->st, write_time_ts); + } + + unix_timespec_to_nt_time(&state->out_creation_time, + get_create_timespec(smbreq->conn, result, + result->fsp_name)); + unix_timespec_to_nt_time(&state->out_last_access_time, + result->fsp_name->st.st_ex_atime); + unix_timespec_to_nt_time(&state->out_last_write_time, + result->fsp_name->st.st_ex_mtime); + unix_timespec_to_nt_time(&state->out_change_time, + get_change_timespec(smbreq->conn, result, + result->fsp_name)); + state->out_allocation_size = + result->fsp_name->st.st_ex_blksize * + result->fsp_name->st.st_ex_blocks; + state->out_end_of_file = result->fsp_name->st.st_ex_size; if (state->out_file_attributes == 0) { state->out_file_attributes = FILE_ATTRIBUTE_NORMAL; } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 74dd173f4f..dacf5f34e0 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5720,7 +5720,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + struct smb_filename *smb_fname) { NTSTATUS status = NT_STATUS_OK; bool delete_on_close; |