X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Ftrans2.c;h=6c082a8273e64a59dbce0b75881a394cc07b84fb;hb=b8f7cdbd79918bba0fea181f97fff5ab0c79192d;hp=1da45a8b58c8ca645a69e48727647737e7025820;hpb=c783d8a32e4d958aec6d943d0fa3de2e7d3a68c2;p=metze%2Fsamba%2Fwip.git diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 1da45a8b58c8..6c082a8273e6 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -24,12 +24,11 @@ */ #include "includes.h" +#include "version.h" +#include "smbd/globals.h" -extern int max_send; extern enum protocol_types Protocol; -extern uint32 global_client_caps; -#define get_file_size(sbuf) ((sbuf).st_size) #define DIR_ENTRY_SAFETY_MARGIN 4096 static char *store_file_unix_basic(connection_struct *conn, @@ -59,31 +58,6 @@ uint64_t smb_roundup(connection_struct *conn, uint64_t val) return val; } -/******************************************************************** - Given a stat buffer return the allocated size on disk, taking into - account sparse files. -********************************************************************/ - -uint64_t get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf) -{ - uint64_t ret; - - if(S_ISDIR(sbuf->st_mode)) { - return 0; - } - -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - ret = (uint64_t)STAT_ST_BLOCKSIZE * (uint64_t)sbuf->st_blocks; -#else - ret = (uint64_t)get_file_size(*sbuf); -#endif - - if (fsp && fsp->initial_allocation_size) - ret = MAX(ret,fsp->initial_allocation_size); - - return smb_roundup(conn, ret); -} - /**************************************************************************** Utility functions for dealing with extended attributes. ****************************************************************************/ @@ -94,7 +68,7 @@ uint64_t get_allocation_size(connection_struct *conn, files_struct *fsp, const S static bool samba_private_attr_name(const char *unix_ea_name) { - static const char *prohibited_ea_names[] = { + static const char * const prohibited_ea_names[] = { SAMBA_POSIX_INHERITANCE_EA_NAME, SAMBA_XATTR_DOS_ATTRIB, NULL @@ -768,6 +742,12 @@ void send_trans2_replies(connection_struct *conn, reply_outbuf(req, 10, total_sent_thistime + alignment_offset + data_alignment_offset); + /* + * We might have SMBtrans2s in req which was transferred to + * the outbuf, fix that. + */ + SCVAL(req->outbuf, smb_com, SMBtrans2); + /* Set total params and data to be sent */ SSVAL(req->outbuf,smb_tprcnt,paramsize); SSVAL(req->outbuf,smb_tdrcnt,datasize); @@ -1000,22 +980,24 @@ static void call_trans2open(connection_struct *conn, return; } - status = create_file(conn, /* conn */ - req, /* req */ - 0, /* root_dir_fid */ - fname, /* fname */ - access_mask, /* access_mask */ - share_mode, /* share_access */ - create_disposition, /* create_disposition*/ - create_options, /* create_options */ - open_attr, /* file_attributes */ - oplock_request, /* oplock_request */ - open_size, /* allocation_size */ - NULL, /* sd */ - ea_list, /* ea_list */ - &fsp, /* result */ - &smb_action, /* pinfo */ - &sbuf); /* psbuf */ + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + CFF_DOS_PATH, /* create_file_flags */ + access_mask, /* access_mask */ + share_mode, /* share_access */ + create_disposition, /* create_disposition*/ + create_options, /* create_options */ + open_attr, /* file_attributes */ + oplock_request, /* oplock_request */ + open_size, /* allocation_size */ + NULL, /* sd */ + ea_list, /* ea_list */ + &fsp, /* result */ + &smb_action, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { @@ -1026,7 +1008,7 @@ static void call_trans2open(connection_struct *conn, return; } - size = get_file_size(sbuf); + size = get_file_size_stat(&sbuf); fattr = dos_mode(conn,fsp->fsp_name,&sbuf); mtime = sbuf.st_mtime; inode = sbuf.st_ino; @@ -1087,15 +1069,13 @@ static bool exact_match(connection_struct *conn, { if (mask[0] == '.' && mask[1] == 0) return False; - if (conn->case_sensitive) - return strcmp(str,mask)==0; - if (StrCaseCmp(str,mask) != 0) { - return False; - } if (dptr_has_wild(conn->dirptr)) { return False; } - return True; + if (conn->case_sensitive) + return strcmp(str,mask)==0; + else + return StrCaseCmp(str,mask) == 0; } /**************************************************************************** @@ -1129,7 +1109,7 @@ static uint32 unix_filetype(mode_t mode) return UNIX_TYPE_SOCKET; #endif - DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode)); + DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode)); return UNIX_TYPE_UNKNOWN; } @@ -1418,13 +1398,14 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, } if (!(mode & aDIR)) { - file_size = get_file_size(sbuf); + file_size = get_file_size_stat(&sbuf); } - allocation_size = get_allocation_size(conn,NULL,&sbuf); + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,NULL,&sbuf); mdate_ts = get_mtimespec(&sbuf); adate_ts = get_atimespec(&sbuf); - create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + create_date_ts = get_create_timespec(&sbuf, + lp_fake_dir_create_times(SNUM(conn))); if (ask_sharemode) { struct timespec write_time_ts; @@ -1447,7 +1428,8 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, mdate = convert_timespec_to_time_t(mdate_ts); adate = convert_timespec_to_time_t(adate_ts); - DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",pathreal,fname)); + DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n", + pathreal,fname)); found = True; @@ -2183,7 +2165,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(req->inbuf,smb_com)), + smb_fn_name(req->cmd), mask, directory, dirtype, numentries ) ); /* @@ -2481,7 +2463,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n", - smb_fn_name(CVAL(req->inbuf,smb_com)), + smb_fn_name(req->cmd), mask, directory, dirtype, numentries ) ); /* Check if we can close the dirptr */ @@ -3065,6 +3047,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned i < conn->server_info->ptok->num_sids; ++i) { sid_bytes += ndr_size_dom_sid( &conn->server_info->ptok->user_sids[i], + NULL, 0); } @@ -3087,6 +3070,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned i < conn->server_info->ptok->num_sids; ++i) { int sid_len = ndr_size_dom_sid( &conn->server_info->ptok->user_sids[i], + NULL, 0); sid_linearize(pdata + data_len, sid_len, @@ -3118,7 +3102,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", - smb_fn_name(CVAL(req->inbuf,smb_com)), info_level) ); + smb_fn_name(req->cmd), info_level) ); return; } @@ -3513,10 +3497,10 @@ static char *store_file_unix_basic(connection_struct *conn, DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n")); DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode)); - SOFF_T(pdata,0,get_file_size(*psbuf)); /* File size 64 Bit */ + SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */ pdata += 8; - SOFF_T(pdata,0,get_allocation_size(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */ + SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */ pdata += 8; put_long_date_timespec(pdata,get_ctimespec(psbuf)); /* Change Time 64 Bit */ @@ -3681,7 +3665,7 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams, unsigned int i; unsigned int ofs = 0; - for (i=0; i max_data_bytes) { - TALLOC_FREE(namebuf); - return NT_STATUS_BUFFER_TOO_SMALL; - } - SIVAL(data, ofs+4, namelen); SOFF_T(data, ofs+8, streams[i].size); SOFF_T(data, ofs+16, streams[i].alloc_size); @@ -3719,10 +3698,6 @@ 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) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - memset(data+next_offset, 0, align); next_offset += align; @@ -3846,7 +3821,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn, files_struct *fsp = NULL; struct file_id fileid; struct ea_list *ea_list = NULL; - uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */ char *lock_data = NULL; bool ms_dfs_link = false; TALLOC_CTX *ctx = talloc_tos(); @@ -3939,7 +3913,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn, pos = fsp->fh->position_information; fileid = vfs_file_id_from_sbuf(conn, &sbuf); get_file_infos(fileid, &delete_pending, &write_time_ts); - access_mask = fsp->access_mask; } } else { @@ -3995,6 +3968,46 @@ static void call_trans2qfilepathinfo(connection_struct *conn, return; } + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_name(fname)) { + char *base; + SMB_STRUCT_STAT bsbuf; + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + reply_nterror(req, status); + return; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn,base,&bsbuf)) { + DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } else { + if (SMB_VFS_STAT(conn,base,&bsbuf) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",base,strerror(errno))); + reply_unixerror(req,ERRDOS,ERRbadpath); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, &bsbuf); + get_file_infos(fileid, &delete_pending, NULL); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + if (INFO_LEVEL_IS_UNIX(info_level)) { /* Always do lstat for UNIX calls. */ if (SMB_VFS_LSTAT(conn,fname,&sbuf)) { @@ -4055,7 +4068,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, fullpathname = fname; if (!(mode & aDIR)) - file_size = get_file_size(sbuf); + file_size = get_file_size_stat(&sbuf); /* Pull out any data sent here before we realloc. */ switch (info_level) { @@ -4141,7 +4154,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd mtime_ts = get_mtimespec(&sbuf); atime_ts = get_atimespec(&sbuf); - allocation_size = get_allocation_size(conn,fsp,&sbuf); + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); if (!fsp) { /* Do we have this path open ? */ @@ -4149,7 +4162,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd fileid = vfs_file_id_from_sbuf(conn, &sbuf); fsp1 = file_find_di_first(fileid); if (fsp1 && fsp1->initial_allocation_size) { - allocation_size = get_allocation_size(conn, fsp1, &sbuf); + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, &sbuf); } } @@ -4403,7 +4416,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_FILE_ACCESS_INFORMATION: DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); - SIVAL(pdata,0,access_mask); + if (fsp) { + SIVAL(pdata,0,fsp->access_mask); + } else { + /* GENERIC_EXECUTE mapping from Windows */ + SIVAL(pdata,0,0x12019F); + } data_size = 4; break; @@ -4850,7 +4868,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn, files_struct *fsp, const char *fname, const SMB_STRUCT_STAT *psbuf, - struct timespec ts[2], + struct smb_file_time *ft, bool setting_write_time) { uint32 action = @@ -4862,23 +4880,29 @@ NTSTATUS smb_set_file_time(connection_struct *conn, } /* get some defaults (no modifications) if any info is zero or -1. */ - if (null_timespec(ts[0])) { - ts[0] = get_atimespec(psbuf); + if (null_timespec(ft->atime)) { + ft->atime= get_atimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } - if (null_timespec(ts[1])) { - ts[1] = get_mtimespec(psbuf); + if (null_timespec(ft->mtime)) { + ft->mtime = get_mtimespec(psbuf); action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } if (!setting_write_time) { - /* ts[1] comes from change time, not write time. */ + /* ft->mtime comes from change time, not write time. */ action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } - DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) )); - DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) )); + DEBUG(5,("smb_set_filetime: actime: %s\n ", + time_to_asc(convert_timespec_to_time_t(ft->atime)))); + DEBUG(5,("smb_set_filetime: modtime: %s\n ", + time_to_asc(convert_timespec_to_time_t(ft->mtime)))); + if (!null_timespec(ft->create_time)) { + DEBUG(5,("smb_set_file_time: createtime: %s\n ", + time_to_asc(convert_timespec_to_time_t(ft->create_time)))); + } /* * Try and set the times of this file if @@ -4888,7 +4912,8 @@ NTSTATUS smb_set_file_time(connection_struct *conn, { struct timespec mts = get_mtimespec(psbuf); struct timespec ats = get_atimespec(psbuf); - if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) { + if ((timespec_compare(&ft->atime, &ats) == 0) && + (timespec_compare(&ft->mtime, &mts) == 0)) { return NT_STATUS_OK; } } @@ -4905,20 +4930,29 @@ NTSTATUS smb_set_file_time(connection_struct *conn, */ DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", - time_to_asc(convert_timespec_to_time_t(ts[1])) )); + time_to_asc(convert_timespec_to_time_t(ft->mtime)))); if (fsp != NULL) { - set_sticky_write_time_fsp(fsp, ts[1]); + if (fsp->base_fsp) { + set_sticky_write_time_fsp(fsp->base_fsp, + ft->mtime); + } else { + set_sticky_write_time_fsp(fsp, ft->mtime); + } } else { set_sticky_write_time_path(conn, fname, vfs_file_id_from_sbuf(conn, psbuf), - ts[1]); + ft->mtime); } } DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); - if(file_ntimes(conn, fname, ts)!=0) { + if (fsp && fsp->base_fsp) { + fname = fsp->base_fsp->fsp_name; + } + + if(file_ntimes(conn, fname, ft)!=0) { return map_nt_error_from_unix(errno); } notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname); @@ -4984,7 +5018,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size)); - if (size == get_file_size(*psbuf)) { + if (size == get_file_size_stat(psbuf)) { return NT_STATUS_OK; } @@ -5000,15 +5034,26 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, return NT_STATUS_OK; } - status = open_file_ntcreate(conn, req, fname, psbuf, - FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_ATTRIBUTE_NORMAL, - FORCE_OPLOCK_BREAK_TO_NONE, - NULL, &new_fsp); - + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + 0, /* create_file_flags */ + FILE_WRITE_ATTRIBUTES, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + FILE_ATTRIBUTE_NORMAL, /* file_attributes */ + FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &new_fsp, /* result */ + NULL, /* pinfo */ + psbuf); /* psbuf */ + if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ return status; @@ -5304,6 +5349,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, char *newname = NULL; char *base_name = NULL; bool dest_has_wcard = False; + SMB_STRUCT_STAT sbuf; + char *newname_last_component = NULL; NTSTATUS status = NT_STATUS_OK; char *p; TALLOC_CTX *ctx = talloc_tos(); @@ -5312,6 +5359,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } + ZERO_STRUCT(sbuf); + overwrite = (CVAL(pdata,0) ? True : False); root_fid = IVAL(pdata,4); len = IVAL(pdata,8); @@ -5344,38 +5393,49 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NOT_SUPPORTED; } - /* Create the base directory. */ - base_name = talloc_strdup(ctx, fname); - if (!base_name) { - return NT_STATUS_NO_MEMORY; - } - p = strrchr_m(base_name, '/'); - if (p) { - p[1] = '\0'; - } else { - base_name = talloc_strdup(ctx, "./"); + if (fsp && fsp->base_fsp) { + /* newname must be a stream name. */ + if (newname[0] != ':') { + return NT_STATUS_NOT_SUPPORTED; + } + base_name = talloc_asprintf(ctx, "%s%s", + fsp->base_fsp->fsp_name, + newname); if (!base_name) { return NT_STATUS_NO_MEMORY; } - } - /* Append the new name. */ - base_name = talloc_asprintf_append(base_name, - "%s", - newname); - if (!base_name) { - return NT_STATUS_NO_MEMORY; - } - - if (fsp) { - SMB_STRUCT_STAT sbuf; - char *newname_last_component = NULL; + } else { + /* newname must *not* be a stream name. */ + if (is_ntfs_stream_name(newname)) { + return NT_STATUS_NOT_SUPPORTED; + } - ZERO_STRUCT(sbuf); + /* Create the base directory. */ + base_name = talloc_strdup(ctx, fname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } + p = strrchr_m(base_name, '/'); + if (p) { + p[1] = '\0'; + } else { + base_name = talloc_strdup(ctx, "./"); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } + } + /* Append the new name. */ + base_name = talloc_asprintf_append(base_name, + "%s", + newname); + if (!base_name) { + return NT_STATUS_NO_MEMORY; + } status = unix_convert(ctx, conn, newname, False, - &newname, - &newname_last_component, - &sbuf); + &newname, + &newname_last_component, + &sbuf); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -5385,7 +5445,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, status)) { return status; } + } + if (fsp) { DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", fsp->fnum, fsp->fsp_name, base_name )); status = rename_internals_fsp(conn, fsp, base_name, @@ -5470,7 +5532,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, ****************************************************************************/ static NTSTATUS smb_set_posix_lock(connection_struct *conn, - const struct smb_request *req, + struct smb_request *req, const char *pdata, int total_data, files_struct *fsp) @@ -5599,16 +5661,21 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf) { - struct timespec ts[2]; + struct smb_file_time ft; + ZERO_STRUCT(ft); if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } + /* create time */ + ft.create_time = interpret_long_date(pdata); + /* access time */ - ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess)); + ft.atime = interpret_long_date(pdata + 8); + /* write time */ - ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite)); + ft.mtime = interpret_long_date(pdata + 16); DEBUG(10,("smb_set_info_standard: file %s\n", fname ? fname : fsp->fsp_name )); @@ -5617,7 +5684,7 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, fsp, fname, psbuf, - ts, + &ft, true); } @@ -5635,47 +5702,49 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, /* Patch to do this correctly from Paul Eggert . */ struct timespec write_time; struct timespec changed_time; + struct smb_file_time ft; uint32 dosmode = 0; - struct timespec ts[2]; NTSTATUS status = NT_STATUS_OK; bool setting_write_time = true; + ZERO_STRUCT(ft); + if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; } /* Set the attributes */ dosmode = IVAL(pdata,32); - status = smb_set_file_dosmode(conn, - fname, - psbuf, - dosmode); + status = smb_set_file_dosmode(conn, fname, psbuf, dosmode); if (!NT_STATUS_IS_OK(status)) { return status; } - /* Ignore create time at offset pdata. */ /* access time */ - ts[0] = interpret_long_date(pdata+8); + ft.atime = interpret_long_date(pdata+8); write_time = interpret_long_date(pdata+16); changed_time = interpret_long_date(pdata+24); /* mtime */ - ts[1] = timespec_min(&write_time, &changed_time); + ft.mtime = timespec_min(&write_time, &changed_time); + + /* create time */ + ft.create_time = interpret_long_date(pdata); - if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) { - ts[1] = write_time; + if ((timespec_compare(&write_time, &ft.mtime) == 1) && + !null_timespec(write_time)) { + ft.mtime = write_time; } /* Prefer a defined time to an undefined one. */ - if (null_timespec(ts[1])) { + if (null_timespec(ft.mtime)) { if (null_timespec(write_time)) { - ts[1] = changed_time; + ft.mtime = changed_time; setting_write_time = false; } else { - ts[1] = write_time; + ft.mtime = write_time; } } @@ -5686,7 +5755,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, fsp, fname, psbuf, - ts, + &ft, setting_write_time); } @@ -5737,7 +5806,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, if (fsp && fsp->fh->fd != -1) { /* Open file handle. */ /* Only change if needed. */ - if (allocation_size != get_file_size(*psbuf)) { + if (allocation_size != get_file_size_stat(psbuf)) { if (vfs_allocate_file_space(fsp, allocation_size) == -1) { return map_nt_error_from_unix(errno); } @@ -5753,14 +5822,25 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, /* Pathname or stat or directory file. */ - status = open_file_ntcreate(conn, req, fname, psbuf, - FILE_WRITE_DATA, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_ATTRIBUTE_NORMAL, - FORCE_OPLOCK_BREAK_TO_NONE, - NULL, &new_fsp); + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + 0, /* create_file_flags */ + FILE_WRITE_DATA, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + FILE_ATTRIBUTE_NORMAL, /* file_attributes */ + FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &new_fsp, /* result */ + NULL, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { /* NB. We check for open_was_deferred in the caller. */ @@ -5768,7 +5848,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } /* Only change if needed. */ - if (allocation_size != get_file_size(*psbuf)) { + if (allocation_size != get_file_size_stat(psbuf)) { if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) { status = map_nt_error_from_unix(errno); close_file(req, new_fsp, NORMAL_CLOSE); @@ -5895,9 +5975,12 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn, */ if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl( - conn, parent_dirname(fname), - fname, unixmode); + char *parent; + if (!parent_dirname(talloc_tos(), fname, &parent, NULL)) { + return NT_STATUS_NO_MEMORY; + } + inherit_access_posix_acl(conn, parent, fname, unixmode); + TALLOC_FREE(parent); } if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { @@ -5920,7 +6003,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) { - struct timespec ts[2]; + struct smb_file_time ft; uint32 raw_unixmode; mode_t unixmode; SMB_OFF_T size = 0; @@ -5930,6 +6013,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, bool delete_on_fail = False; enum perm_type ptype; + ZERO_STRUCT(ft); + if (total_data < 100) { return NT_STATUS_INVALID_PARAMETER; } @@ -5947,8 +6032,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, #endif /* LARGE_SMB_OFF_T */ } - ts[0] = interpret_long_date(pdata+24); /* access_time */ - ts[1] = interpret_long_date(pdata+32); /* modification_time */ + ft.atime = interpret_long_date(pdata+24); /* access_time */ + ft.mtime = interpret_long_date(pdata+32); /* modification_time */ set_owner = (uid_t)IVAL(pdata,40); set_grp = (gid_t)IVAL(pdata,48); raw_unixmode = IVAL(pdata,84); @@ -5990,9 +6075,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", /* Ensure we don't try and change anything else. */ raw_unixmode = SMB_MODE_NO_CHANGE; - size = get_file_size(*psbuf); - ts[0] = get_atimespec(psbuf); - ts[1] = get_mtimespec(psbuf); + size = get_file_size_stat(psbuf); + ft.atime = get_atimespec(psbuf); + ft.mtime = get_mtimespec(psbuf); /* * We continue here as we might want to change the * owner uid/gid. @@ -6006,7 +6091,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", * */ if (!size) { - size = get_file_size(*psbuf); + size = get_file_size_stat(psbuf); } #endif @@ -6080,7 +6165,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", fsp, fname, psbuf, - ts, + &ft, true); } @@ -6184,16 +6269,24 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", fname, (unsigned int)unixmode )); - status = open_directory(conn, req, - fname, - psbuf, - FILE_READ_ATTRIBUTES, /* Just a stat open */ - FILE_SHARE_NONE, /* Ignored for stat opens */ - FILE_CREATE, - 0, - mod_unixmode, - &info, - &fsp); + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + 0, /* create_file_flags */ + FILE_READ_ATTRIBUTES, /* access_mask */ + FILE_SHARE_NONE, /* share_access */ + FILE_CREATE, /* create_disposition*/ + FILE_DIRECTORY_FILE, /* create_options */ + mod_unixmode, /* file_attributes */ + 0, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); @@ -6350,17 +6443,25 @@ static NTSTATUS smb_posix_open(connection_struct *conn, (unsigned int)wire_open_mode, (unsigned int)unixmode )); - status = open_file_ntcreate(conn, req, - fname, - psbuf, - access_mask, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - create_disp, - 0, /* no create options yet. */ - mod_unixmode, - oplock_request, - &info, - &fsp); + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + 0, /* create_file_flags */ + access_mask, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + create_disp, /* create_disposition*/ + 0, /* create_options */ + mod_unixmode, /* file_attributes */ + oplock_request, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -6445,6 +6546,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, uint16 flags = 0; char del = 1; int info = 0; + int create_options = 0; int i; struct share_mode_lock *lck = NULL; @@ -6468,30 +6570,28 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, fname)); if (VALID_STAT_OF_DIR(*psbuf)) { - status = open_directory(conn, req, - fname, - psbuf, - DELETE_ACCESS, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_FLAG_POSIX_SEMANTICS|0777, - &info, - &fsp); - } else { - - status = open_file_ntcreate(conn, req, - fname, - psbuf, - DELETE_ACCESS, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_FLAG_POSIX_SEMANTICS|0777, - 0, /* No oplock, but break existing ones. */ - &info, - &fsp); - } + create_options |= FILE_DIRECTORY_FILE; + } + + status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + req, /* req */ + 0, /* root_dir_fid */ + fname, /* fname */ + 0, /* create_file_flags */ + DELETE_ACCESS, /* access_mask */ + (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ + FILE_SHARE_DELETE), + FILE_OPEN, /* create_disposition*/ + create_options, /* create_options */ + FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */ + 0, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + &info, /* pinfo */ + psbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { return status; @@ -7113,7 +7213,6 @@ static void call_trans2findnotifyfirst(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { - static uint16 fnf_handle = 257; char *params = *pparams; uint16 info_level; @@ -7251,7 +7350,7 @@ static void call_trans2ioctl(connection_struct *conn, unsigned int max_data_bytes) { char *pdata = *ppdata; - files_struct *fsp = file_fsp(req, SVAL(req->inbuf,smb_vwv15)); + files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0)); /* check for an invalid fid before proceeding */ @@ -7260,8 +7359,8 @@ static void call_trans2ioctl(connection_struct *conn, return; } - if ((SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL) - && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + if ((SVAL(req->vwv+16, 0) == LMCAT_SPL) + && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) { *ppdata = (char *)SMB_REALLOC(*ppdata, 32); if (*ppdata == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); @@ -7304,7 +7403,7 @@ void reply_findclose(struct smb_request *req) return; } - dptr_num = SVALS(req->inbuf,smb_vwv0); + dptr_num = SVALS(req->vwv+0, 0); DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num)); @@ -7334,7 +7433,7 @@ void reply_findnclose(struct smb_request *req) return; } - dptr_num = SVAL(req->inbuf,smb_vwv0); + dptr_num = SVAL(req->vwv+0, 0); DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num)); @@ -7524,8 +7623,6 @@ void reply_trans2(struct smb_request *req) unsigned int psoff; unsigned int pscnt; unsigned int tran_call; - unsigned int size; - unsigned int av_size; struct trans_state *state; NTSTATUS result; @@ -7537,13 +7634,11 @@ void reply_trans2(struct smb_request *req) return; } - dsoff = SVAL(req->inbuf, smb_dsoff); - dscnt = SVAL(req->inbuf, smb_dscnt); - psoff = SVAL(req->inbuf, smb_psoff); - pscnt = SVAL(req->inbuf, smb_pscnt); - tran_call = SVAL(req->inbuf, smb_setup0); - size = smb_len(req->inbuf) + 4; - av_size = smb_len(req->inbuf); + dsoff = SVAL(req->vwv+12, 0); + dscnt = SVAL(req->vwv+11, 0); + psoff = SVAL(req->vwv+10, 0); + pscnt = SVAL(req->vwv+9, 0); + tran_call = SVAL(req->vwv+14, 0); result = allow_new_trans(conn->pending_trans, req->mid); if (!NT_STATUS_IS_OK(result)) { @@ -7581,17 +7676,17 @@ void reply_trans2(struct smb_request *req) state->mid = req->mid; state->vuid = req->vuid; - state->setup_count = SVAL(req->inbuf, smb_suwcnt); + state->setup_count = SVAL(req->vwv+13, 0); state->setup = NULL; - state->total_param = SVAL(req->inbuf, smb_tpscnt); + state->total_param = SVAL(req->vwv+0, 0); state->param = NULL; - state->total_data = SVAL(req->inbuf, smb_tdscnt); + state->total_data = SVAL(req->vwv+1, 0); state->data = NULL; - state->max_param_return = SVAL(req->inbuf, smb_mprcnt); - state->max_data_return = SVAL(req->inbuf, smb_mdrcnt); - state->max_setup_return = SVAL(req->inbuf, smb_msrcnt); - state->close_on_completion = BITSETW(req->inbuf+smb_vwv5,0); - state->one_way = BITSETW(req->inbuf+smb_vwv5,1); + state->max_param_return = SVAL(req->vwv+2, 0); + state->max_data_return = SVAL(req->vwv+3, 0); + state->max_setup_return = SVAL(req->vwv+4, 0); + state->close_on_completion = BITSETW(req->vwv+5, 0); + state->one_way = BITSETW(req->vwv+5, 1); state->call = tran_call; @@ -7608,8 +7703,8 @@ void reply_trans2(struct smb_request *req) */ if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) - && (SVAL(req->inbuf,(smb_setup+4)) == LMCAT_SPL) - && (SVAL(req->inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { + && (SVAL(req->vwv+16, 0) == LMCAT_SPL) + && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) { DEBUG(2,("Got Trans2 DevIOctl jobid\n")); } else { DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count)); @@ -7625,6 +7720,12 @@ void reply_trans2(struct smb_request *req) goto bad_param; if (state->total_data) { + + if (trans_oob(state->total_data, 0, dscnt) + || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ state->data = (char *)SMB_MALLOC(state->total_data); @@ -7637,21 +7738,16 @@ void reply_trans2(struct smb_request *req) return; } - if (dscnt > state->total_data || - dsoff+dscnt < dsoff) { - goto bad_param; - } - - if (dsoff > av_size || - dscnt > av_size || - dsoff+dscnt > av_size) { - goto bad_param; - } - memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt); } if (state->total_param) { + + if (trans_oob(state->total_param, 0, pscnt) + || trans_oob(smb_len(req->inbuf), psoff, pscnt)) { + goto bad_param; + } + /* Can't use talloc here, the core routines do realloc on the * params and data. */ state->param = (char *)SMB_MALLOC(state->total_param); @@ -7665,17 +7761,6 @@ void reply_trans2(struct smb_request *req) return; } - if (pscnt > state->total_param || - psoff+pscnt < psoff) { - goto bad_param; - } - - if (psoff > av_size || - pscnt > av_size || - psoff+pscnt > av_size) { - goto bad_param; - } - memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt); } @@ -7723,8 +7808,6 @@ void reply_transs2(struct smb_request *req) connection_struct *conn = req->conn; unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp; struct trans_state *state; - unsigned int size; - unsigned int av_size; START_PROFILE(SMBtranss2); @@ -7736,9 +7819,6 @@ void reply_transs2(struct smb_request *req) return; } - size = smb_len(req->inbuf)+4; - av_size = smb_len(req->inbuf); - for (state = conn->pending_trans; state != NULL; state = state->next) { if (state->mid == req->mid) { @@ -7755,18 +7835,18 @@ void reply_transs2(struct smb_request *req) /* Revise state->total_param and state->total_data in case they have changed downwards */ - if (SVAL(req->inbuf, smb_tpscnt) < state->total_param) - state->total_param = SVAL(req->inbuf, smb_tpscnt); - if (SVAL(req->inbuf, smb_tdscnt) < state->total_data) - state->total_data = SVAL(req->inbuf, smb_tdscnt); + if (SVAL(req->vwv+0, 0) < state->total_param) + state->total_param = SVAL(req->vwv+0, 0); + if (SVAL(req->vwv+1, 0) < state->total_data) + state->total_data = SVAL(req->vwv+1, 0); - pcnt = SVAL(req->inbuf, smb_spscnt); - poff = SVAL(req->inbuf, smb_spsoff); - pdisp = SVAL(req->inbuf, smb_spsdisp); + pcnt = SVAL(req->vwv+2, 0); + poff = SVAL(req->vwv+3, 0); + pdisp = SVAL(req->vwv+4, 0); - dcnt = SVAL(req->inbuf, smb_sdscnt); - doff = SVAL(req->inbuf, smb_sdsoff); - ddisp = SVAL(req->inbuf, smb_sdsdisp); + dcnt = SVAL(req->vwv+5, 0); + doff = SVAL(req->vwv+6, 0); + ddisp = SVAL(req->vwv+7, 0); state->received_param += pcnt; state->received_data += dcnt; @@ -7776,41 +7856,19 @@ void reply_transs2(struct smb_request *req) goto bad_param; if (pcnt) { - if (pdisp > state->total_param || - pcnt > state->total_param || - pdisp+pcnt > state->total_param || - pdisp+pcnt < pdisp) { - goto bad_param; - } - - if (poff > av_size || - pcnt > av_size || - poff+pcnt > av_size || - poff+pcnt < poff) { + if (trans_oob(state->total_param, pdisp, pcnt) + || trans_oob(smb_len(req->inbuf), poff, pcnt)) { goto bad_param; } - - memcpy(state->param+pdisp,smb_base(req->inbuf)+poff, - pcnt); + memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt); } if (dcnt) { - if (ddisp > state->total_data || - dcnt > state->total_data || - ddisp+dcnt > state->total_data || - ddisp+dcnt < ddisp) { - goto bad_param; - } - - if (ddisp > av_size || - dcnt > av_size || - ddisp+dcnt > av_size || - ddisp+dcnt < ddisp) { + if (trans_oob(state->total_data, ddisp, dcnt) + || trans_oob(smb_len(req->inbuf), doff, dcnt)) { goto bad_param; } - - memcpy(state->data+ddisp, smb_base(req->inbuf)+doff, - dcnt); + memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt); } if ((state->received_param < state->total_param) || @@ -7819,12 +7877,6 @@ void reply_transs2(struct smb_request *req) return; } - /* - * construct_reply_common will copy smb_com from inbuf to - * outbuf. SMBtranss2 is wrong here. - */ - SCVAL(req->inbuf,smb_com,SMBtrans2); - handle_trans2(conn, req, state); DLIST_REMOVE(conn->pending_trans, state);