diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/smb2_getinfo.c | 140 |
1 files changed, 139 insertions, 1 deletions
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c index ba725fdec9..b6b7462e90 100644 --- a/source3/smbd/smb2_getinfo.c +++ b/source3/smbd/smb2_getinfo.c @@ -233,7 +233,145 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + if (IS_IPC(conn)) { + tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED); + return tevent_req_post(req, ev); + } + + switch (in_info_type) { + case 0x01:/* SMB2_GETINFO_FILE */ + { + uint16_t file_info_level; + char *data = NULL; + unsigned int data_size = 0; + struct smb_filename *smb_fname = NULL; + bool delete_pending = false; + struct timespec write_time_ts; + 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; + + ZERO_STRUCT(write_time_ts); + + switch (in_file_info_class) { + case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */ + file_info_level = 0xFF00 | in_file_info_class; + break; + + case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */ + file_info_level = 0xFF00 | in_file_info_class; + break; + + default: + /* the levels directly map to the passthru levels */ + file_info_level = in_file_info_class + 1000; + break; + } + + status = create_synthetic_smb_fname_split(state, + fsp->fsp_name, + NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + 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 && (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(file_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))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + } 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))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + 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 (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) { + DEBUG(3, ("fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); + status = map_nt_error_from_unix(errno); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st); + get_file_infos(fileid, &delete_pending, &write_time_ts); + } + + status = smbd_do_qfilepathinfo(conn, state, + file_info_level, + fsp, + smb_fname, + delete_pending, + write_time_ts, + ms_dfs_link, + ea_list, + lock_data_count, + lock_data, + STR_UNICODE, + in_output_buffer_length, + &data, + &data_size); + if (!NT_STATUS_IS_OK(status)) { + SAFE_FREE(data); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + if (data_size > 0) { + state->out_output_buffer = data_blob_talloc(state, + data, + data_size); + SAFE_FREE(data); + if (tevent_req_nomem(state->out_output_buffer.data, req)) { + return tevent_req_post(req, ev); + } + } + SAFE_FREE(data); + break; + } + + default: + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); return tevent_req_post(req, ev); } |