From 7d1395536bbcc937e3115aa067eed3f69f3909be Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Jun 2012 17:51:47 +0200 Subject: s3:smbd: make use of smbXsrv_open for smb1/2/3 This makes sure we generate unique persistent file ids, which are stored in smbXsrv_open_global.tdb. Pair-Programmed-With: Michael Adam metze Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Fri Jun 29 21:01:11 CEST 2012 on sn-devel-104 --- source3/include/vfs.h | 1 + source3/smbd/files.c | 172 ++++++++++++--------------------------------- source3/smbd/globals.h | 14 +++- source3/smbd/process.c | 10 +++ source3/smbd/proto.h | 1 - source3/smbd/smb2_break.c | 5 +- source3/smbd/smb2_create.c | 4 +- source3/smbd/smb2_lock.c | 2 +- source3/smbd/smb2_read.c | 4 +- source3/smbd/smb2_write.c | 2 +- 10 files changed, 74 insertions(+), 141 deletions(-) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index bd66d34043..754d4e4d2a 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -186,6 +186,7 @@ struct fd_handle { typedef struct files_struct { struct files_struct *next, *prev; uint64_t fnum; + struct smbXsrv_open0 *op; struct connection_struct *conn; struct fd_handle *fh; unsigned int num_smb_operations; diff --git a/source3/smbd/files.c b/source3/smbd/files.c index b5be0834b3..0929d994a8 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -27,33 +27,6 @@ #define FILE_HANDLE_OFFSET 0x1000 -/**************************************************************************** - Return a unique number identifying this fsp over the life of this pid, - and try to make it as globally unique as possible. - See bug #8995 for the details. -****************************************************************************/ - -static unsigned long get_gen_count(struct smbd_server_connection *sconn) -{ - /* - * While fsp->fh->gen_id is 'unsigned long' currently - * (which might by 8 bytes), - * there's some oplock code which truncates it to - * uint32_t(using IVAL()). - */ - if (sconn->file_gen_counter == 0) { - sconn->file_gen_counter = generate_random(); - } - sconn->file_gen_counter += 1; - if (sconn->file_gen_counter >= UINT32_MAX) { - sconn->file_gen_counter = 0; - } - if (sconn->file_gen_counter == 0) { - sconn->file_gen_counter += 1; - } - return sconn->file_gen_counter; -} - /** * create new fsp to be used for file_new or a durable handle reconnect */ @@ -110,7 +83,6 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, files_struct **result) { struct smbd_server_connection *sconn = conn->sconn; - int i = -1; files_struct *fsp; NTSTATUS status; @@ -121,41 +93,21 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, GetTimeOfDay(&fsp->open_time); - if (sconn->file_bmap != NULL) { - - /* - * we want to give out file handles differently on each new - * connection because of a common bug in MS clients where they - * try to reuse a file descriptor from an earlier smb - * connection. This code increases the chance that the errant - * client will get an error rather than causing corruption - */ - if (sconn->first_file == 0) { - sconn->first_file = (getpid() ^ (int)time(NULL)); - sconn->first_file %= sconn->real_max_open_files; - } + if (sconn->conn) { + struct smbXsrv_open *op = NULL; + NTTIME now = timeval_to_nttime(&fsp->open_time); - /* TODO: Port the id-tree implementation from Samba4 */ - - i = bitmap_find(sconn->file_bmap, sconn->first_file); - if (i == -1) { - DEBUG(0,("ERROR! Out of file structures\n")); - /* - * TODO: We have to unconditionally return a DOS error - * here, W2k3 even returns ERRDOS/ERRnofids for - * ntcreate&x with NTSTATUS negotiated - */ - return NT_STATUS_TOO_MANY_OPENED_FILES; + status = smbXsrv_open_create(sconn->conn, + conn->session_info, + now, &op); + if (!NT_STATUS_IS_OK(status)) { + file_free(NULL, fsp); + return status; } - - sconn->first_file = (i+1) % (sconn->real_max_open_files); - - bitmap_set(sconn->file_bmap, i); - - fsp->fnum = i + FILE_HANDLE_OFFSET; - SMB_ASSERT(fsp->fnum < 65536); - - fsp->fh->gen_id = get_gen_count(sconn); + fsp->op = op; + op->compat = fsp; + fsp->fnum = op->local_id; + fsp->fh->gen_id = smbXsrv_open_hash(op); } /* @@ -170,8 +122,8 @@ NTSTATUS file_new(struct smb_request *req, connection_struct *conn, return status; } - DEBUG(5,("allocated file structure %d, %s (%u used)\n", - i, fsp_fnum_dbg(fsp), (unsigned int)sconn->num_files)); + DEBUG(5,("allocated file structure %s (%u used)\n", + fsp_fnum_dbg(fsp), (unsigned int)sconn->num_files)); if (req != NULL) { req->chain_fsp = fsp; @@ -273,11 +225,6 @@ bool file_init(struct smbd_server_connection *sconn) sconn->real_max_open_files = files_max_open_fds; - sconn->file_bmap = bitmap_talloc(sconn, sconn->real_max_open_files); - if (!sconn->file_bmap) { - return false; - } - return true; } @@ -540,9 +487,10 @@ void file_free(struct smb_request *req, files_struct *fsp) /* Ensure this event will never fire. */ TALLOC_FREE(fsp->update_write_time_event); - if (sconn->file_bmap != NULL) { - bitmap_clear(sconn->file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); + if (fsp->op != NULL) { + fsp->op->compat = NULL; } + TALLOC_FREE(fsp->op); if ((req != NULL) && (fsp == req->chain_fsp)) { req->chain_fsp = NULL; @@ -570,37 +518,15 @@ void file_free(struct smb_request *req, files_struct *fsp) (unsigned long long)fnum, (unsigned int)sconn->num_files)); } -/**************************************************************************** - Get an fsp from a 16 bit fnum. -****************************************************************************/ - -static struct files_struct *file_fnum(struct smbd_server_connection *sconn, - uint16 fnum) -{ - files_struct *fsp; - int count=0; - - for (fsp=sconn->files; fsp; fsp=fsp->next, count++) { - if (fsp->fnum == FNUM_FIELD_INVALID) { - continue; - } - - if (fsp->fnum == fnum) { - if (count > 10) { - DLIST_PROMOTE(sconn->files, fsp); - } - return fsp; - } - } - return NULL; -} - /**************************************************************************** Get an fsp from a packet given a 16 bit fnum. ****************************************************************************/ files_struct *file_fsp(struct smb_request *req, uint16 fid) { + struct smbXsrv_open *op; + NTSTATUS status; + NTTIME now = 0; files_struct *fsp; if (req == NULL) { @@ -620,59 +546,49 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid) return req->chain_fsp; } - fsp = file_fnum(req->sconn, fid); + if (req->sconn->conn == NULL) { + return NULL; + } + + now = timeval_to_nttime(&req->request_time); + + status = smb1srv_open_lookup(req->sconn->conn, + fid, now, &op); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + fsp = op->compat; if (fsp != NULL) { req->chain_fsp = fsp; } return fsp; } -uint64_t fsp_persistent_id(const struct files_struct *fsp) -{ - uint64_t persistent_id; - - /* - * This calculates a number that is most likely - * globally unique. In future we will have a database - * to make it completely unique. - * - * 32-bit random gen_id - * 16-bit truncated open_time - * 16-bit fnum (valatile_id) - */ - persistent_id = fsp->fh->gen_id & UINT32_MAX; - persistent_id <<= 16; - persistent_id &= 0x0000FFFFFFFF0000LLU; - persistent_id |= fsp->open_time.tv_usec & UINT16_MAX; - persistent_id <<= 16; - persistent_id &= 0xFFFFFFFFFFFF0000LLU; - persistent_id |= fsp->fnum & UINT16_MAX; - - return persistent_id; -} - struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req, uint64_t persistent_id, uint64_t volatile_id) { + struct smbXsrv_open *op; + NTSTATUS status; + NTTIME now = 0; struct files_struct *fsp; - uint64_t fsp_persistent; if (smb2req->compat_chain_fsp != NULL) { return smb2req->compat_chain_fsp; } - if (volatile_id > UINT16_MAX) { - return NULL; - } + now = timeval_to_nttime(&smb2req->request_time); - fsp = file_fnum(smb2req->sconn, (uint16_t)volatile_id); - if (fsp == NULL) { + status = smb2srv_open_lookup(smb2req->sconn->conn, + persistent_id, volatile_id, + now, &op); + if (!NT_STATUS_IS_OK(status)) { return NULL; } - fsp_persistent = fsp_persistent_id(fsp); - if (persistent_id != fsp_persistent) { + fsp = op->compat; + if (fsp == NULL) { return NULL; } diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index d6c618f405..6c1efaf44b 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -354,8 +354,19 @@ struct smbXsrv_connection { uint64_t smbd_idle_profstamp; + /* + * this session_table is used for SMB1 and SMB2, + */ struct smbXsrv_session_table *session_table; + /* + * this tcon_table is only used for SMB1. + */ struct smbXsrv_tcon_table *tcon_table; + /* + * this open_table is used for SMB1 and SMB2, + * because we have a global sconn->real_max_open_files + * limit. + */ struct smbXsrv_open_table *open_table; }; @@ -552,11 +563,8 @@ struct smbd_server_connection { size_t num_files; struct files_struct *files; - struct bitmap *file_bmap; int real_max_open_files; struct fsp_singleton_cache fsp_fi_cache; - unsigned long file_gen_counter; - int first_file; struct pending_message_list *deferred_open_queue; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index a437a9813b..55a125fb88 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -3211,6 +3211,11 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn, if (!NT_STATUS_IS_OK(status)) { return status; } + + status = smb2srv_open_table_init(conn); + if (!NT_STATUS_IS_OK(status)) { + return status; + } } else { status = smb1srv_session_table_init(conn); if (!NT_STATUS_IS_OK(status)) { @@ -3221,6 +3226,11 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn, if (!NT_STATUS_IS_OK(status)) { return status; } + + status = smb1srv_open_table_init(conn); + if (!NT_STATUS_IS_OK(status)) { + return status; + } } return NT_STATUS_OK; diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 3efbe8f447..35a677c079 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -386,7 +386,6 @@ void file_sync_all(connection_struct *conn); void fsp_free(files_struct *fsp); void file_free(struct smb_request *req, files_struct *fsp); files_struct *file_fsp(struct smb_request *req, uint16 fid); -uint64_t fsp_persistent_id(const struct files_struct *fsp); struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req, uint64_t persistent_id, uint64_t volatile_id); diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c index 95e1d8b537..77f4709620 100644 --- a/source3/smbd/smb2_break.c +++ b/source3/smbd/smb2_break.c @@ -237,7 +237,6 @@ void send_break_message_smb2(files_struct *fsp, int level) SMB2_OPLOCK_LEVEL_II : SMB2_OPLOCK_LEVEL_NONE; NTSTATUS status; - uint64_t fsp_persistent = fsp_persistent_id(fsp); DEBUG(10,("send_break_message_smb2: sending oplock break " "for file %s, %s, smb2 level %u\n", @@ -246,8 +245,8 @@ void send_break_message_smb2(files_struct *fsp, int level) (unsigned int)smb2_oplock_level )); status = smbd_smb2_send_oplock_break(fsp->conn->sconn, - fsp_persistent, - fsp->fnum, + fsp->op->global->open_persistent_id, + fsp->op->global->open_volatile_id, smb2_oplock_level); if (!NT_STATUS_IS_OK(status)) { smbd_server_connection_terminate(fsp->conn->sconn, diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index b729ebfecd..18c3fb954f 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -822,8 +822,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, if (state->out_file_attributes == 0) { state->out_file_attributes = FILE_ATTRIBUTE_NORMAL; } - state->out_file_id_persistent = fsp_persistent_id(result); - state->out_file_id_volatile = result->fnum; + state->out_file_id_persistent = result->op->global->open_persistent_id; + state->out_file_id_volatile = result->op->global->open_volatile_id; state->out_context_blobs = out_context_blobs; DEBUG(10,("smbd_smb2_create_send: %s - %s\n", diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 68ad9e6e37..b4d21a3fc2 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -317,7 +317,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - locks[i].smblctx = fsp->fnum; + locks[i].smblctx = fsp->op->global->open_persistent_id; locks[i].offset = in_locks[i].offset; locks[i].count = in_locks[i].length; diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 0e08ff4a52..289cbc0208 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -252,7 +252,7 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) } init_strict_lock_struct(fsp, - fsp->fnum, + fsp->op->global->open_persistent_id, in_offset, in_length, READ_LOCK, @@ -479,7 +479,7 @@ static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx, /* Fallback to synchronous. */ init_strict_lock_struct(fsp, - fsp->fnum, + fsp->op->global->open_persistent_id, in_offset, in_length, READ_LOCK, diff --git a/source3/smbd/smb2_write.c b/source3/smbd/smb2_write.c index 0150b0cd25..8ddd8cc783 100644 --- a/source3/smbd/smb2_write.c +++ b/source3/smbd/smb2_write.c @@ -324,7 +324,7 @@ static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx, /* Fallback to synchronous. */ init_strict_lock_struct(fsp, - fsp->fnum, + fsp->op->global->open_persistent_id, in_offset, in_data.length, WRITE_LOCK, -- cgit