X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Ftrans2.c;h=28862d1f4e8d78de92d71543895c192437117071;hb=bd269443e311d96ef495a9db47d1b95eb83bb8f4;hp=4bf27863bdec1821ed9f3da0123d0bff3c1421cf;hpb=dcc97c5ad7d274e88ee2be2bbd37234030737bc2;p=samba.git diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 4bf27863bde..28862d1f4e8 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -28,8 +28,6 @@ #include "smbd/globals.h" #include "../libcli/auth/libcli_auth.h" -extern enum protocol_types Protocol; - #define DIR_ENTRY_SAFETY_MARGIN 4096 static char *store_file_unix_basic(connection_struct *conn, @@ -72,6 +70,8 @@ static bool samba_private_attr_name(const char *unix_ea_name) static const char * const prohibited_ea_names[] = { SAMBA_POSIX_INHERITANCE_EA_NAME, SAMBA_XATTR_DOS_ATTRIB, + SAMBA_XATTR_MARKER, + XATTR_NTACL_NAME, NULL }; @@ -155,7 +155,9 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, ssize_t sizeret = -1; if (!lp_ea_support(SNUM(conn))) { - *pnames = NULL; + if (pnames) { + *pnames = NULL; + } *pnum_names = 0; return NT_STATUS_OK; } @@ -206,7 +208,9 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, if (sizeret == 0) { TALLOC_FREE(names); - *pnames = NULL; + if (pnames) { + *pnames = NULL; + } *pnum_names = 0; return NT_STATUS_OK; } @@ -243,7 +247,11 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, names[num_names++] = p; } - *pnames = names; + if (pnames) { + *pnames = names; + } else { + TALLOC_FREE(names); + } *pnum_names = num_names; return NT_STATUS_OK; } @@ -367,6 +375,69 @@ static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned in return ret_data_size; } +static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx, + char *pdata, + unsigned int total_data_size, + unsigned int *ret_data_size, + connection_struct *conn, + struct ea_list *ea_list) +{ + uint8_t *p = (uint8_t *)pdata; + uint8_t *last_start = NULL; + + *ret_data_size = 0; + + if (!lp_ea_support(SNUM(conn))) { + return NT_STATUS_NO_EAS_ON_FILE; + } + + for (; ea_list; ea_list = ea_list->next) { + size_t dos_namelen; + fstring dos_ea_name; + size_t this_size; + + if (last_start) { + SIVAL(last_start, 0, PTR_DIFF(p, last_start)); + } + last_start = p; + + push_ascii_fstring(dos_ea_name, ea_list->ea.name); + dos_namelen = strlen(dos_ea_name); + if (dos_namelen > 255 || dos_namelen == 0) { + return NT_STATUS_INTERNAL_ERROR; + } + if (ea_list->ea.value.length > 65535) { + return NT_STATUS_INTERNAL_ERROR; + } + + this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length; + + if (ea_list->next) { + size_t pad = 4 - (this_size % 4); + this_size += pad; + } + + 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); + fstrcpy((char *)(p+0x08), dos_ea_name); + memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length); + + total_data_size -= this_size; + p += this_size; + } + + *ret_data_size = PTR_DIFF(p, pdata); + DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size)); + return NT_STATUS_OK; +} + static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname) { size_t total_ea_len = 0; @@ -408,17 +479,13 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname, struct ea_list *ea_list) { char *fname = NULL; - NTSTATUS status; if (!lp_ea_support(SNUM(conn))) { return NT_STATUS_EAS_NOT_SUPPORTED; } - status = get_full_smb_filename(talloc_tos(), smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + /* For now setting EAs on streams isn't supported. */ + fname = smb_fname->base_name; for (;ea_list; ea_list = ea_list->next) { int ret; @@ -439,8 +506,9 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, if (ea_list->ea.value.length == 0) { /* Remove the attribute. */ if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); + DEBUG(10,("set_ea: deleting ea name %s on " + "file %s by file descriptor.\n", + unix_ea_name, fsp_str_dbg(fsp))); ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name); } else { DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", @@ -457,8 +525,9 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, #endif } else { if (fsp && (fsp->fh->fd != -1)) { - DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n", - unix_ea_name, fsp->fsp_name)); + DEBUG(10,("set_ea: setting ea name %s on file " + "%s by file descriptor.\n", + unix_ea_name, fsp_str_dbg(fsp))); ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name, ea_list->ea.value.data, ea_list->ea.value.length, 0); } else { @@ -943,7 +1012,7 @@ static void call_trans2open(connection_struct *conn, pname = ¶ms[28]; if (IS_IPC(conn)) { - reply_doserror(req, ERRSRV, ERRaccess); + reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED); goto out; } @@ -963,8 +1032,9 @@ static void call_trans2open(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &smb_fname, - NULL); + 0, + NULL, + &smb_fname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, @@ -981,13 +1051,11 @@ static void call_trans2open(connection_struct *conn, goto out; } - if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode, - open_ofun, - &access_mask, - &share_mode, - &create_disposition, - &create_options)) { - reply_doserror(req, ERRDOS, ERRbadaccess); + if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun, + &access_mask, &share_mode, + &create_disposition, + &create_options)) { + reply_nterror(req, NT_STATUS_ACCESS_DENIED); goto out; } @@ -1053,7 +1121,7 @@ static void call_trans2open(connection_struct *conn, inode = smb_fname->st.st_ex_ino; if (fattr & aDIR) { close_file(req, fsp, ERROR_CLOSE); - reply_doserror(req, ERRDOS,ERRnoaccess); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); goto out; } @@ -1085,7 +1153,8 @@ static void call_trans2open(connection_struct *conn, SIVAL(params,20,inode); SSVAL(params,24,0); /* Padding. */ if (flags & 8) { - uint32 ea_size = estimate_ea_size(conn, fsp, fsp->fsp_name); + uint32 ea_size = estimate_ea_size(conn, fsp, + fsp->fsp_name->base_name); SIVAL(params, 26, ea_size); } else { SIVAL(params, 26, 0); @@ -1104,19 +1173,24 @@ static void call_trans2open(connection_struct *conn, Case can be significant or not. **********************************************************/ -static bool exact_match(connection_struct *conn, - const char *str, - const char *mask) +static bool exact_match(bool has_wild, + bool case_sensitive, + const char *str, + const char *mask) { - if (mask[0] == '.' && mask[1] == 0) - return False; - if (dptr_has_wild(conn->dirptr)) { - return False; + if (mask[0] == '.' && mask[1] == 0) { + return false; + } + + if (has_wild) { + return false; } - if (conn->case_sensitive) + + if (case_sensitive) { return strcmp(str,mask)==0; - else + } else { return StrCaseCmp(str,mask) == 0; + } } /**************************************************************************** @@ -1256,671 +1330,699 @@ static bool check_msdfs_link(connection_struct *conn, Get a level dependent lanman2 dir entry. ****************************************************************************/ -static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, - connection_struct *conn, - uint16 flags2, - const char *path_mask, - uint32 dirtype, - int info_level, - int requires_resume_key, - bool dont_descend, - bool ask_sharemode, - char **ppdata, - char *base_data, - char *end_data, - int space_remaining, - bool *out_of_space, - bool *got_exact_match, - int *last_entry_off, - struct ea_list *name_list) +struct smbd_dirptr_lanman2_state { + connection_struct *conn; + uint32_t info_level; + bool check_mangled_names; + bool has_wild; + bool got_exact_match; +}; + +static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx, + void *private_data, + const char *dname, + const char *mask, + char **_fname) { - char *dname; - bool found = False; - SMB_STRUCT_STAT sbuf; - const char *mask = NULL; - char *pathreal = NULL; - char *fname = NULL; - char *p, *q, *pdata = *ppdata; - uint32 reskey=0; - long prev_dirpos=0; - uint32 mode=0; - SMB_OFF_T file_size = 0; - uint64_t allocation_size = 0; - uint32 len; - struct timespec mdate_ts, adate_ts, create_date_ts; - time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0; - char *nameptr; - char *last_entry_ptr; - bool was_8_3; - uint32 nt_extmode; /* Used for NT connections instead of mode */ - bool needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); - bool check_mangled_names = lp_manglednames(conn->params); + struct smbd_dirptr_lanman2_state *state = + (struct smbd_dirptr_lanman2_state *)private_data; + bool ok; char mangled_name[13]; /* mangled 8.3 name. */ + bool got_match; + const char *fname; - *out_of_space = False; - *got_exact_match = False; - - ZERO_STRUCT(mdate_ts); - ZERO_STRUCT(adate_ts); - ZERO_STRUCT(create_date_ts); - - if (!conn->dirptr) { - return(False); - } - - p = strrchr_m(path_mask,'/'); - if(p != NULL) { - if(p[1] == '\0') { - mask = talloc_strdup(ctx,"*.*"); - } else { - mask = p+1; + /* Mangle fname if it's an illegal name. */ + if (mangle_must_mangle(dname, state->conn->params)) { + ok = name_to_8_3(dname, mangled_name, + true, state->conn->params); + if (!ok) { + return false; } + fname = mangled_name; } else { - mask = path_mask; + fname = dname; } - while (!found) { - bool got_match; - bool ms_dfs_link = False; - - /* Needed if we run out of space */ - long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr); - dname = dptr_ReadDirName(ctx,conn->dirptr,&curr_dirpos,&sbuf); - - /* - * Due to bugs in NT client redirectors we are not using - * resume keys any more - set them to zero. - * Check out the related comments in findfirst/findnext. - * JRA. - */ - - reskey = 0; - - DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n", - (long)conn->dirptr,curr_dirpos)); - - if (!dname) { - return(False); - } + got_match = exact_match(state->has_wild, + state->conn->case_sensitive, + fname, mask); + state->got_exact_match = got_match; + if (!got_match) { + got_match = mask_match(fname, mask, + state->conn->case_sensitive); + } + if(!got_match && state->check_mangled_names && + !mangle_is_8_3(fname, false, state->conn->params)) { /* - * fname may get mangled, dname is never mangled. - * Whenever we're accessing the filesystem we use - * pathreal which is composed from dname. + * It turns out that NT matches wildcards against + * both long *and* short names. This may explain some + * of the wildcard wierdness from old DOS clients + * that some people have been seeing.... JRA. */ - - pathreal = NULL; - fname = dname; - - /* Mangle fname if it's an illegal name. */ - if (mangle_must_mangle(dname,conn->params)) { - if (!name_to_8_3(dname,mangled_name,True,conn->params)) { - TALLOC_FREE(fname); - continue; /* Error - couldn't mangle. */ - } - fname = talloc_strdup(ctx, mangled_name); - if (!fname) { - return False; - } - } - - if(!(got_match = *got_exact_match = exact_match(conn, fname, mask))) { - got_match = mask_match(fname, mask, conn->case_sensitive); + /* Force the mangling into 8.3. */ + ok = name_to_8_3(fname, mangled_name, + false, state->conn->params); + if (!ok) { + return false; } - if(!got_match && check_mangled_names && - !mangle_is_8_3(fname, False, conn->params)) { - /* - * It turns out that NT matches wildcards against - * both long *and* short names. This may explain some - * of the wildcard wierdness from old DOS clients - * that some people have been seeing.... JRA. - */ - /* Force the mangling into 8.3. */ - if (!name_to_8_3( fname, mangled_name, False, conn->params)) { - TALLOC_FREE(fname); - continue; /* Error - couldn't mangle. */ - } - - if(!(got_match = *got_exact_match = exact_match(conn, mangled_name, mask))) { - got_match = mask_match(mangled_name, mask, conn->case_sensitive); - } + got_match = exact_match(state->has_wild, + state->conn->case_sensitive, + mangled_name, mask); + state->got_exact_match = got_match; + if (!got_match) { + got_match = mask_match(mangled_name, mask, + state->conn->case_sensitive); } + } - if (got_match) { - bool isdots = (ISDOT(dname) || ISDOTDOT(dname)); - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - if (dont_descend && !isdots) { - TALLOC_FREE(fname); - continue; - } - - if (needslash) { - pathreal = NULL; - pathreal = talloc_asprintf(ctx, - "%s/%s", - conn->dirpath, - dname); - } else { - pathreal = talloc_asprintf(ctx, - "%s%s", - conn->dirpath, - dname); - } + if (!got_match) { + return false; + } - if (!pathreal) { - TALLOC_FREE(fname); - return False; - } + *_fname = talloc_strdup(ctx, fname); + if (*_fname == NULL) { + return false; + } - /* A dirent from dptr_ReadDirName isn't a stream. */ - status = create_synthetic_smb_fname(ctx, pathreal, - NULL, &sbuf, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fname); - return false; - } + return true; +} - if (INFO_LEVEL_IS_UNIX(info_level)) { - if (SMB_VFS_LSTAT(conn, smb_fname) != 0) { - DEBUG(5,("get_lanman2_dir_entry: " - "Couldn't lstat [%s] (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - TALLOC_FREE(smb_fname); - TALLOC_FREE(pathreal); - TALLOC_FREE(fname); - continue; - } - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname) != 0) { - /* Needed to show the msdfs symlinks as - * directories */ - - ms_dfs_link = - check_msdfs_link(conn, - smb_fname->base_name, - &smb_fname->st); - if (!ms_dfs_link) { - DEBUG(5,("get_lanman2_dir_entry: " - "Couldn't stat [%s] (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - TALLOC_FREE(smb_fname); - TALLOC_FREE(pathreal); - TALLOC_FREE(fname); - continue; - } - } +static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx, + void *private_data, + struct smb_filename *smb_fname, + uint32_t *_mode) +{ + struct smbd_dirptr_lanman2_state *state = + (struct smbd_dirptr_lanman2_state *)private_data; + bool ms_dfs_link = false; + uint32_t mode = 0; - if (ms_dfs_link) { - mode = dos_mode_msdfs(conn, smb_fname); - } else { - mode = dos_mode(conn, smb_fname); - } + if (INFO_LEVEL_IS_UNIX(state->info_level)) { + if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) { + DEBUG(5,("smbd_dirptr_lanman2_mode_fn: " + "Couldn't lstat [%s] (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + return false; + } + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(state->conn, smb_fname) != 0) { + /* Needed to show the msdfs symlinks as + * directories */ + + ms_dfs_link = check_msdfs_link(state->conn, + smb_fname->base_name, + &smb_fname->st); + if (!ms_dfs_link) { + DEBUG(5,("smbd_dirptr_lanman2_mode_fn: " + "Couldn't stat [%s] (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + return false; + } + } - if (!dir_check_ftype(conn,mode,dirtype)) { - DEBUG(5,("get_lanman2_dir_entry: [%s] attribs didn't match %x\n",fname,dirtype)); - TALLOC_FREE(smb_fname); - TALLOC_FREE(pathreal); - TALLOC_FREE(fname); - continue; - } + if (ms_dfs_link) { + mode = dos_mode_msdfs(state->conn, smb_fname); + } else { + mode = dos_mode(state->conn, smb_fname); + } - if (!(mode & aDIR)) { - file_size = get_file_size_stat(&smb_fname->st); - } - allocation_size = - SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st); - - if (ask_sharemode) { - struct timespec write_time_ts; - struct file_id fileid; - - ZERO_STRUCT(write_time_ts); - fileid = vfs_file_id_from_sbuf(conn, - &smb_fname->st); - get_file_infos(fileid, NULL, &write_time_ts); - if (!null_timespec(write_time_ts)) { - update_stat_ex_mtime(&smb_fname->st, - write_time_ts); - } - } + *_mode = mode; + return true; +} - mdate_ts = smb_fname->st.st_ex_mtime; - adate_ts = smb_fname->st.st_ex_atime; - create_date_ts = smb_fname->st.st_ex_btime; +static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + uint16_t flags2, + uint32_t info_level, + struct ea_list *name_list, + bool check_mangled_names, + bool requires_resume_key, + uint32_t mode, + const char *fname, + const struct smb_filename *smb_fname, + uint64_t space_remaining, + uint8_t align, + bool do_pad, + char *base_data, + char **ppdata, + char *end_data, + bool *out_of_space, + uint64_t *last_entry_off) +{ + char *p, *q, *pdata = *ppdata; + uint32_t reskey=0; + uint64_t file_size = 0; + uint64_t allocation_size = 0; + uint32_t len; + struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts; + time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0; + time_t c_date = (time_t)0; + char *nameptr; + char *last_entry_ptr; + bool was_8_3; + off_t off; + off_t pad = 0; - if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&create_date_ts); - dos_filetime_timespec(&mdate_ts); - dos_filetime_timespec(&adate_ts); - } + *out_of_space = false; - create_date = convert_timespec_to_time_t(create_date_ts); - mdate = convert_timespec_to_time_t(mdate_ts); - adate = convert_timespec_to_time_t(adate_ts); + ZERO_STRUCT(mdate_ts); + ZERO_STRUCT(adate_ts); + ZERO_STRUCT(create_date_ts); + ZERO_STRUCT(cdate_ts); - DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n", - smb_fname_str_dbg(smb_fname), fname)); + if (!(mode & aDIR)) { + file_size = get_file_size_stat(&smb_fname->st); + } + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st); - found = True; + mdate_ts = smb_fname->st.st_ex_mtime; + adate_ts = smb_fname->st.st_ex_atime; + create_date_ts = get_create_timespec(conn, NULL, smb_fname); + cdate_ts = get_change_timespec(conn, NULL, smb_fname); - dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos); - sbuf = smb_fname->st; + if (lp_dos_filetime_resolution(SNUM(conn))) { + dos_filetime_timespec(&create_date_ts); + dos_filetime_timespec(&mdate_ts); + dos_filetime_timespec(&adate_ts); + dos_filetime_timespec(&cdate_ts); + } - TALLOC_FREE(smb_fname); - } + create_date = convert_timespec_to_time_t(create_date_ts); + mdate = convert_timespec_to_time_t(mdate_ts); + adate = convert_timespec_to_time_t(adate_ts); + c_date = convert_timespec_to_time_t(cdate_ts); - if (!found) - TALLOC_FREE(fname); + /* align the record */ + off = PTR_DIFF(pdata, base_data); + pad = (off + (align-1)) & ~(align-1); + pad -= off; + off += pad; + /* initialize padding to 0 */ + if (pad) { + memset(pdata, 0, pad); } + space_remaining -= pad; + pdata += pad; p = pdata; last_entry_ptr = p; - nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL; + pad = 0; + off = 0; switch (info_level) { - case SMB_FIND_INFO_STANDARD: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n")); - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - p += 23; - nameptr = p; - if (flags2 & FLAGS2_UNICODE_STRINGS) { - p += ucs2_align(base_data, p, 0); - } - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - SCVAL(nameptr, -1, len - 2); - } else { - SCVAL(nameptr, -1, 0); - } + case SMB_FIND_INFO_STANDARD: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n")); + if(requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + SSVAL(p,20,mode); + p += 23; + nameptr = p; + if (flags2 & FLAGS2_UNICODE_STRINGS) { + p += ucs2_align(base_data, p, 0); + } + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + SCVAL(nameptr, -1, len - 2); } else { - if (len > 1) { - SCVAL(nameptr, -1, len - 1); - } else { - SCVAL(nameptr, -1, 0); - } - } - p += len; - break; - - case SMB_FIND_EA_SIZE: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n")); - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - { - unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); - SIVAL(p,22,ea_size); /* Extended attributes */ + SCVAL(nameptr, -1, 0); } - p += 27; - nameptr = p - 1; - len = srvstr_push(base_data, flags2, - p, fname, PTR_DIFF(end_data, p), - STR_TERMINATE | STR_NOALIGN); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - len -= 2; - } else { - len = 0; - } + } else { + if (len > 1) { + SCVAL(nameptr, -1, len - 1); } else { - if (len > 1) { - len -= 1; - } else { - len = 0; - } + SCVAL(nameptr, -1, 0); } - SCVAL(nameptr,0,len); - p += len; - SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ - break; + } + p += len; + break; - case SMB_FIND_EA_LIST: + case SMB_FIND_EA_SIZE: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n")); + if (requires_resume_key) { + SIVAL(p,0,reskey); + p += 4; + } + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + SSVAL(p,20,mode); { - struct ea_list *file_list = NULL; - size_t ea_len = 0; - - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n")); - if (!name_list) { - return False; - } - if(requires_resume_key) { - SIVAL(p,0,reskey); - p += 4; - } - srv_put_dos_date2(p,0,create_date); - srv_put_dos_date2(p,4,adate); - srv_put_dos_date2(p,8,mdate); - SIVAL(p,12,(uint32)file_size); - SIVAL(p,16,(uint32)allocation_size); - SSVAL(p,20,mode); - p += 22; /* p now points to the EA area. */ - - file_list = get_ea_list_from_file(ctx, conn, NULL, pathreal, &ea_len); - name_list = ea_list_union(name_list, file_list, &ea_len); - - /* We need to determine if this entry will fit in the space available. */ - /* Max string size is 255 bytes. */ - if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) { - /* Move the dirptr back to prev_dirpos */ - dptr_SeekDir(conn->dirptr, prev_dirpos); - *out_of_space = True; - DEBUG(9,("get_lanman2_dir_entry: out of space\n")); - return False; /* Not finished - just out of space */ + unsigned int ea_size = estimate_ea_size(conn, NULL, + smb_fname->base_name); + SIVAL(p,22,ea_size); /* Extended attributes */ + } + p += 27; + nameptr = p - 1; + len = srvstr_push(base_data, flags2, + p, fname, PTR_DIFF(end_data, p), + STR_TERMINATE | STR_NOALIGN); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + len -= 2; + } else { + len = 0; } - - /* Push the ea_data followed by the name. */ - p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); - nameptr = p; - len = srvstr_push(base_data, flags2, - p + 1, fname, PTR_DIFF(end_data, p+1), - STR_TERMINATE | STR_NOALIGN); - if (flags2 & FLAGS2_UNICODE_STRINGS) { - if (len > 2) { - len -= 2; - } else { - len = 0; - } + } else { + if (len > 1) { + len -= 1; } else { - if (len > 1) { - len -= 1; - } else { - len = 0; - } + len = 0; } - SCVAL(nameptr,0,len); - p += len + 1; - SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ - break; } + SCVAL(nameptr,0,len); + p += len; + SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ + break; - case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n")); - was_8_3 = mangle_is_8_3(fname, True, conn->params); + case SMB_FIND_EA_LIST: + { + struct ea_list *file_list = NULL; + size_t ea_len = 0; + + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n")); + if (!name_list) { + return false; + } + if (requires_resume_key) { + SIVAL(p,0,reskey); p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(p,create_date_ts); p += 8; - put_long_date_timespec(p,adate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); - SIVAL(p,0,ea_size); /* Extended attributes */ - p += 4; + } + srv_put_dos_date2(p,0,create_date); + srv_put_dos_date2(p,4,adate); + srv_put_dos_date2(p,8,mdate); + SIVAL(p,12,(uint32)file_size); + SIVAL(p,16,(uint32)allocation_size); + 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); + name_list = ea_list_union(name_list, file_list, &ea_len); + + /* We need to determine if this entry will fit in the space available. */ + /* Max string size is 255 bytes. */ + if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) { + *out_of_space = true; + DEBUG(9,("smbd_marshall_dir_entry: out of space\n")); + return False; /* Not finished - just out of space */ + } + + /* Push the ea_data followed by the name. */ + p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list); + nameptr = p; + len = srvstr_push(base_data, flags2, + p + 1, fname, PTR_DIFF(end_data, p+1), + STR_TERMINATE | STR_NOALIGN); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + if (len > 2) { + len -= 2; + } else { + len = 0; } - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - if (!was_8_3 && check_mangled_names) { - if (!name_to_8_3(fname,mangled_name,True, - conn->params)) { - /* Error - mangle failed ! */ - memset(mangled_name,'\0',12); - } - mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, - p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); - if (len < 24) { - memset(p + 2 + len,'\0',24 - len); - } - SSVAL(p, 0, len); + } else { + if (len > 1) { + len -= 1; } else { - memset(p,'\0',26); + len = 0; } - p += 2 + 24; - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; + } + SCVAL(nameptr,0,len); + p += len + 1; + SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */ + break; + } - case SMB_FIND_FILE_DIRECTORY_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n")); + case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n")); + was_8_3 = mangle_is_8_3(fname, True, conn->params); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, + smb_fname->base_name); + SIVAL(p,0,ea_size); /* Extended attributes */ p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(p,create_date_ts); p += 8; - put_long_date_timespec(p,adate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; + } + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + if (!was_8_3 && check_mangled_names) { + char mangled_name[13]; /* mangled 8.3 name. */ + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); + } + mangled_name[12] = 0; len = srvstr_push(base_data, flags2, - p + 4, fname, PTR_DIFF(end_data, p+4), - STR_TERMINATE_ASCII); - SIVAL(p,0,len); - p += 4 + len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); - p = pdata + len; - break; - - case SMB_FIND_FILE_FULL_DIRECTORY_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(p,create_date_ts); p += 8; - put_long_date_timespec(p,adate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; + p+2, mangled_name, 24, + STR_UPPER|STR_UNICODE); + if (len < 24) { + memset(p + 2 + len,'\0',24 - len); } - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q, 0, len); - p += len; + SSVAL(p, 0, len); + } else { + memset(p,'\0',26); + } + p += 2 + 24; + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q,0,len); + p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { p = pdata + len; - break; + } + break; - case SMB_FIND_FILE_NAMES_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - p += 4; - /* this must *not* be null terminated or w2k gets in a loop trying to set an - acl on a dir (tridge) */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(p, -4, len); - p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); + case SMB_FIND_FILE_DIRECTORY_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + len = srvstr_push(base_data, flags2, + p + 4, fname, PTR_DIFF(end_data, p+4), + STR_TERMINATE_ASCII); + SIVAL(p,0,len); + p += 4 + len; + + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { p = pdata + len; - break; + } + break; - case SMB_FIND_ID_FULL_DIRECTORY_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n")); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(p,create_date_ts); p += 8; - put_long_date_timespec(p,adate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; /* q is placeholder for name length. */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; - } - SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */ - SIVAL(p,0,sbuf.st_ex_ino); p += 4; /* FileIndexLow */ - SIVAL(p,0,sbuf.st_ex_dev); p += 4; /* FileIndexHigh */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q, 0, len); - p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); + case SMB_FIND_FILE_FULL_DIRECTORY_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, + smb_fname->base_name); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; + } + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q, 0, len); + p += len; + + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { p = pdata + len; - break; + } + break; - case SMB_FIND_ID_BOTH_DIRECTORY_INFO: - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n")); - was_8_3 = mangle_is_8_3(fname, True, conn->params); - p += 4; - SIVAL(p,0,reskey); p += 4; - put_long_date_timespec(p,create_date_ts); p += 8; - put_long_date_timespec(p,adate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - put_long_date_timespec(p,mdate_ts); p += 8; - SOFF_T(p,0,file_size); p += 8; - SOFF_T(p,0,allocation_size); p += 8; - SIVAL(p,0,nt_extmode); p += 4; - q = p; p += 4; /* q is placeholder for name length */ - { - unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal); - SIVAL(p,0,ea_size); /* Extended attributes */ - p +=4; + case SMB_FIND_FILE_NAMES_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + p += 4; + /* this must *not* be null terminated or w2k gets in a loop trying to set an + acl on a dir (tridge) */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(p, -4, len); + p += len; + + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { + p = pdata + len; + } + break; + + case SMB_FIND_ID_FULL_DIRECTORY_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n")); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length. */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, + smb_fname->base_name); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; + } + SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */ + SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */ + SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q, 0, len); + p += len; + + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { + p = pdata + len; + } + break; + + case SMB_FIND_ID_BOTH_DIRECTORY_INFO: + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n")); + was_8_3 = mangle_is_8_3(fname, True, conn->params); + p += 4; + SIVAL(p,0,reskey); p += 4; + put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8; + put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8; + SOFF_T(p,0,file_size); p += 8; + SOFF_T(p,0,allocation_size); p += 8; + SIVAL(p,0,mode); p += 4; + q = p; p += 4; /* q is placeholder for name length */ + { + unsigned int ea_size = estimate_ea_size(conn, NULL, + smb_fname->base_name); + SIVAL(p,0,ea_size); /* Extended attributes */ + p +=4; + } + /* Clear the short name buffer. This is + * IMPORTANT as not doing so will trigger + * a Win2k client bug. JRA. + */ + if (!was_8_3 && check_mangled_names) { + char mangled_name[13]; /* mangled 8.3 name. */ + if (!name_to_8_3(fname,mangled_name,True, + conn->params)) { + /* Error - mangle failed ! */ + memset(mangled_name,'\0',12); } - /* Clear the short name buffer. This is - * IMPORTANT as not doing so will trigger - * a Win2k client bug. JRA. - */ - if (!was_8_3 && check_mangled_names) { - if (!name_to_8_3(fname,mangled_name,True, - conn->params)) { - /* Error - mangle failed ! */ - memset(mangled_name,'\0',12); - } - mangled_name[12] = 0; - len = srvstr_push(base_data, flags2, - p+2, mangled_name, 24, - STR_UPPER|STR_UNICODE); - SSVAL(p, 0, len); - if (len < 24) { - memset(p + 2 + len,'\0',24 - len); - } - SSVAL(p, 0, len); - } else { - memset(p,'\0',26); + mangled_name[12] = 0; + len = srvstr_push(base_data, flags2, + p+2, mangled_name, 24, + STR_UPPER|STR_UNICODE); + SSVAL(p, 0, len); + if (len < 24) { + memset(p + 2 + len,'\0',24 - len); } - p += 26; - SSVAL(p,0,0); p += 2; /* Reserved ? */ - SIVAL(p,0,sbuf.st_ex_ino); p += 4; /* FileIndexLow */ - SIVAL(p,0,sbuf.st_ex_dev); p += 4; /* FileIndexHigh */ - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE_ASCII); - SIVAL(q,0,len); - p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); + SSVAL(p, 0, len); + } else { + memset(p,'\0',26); + } + p += 26; + SSVAL(p,0,0); p += 2; /* Reserved ? */ + SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */ + SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */ + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE_ASCII); + SIVAL(q,0,len); + p += len; + + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { p = pdata + len; - break; + } + break; - /* CIFS UNIX Extension. */ + /* CIFS UNIX Extension. */ - case SMB_FIND_FILE_UNIX: - case SMB_FIND_FILE_UNIX_INFO2: - p+= 4; - SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ + case SMB_FIND_FILE_UNIX: + case SMB_FIND_FILE_UNIX_INFO2: + p+= 4; + SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */ - /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ + /* Begin of SMB_QUERY_FILE_UNIX_BASIC */ - if (info_level == SMB_FIND_FILE_UNIX) { - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n")); - p = store_file_unix_basic(conn, p, - NULL, &sbuf); - len = srvstr_push(base_data, flags2, p, - fname, PTR_DIFF(end_data, p), - STR_TERMINATE); - } else { - DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); - p = store_file_unix_basic_info2(conn, p, - NULL, &sbuf); - nameptr = p; - p += 4; - len = srvstr_push(base_data, flags2, p, fname, - PTR_DIFF(end_data, p), 0); - SIVAL(nameptr, 0, len); - } + if (info_level == SMB_FIND_FILE_UNIX) { + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n")); + p = store_file_unix_basic(conn, p, + NULL, &smb_fname->st); + len = srvstr_push(base_data, flags2, p, + fname, PTR_DIFF(end_data, p), + STR_TERMINATE); + } else { + DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n")); + p = store_file_unix_basic_info2(conn, p, + NULL, &smb_fname->st); + nameptr = p; + p += 4; + len = srvstr_push(base_data, flags2, p, fname, + PTR_DIFF(end_data, p), 0); + SIVAL(nameptr, 0, len); + } - p += len; - SIVAL(p,0,0); /* Ensure any padding is null. */ + p += len; - len = PTR_DIFF(p, pdata); - len = (len + 3) & ~3; - SIVAL(pdata,0,len); /* Offset from this structure to the beginning of the next one */ + len = PTR_DIFF(p, pdata); + pad = (len + (align-1)) & ~(align-1); + /* + * offset to the next entry, the caller + * will overwrite it for the last entry + * that's why we always include the padding + */ + SIVAL(pdata,0,pad); + /* + * set padding to zero + */ + if (do_pad) { + memset(p, 0, pad - len); + p = pdata + pad; + } else { p = pdata + len; - /* End of SMB_QUERY_FILE_UNIX_BASIC */ + } + /* End of SMB_QUERY_FILE_UNIX_BASIC */ - break; + break; - default: - TALLOC_FREE(fname); - return(False); + default: + return false; } - TALLOC_FREE(fname); if (PTR_DIFF(p,pdata) > space_remaining) { - /* Move the dirptr back to prev_dirpos */ - dptr_SeekDir(conn->dirptr, prev_dirpos); - *out_of_space = True; - DEBUG(9,("get_lanman2_dir_entry: out of space\n")); - return False; /* Not finished - just out of space */ + *out_of_space = true; + DEBUG(9,("smbd_marshall_dir_entry: out of space\n")); + return false; /* Not finished - just out of space */ } /* Setup the last entry pointer, as an offset from base_data */ @@ -1928,7 +2030,147 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, /* Advance the data pointer to the next slot */ *ppdata = p; - return(found); + return true; +} + +bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, + connection_struct *conn, + struct dptr_struct *dirptr, + uint16 flags2, + const char *path_mask, + uint32 dirtype, + int info_level, + int requires_resume_key, + bool dont_descend, + bool ask_sharemode, + uint8_t align, + bool do_pad, + char **ppdata, + char *base_data, + char *end_data, + int space_remaining, + bool *out_of_space, + bool *got_exact_match, + int *_last_entry_off, + struct ea_list *name_list) +{ + const char *p; + const char *mask = NULL; + long prev_dirpos = 0; + uint32_t mode = 0; + char *fname = NULL; + struct smb_filename *smb_fname = NULL; + struct smbd_dirptr_lanman2_state state; + bool ok; + uint64_t last_entry_off = 0; + + ZERO_STRUCT(state); + state.conn = conn; + state.info_level = info_level; + state.check_mangled_names = lp_manglednames(conn->params); + state.has_wild = dptr_has_wild(dirptr); + state.got_exact_match = false; + + *out_of_space = false; + *got_exact_match = false; + + p = strrchr_m(path_mask,'/'); + if(p != NULL) { + if(p[1] == '\0') { + mask = "*.*"; + } else { + mask = p+1; + } + } else { + mask = path_mask; + } + + ok = smbd_dirptr_get_entry(ctx, + dirptr, + mask, + dirtype, + dont_descend, + ask_sharemode, + smbd_dirptr_lanman2_match_fn, + smbd_dirptr_lanman2_mode_fn, + &state, + &fname, + &smb_fname, + &mode, + &prev_dirpos); + if (!ok) { + return false; + } + + *got_exact_match = state.got_exact_match; + + ok = smbd_marshall_dir_entry(ctx, + conn, + flags2, + info_level, + name_list, + state.check_mangled_names, + requires_resume_key, + mode, + fname, + smb_fname, + space_remaining, + align, + do_pad, + base_data, + ppdata, + end_data, + out_of_space, + &last_entry_off); + TALLOC_FREE(fname); + TALLOC_FREE(smb_fname); + if (*out_of_space) { + dptr_SeekDir(dirptr, prev_dirpos); + return false; + } + if (!ok) { + return false; + } + + *_last_entry_off = last_entry_off; + return true; +} + +static bool get_lanman2_dir_entry(TALLOC_CTX *ctx, + connection_struct *conn, + struct dptr_struct *dirptr, + uint16 flags2, + const char *path_mask, + uint32 dirtype, + int info_level, + bool requires_resume_key, + bool dont_descend, + bool ask_sharemode, + char **ppdata, + char *base_data, + char *end_data, + int space_remaining, + bool *out_of_space, + bool *got_exact_match, + int *last_entry_off, + struct ea_list *name_list) +{ + uint8_t align = 4; + const bool do_pad = true; + + if (info_level >= 1 && info_level <= 3) { + /* No alignment on earlier info levels. */ + align = 1; + } + + return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2, + path_mask, dirtype, info_level, + requires_resume_key, dont_descend, ask_sharemode, + align, do_pad, + ppdata, base_data, end_data, + space_remaining, + out_of_space, got_exact_match, + last_entry_off, name_list); } /**************************************************************************** @@ -1973,10 +2215,12 @@ static void call_trans2findfirst(connection_struct *conn, NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); TALLOC_CTX *ctx = talloc_tos(); + struct dptr_struct *dirptr = NULL; + struct smbd_server_connection *sconn = smbd_server_conn; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } dirtype = SVAL(params,0); @@ -2014,12 +2258,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", ask_sharemode = false; if (!lp_unix_extensions()) { reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + goto out; } break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + goto out; } srvstr_get_path_wcard(ctx, params, req->flags2, &directory, @@ -2027,45 +2271,29 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", STR_TERMINATE, &ntstatus, &mask_contains_wcard); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } - ntstatus = resolve_dfspath_wcard(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - directory, - &directory, - &mask_contains_wcard); + ntstatus = filename_convert(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + directory, + (UCF_SAVE_LCOMP | + UCF_ALWAYS_ALLOW_WCARD_LCOMP), + &mask_contains_wcard, + &smb_dname); if (!NT_STATUS_IS_OK(ntstatus)) { if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); - return; + goto out; } reply_nterror(req, ntstatus); - return; - } - - ntstatus = unix_convert(ctx, conn, directory, &smb_dname, - (UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP)); - if (!NT_STATUS_IS_OK(ntstatus)) { - reply_nterror(req, ntstatus); - return; + goto out; } mask = smb_dname->original_lcomp; - ntstatus = get_full_smb_filename(ctx, smb_dname, &directory); - TALLOC_FREE(smb_dname); - if (!NT_STATUS_IS_OK(ntstatus)) { - reply_nterror(req, ntstatus); - return; - } - - ntstatus = check_name(conn, directory); - if (!NT_STATUS_IS_OK(ntstatus)) { - reply_nterror(req, ntstatus); - return; - } + directory = smb_dname->base_name; p = strrchr_m(directory,'/'); if(p == NULL) { @@ -2074,14 +2302,14 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", mask = talloc_strdup(ctx,"*"); if (!mask) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } mask_contains_wcard = True; } directory = talloc_strdup(talloc_tos(), "./"); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } } else { *p = 0; @@ -2094,7 +2322,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", if (total_data < 4) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } ea_size = IVAL(pdata,0); @@ -2102,19 +2330,19 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } if (!lp_ea_support(SNUM(conn))) { - reply_doserror(req, ERRDOS, ERReasnotsupported); - return; + reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); + goto out; } /* Pull out the list of names. */ ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } } @@ -2122,7 +2350,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); if(*ppdata == NULL ) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } pdata = *ppdata; data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1; @@ -2131,7 +2359,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd *pparams = (char *)SMB_REALLOC(*pparams, 10); if (*pparams == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } params = *pparams; @@ -2146,24 +2374,25 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd mask, mask_contains_wcard, dirtype, - &conn->dirptr); + &dirptr); if (!NT_STATUS_IS_OK(ntstatus)) { reply_nterror(req, ntstatus); - return; + goto out; } - dptr_num = dptr_dnum(conn->dirptr); + dptr_num = dptr_dnum(dirptr); DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype)); /* Initialize per TRANS2_FIND_FIRST operation data */ - dptr_init_search_op(conn->dirptr); + dptr_init_search_op(dirptr); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", + directory,lp_dontdescend(SNUM(conn)))); + if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -2181,6 +2410,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { finished = !get_lanman2_dir_entry(ctx, conn, + dirptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -2219,7 +2449,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check if we can close the dirptr */ if(close_after_first || (finished && close_if_end)) { DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num)); - dptr_close(&dptr_num); + dptr_close(sconn, &dptr_num); } /* @@ -2230,14 +2460,14 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd */ if(numentries == 0) { - dptr_close(&dptr_num); - if (Protocol < PROTOCOL_NT1) { - reply_doserror(req, ERRDOS, ERRnofiles); - return; + dptr_close(sconn, &dptr_num); + if (get_Protocol() < PROTOCOL_NT1) { + reply_force_doserror(req, ERRDOS, ERRnofiles); + goto out; } else { reply_botherror(req, NT_STATUS_NO_SUCH_FILE, ERRDOS, ERRbadfile); - return; + goto out; } } @@ -2253,8 +2483,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); - if ((! *directory) && dptr_path(dptr_num)) { - directory = talloc_strdup(talloc_tos(),dptr_path(dptr_num)); + if ((! *directory) && dptr_path(sconn, dptr_num)) { + directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num)); if (!directory) { reply_nterror(req, NT_STATUS_NO_MEMORY); } @@ -2276,7 +2506,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd char mangled_name[13]; name_to_8_3(mask, mangled_name, True, conn->params); } - + out: + TALLOC_FREE(smb_dname); return; } @@ -2323,6 +2554,8 @@ static void call_trans2findnext(connection_struct *conn, NTSTATUS ntstatus = NT_STATUS_OK; bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); TALLOC_CTX *ctx = talloc_tos(); + struct dptr_struct *dirptr; + struct smbd_server_connection *sconn = smbd_server_conn; if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2339,23 +2572,26 @@ static void call_trans2findnext(connection_struct *conn, requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME); continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE); - srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name, + if (!continue_bit) { + /* We only need resume_name if continue_bit is zero. */ + srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name, params+12, total_params - 12, STR_TERMINATE, &ntstatus, &mask_contains_wcard); - if (!NT_STATUS_IS_OK(ntstatus)) { - /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to - complain (it thinks we're asking for the directory above the shared - path or an invalid name). Catch this as the resume name is only compared, never used in - a file access. JRA. */ - srvstr_pull_talloc(ctx, params, req->flags2, + if (!NT_STATUS_IS_OK(ntstatus)) { + /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to + complain (it thinks we're asking for the directory above the shared + path or an invalid name). Catch this as the resume name is only compared, never used in + a file access. JRA. */ + srvstr_pull_talloc(ctx, params, req->flags2, &resume_name, params+12, total_params - 12, STR_TERMINATE); - if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) { - reply_nterror(req, ntstatus); - return; + if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) { + reply_nterror(req, ntstatus); + return; + } } } @@ -2363,7 +2599,8 @@ static void call_trans2findnext(connection_struct *conn, close_after_request=%d, close_if_end = %d requires_resume_key = %d \ resume_key = %d resume name = %s continue=%d level = %d\n", dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, - requires_resume_key, resume_key, resume_name, continue_bit, info_level)); + requires_resume_key, resume_key, + resume_name ? resume_name : "(NULL)", continue_bit, info_level)); if (!maxentries) { /* W2K3 seems to treat zero as 1. */ @@ -2412,7 +2649,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } if (!lp_ea_support(SNUM(conn))) { - reply_doserror(req, ERRDOS, ERReasnotsupported); + reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); return; } @@ -2444,39 +2681,39 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd params = *pparams; /* Check that the dptr is valid */ - if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) { - reply_doserror(req, ERRDOS, ERRnofiles); + if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) { + reply_nterror(req, STATUS_NO_MORE_FILES); return; } - string_set(&conn->dirpath,dptr_path(dptr_num)); + directory = dptr_path(sconn, dptr_num); /* Get the wildcard mask from the dptr */ - if((p = dptr_wcard(dptr_num))== NULL) { + if((p = dptr_wcard(sconn, dptr_num))== NULL) { DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num)); - reply_doserror(req, ERRDOS, ERRnofiles); + reply_nterror(req, STATUS_NO_MORE_FILES); return; } mask = p; - directory = conn->dirpath; /* Get the attr mask from the dptr */ - dirtype = dptr_attr(dptr_num); + dirtype = dptr_attr(sconn, dptr_num); DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n", dptr_num, mask, dirtype, - (long)conn->dirptr, - dptr_TellDir(conn->dirptr))); + (long)dirptr, + dptr_TellDir(dirptr))); /* Initialize per TRANS2_FIND_NEXT operation data */ - dptr_init_search_op(conn->dirptr); + dptr_init_search_op(dirptr); /* We don't need to check for VOL here as this is returned by a different TRANS2 call. */ - DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) + DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", + directory,lp_dontdescend(SNUM(conn)))); + if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -2488,7 +2725,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd * depend on the last file name instead. */ - if(*resume_name && !continue_bit) { + if(!continue_bit && resume_name && *resume_name) { SMB_STRUCT_STAT st; long current_pos = 0; @@ -2518,7 +2755,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd * should already be at the correct place. */ - finished = !dptr_SearchDir(conn->dirptr, resume_name, ¤t_pos, &st); + finished = !dptr_SearchDir(dirptr, resume_name, ¤t_pos, &st); } /* end if resume_name && !continue_bit */ for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) { @@ -2532,6 +2769,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } else { finished = !get_lanman2_dir_entry(ctx, conn, + dirptr, req->flags2, mask,dirtype,info_level, requires_resume_key,dont_descend, @@ -2568,7 +2806,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* Check if we can close the dirptr */ if(close_after_request || (finished && close_if_end)) { DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num)); - dptr_close(&dptr_num); /* This frees up the saved mask */ + dptr_close(sconn, &dptr_num); /* This frees up the saved mask */ } /* Set up the return parameter block */ @@ -2624,67 +2862,48 @@ static void samba_extended_info_version(struct smb_extended_info *extended_info) "%s", samba_version_string()); } -/**************************************************************************** - Reply to a TRANS2_QFSINFO (query filesystem info). -****************************************************************************/ - -static void call_trans2qfsinfo(connection_struct *conn, - struct smb_request *req, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) +NTSTATUS smbd_do_qfsinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + int *ret_data_len) { char *pdata, *end_data; - char *params = *pparams; - uint16 info_level; - int data_len, len; - SMB_STRUCT_STAT st; + int data_len = 0, len; const char *vname = volume_label(SNUM(conn)); int snum = SNUM(conn); char *fstype = lp_fstype(SNUM(conn)); uint32 additional_flags = 0; - - if (total_params < 2) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); + struct smb_filename smb_fname_dot; + SMB_STRUCT_STAT st; if (IS_IPC(conn)) { if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("call_trans2qfsinfo: not an allowed " + DEBUG(0,("smbd_do_qfsinfo: not an allowed " "info level (0x%x) on IPC$.\n", (unsigned int)info_level)); - reply_nterror(req, NT_STATUS_ACCESS_DENIED); - return; + return NT_STATUS_ACCESS_DENIED; } } - if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { - if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { - DEBUG(0,("call_trans2qfsinfo: encryption required " - "and info level 0x%x sent.\n", - (unsigned int)info_level)); - exit_server_cleanly("encryption required " - "on connection"); - return; - } - } + DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level)); - DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + ZERO_STRUCT(smb_fname_dot); + smb_fname_dot.base_name = discard_const_p(char, "."); - if(vfs_stat_smb_fname(conn,".",&st)!=0) { - DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno))); - reply_doserror(req, ERRSRV, ERRinvdevice); - return; + if(SMB_VFS_STAT(conn, &smb_fname_dot) != 0) { + DEBUG(2,("stat of . failed (%s)\n", strerror(errno))); + return map_nt_error_from_unix(errno); } + st = smb_fname_dot.st; + *ppdata = (char *)SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN); - if (*ppdata == NULL ) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + if (*ppdata == NULL) { + return NT_STATUS_NO_MEMORY; } pdata = *ppdata; @@ -2697,8 +2916,7 @@ static void call_trans2qfsinfo(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) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); @@ -2717,7 +2935,7 @@ static void call_trans2qfsinfo(connection_struct *conn, bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); @@ -2743,13 +2961,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u * the pushed string. The change here was adding the STR_TERMINATE. JRA. */ len = srvstr_push( - pdata, req->flags2, + pdata, flags2, pdata+l2_vol_szVolLabel, vname, PTR_DIFF(end_data, pdata+l2_vol_szVolLabel), STR_NOALIGN|STR_TERMINATE); SCVAL(pdata,l2_vol_cch,len); data_len = l2_vol_szVolLabel + len; - DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n", + DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n", (unsigned)convert_timespec_to_time_t(st.st_ex_ctime), len, vname)); break; @@ -2768,6 +2986,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u /* Capabilities are filled in at connection time through STATVFS call */ additional_flags |= conn->fs_capabilities; + additional_flags |= lp_parm_int(conn->params->service, + "share", "fake_fscaps", + 0); SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH| FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK| @@ -2776,7 +2997,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u SIVAL(pdata,4,255); /* Max filename component length */ /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it and will think we can't do long filenames */ - len = srvstr_push(pdata, req->flags2, pdata+12, fstype, + len = srvstr_push(pdata, flags2, pdata+12, fstype, PTR_DIFF(end_data, pdata+12), STR_UNICODE); SIVAL(pdata,8,len); @@ -2785,7 +3006,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u case SMB_QUERY_FS_LABEL_INFO: case SMB_FS_LABEL_INFORMATION: - len = srvstr_push(pdata, req->flags2, pdata+4, vname, + len = srvstr_push(pdata, flags2, pdata+4, vname, PTR_DIFF(end_data, pdata+4), 0); data_len = 4 + len; SIVAL(pdata,0,len); @@ -2802,13 +3023,13 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u (str_checksum(get_local_machine_name())<<16)); /* Max label len is 32 characters. */ - len = srvstr_push(pdata, req->flags2, pdata+18, vname, + len = srvstr_push(pdata, flags2, pdata+18, vname, PTR_DIFF(end_data, pdata+18), STR_UNICODE); SIVAL(pdata,12,len); data_len = 18+len; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", (int)strlen(vname),vname, lp_servicename(snum))); break; @@ -2818,8 +3039,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) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -2836,7 +3056,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); @@ -2851,8 +3071,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) { - reply_unixerror(req, ERRHRD, ERRgeneral); - return; + return map_nt_error_from_unix(errno); } block_size = lp_block_size(snum); if (bsize < block_size) { @@ -2869,7 +3088,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } bytes_per_sector = 512; sectors_per_unit = bsize/bytes_per_sector; - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit, (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree)); SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */ @@ -2922,24 +3141,23 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned fsp.fnum = -1; /* access check */ - if (conn->server_info->utok.uid != 0) { + if (conn->server_info->utok.uid != sec_initial_uid()) { DEBUG(0,("set_user_quota: access_denied " "service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_doserror(req, ERRDOS, ERRnoaccess); - return; + return NT_STATUS_ACCESS_DENIED; } if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); - return; + return map_nt_error_from_unix(errno); } data_len = 48; - DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn)))); + DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n", + lp_servicename(SNUM(conn)))); /* Unknown1 24 NULL bytes*/ SBIG_UINT(pdata,0,(uint64_t)0); @@ -2990,8 +3208,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int encrypt_caps = 0; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } switch (conn->encrypt_level) { @@ -3036,8 +3253,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned vfs_statvfs_struct svfs; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } rc = SMB_VFS_STATVFS(conn, ".", &svfs); @@ -3052,16 +3268,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned SBIG_UINT(pdata,32,svfs.TotalFileNodes); SBIG_UINT(pdata,40,svfs.FreeFileNodes); SBIG_UINT(pdata,48,svfs.FsIdentifier); - DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); + DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n")); #ifdef EOPNOTSUPP } else if (rc == EOPNOTSUPP) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; #endif /* EOPNOTSUPP */ } else { DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); - return; + return NT_STATUS_DOS(ERRSRV, ERRerror); } break; } @@ -3073,13 +3287,11 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int i; if (!lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } if (max_data_bytes < 40) { - reply_nterror(req, NT_STATUS_BUFFER_TOO_SMALL); - return; + return NT_STATUS_BUFFER_TOO_SMALL; } /* We ARE guest if global_sid_Builtin_Guests is @@ -3193,12 +3405,59 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } /* drop through */ default: - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return NT_STATUS_INVALID_LEVEL; + } + + *ret_data_len = data_len; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_QFSINFO (query filesystem info). +****************************************************************************/ + +static void call_trans2qfsinfo(connection_struct *conn, + struct smb_request *req, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + uint16_t info_level; + int data_len = 0; + NTSTATUS status; + + if (total_params < 2) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + + if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) { + if (info_level != SMB_QUERY_CIFS_UNIX_INFO) { + DEBUG(0,("call_trans2qfsinfo: encryption required " + "and info level 0x%x sent.\n", + (unsigned int)info_level)); + exit_server_cleanly("encryption required " + "on connection"); return; + } } + DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level)); + + status = smbd_do_qfsinfo(conn, req, + info_level, + req->flags2, + max_data_bytes, + ppdata, &data_len); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } - send_trans2_replies(conn, req, params, 0, pdata, data_len, + send_trans2_replies(conn, req, params, 0, *ppdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", @@ -3369,12 +3628,12 @@ cap_low = 0x%x, cap_high = 0x%x\n", ZERO_STRUCT(quotas); /* access check */ - if ((conn->server_info->utok.uid != 0) + if ((conn->server_info->utok.uid != sec_initial_uid()) ||!CAN_WRITE(conn)) { DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n", lp_servicename(SNUM(conn)), conn->server_info->unix_name)); - reply_doserror(req, ERRSRV, ERRaccess); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -3443,7 +3702,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", /* now set the quotas */ if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) { DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn)))); - reply_doserror(req, ERRSRV, ERRerror); + reply_nterror(req, map_nt_error_from_unix(errno)); return; } @@ -3603,9 +3862,9 @@ static char *store_file_unix_basic(connection_struct *conn, 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, psbuf->st_ex_ctime); /* Change Time 64 Bit */ - put_long_date_timespec(pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */ - put_long_date_timespec(pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */ + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */ pdata += 24; SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */ @@ -3739,7 +3998,7 @@ static char *store_file_unix_basic_info2(connection_struct *conn, pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); /* Create (birth) time 64 bit */ - put_long_date_timespec(pdata, psbuf->st_ex_btime); + put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime); pdata += 8; map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask); @@ -3878,629 +4137,384 @@ static void call_trans2qpipeinfo(connection_struct *conn, return; } -/**************************************************************************** - Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by - file name or file id). -****************************************************************************/ - -static void call_trans2qfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) +NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + struct smb_filename *smb_fname, + bool delete_pending, + struct timespec write_time_ts, + bool ms_dfs_link, + struct ea_list *ea_list, + int lock_data_count, + char *lock_data, + uint16_t flags2, + unsigned int max_data_bytes, + char **ppdata, + unsigned int *pdata_size) { - char *params = *pparams; char *pdata = *ppdata; char *dstart, *dend; - uint16 info_level; - int mode=0; - int nlink; - SMB_OFF_T file_size=0; - uint64_t allocation_size=0; - unsigned int data_size = 0; - unsigned int param_size = 2; - SMB_STRUCT_STAT sbuf; - char *dos_fname = NULL; - char *fname = NULL; - struct smb_filename *smb_fname = NULL; - char *fullpathname; - char *base_name; + unsigned int data_size; + struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts; + time_t create_time, mtime, atime, c_time; + SMB_STRUCT_STAT *psbuf = &smb_fname->st; char *p; - SMB_OFF_T pos = 0; - bool delete_pending = False; - int len; - time_t create_time, mtime, atime; - struct timespec create_time_ts, mtime_ts, atime_ts; - struct timespec write_time_ts; - files_struct *fsp = NULL; - struct file_id fileid; - struct ea_list *ea_list = NULL; - char *lock_data = NULL; - bool ms_dfs_link = false; - TALLOC_CTX *ctx = talloc_tos(); - NTSTATUS status = NT_STATUS_OK; + char *base_name; + char *dos_fname; + int mode; + int nlink; + NTSTATUS status; + uint64_t file_size = 0; + uint64_t pos = 0; + uint64_t allocation_size = 0; + uint64_t file_index = 0; + uint32_t access_mask = 0; - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + return NT_STATUS_INVALID_LEVEL; } - ZERO_STRUCT(write_time_ts); - - if (tran_call == TRANSACT2_QFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } + DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n", + smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1, + info_level, max_data_bytes)); - if (IS_IPC(conn)) { - call_trans2qpipeinfo(conn, req, tran_call, - pparams, total_params, - ppdata, total_data, - max_data_bytes); - return; - } + if (ms_dfs_link) { + mode = dos_mode_msdfs(conn, smb_fname); + } else { + mode = dos_mode(conn, smb_fname); + } - fsp = file_fsp(req, SVAL(params,0)); - info_level = SVAL(params,2); + nlink = psbuf->st_ex_nlink; - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); + if (nlink && (mode&aDIR)) { + nlink = 1; + } - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } + if ((nlink > 0) && delete_pending) { + nlink -= 1; + } - /* Initial check for valid fsp ptr. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } + data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN; + *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); + if (*ppdata == NULL) { + return NT_STATUS_NO_MEMORY; + } + pdata = *ppdata; + dstart = pdata; + dend = dstart + data_size - 1; - fname = talloc_strdup(talloc_tos(),fsp->fsp_name); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } + if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { + update_stat_ex_mtime(psbuf, write_time_ts); + } - status = create_synthetic_smb_fname_split(talloc_tos(), fname, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } + create_time_ts = get_create_timespec(conn, fsp, smb_fname); + mtime_ts = psbuf->st_ex_mtime; + atime_ts = psbuf->st_ex_atime; + ctime_ts = get_change_timespec(conn, fsp, smb_fname); - if(fsp->fake_file_handle) { - /* - * This is actually for the QUOTA_FAKE_FILE --metze - */ + if (lp_dos_filetime_resolution(SNUM(conn))) { + dos_filetime_timespec(&create_time_ts); + dos_filetime_timespec(&mtime_ts); + dos_filetime_timespec(&atime_ts); + dos_filetime_timespec(&ctime_ts); + } - /* We know this name is ok, it's already passed the checks. */ + create_time = convert_timespec_to_time_t(create_time_ts); + mtime = convert_timespec_to_time_t(mtime_ts); + atime = convert_timespec_to_time_t(atime_ts); + c_time = convert_timespec_to_time_t(ctime_ts); - } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { - /* - * This is actually a QFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ + p = strrchr_m(smb_fname->base_name,'/'); + if (!p) + base_name = smb_fname->base_name; + else + base_name = p+1; - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else if (SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; + /* NT expects the name to be in an exact form of the *full* + filename. See the trans2 torture test */ + if (ISDOT(base_name)) { + dos_fname = talloc_strdup(mem_ctx, "\\"); + if (!dos_fname) { + return NT_STATUS_NO_MEMORY; + } + } else { + dos_fname = talloc_asprintf(mem_ctx, + "\\%s", + smb_fname->base_name); + if (!dos_fname) { + return NT_STATUS_NO_MEMORY; + } + if (is_ntfs_stream_smb_fname(smb_fname)) { + dos_fname = talloc_asprintf(dos_fname, "%s", + smb_fname->stream_name); + if (!dos_fname) { + return NT_STATUS_NO_MEMORY; } + } - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } + string_replace(dos_fname, '/', '\\'); + } - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3, ("fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadfid); - return; - } - pos = fsp->fh->position_information; - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf); + + if (!fsp) { + /* Do we have this path open ? */ + files_struct *fsp1; + struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf); + fsp1 = file_find_di_first(fileid); + if (fsp1 && fsp1->initial_allocation_size) { + allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf); } + } + + if (!(mode & aDIR)) { + file_size = get_file_size_stat(psbuf); + } + if (fsp) { + pos = fsp->fh->position_information; + } + + if (fsp) { + access_mask = fsp->access_mask; } else { - /* qpathinfo */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } + /* GENERIC_EXECUTE mapping from Windows */ + access_mask = 0x12019F; + } - info_level = SVAL(params,0); + /* This should be an index number - looks like + dev/ino to me :-) - DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); + I think this causes us to fail the IFSKIT + BasicFileInformationTest. -tpot */ + file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */ + file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */ - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } + switch (info_level) { + case SMB_INFO_STANDARD: + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n")); + data_size = 22; + srv_put_dos_date2(pdata,l1_fdateCreation,create_time); + srv_put_dos_date2(pdata,l1_fdateLastAccess,atime); + srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */ + SIVAL(pdata,l1_cbFile,(uint32)file_size); + SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); + SSVAL(pdata,l1_attrFile,mode); + break; - srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], - total_params - 6, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; + case SMB_INFO_QUERY_EA_SIZE: + { + unsigned int ea_size = + estimate_ea_size(conn, fsp, + smb_fname->base_name); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); + data_size = 26; + srv_put_dos_date2(pdata,0,create_time); + srv_put_dos_date2(pdata,4,atime); + srv_put_dos_date2(pdata,8,mtime); /* write time */ + SIVAL(pdata,12,(uint32)file_size); + SIVAL(pdata,16,(uint32)allocation_size); + SSVAL(pdata,20,mode); + SIVAL(pdata,22,ea_size); + break; } - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - return; + case SMB_INFO_IS_NAME_VALID: + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); + if (fsp) { + /* os/2 needs this ? really ?*/ + return NT_STATUS_DOS(ERRDOS, ERRbadfunc); } - reply_nterror(req, status); - return; - } + /* This is only reached for qpathinfo */ + data_size = 0; + break; - /* 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; + case SMB_INFO_QUERY_EAS_FROM_LIST: + { + size_t total_ea_len = 0; + struct ea_list *ea_file_list = NULL; - /* 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); - return; - } + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { - DEBUG(3,("call_trans2qfilepathinfo: " - "fileinfo of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname_base), - strerror(errno))); - TALLOC_FREE(smb_fname_base); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } + ea_file_list = + get_ea_list_from_file(mem_ctx, conn, fsp, + smb_fname->base_name, + &total_ea_len); + ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len); - fileid = vfs_file_id_from_sbuf(conn, - &smb_fname_base->st); - TALLOC_FREE(smb_fname_base); - get_file_infos(fileid, &delete_pending, NULL); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; + 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. */ + break; } + + data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); + break; } - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_LSTAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } + case SMB_INFO_QUERY_ALL_EAS: + { + /* We have data_size bytes to put EA's into. */ + size_t total_ea_len = 0; - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname) && - (info_level != SMB_INFO_IS_NAME_VALID)) { - ms_dfs_link = check_msdfs_link(conn, fname, - &smb_fname->st); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); - if (!ms_dfs_link) { - DEBUG(3,("call_trans2qfilepathinfo: " - "SMB_VFS_STAT of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; + ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, + smb_fname->base_name, + &total_ea_len); + 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. */ + break; } - } - fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); - get_file_infos(fileid, &delete_pending, &write_time_ts); - if (delete_pending) { - reply_nterror(req, NT_STATUS_DELETE_PENDING); - return; + data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list); + break; } - } - /* Set sbuf for use below. */ - sbuf = smb_fname->st; - - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; - } + case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/ + { + /* This is FileFullEaInformation - 0xF which maps to + * 1015 (decimal) in smbd_do_setfilepathinfo. */ - DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n", - fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); + /* We have data_size bytes to put EA's into. */ + size_t total_ea_len = 0; + struct ea_list *ea_file_list = NULL; - p = strrchr_m(smb_fname->base_name,'/'); - if (!p) - base_name = smb_fname->base_name; - else - base_name = p+1; + DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n")); - if (ms_dfs_link) { - mode = dos_mode_msdfs(conn, smb_fname); - } else { - mode = dos_mode(conn, smb_fname); - } - if (!mode) - mode = FILE_ATTRIBUTE_NORMAL; + /*TODO: add filtering and index handling */ - nlink = sbuf.st_ex_nlink; + ea_file_list = + get_ea_list_from_file(mem_ctx, conn, fsp, + smb_fname->base_name, + &total_ea_len); + if (!ea_file_list) { + return NT_STATUS_NO_EAS_ON_FILE; + } - if (nlink && (mode&aDIR)) { - nlink = 1; - } + status = fill_ea_chained_buffer(mem_ctx, + pdata, + data_size, + &data_size, + conn, ea_file_list); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + } - if ((nlink > 0) && delete_pending) { - nlink -= 1; - } + case SMB_FILE_BASIC_INFORMATION: + case SMB_QUERY_FILE_BASIC_INFO: - fullpathname = fname; - if (!(mode & aDIR)) - file_size = get_file_size_stat(&sbuf); + if (info_level == SMB_QUERY_FILE_BASIC_INFO) { + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); + data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ + } else { + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); + data_size = 40; + SIVAL(pdata,36,0); + } + put_long_date_timespec(conn->ts_res,pdata,create_time_ts); + put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); + put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ + SIVAL(pdata,32,mode); - /* Pull out any data sent here before we realloc. */ - switch (info_level) { - case SMB_INFO_QUERY_EAS_FROM_LIST: - { - /* Pull any EA list from the data portion. */ - uint32 ea_size; + DEBUG(5,("SMB_QFBI - ")); + DEBUG(5,("create: %s ", ctime(&create_time))); + DEBUG(5,("access: %s ", ctime(&atime))); + DEBUG(5,("write: %s ", ctime(&mtime))); + DEBUG(5,("change: %s ", ctime(&c_time))); + DEBUG(5,("mode: %x\n", mode)); + break; - if (total_data < 4) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } - ea_size = IVAL(pdata,0); + case SMB_FILE_STANDARD_INFORMATION: + case SMB_QUERY_FILE_STANDARD_INFO: - if (total_data > 0 && ea_size != total_data) { - DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ -total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); + data_size = 24; + SOFF_T(pdata,0,allocation_size); + SOFF_T(pdata,8,file_size); + SIVAL(pdata,16,nlink); + SCVAL(pdata,20,delete_pending?1:0); + SCVAL(pdata,21,(mode&aDIR)?1:0); + SSVAL(pdata,22,0); /* Padding. */ + break; - if (!lp_ea_support(SNUM(conn))) { - reply_doserror(req, ERRDOS, - ERReasnotsupported); - return; - } + case SMB_FILE_EA_INFORMATION: + case SMB_QUERY_FILE_EA_INFO: + { + unsigned int ea_size = + estimate_ea_size(conn, fsp, smb_fname->base_name); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); + data_size = 4; + SIVAL(pdata,0,ea_size); + break; + } - /* Pull out the list of names. */ - ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4); - if (!ea_list) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; + /* Get the 8.3 name - used if NT SMB was negotiated. */ + case SMB_QUERY_FILE_ALT_NAME_INFO: + case SMB_FILE_ALTERNATE_NAME_INFORMATION: + { + int len; + char mangled_name[13]; + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); + if (!name_to_8_3(base_name,mangled_name, + True,conn->params)) { + return NT_STATUS_NO_MEMORY; } + len = srvstr_push(dstart, flags2, + pdata+4, mangled_name, + PTR_DIFF(dend, pdata+4), + STR_UNICODE); + data_size = 4 + len; + SIVAL(pdata,0,len); break; } - case SMB_QUERY_POSIX_LOCK: + case SMB_QUERY_FILE_NAME_INFO: { - if (fsp == NULL || fsp->fh->fd == -1) { - reply_nterror(req, NT_STATUS_INVALID_HANDLE); - return; - } + int len; + /* + this must be *exactly* right for ACLs on mapped drives to work + */ + len = srvstr_push(dstart, flags2, + pdata+4, dos_fname, + PTR_DIFF(dend, pdata+4), + STR_UNICODE); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); + data_size = 4 + len; + SIVAL(pdata,0,len); + break; + } - if (total_data != POSIX_LOCK_DATA_SIZE) { - reply_nterror( - req, NT_STATUS_INVALID_PARAMETER); - return; - } + case SMB_FILE_ALLOCATION_INFORMATION: + case SMB_QUERY_FILE_ALLOCATION_INFO: + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); + data_size = 8; + SOFF_T(pdata,0,allocation_size); + break; - /* Copy the lock range data. */ - lock_data = (char *)TALLOC_MEMDUP( - ctx, pdata, total_data); - if (!lock_data) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - } - default: - break; - } - - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - params = *pparams; - SSVAL(params,0,0); - data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN; - *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); - if (*ppdata == NULL ) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - pdata = *ppdata; - dstart = pdata; - dend = dstart + data_size - 1; - - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); - - if (!fsp) { - /* Do we have this path open ? */ - files_struct *fsp1; - fileid = vfs_file_id_from_sbuf(conn, &sbuf); - fsp1 = file_find_di_first(fileid); - if (fsp1 && fsp1->initial_allocation_size) { - allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, &sbuf); - } - } - - if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) { - update_stat_ex_mtime(&sbuf, write_time_ts); - } - - create_time_ts = sbuf.st_ex_btime; - mtime_ts = sbuf.st_ex_mtime; - atime_ts = sbuf.st_ex_atime; - - if (lp_dos_filetime_resolution(SNUM(conn))) { - dos_filetime_timespec(&create_time_ts); - dos_filetime_timespec(&mtime_ts); - dos_filetime_timespec(&atime_ts); - } - - create_time = convert_timespec_to_time_t(create_time_ts); - mtime = convert_timespec_to_time_t(mtime_ts); - atime = convert_timespec_to_time_t(atime_ts); - - /* NT expects the name to be in an exact form of the *full* - filename. See the trans2 torture test */ - if (ISDOT(base_name)) { - dos_fname = talloc_strdup(ctx, "\\"); - if (!dos_fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - } else { - dos_fname = talloc_asprintf(ctx, - "\\%s", - fname); - if (!dos_fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - string_replace(dos_fname, '/', '\\'); - } - - switch (info_level) { - case SMB_INFO_STANDARD: - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n")); - data_size = 22; - srv_put_dos_date2(pdata,l1_fdateCreation,create_time); - srv_put_dos_date2(pdata,l1_fdateLastAccess,atime); - srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */ - SIVAL(pdata,l1_cbFile,(uint32)file_size); - SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size); - SSVAL(pdata,l1_attrFile,mode); - break; - - case SMB_INFO_QUERY_EA_SIZE: - { - unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n")); - data_size = 26; - srv_put_dos_date2(pdata,0,create_time); - srv_put_dos_date2(pdata,4,atime); - srv_put_dos_date2(pdata,8,mtime); /* write time */ - SIVAL(pdata,12,(uint32)file_size); - SIVAL(pdata,16,(uint32)allocation_size); - SSVAL(pdata,20,mode); - SIVAL(pdata,22,ea_size); - break; - } - - case SMB_INFO_IS_NAME_VALID: - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n")); - if (tran_call == TRANSACT2_QFILEINFO) { - /* os/2 needs this ? really ?*/ - reply_doserror(req, ERRDOS, ERRbadfunc); - return; - } - data_size = 0; - param_size = 0; - break; - - case SMB_INFO_QUERY_EAS_FROM_LIST: - { - size_t total_ea_len = 0; - struct ea_list *ea_file_list = NULL; - - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n")); - - ea_file_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); - ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len); - - 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. */ - break; - } - - data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); - break; - } - - case SMB_INFO_QUERY_ALL_EAS: - { - /* We have data_size bytes to put EA's into. */ - size_t total_ea_len = 0; - - DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n")); - - ea_list = get_ea_list_from_file(ctx, conn, fsp, fname, &total_ea_len); - 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. */ - break; - } - - data_size = fill_ea_buffer(ctx, pdata, data_size, conn, ea_list); - break; - } - - case SMB_FILE_BASIC_INFORMATION: - case SMB_QUERY_FILE_BASIC_INFO: - - if (info_level == SMB_QUERY_FILE_BASIC_INFO) { - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n")); - data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */ - } else { - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n")); - data_size = 40; - SIVAL(pdata,36,0); - } - put_long_date_timespec(pdata,create_time_ts); - put_long_date_timespec(pdata+8,atime_ts); - put_long_date_timespec(pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(pdata+24,mtime_ts); /* change time */ - SIVAL(pdata,32,mode); - - DEBUG(5,("SMB_QFBI - ")); - DEBUG(5,("create: %s ", ctime(&create_time))); - DEBUG(5,("access: %s ", ctime(&atime))); - DEBUG(5,("write: %s ", ctime(&mtime))); - DEBUG(5,("change: %s ", ctime(&mtime))); - DEBUG(5,("mode: %x\n", mode)); - break; - - case SMB_FILE_STANDARD_INFORMATION: - case SMB_QUERY_FILE_STANDARD_INFO: - - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n")); - data_size = 24; - SOFF_T(pdata,0,allocation_size); - SOFF_T(pdata,8,file_size); - SIVAL(pdata,16,nlink); - SCVAL(pdata,20,delete_pending?1:0); - SCVAL(pdata,21,(mode&aDIR)?1:0); - SSVAL(pdata,22,0); /* Padding. */ - break; - - case SMB_FILE_EA_INFORMATION: - case SMB_QUERY_FILE_EA_INFO: - { - unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n")); - data_size = 4; - SIVAL(pdata,0,ea_size); - break; - } - - /* Get the 8.3 name - used if NT SMB was negotiated. */ - case SMB_QUERY_FILE_ALT_NAME_INFO: - case SMB_FILE_ALTERNATE_NAME_INFORMATION: - { - char mangled_name[13]; - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n")); - if (!name_to_8_3(base_name,mangled_name, - True,conn->params)) { - reply_nterror( - req, - NT_STATUS_NO_MEMORY); - } - len = srvstr_push(dstart, req->flags2, - pdata+4, mangled_name, - PTR_DIFF(dend, pdata+4), - STR_UNICODE); - data_size = 4 + len; - SIVAL(pdata,0,len); - break; - } - - case SMB_QUERY_FILE_NAME_INFO: - /* - this must be *exactly* right for ACLs on mapped drives to work - */ - len = srvstr_push(dstart, req->flags2, - pdata+4, dos_fname, - PTR_DIFF(dend, pdata+4), - STR_UNICODE); - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n")); - data_size = 4 + len; - SIVAL(pdata,0,len); - break; - - case SMB_FILE_ALLOCATION_INFORMATION: - case SMB_QUERY_FILE_ALLOCATION_INFO: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n")); - data_size = 8; - SOFF_T(pdata,0,allocation_size); - break; - - case SMB_FILE_END_OF_FILE_INFORMATION: - case SMB_QUERY_FILE_END_OF_FILEINFO: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); - data_size = 8; - SOFF_T(pdata,0,file_size); + case SMB_FILE_END_OF_FILE_INFORMATION: + case SMB_QUERY_FILE_END_OF_FILEINFO: + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n")); + data_size = 8; + SOFF_T(pdata,0,file_size); break; case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: { - unsigned int ea_size = estimate_ea_size(conn, fsp, fname); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n")); - put_long_date_timespec(pdata,create_time_ts); - put_long_date_timespec(pdata+8,atime_ts); - put_long_date_timespec(pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(pdata+24,mtime_ts); /* change time */ + int len; + unsigned int ea_size = + estimate_ea_size(conn, fsp, smb_fname->base_name); + 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); + put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ SIVAL(pdata,32,mode); SIVAL(pdata,36,0); /* padding. */ pdata += 40; @@ -4513,7 +4527,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd pdata += 24; SIVAL(pdata,0,ea_size); pdata += 4; /* EA info */ - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata+4, dos_fname, PTR_DIFF(dend, pdata+4), STR_UNICODE); @@ -4522,27 +4536,53 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd data_size = PTR_DIFF(pdata,(*ppdata)); break; } - case SMB_FILE_INTERNAL_INFORMATION: - /* This should be an index number - looks like - dev/ino to me :-) - I think this causes us to fail the IFSKIT - BasicFileInformationTest. -tpot */ + case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/ + { + int len; + unsigned int ea_size = + estimate_ea_size(conn, fsp, smb_fname->base_name); + 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); + put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */ + SIVAL(pdata, 0x20, mode); + SIVAL(pdata, 0x24, 0); /* padding. */ + SBVAL(pdata, 0x28, allocation_size); + SBVAL(pdata, 0x30, file_size); + SIVAL(pdata, 0x38, nlink); + SCVAL(pdata, 0x3C, delete_pending); + SCVAL(pdata, 0x3D, (mode&aDIR)?1:0); + SSVAL(pdata, 0x3E, 0); /* padding */ + SBVAL(pdata, 0x40, file_index); + SIVAL(pdata, 0x48, ea_size); + SIVAL(pdata, 0x4C, access_mask); + SBVAL(pdata, 0x50, pos); + SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */ + SIVAL(pdata, 0x5C, 0); /* No alignment needed. */ + + pdata += 0x60; + + len = srvstr_push(dstart, flags2, + pdata+4, dos_fname, + PTR_DIFF(dend, pdata+4), + STR_UNICODE); + SIVAL(pdata,0,len); + pdata += 4 + len; + data_size = PTR_DIFF(pdata,(*ppdata)); + break; + } + case SMB_FILE_INTERNAL_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); - SIVAL(pdata,0,sbuf.st_ex_ino); /* FileIndexLow */ - SIVAL(pdata,4,sbuf.st_ex_dev); /* FileIndexHigh */ + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n")); + SBVAL(pdata, 0, file_index); data_size = 8; break; case SMB_FILE_ACCESS_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); - if (fsp) { - SIVAL(pdata,0,fsp->access_mask); - } else { - /* GENERIC_EXECUTE mapping from Windows */ - SIVAL(pdata,0,0x12019F); - } + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); + SIVAL(pdata, 0, access_mask); data_size = 4; break; @@ -4551,32 +4591,32 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd { size_t byte_len; byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False); - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n")); SIVAL(pdata,0,byte_len); data_size = 4 + byte_len; break; } case SMB_FILE_DISPOSITION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n")); data_size = 1; SCVAL(pdata,0,delete_pending); break; case SMB_FILE_POSITION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n")); data_size = 8; SOFF_T(pdata,0,pos); break; case SMB_FILE_MODE_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n")); SIVAL(pdata,0,mode); data_size = 4; break; case SMB_FILE_ALIGNMENT_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n")); SIVAL(pdata,0,0); /* No alignment needed. */ data_size = 4; break; @@ -4594,18 +4634,21 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd unsigned int num_streams; struct stream_struct *streams; - DEBUG(10,("call_trans2qfilepathinfo: " + DEBUG(10,("smbd_do_qfilepathinfo: " "SMB_FILE_STREAM_INFORMATION\n")); + if (is_ntfs_stream_smb_fname(smb_fname)) { + return NT_STATUS_INVALID_PARAMETER; + } + status = SMB_VFS_STREAMINFO( - conn, fsp, fname, talloc_tos(), + conn, fsp, smb_fname->base_name, talloc_tos(), &num_streams, &streams); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("could not get stream info: %s\n", nt_errstr(status))); - reply_nterror(req, status); - return; + return status; } status = marshall_stream_info(num_streams, streams, @@ -4615,8 +4658,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("marshall_stream_info failed: %s\n", nt_errstr(status))); - reply_nterror(req, status); - return; + return status; } TALLOC_FREE(streams); @@ -4625,7 +4667,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd } case SMB_QUERY_COMPRESSION_INFO: case SMB_FILE_COMPRESSION_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n")); SOFF_T(pdata,0,file_size); SIVAL(pdata,8,0); /* ??? */ SIVAL(pdata,12,0); /* ??? */ @@ -4633,11 +4675,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; case SMB_FILE_NETWORK_OPEN_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); - put_long_date_timespec(pdata,create_time_ts); - put_long_date_timespec(pdata+8,atime_ts); - put_long_date_timespec(pdata+16,mtime_ts); /* write time */ - put_long_date_timespec(pdata+24,mtime_ts); /* change time */ + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n")); + put_long_date_timespec(conn->ts_res,pdata,create_time_ts); + put_long_date_timespec(conn->ts_res,pdata+8,atime_ts); + put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */ + put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */ SOFF_T(pdata,32,allocation_size); SOFF_T(pdata,40,file_size); SIVAL(pdata,48,mode); @@ -4646,7 +4688,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd break; case SMB_FILE_ATTRIBUTE_TAG_INFORMATION: - DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n")); SIVAL(pdata,0,mode); SIVAL(pdata,4,0); data_size = 8; @@ -4658,12 +4700,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_UNIX_BASIC: - pdata = store_file_unix_basic(conn, pdata, fsp, &sbuf); + pdata = store_file_unix_basic(conn, pdata, fsp, psbuf); data_size = PTR_DIFF(pdata,(*ppdata)); { int i; - DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); + DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4674,12 +4716,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_UNIX_INFO2: - pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf); + pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf); data_size = PTR_DIFF(pdata,(*ppdata)); { int i; - DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); + DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 ")); for (i=0; i<100; i++) DEBUG(4,("%d=%x, ",i, (*ppdata)[i])); @@ -4690,33 +4732,29 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_QUERY_FILE_UNIX_LINK: { - char *buffer = TALLOC_ARRAY(ctx, char, PATH_MAX+1); + int len; + char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1); if (!buffer) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + return NT_STATUS_NO_MEMORY; } - DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); + DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n")); #ifdef S_ISLNK - if(!S_ISLNK(sbuf.st_ex_mode)) { - reply_unixerror(req, ERRSRV, - ERRbadlink); - return; + if(!S_ISLNK(psbuf->st_ex_mode)) { + return NT_STATUS_DOS(ERRSRV, ERRbadlink); } #else - reply_unixerror(req, ERRDOS, ERRbadlink); - return; + return NT_STATUS_DOS(ERRDOS, ERRbadlink); #endif - len = SMB_VFS_READLINK(conn,fullpathname, - buffer, PATH_MAX); + len = SMB_VFS_READLINK(conn, + smb_fname->base_name, + buffer, PATH_MAX); if (len == -1) { - reply_unixerror(req, ERRDOS, - ERRnoaccess); - return; + return map_nt_error_from_unix(errno); } buffer[len] = 0; - len = srvstr_push(dstart, req->flags2, + len = srvstr_push(dstart, flags2, pdata, buffer, PTR_DIFF(dend, pdata), STR_TERMINATE); @@ -4737,23 +4775,33 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) { file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp); } else { - file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS); + file_acl = + SMB_VFS_SYS_ACL_GET_FILE(conn, + smb_fname->base_name, + SMB_ACL_TYPE_ACCESS); } if (file_acl == NULL && no_acl_syscall_error(errno)) { - DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n", - fname )); - reply_nterror( - req, - NT_STATUS_NOT_IMPLEMENTED); - return; + DEBUG(5,("smbd_do_qfilepathinfo: ACLs " + "not implemented on " + "filesystem containing %s\n", + smb_fname->base_name)); + return NT_STATUS_NOT_IMPLEMENTED; } - if (S_ISDIR(sbuf.st_ex_mode)) { + if (S_ISDIR(psbuf->st_ex_mode)) { if (fsp && fsp->is_directory) { - def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); + def_acl = + SMB_VFS_SYS_ACL_GET_FILE( + conn, + fsp->fsp_name->base_name, + SMB_ACL_TYPE_DEFAULT); } else { - def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT); + def_acl = + SMB_VFS_SYS_ACL_GET_FILE( + conn, + smb_fname->base_name, + SMB_ACL_TYPE_DEFAULT); } def_acl = free_empty_sys_acl(conn, def_acl); } @@ -4762,7 +4810,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd num_def_acls = count_acl_entries(conn, def_acl); if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) { - DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n", + DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n", data_size, (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) )); @@ -4772,131 +4820,502 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, - NT_STATUS_BUFFER_TOO_SMALL); - return; + return NT_STATUS_BUFFER_TOO_SMALL; } SSVAL(pdata,0,SMB_POSIX_ACL_VERSION); SSVAL(pdata,2,num_file_acls); SSVAL(pdata,4,num_def_acls); - if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) { + 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); } if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, NT_STATUS_INTERNAL_ERROR); - return; + return NT_STATUS_INTERNAL_ERROR; } - if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) { + 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); } if (def_acl) { SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } - reply_nterror( - req, - NT_STATUS_INTERNAL_ERROR); - return; + return NT_STATUS_INTERNAL_ERROR; + } + + if (file_acl) { + SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); + } + if (def_acl) { + SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); } + data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE; + break; + } +#endif + + + case SMB_QUERY_POSIX_LOCK: + { + uint64_t count; + uint64_t offset; + uint32 lock_pid; + enum brl_type lock_type; + + /* We need an open file with a real fd for this. */ + if (!fsp || fsp->is_directory || fsp->fh->fd == -1) { + return NT_STATUS_INVALID_LEVEL; + } + + if (lock_data_count != POSIX_LOCK_DATA_SIZE) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) { + case POSIX_LOCK_TYPE_READ: + lock_type = READ_LOCK; + break; + case POSIX_LOCK_TYPE_WRITE: + lock_type = WRITE_LOCK; + break; + case POSIX_LOCK_TYPE_UNLOCK: + default: + /* There's no point in asking for an unlock... */ + return NT_STATUS_INVALID_PARAMETER; + } + + lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET); +#if defined(HAVE_LONGLONG) + offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) | + ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET)); + count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) | + ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET)); +#else /* HAVE_LONGLONG */ + offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET); + count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET); +#endif /* HAVE_LONGLONG */ + + status = query_lock(fsp, + &lock_pid, + &count, + &offset, + &lock_type, + POSIX_LOCK); + + if (ERROR_WAS_LOCK_DENIED(status)) { + /* Here we need to report who has it locked... */ + data_size = POSIX_LOCK_DATA_SIZE; + + SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type); + SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0); + SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid); +#if defined(HAVE_LONGLONG) + SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF)); + SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF)); + SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF)); + SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF)); +#else /* HAVE_LONGLONG */ + SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset); + SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count); +#endif /* HAVE_LONGLONG */ + + } else if (NT_STATUS_IS_OK(status)) { + /* For success we just return a copy of what we sent + with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */ + data_size = POSIX_LOCK_DATA_SIZE; + memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE); + SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK); + } else { + return status; + } + break; + } + + default: + return NT_STATUS_INVALID_LEVEL; + } + + *pdata_size = data_size; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by + file name or file id). +****************************************************************************/ + +static void call_trans2qfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + char *pdata = *ppdata; + uint16 info_level; + unsigned int data_size = 0; + unsigned int param_size = 2; + struct smb_filename *smb_fname = NULL; + bool delete_pending = False; + struct timespec write_time_ts; + files_struct *fsp = NULL; + struct file_id fileid; + struct ea_list *ea_list = NULL; + int lock_data_count = 0; + char *lock_data = NULL; + bool ms_dfs_link = false; + NTSTATUS status = NT_STATUS_OK; + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + ZERO_STRUCT(write_time_ts); + + if (tran_call == TRANSACT2_QFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (IS_IPC(conn)) { + call_trans2qpipeinfo(conn, req, tran_call, + pparams, total_params, + ppdata, total_data, + max_data_bytes); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + info_level = SVAL(params,2); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + /* Initial check for valid fsp ptr. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + + status = copy_smb_filename(talloc_tos(), fsp->fsp_name, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + if(fsp->fake_file_handle) { + /* + * This is actually for the QUOTA_FAKE_FILE --metze + */ + + /* We know this name is ok, it's already passed the checks. */ + + } else if(fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a QFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } else if (SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3, ("fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } + + } else { + char *fname = NULL; + + /* qpathinfo */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + + DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); + + if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], + total_params - 6, + STR_TERMINATE, &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = filename_convert(req, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + 0, + NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + return; + } + reply_nterror(req, status); + return; + } + + /* 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; + + /* 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); + return; + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } else { + if (SMB_VFS_STAT(conn, smb_fname_base) != 0) { + DEBUG(3,("call_trans2qfilepathinfo: " + "fileinfo of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname_base), + strerror(errno))); + TALLOC_FREE(smb_fname_base); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } + } + + fileid = vfs_file_id_from_sbuf(conn, + &smb_fname_base->st); + TALLOC_FREE(smb_fname_base); + 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, smb_fname)) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_LSTAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; + } - if (file_acl) { - SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); - } - if (def_acl) { - SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl); - } - data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE; - break; + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname) && + (info_level != SMB_INFO_IS_NAME_VALID)) { + ms_dfs_link = check_msdfs_link(conn, + smb_fname->base_name, + &smb_fname->st); + + if (!ms_dfs_link) { + DEBUG(3,("call_trans2qfilepathinfo: " + "SMB_VFS_STAT of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, + map_nt_error_from_unix(errno)); + return; } -#endif + } + + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + if (delete_pending) { + reply_nterror(req, NT_STATUS_DELETE_PENDING); + return; + } + } + DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d " + "total_data=%d\n", smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level,tran_call,total_data)); - case SMB_QUERY_POSIX_LOCK: + /* Pull out any data sent here before we realloc. */ + switch (info_level) { + case SMB_INFO_QUERY_EAS_FROM_LIST: { - uint64_t count; - uint64_t offset; - uint32 lock_pid; - enum brl_type lock_type; + /* Pull any EA list from the data portion. */ + uint32 ea_size; - if (total_data != POSIX_LOCK_DATA_SIZE) { + if (total_data < 4) { reply_nterror( req, NT_STATUS_INVALID_PARAMETER); return; } + ea_size = IVAL(pdata,0); - switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) { - case POSIX_LOCK_TYPE_READ: - lock_type = READ_LOCK; - break; - case POSIX_LOCK_TYPE_WRITE: - lock_type = WRITE_LOCK; - break; - case POSIX_LOCK_TYPE_UNLOCK: - default: - /* There's no point in asking for an unlock... */ - reply_nterror( - req, - NT_STATUS_INVALID_PARAMETER); - return; + if (total_data > 0 && ea_size != total_data) { + DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \ +total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) )); + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; } - lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET); -#if defined(HAVE_LONGLONG) - offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) | - ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET)); - count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) | - ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET)); -#else /* HAVE_LONGLONG */ - offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET); - count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET); -#endif /* HAVE_LONGLONG */ + if (!lp_ea_support(SNUM(conn))) { + reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); + return; + } - status = query_lock(fsp, - &lock_pid, - &count, - &offset, - &lock_type, - POSIX_LOCK); + /* Pull out the list of names. */ + ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4); + if (!ea_list) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } + break; + } - if (ERROR_WAS_LOCK_DENIED(status)) { - /* Here we need to report who has it locked... */ - data_size = POSIX_LOCK_DATA_SIZE; + case SMB_QUERY_POSIX_LOCK: + { + if (fsp == NULL || fsp->fh->fd == -1) { + reply_nterror(req, NT_STATUS_INVALID_HANDLE); + return; + } - SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type); - SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0); - SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid); -#if defined(HAVE_LONGLONG) - SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF)); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF)); -#else /* HAVE_LONGLONG */ - SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset); - SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count); -#endif /* HAVE_LONGLONG */ + if (total_data != POSIX_LOCK_DATA_SIZE) { + reply_nterror( + req, NT_STATUS_INVALID_PARAMETER); + return; + } - } else if (NT_STATUS_IS_OK(status)) { - /* For success we just return a copy of what we sent - with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */ - data_size = POSIX_LOCK_DATA_SIZE; - memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE); - SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK); - } else { - reply_nterror(req, status); + /* Copy the lock range data. */ + lock_data = (char *)TALLOC_MEMDUP( + req, pdata, total_data); + if (!lock_data) { + reply_nterror(req, NT_STATUS_NO_MEMORY); return; } - break; + lock_data_count = total_data; } - default: - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + break; + } + + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + params = *pparams; + SSVAL(params,0,0); + + /* + * draft-leach-cifs-v1-spec-02.txt + * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path + * says: + * + * The requested information is placed in the Data portion of the + * transaction response. For the information levels greater than 0x100, + * the transaction response has 1 parameter word which should be + * ignored by the client. + * + * However Windows only follows this rule for the IS_NAME_VALID call. + */ + switch (info_level) { + case SMB_INFO_IS_NAME_VALID: + param_size = 0; + break; + } + + if ((info_level & 0xFF00) == 0xFF00) { + /* + * We use levels that start with 0xFF00 + * internally to represent SMB2 specific levels + */ + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + + status = smbd_do_qfilepathinfo(conn, req, info_level, + fsp, smb_fname, + delete_pending, write_time_ts, + ms_dfs_link, ea_list, + lock_data_count, lock_data, + req->flags2, max_data_bytes, + ppdata, &data_size); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; } send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, @@ -4915,8 +5334,6 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, const struct smb_filename *smb_fname_old, const struct smb_filename *smb_fname_new) { - char *oldname = NULL; - char *newname = NULL; NTSTATUS status = NT_STATUS_OK; /* source must already exist. */ @@ -4934,25 +5351,22 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx, return NT_STATUS_FILE_IS_A_DIRECTORY; } - status = get_full_smb_filename(ctx, smb_fname_new, &newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - status = get_full_smb_filename(ctx, smb_fname_old, &oldname); - if (!NT_STATUS_IS_OK(status)) { - goto out; + /* Setting a hardlink to/from a stream isn't currently supported. */ + if (is_ntfs_stream_smb_fname(smb_fname_old) || + is_ntfs_stream_smb_fname(smb_fname_new)) { + return NT_STATUS_INVALID_PARAMETER; } - DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); + DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", + smb_fname_old->base_name, smb_fname_new->base_name)); - if (SMB_VFS_LINK(conn,oldname,newname) != 0) { + if (SMB_VFS_LINK(conn, smb_fname_old->base_name, + smb_fname_new->base_name) != 0) { status = map_nt_error_from_unix(errno); DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", - nt_errstr(status), newname, oldname)); + nt_errstr(status), smb_fname_old->base_name, + smb_fname_new->base_name)); } - out: - TALLOC_FREE(newname); - TALLOC_FREE(oldname); return status; } @@ -4966,24 +5380,26 @@ NTSTATUS smb_set_file_time(connection_struct *conn, struct smb_file_time *ft, bool setting_write_time) { - struct smb_filename *smb_fname_base = NULL; + struct smb_filename smb_fname_base; uint32 action = FILE_NOTIFY_CHANGE_LAST_ACCESS - |FILE_NOTIFY_CHANGE_LAST_WRITE; - NTSTATUS status; + |FILE_NOTIFY_CHANGE_LAST_WRITE + |FILE_NOTIFY_CHANGE_CREATION; if (!VALID_STAT(smb_fname->st)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* get some defaults (no modifications) if any info is zero or -1. */ + if (null_timespec(ft->create_time)) { + action &= ~FILE_NOTIFY_CHANGE_CREATION; + } + if (null_timespec(ft->atime)) { - ft->atime= smb_fname->st.st_ex_atime; action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } if (null_timespec(ft->mtime)) { - ft->mtime = smb_fname->st.st_ex_mtime; action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } @@ -4992,28 +5408,22 @@ NTSTATUS smb_set_file_time(connection_struct *conn, action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } + /* Ensure the resolution is the correct for + * what we can store on this filesystem. */ + + round_timespec(conn->ts_res, &ft->create_time); + round_timespec(conn->ts_res, &ft->ctime); + round_timespec(conn->ts_res, &ft->atime); + round_timespec(conn->ts_res, &ft->mtime); + 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 - * they are different from the current values. - */ - - { - struct timespec mts = smb_fname->st.st_ex_mtime; - struct timespec ats = smb_fname->st.st_ex_atime; - if ((timespec_compare(&ft->atime, &ats) == 0) && - (timespec_compare(&ft->mtime, &mts) == 0)) { - return NT_STATUS_OK; - } - } + DEBUG(5,("smb_set_filetime: ctime: %s\n ", + time_to_asc(convert_timespec_to_time_t(ft->ctime)))); + DEBUG(5,("smb_set_file_time: createtime: %s\n ", + time_to_asc(convert_timespec_to_time_t(ft->create_time)))); if (setting_write_time) { /* @@ -5046,18 +5456,12 @@ NTSTATUS smb_set_file_time(connection_struct *conn, DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); /* Always call ntimes on the base, 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 = *smb_fname; + smb_fname_base.stream_name = NULL; - if(file_ntimes(conn, smb_fname_base, ft)!=0) { - TALLOC_FREE(smb_fname_base); + if(file_ntimes(conn, &smb_fname_base, ft)!=0) { return map_nt_error_from_unix(errno); } - TALLOC_FREE(smb_fname_base); notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, smb_fname->base_name); @@ -5128,7 +5532,8 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname, const SMB_STRUCT_STAT *psbuf, - SMB_OFF_T size) + SMB_OFF_T size, + bool fail_after_createfile) { NTSTATUS status = NT_STATUS_OK; struct smb_filename *smb_fname_tmp = NULL; @@ -5168,7 +5573,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, req, /* req */ 0, /* root_dir_fid */ smb_fname_tmp, /* fname */ - FILE_WRITE_ATTRIBUTES, /* access_mask */ + FILE_WRITE_DATA, /* access_mask */ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */ FILE_SHARE_DELETE), FILE_OPEN, /* create_disposition*/ @@ -5188,6 +5593,12 @@ static NTSTATUS smb_set_file_size(connection_struct *conn, return status; } + /* See RAW-SFILEINFO-END-OF-FILE */ + if (fail_after_createfile) { + close_file(req, new_fsp,NORMAL_CLOSE); + return NT_STATUS_INVALID_LEVEL; + } + if (vfs_set_filelen(new_fsp, size) == -1) { status = map_nt_error_from_unix(errno); close_file(req, new_fsp,NORMAL_CLOSE); @@ -5242,6 +5653,53 @@ static NTSTATUS smb_info_set_ea(connection_struct *conn, return status; } +/**************************************************************************** + Deal with SMB_FILE_FULL_EA_INFORMATION set. +****************************************************************************/ + +static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn, + const char *pdata, + int total_data, + files_struct *fsp) +{ + struct ea_list *ea_list = NULL; + NTSTATUS status; + + if (!fsp) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!lp_ea_support(SNUM(conn))) { + DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but " + "EA's not supported.\n", + (unsigned int)total_data)); + return NT_STATUS_EAS_NOT_SUPPORTED; + } + + if (total_data < 10) { + DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u " + "too small.\n", + (unsigned int)total_data)); + return NT_STATUS_INVALID_PARAMETER; + } + + ea_list = read_nttrans_ea_list(talloc_tos(), + pdata, + total_data); + + if (!ea_list) { + return NT_STATUS_INVALID_PARAMETER; + } + status = set_ea(conn, fsp, fsp->fsp_name, ea_list); + + DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n", + smb_fname_str_dbg(fsp->fsp_name), + nt_errstr(status) )); + + return status; +} + + /**************************************************************************** Deal with SMB_SET_FILE_DISPOSITION_INFO. ****************************************************************************/ @@ -5250,7 +5708,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; @@ -5273,10 +5731,11 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn, (unsigned int)dosmode, (unsigned int)delete_on_close )); - status = can_set_delete_on_close(fsp, delete_on_close, dosmode); - - if (!NT_STATUS_IS_OK(status)) { - return status; + if (delete_on_close) { + status = can_set_delete_on_close(fsp, dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } } /* The set is across all open files on this dev/inode pair. */ @@ -5317,8 +5776,9 @@ static NTSTATUS smb_file_position_information(connection_struct *conn, } #endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("smb_file_position_information: Set file position information for file %s to %.0f\n", - fsp->fsp_name, (double)position_information )); + DEBUG(10,("smb_file_position_information: Set file position " + "information for file %s to %.0f\n", fsp_str_dbg(fsp), + (double)position_information)); fsp->fh->position_information = position_information; return NT_STATUS_OK; } @@ -5351,10 +5811,10 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const char *fname) + const struct smb_filename *smb_fname) { char *link_target = NULL; - const char *newname = fname; + const char *newname = smb_fname->base_name; NTSTATUS status = NT_STATUS_OK; TALLOC_CTX *ctx = talloc_tos(); @@ -5372,44 +5832,8 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata, total_data, STR_TERMINATE); - if (!link_target) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* !widelinks forces the target path to be within the share. */ - /* This means we can interpret the target as a pathname. */ - if (!lp_widelinks(SNUM(conn))) { - char *rel_name = NULL; - char *last_dirp = NULL; - - if (*link_target == '/') { - /* No absolute paths allowed. */ - return NT_STATUS_ACCESS_DENIED; - } - rel_name = talloc_strdup(ctx,newname); - if (!rel_name) { - return NT_STATUS_NO_MEMORY; - } - last_dirp = strrchr_m(rel_name, '/'); - if (last_dirp) { - last_dirp[1] = '\0'; - } else { - rel_name = talloc_strdup(ctx,"./"); - if (!rel_name) { - return NT_STATUS_NO_MEMORY; - } - } - rel_name = talloc_asprintf_append(rel_name, - "%s", - link_target); - if (!rel_name) { - return NT_STATUS_NO_MEMORY; - } - - status = check_name(conn, rel_name); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + if (!link_target) { + return NT_STATUS_INVALID_PARAMETER; } DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", @@ -5454,8 +5878,9 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, oldname, - &smb_fname_old, - NULL); + 0, + NULL, + &smb_fname_old); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -5472,14 +5897,13 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const char *fname) + struct smb_filename *smb_fname_src) { bool overwrite; uint32 root_fid; uint32 len; char *newname = NULL; - char *base_name = NULL; - struct smb_filename *smb_fname = NULL; + struct smb_filename *smb_fname_dst = NULL; bool dest_has_wcard = False; NTSTATUS status = NT_STATUS_OK; char *p; @@ -5529,8 +5953,8 @@ 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, - newname, NULL, &smb_fname); + fsp->base_fsp->fsp_name->base_name, newname, NULL, + &smb_fname_dst); if (!NT_STATUS_IS_OK(status)) { goto out; } @@ -5539,28 +5963,31 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, * Set the original last component, since * rename_internals_fsp() requires it. */ - smb_fname->original_lcomp = talloc_strdup(smb_fname, newname); - if (smb_fname->original_lcomp == NULL) { + smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, + newname); + if (smb_fname_dst->original_lcomp == NULL) { status = NT_STATUS_NO_MEMORY; goto out; } - /* Create a char * to call rename_internals() with. */ - base_name = talloc_asprintf(ctx, "%s%s", - fsp->base_fsp->fsp_name, - newname); - if (!base_name) { - status = NT_STATUS_NO_MEMORY; - goto out; - } } else { + /* + * Build up an smb_fname_dst based on the filename passed in. + * We basically just strip off the last component, and put on + * the newname instead. + */ + char *base_name = NULL; + /* newname must *not* be a stream name. */ if (newname[0] == ':') { return NT_STATUS_NOT_SUPPORTED; } - /* Create the base directory. */ - base_name = talloc_strdup(ctx, fname); + /* + * Strip off the last component (filename) of the path passed + * in. + */ + base_name = talloc_strdup(ctx, smb_fname_src->base_name); if (!base_name) { return NT_STATUS_NO_MEMORY; } @@ -5581,8 +6008,11 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, return NT_STATUS_NO_MEMORY; } - status = unix_convert(ctx, conn, base_name, &smb_fname, - UCF_SAVE_LCOMP); + status = unix_convert(ctx, conn, base_name, &smb_fname_dst, + (UCF_SAVE_LCOMP | + (dest_has_wcard ? + UCF_ALWAYS_ALLOW_WCARD_LCOMP : + 0))); /* If an error we expect this to be * NT_STATUS_OBJECT_PATH_NOT_FOUND */ @@ -5593,30 +6023,35 @@ 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(talloc_tos(), + status = create_synthetic_smb_fname(ctx, base_name, NULL, - NULL, &smb_fname); + NULL, + &smb_fname_dst); if (!NT_STATUS_IS_OK(status)) { goto out; } } - } 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, smb_fname, 0, + DEBUG(10,("smb_file_rename_information: " + "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", + fsp->fnum, fsp_str_dbg(fsp), + smb_fname_str_dbg(smb_fname_dst))); + status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0, overwrite); } else { - DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", - fname, base_name )); - status = rename_internals(ctx, conn, req, fname, base_name, 0, - overwrite, False, dest_has_wcard, - FILE_WRITE_ATTRIBUTES); + DEBUG(10,("smb_file_rename_information: " + "SMB_FILE_RENAME_INFORMATION %s -> %s\n", + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); + status = rename_internals(ctx, conn, req, smb_fname_src, + smb_fname_dst, 0, overwrite, false, + dest_has_wcard, + FILE_WRITE_ATTRIBUTES); } out: - TALLOC_FREE(smb_fname); + TALLOC_FREE(smb_fname_dst); return status; } @@ -5629,8 +6064,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const char *fname, - SMB_STRUCT_STAT *psbuf) + const struct smb_filename *smb_fname) { uint16 posix_acl_version; uint16 num_file_acls; @@ -5665,18 +6099,20 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, } DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", - fname ? fname : fsp->fsp_name, + smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp), (unsigned int)num_file_acls, (unsigned int)num_def_acls)); - if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE)) { + if (valid_file_acls && !set_unix_posix_acl(conn, fsp, + smb_fname->base_name, num_file_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE)) { return map_nt_error_from_unix(errno); } - if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, psbuf, num_def_acls, - pdata + SMB_POSIX_ACL_HEADER_SIZE + - (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { + if (valid_def_acls && !set_unix_posix_default_acl(conn, + smb_fname->base_name, &smb_fname->st, num_def_acls, + pdata + SMB_POSIX_ACL_HEADER_SIZE + + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK; @@ -5752,7 +6188,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u," "lock_pid = %u, count = %.0f, offset = %.0f\n", - fsp->fsp_name, + fsp_str_dbg(fsp), (unsigned int)lock_type, (unsigned int)lock_pid, (double)count, @@ -5808,100 +6244,85 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, } /**************************************************************************** - Deal with SMB_INFO_STANDARD. + Deal with SMB_SET_FILE_BASIC_INFO. ****************************************************************************/ -static NTSTATUS smb_set_info_standard(connection_struct *conn, +static NTSTATUS smb_set_file_basic_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, const struct smb_filename *smb_fname) { + /* Patch to do this correctly from Paul Eggert . */ struct smb_file_time ft; + uint32 dosmode = 0; + NTSTATUS status = NT_STATUS_OK; + ZERO_STRUCT(ft); - if (total_data < 12) { + if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; } + /* Set the attributes */ + dosmode = IVAL(pdata,32); + status = smb_set_file_dosmode(conn, smb_fname, dosmode); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* create time */ ft.create_time = interpret_long_date(pdata); /* access time */ - ft.atime = interpret_long_date(pdata + 8); + ft.atime = interpret_long_date(pdata+8); - /* write time */ - ft.mtime = interpret_long_date(pdata + 16); + /* write time. */ + ft.mtime = interpret_long_date(pdata+16); - DEBUG(10,("smb_set_info_standard: file %s\n", - smb_fname_str_dbg(smb_fname))); + /* change time. */ + ft.ctime = interpret_long_date(pdata+24); + + DEBUG(10, ("smb_set_file_basic_info: file %s\n", + smb_fname_str_dbg(smb_fname))); - return smb_set_file_time(conn, fsp, smb_fname, &ft, true); + return smb_set_file_time(conn, fsp, smb_fname, &ft, + true); } /**************************************************************************** - Deal with SMB_SET_FILE_BASIC_INFO. + Deal with SMB_INFO_STANDARD. ****************************************************************************/ -static NTSTATUS smb_set_file_basic_info(connection_struct *conn, +static NTSTATUS smb_set_info_standard(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, const struct smb_filename *smb_fname) { - /* Patch to do this correctly from Paul Eggert . */ - struct timespec write_time; - struct timespec changed_time; struct smb_file_time ft; - uint32 dosmode = 0; - NTSTATUS status = NT_STATUS_OK; - bool setting_write_time = true; ZERO_STRUCT(ft); - if (total_data < 36) { + if (total_data < 12) { return NT_STATUS_INVALID_PARAMETER; } - /* Set the attributes */ - dosmode = IVAL(pdata,32); - status = smb_set_file_dosmode(conn, smb_fname, dosmode); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* access time */ - ft.atime = interpret_long_date(pdata+8); - - write_time = interpret_long_date(pdata+16); - changed_time = interpret_long_date(pdata+24); - - /* mtime */ - ft.mtime = timespec_min(&write_time, &changed_time); - /* create time */ - ft.create_time = interpret_long_date(pdata); - - 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(ft.mtime)) { - if (null_timespec(write_time)) { - ft.mtime = changed_time; - setting_write_time = false; - } else { - ft.mtime = write_time; - } - } + ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata)); + /* access time */ + ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4)); + /* write time */ + ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8)); - DEBUG(10, ("smb_set_file_basic_info: file %s\n", - smb_fname_str_dbg(smb_fname))); + DEBUG(10,("smb_set_info_standard: file %s\n", + smb_fname_str_dbg(smb_fname))); - return smb_set_file_time(conn, fsp, smb_fname, &ft, - setting_write_time); + return smb_set_file_time(conn, + fsp, + smb_fname, + &ft, + true); } /**************************************************************************** @@ -6019,7 +6440,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, const char *pdata, int total_data, files_struct *fsp, - const struct smb_filename *smb_fname) + const struct smb_filename *smb_fname, + bool fail_after_createfile) { SMB_OFF_T size; @@ -6044,7 +6466,8 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn, fsp, smb_fname, &smb_fname->st, - size); + size, + fail_after_createfile); } /**************************************************************************** @@ -6330,7 +6753,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, fsp, smb_fname, &sbuf, - size); + size, + false); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6444,11 +6868,9 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - const char *fname, - SMB_STRUCT_STAT *psbuf, + struct smb_filename *smb_fname, int *pdata_return_size) { - struct smb_filename *smb_fname; NTSTATUS status = NT_STATUS_OK; uint32 raw_unixmode = 0; uint32 mod_unixmode = 0; @@ -6465,7 +6887,8 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode); + status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, + PERM_NEW_DIR, &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6473,13 +6896,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS; DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n", - fname, (unsigned int)unixmode )); - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + smb_fname_str_dbg(smb_fname), (unsigned int)unixmode)); status = SMB_VFS_CREATE_FILE( conn, /* conn */ @@ -6498,9 +6915,6 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, &fsp, /* result */ &info); /* pinfo */ - *psbuf = smb_fname->st; - TALLOC_FREE(smb_fname); - if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); } @@ -6531,12 +6945,14 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic(conn, pdata + 12, fsp, + &smb_fname->st); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* Padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic_info2(conn, pdata + 12, fsp, + &smb_fname->st); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -6555,11 +6971,9 @@ static NTSTATUS smb_posix_open(connection_struct *conn, struct smb_request *req, char **ppdata, int total_data, - const char *fname, - SMB_STRUCT_STAT *psbuf, + struct smb_filename *smb_fname, int *pdata_return_size) { - struct smb_filename *smb_fname = NULL; bool extended_oplock_granted = False; char *pdata = *ppdata; uint32 flags = 0; @@ -6592,8 +7006,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn, return smb_posix_mkdir(conn, req, ppdata, total_data, - fname, - psbuf, + smb_fname, pdata_return_size); } @@ -6632,11 +7045,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn, raw_unixmode = IVAL(pdata,8); /* Next 4 bytes are not yet defined. */ - status = unix_perms_from_wire(conn, - psbuf, - raw_unixmode, - VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE, - &unixmode); + status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode, + (VALID_STAT(smb_fname->st) ? + PERM_EXISTING_FILE : PERM_NEW_FILE), + &unixmode); if (!NT_STATUS_IS_OK(status)) { return status; @@ -6655,16 +7067,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn, } DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n", - fname, + smb_fname_str_dbg(smb_fname), (unsigned int)wire_open_mode, (unsigned int)unixmode )); - status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf, - &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ @@ -6683,9 +7089,6 @@ static NTSTATUS smb_posix_open(connection_struct *conn, &fsp, /* result */ &info); /* pinfo */ - *psbuf = smb_fname->st; - TALLOC_FREE(smb_fname); - if (!NT_STATUS_IS_OK(status)) { return status; } @@ -6738,12 +7141,14 @@ static NTSTATUS smb_posix_open(connection_struct *conn, case SMB_QUERY_FILE_UNIX_BASIC: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic(conn, pdata + 12, fsp, + &smb_fname->st); break; case SMB_QUERY_FILE_UNIX_INFO2: SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2); SSVAL(pdata,10,0); /* padding. */ - store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf); + store_file_unix_basic_info2(conn, pdata + 12, fsp, + &smb_fname->st); break; default: SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED); @@ -6826,7 +7231,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, NULL); if (lck == NULL) { DEBUG(0, ("smb_posix_unlink: Could not get share mode " - "lock for file %s\n", fsp->fsp_name)); + "lock for file %s\n", fsp_str_dbg(fsp))); close_file(req, fsp, NORMAL_CLOSE); return NT_STATUS_INVALID_PARAMETER; } @@ -6838,229 +7243,65 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, */ for (i=0; inum_share_modes; i++) { struct share_mode_entry *e = &lck->share_modes[i]; - if (is_valid_share_mode_entry(e)) { - if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) { - continue; - } - /* Fail with sharing violation. */ - close_file(req, fsp, NORMAL_CLOSE); - TALLOC_FREE(lck); - return NT_STATUS_SHARING_VIOLATION; - } - } - - /* - * Set the delete on close. - */ - status = smb_set_file_disposition_info(conn, - &del, - 1, - fsp, - smb_fname); - - 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); -} - -/**************************************************************************** - Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). -****************************************************************************/ - -static void call_trans2setfilepathinfo(connection_struct *conn, - struct smb_request *req, - unsigned int tran_call, - char **pparams, int total_params, - char **ppdata, int total_data, - unsigned int max_data_bytes) -{ - char *params = *pparams; - char *pdata = *ppdata; - uint16 info_level; - SMB_STRUCT_STAT sbuf; - char *fname = NULL; - struct smb_filename *smb_fname = NULL; - files_struct *fsp = NULL; - NTSTATUS status = NT_STATUS_OK; - int data_return_size = 0; - TALLOC_CTX *ctx = talloc_tos(); - - if (!params) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - if (tran_call == TRANSACT2_SETFILEINFO) { - if (total_params < 4) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - fsp = file_fsp(req, SVAL(params,0)); - /* Basic check for non-null fsp. */ - if (!check_fsp_open(conn, req, fsp)) { - return; - } - info_level = SVAL(params,2); - - fname = talloc_strdup(talloc_tos(),fsp->fsp_name); - if (!fname) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - - status = create_synthetic_smb_fname_split(talloc_tos(), fname, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - if(fsp->is_directory || fsp->fh->fd == -1) { - /* - * This is actually a SETFILEINFO on a directory - * handle (returned from an NT SMB). NT5.0 seems - * to do this call. JRA. - */ - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* Always do lstat for UNIX calls. */ - if (SMB_VFS_LSTAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: " - "SMB_VFS_LSTAT of %s failed " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } else { - if (SMB_VFS_STAT(conn, smb_fname) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: " - "fileinfo of %s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req,ERRDOS,ERRbadpath); - return; - } - } - } else if (fsp->print_file) { - /* - * Doing a DELETE_ON_CLOSE should cancel a print job. - */ - if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { - fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; - - DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); - - SSVAL(params,0,0); - send_trans2_replies(conn, req, params, 2, - *ppdata, 0, - max_data_bytes); - return; - } else { - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } - } else { - /* - * Original code - this is an open file. - */ - if (!check_fsp(conn, req, fsp)) { - return; - } - - if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat " - "of fnum %d failed (%s)\n", fsp->fnum, - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadfid); - return; - } - } - } else { - /* set path info */ - if (total_params < 7) { - reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; - } - - info_level = SVAL(params,0); - srvstr_get_path(ctx, params, req->flags2, &fname, ¶ms[6], - total_params - 6, STR_TERMINATE, - &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = filename_convert(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &smb_fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - return; + if (is_valid_share_mode_entry(e)) { + if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) { + continue; } - reply_nterror(req, status); - return; + /* Fail with sharing violation. */ + close_file(req, fsp, NORMAL_CLOSE); + TALLOC_FREE(lck); + return NT_STATUS_SHARING_VIOLATION; } + } - if (INFO_LEVEL_IS_UNIX(info_level)) { - /* - * For CIFS UNIX extensions the target name may not exist. - */ - - /* Always do lstat for UNIX calls. */ - SMB_VFS_LSTAT(conn, smb_fname); + /* + * Set the delete on close. + */ + status = smb_set_file_disposition_info(conn, + &del, + 1, + fsp, + smb_fname); - } else if (!VALID_STAT(smb_fname->st) && - SMB_VFS_STAT(conn, smb_fname)) { - DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " - "%s failed (%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno))); - reply_unixerror(req, ERRDOS, ERRbadpath); - return; - } + 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); +} - /* Set sbuf for use below. */ - sbuf = smb_fname->st; +NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, + struct smb_request *req, + TALLOC_CTX *mem_ctx, + uint16_t info_level, + files_struct *fsp, + struct smb_filename *smb_fname, + char **ppdata, int total_data, + int *ret_data_size) +{ + char *pdata = *ppdata; + NTSTATUS status = NT_STATUS_OK; + int data_return_size = 0; + + *ret_data_size = 0; if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } if (!CAN_WRITE(conn)) { /* Allow POSIX opens. The open path will deny * any non-readonly opens. */ if (info_level != SMB_POSIX_PATH_OPEN) { - reply_doserror(req, ERRSRV, ERRaccess); - return; + return NT_STATUS_DOS(ERRSRV, ERRaccess); } } - DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n", - tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data)); - - /* Realloc the parameter size */ - *pparams = (char *)SMB_REALLOC(*pparams,2); - if (*pparams == NULL) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - return; - } - params = *pparams; - - SSVAL(params,0,0); + DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d " + "totdata=%d\n", smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level, total_data)); switch (info_level) { @@ -7109,11 +7350,22 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_FILE_END_OF_FILE_INFORMATION: case SMB_SET_FILE_END_OF_FILE_INFO: { + /* + * XP/Win7 both fail after the createfile with + * SMB_SET_FILE_END_OF_FILE_INFO but not + * SMB_FILE_END_OF_FILE_INFORMATION (pass-through). + * The level is known here, so pass it down + * appropriately. + */ + bool should_fail = + (info_level == SMB_SET_FILE_END_OF_FILE_INFO); + status = smb_set_file_end_of_file_info(conn, req, pdata, total_data, fsp, - smb_fname); + smb_fname, + should_fail); break; } @@ -7146,6 +7398,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn, break; } + case SMB_FILE_FULL_EA_INFORMATION: + { + status = smb_set_file_full_ea_info(conn, + pdata, + total_data, + fsp); + break; + } + /* From tridge Samba4 : * MODE_INFORMATION in setfileinfo (I have no * idea what "mode information" on a file is - it takes a value of 0, @@ -7186,22 +7447,20 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_UNIX_LINK: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_set_file_unix_link(conn, req, pdata, - total_data, fname); + total_data, smb_fname); break; } case SMB_SET_FILE_UNIX_HLINK: { - if (tran_call != TRANSACT2_SETPATHINFO || smb_fname == NULL) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_set_file_unix_hlink(conn, req, pdata, total_data, @@ -7213,7 +7472,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, { status = smb_file_rename_information(conn, req, pdata, total_data, - fsp, fname); + fsp, smb_fname); break; } @@ -7224,17 +7483,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn, pdata, total_data, fsp, - fname, - &sbuf); + smb_fname); break; } #endif case SMB_SET_POSIX_LOCK: { - if (tran_call != TRANSACT2_SETFILEINFO) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + if (!fsp) { + return NT_STATUS_INVALID_LEVEL; } status = smb_set_posix_lock(conn, req, pdata, total_data, fsp); @@ -7243,27 +7500,24 @@ static void call_trans2setfilepathinfo(connection_struct *conn, case SMB_POSIX_PATH_OPEN: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_posix_open(conn, req, ppdata, total_data, - fname, - &sbuf, + smb_fname, &data_return_size); break; } case SMB_POSIX_PATH_UNLINK: { - if (tran_call != TRANSACT2_SETPATHINFO) { + if (fsp) { /* We must have a pathname for this. */ - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + return NT_STATUS_INVALID_LEVEL; } status = smb_posix_unlink(conn, req, @@ -7274,10 +7528,199 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } default: - reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return NT_STATUS_INVALID_LEVEL; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *ret_data_size = data_return_size; + return NT_STATUS_OK; +} + +/**************************************************************************** + Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). +****************************************************************************/ + +static void call_trans2setfilepathinfo(connection_struct *conn, + struct smb_request *req, + unsigned int tran_call, + char **pparams, int total_params, + char **ppdata, int total_data, + unsigned int max_data_bytes) +{ + char *params = *pparams; + char *pdata = *ppdata; + uint16 info_level; + struct smb_filename *smb_fname = NULL; + files_struct *fsp = NULL; + NTSTATUS status = NT_STATUS_OK; + int data_return_size = 0; + + if (!params) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (tran_call == TRANSACT2_SETFILEINFO) { + if (total_params < 4) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + fsp = file_fsp(req, SVAL(params,0)); + /* Basic check for non-null fsp. */ + if (!check_fsp_open(conn, req, fsp)) { + return; + } + 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); + return; + } + + if(fsp->is_directory || fsp->fh->fd == -1) { + /* + * This is actually a SETFILEINFO on a directory + * handle (returned from an NT SMB). NT5.0 seems + * to do this call. JRA. + */ + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* Always do lstat for UNIX calls. */ + if (SMB_VFS_LSTAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: " + "SMB_VFS_LSTAT of %s failed " + "(%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } else { + if (SMB_VFS_STAT(conn, smb_fname) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: " + "fileinfo of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + } else if (fsp->print_file) { + /* + * Doing a DELETE_ON_CLOSE should cancel a print job. + */ + if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { + fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; + + DEBUG(3,("call_trans2setfilepathinfo: " + "Cancelling print job (%s)\n", + fsp_str_dbg(fsp))); + + SSVAL(params,0,0); + send_trans2_replies(conn, req, params, 2, + *ppdata, 0, + max_data_bytes); + return; + } else { + reply_nterror(req, + NT_STATUS_OBJECT_PATH_NOT_FOUND); + return; + } + } else { + /* + * Original code - this is an open file. + */ + if (!check_fsp(conn, req, fsp)) { + return; + } + + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3,("call_trans2setfilepathinfo: fstat " + "of fnum %d failed (%s)\n", fsp->fnum, + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); + return; + } + } + } else { + char *fname = NULL; + + /* set path info */ + if (total_params < 7) { + reply_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + info_level = SVAL(params,0); + srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], + total_params - 6, STR_TERMINATE, + &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } + + status = filename_convert(req, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + 0, + NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + return; + } + reply_nterror(req, status); + return; + } + + if (INFO_LEVEL_IS_UNIX(info_level)) { + /* + * For CIFS UNIX extensions the target name may not exist. + */ + + /* Always do lstat for UNIX calls. */ + SMB_VFS_LSTAT(conn, smb_fname); + + } else if (!VALID_STAT(smb_fname->st) && + SMB_VFS_STAT(conn, smb_fname)) { + DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of " + "%s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); + reply_nterror(req, map_nt_error_from_unix(errno)); return; + } + } + + DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d " + "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname), + fsp ? fsp->fnum : -1, info_level,total_data)); + + /* Realloc the parameter size */ + *pparams = (char *)SMB_REALLOC(*pparams,2); + if (*pparams == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + return; } + params = *pparams; + + SSVAL(params,0,0); + status = smbd_do_setfilepathinfo(conn, req, req, + info_level, + fsp, + smb_fname, + ppdata, total_data, + &data_return_size); if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ @@ -7301,7 +7744,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - SSVAL(params,0,0); send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size, max_data_bytes); @@ -7326,7 +7768,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, TALLOC_CTX *ctx = talloc_tos(); if (!CAN_WRITE(conn)) { - reply_doserror(req, ERRSRV, ERRaccess); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); return; } @@ -7349,8 +7791,9 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - &smb_dname, - NULL); + 0, + NULL, + &smb_dname); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -7544,7 +7987,7 @@ static void call_trans2getdfsreferral(connection_struct *conn, max_referral_level = SVAL(params,0); if(!lp_host_msdfs()) { - reply_doserror(req, ERRDOS, ERRbadfunc); + reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); return; } @@ -7586,7 +8029,7 @@ static void call_trans2ioctl(connection_struct *conn, /* check for an invalid fid before proceeding */ if (!fsp) { - reply_doserror(req, ERRDOS, ERRbadfid); + reply_nterror(req, NT_STATUS_INVALID_HANDLE); return; } @@ -7615,7 +8058,7 @@ static void call_trans2ioctl(connection_struct *conn, } DEBUG(2,("Unknown TRANS2_IOCTL\n")); - reply_doserror(req, ERRSRV, ERRerror); + reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); } /**************************************************************************** @@ -7625,6 +8068,7 @@ static void call_trans2ioctl(connection_struct *conn, void reply_findclose(struct smb_request *req) { int dptr_num; + struct smbd_server_connection *sconn = smbd_server_conn; START_PROFILE(SMBfindclose); @@ -7638,7 +8082,7 @@ void reply_findclose(struct smb_request *req) DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num)); - dptr_close(&dptr_num); + dptr_close(sconn, &dptr_num); reply_outbuf(req, 0, 0); @@ -7683,7 +8127,7 @@ void reply_findnclose(struct smb_request *req) static void handle_trans2(connection_struct *conn, struct smb_request *req, struct trans_state *state) { - if (Protocol >= PROTOCOL_NT1) { + if (get_Protocol() >= PROTOCOL_NT1) { req->flags2 |= 0x40; /* IS_LONG_NAME */ SSVAL(req->inbuf,smb_flg2,req->flags2); } @@ -7840,7 +8284,7 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req, default: /* Error in request */ DEBUG(2,("Unknown request %d in trans2 call\n", state->call)); - reply_doserror(req, ERRSRV,ERRerror); + reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED); } } @@ -7892,7 +8336,7 @@ void reply_trans2(struct smb_request *req) case TRANSACT2_SETFSINFO: break; default: - reply_doserror(req, ERRSRV, ERRaccess); + reply_nterror(req, NT_STATUS_ACCESS_DENIED); END_PROFILE(SMBtrans2); return; }