The branch, master has been updated via 3272e16 Missed one debug printf of name_hash. Ensure always use %x. via 4473273 Fix bug #7863 - Unlink may unlink wrong file when hardlinks are involved. via a65bce4 Add uint32_t name_hash argument (currently unused) to get_file_infos(). via b97f1ce Add name_hash into the share mode entry struct (as yet only use for renames to identify a specific path). via 76418e2 Add name_hash to files_struct. Set within fsp_set_smb_fname(). from 6e22637 s4-test/delete_object: Remove global ldb connections
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 3272e16846f6b7363c5a42c8cececaf4bb409688 Author: Jeremy Allison <j...@samba.org> Date: Tue Jan 25 14:59:44 2011 -0800 Missed one debug printf of name_hash. Ensure always use %x. Autobuild-User: Jeremy Allison <j...@samba.org> Autobuild-Date: Wed Jan 26 00:46:28 CET 2011 on sn-devel-104 commit 44732734cca2328a8aceb2db9b577c923920f644 Author: Jeremy Allison <j...@samba.org> Date: Tue Jan 25 14:23:19 2011 -0800 Fix bug #7863 - Unlink may unlink wrong file when hardlinks are involved. Do this by keeping a linked list of delete on close tokens, one for each filename that identifies a path to the dev/inode. Use the jenkins hash of the pathname to identify the correct token. commit a65bce4e38d0b940286c7c93c226651e5fb45082 Author: Jeremy Allison <j...@samba.org> Date: Tue Jan 25 13:57:38 2011 -0800 Add uint32_t name_hash argument (currently unused) to get_file_infos(). Will be used when we store more than one delete on close token. commit b97f1ce68a512cb0da71ee1de9ddaa49dd466068 Author: Jeremy Allison <j...@samba.org> Date: Tue Jan 25 14:01:52 2011 -0800 Add name_hash into the share mode entry struct (as yet only use for renames to identify a specific path). commit 76418e23bcde1eba4dfefbc10c51c083567a52e6 Author: Jeremy Allison <j...@samba.org> Date: Tue Jan 25 13:49:01 2011 -0800 Add name_hash to files_struct. Set within fsp_set_smb_fname(). ----------------------------------------------------------------------- Summary of changes: source3/include/proto.h | 13 ++- source3/include/smb.h | 40 +++-- source3/libsmb/smb_share_modes.c | 45 ++++- source3/locking/locking.c | 350 +++++++++++++++++++++++++++---------- source3/smbd/close.c | 59 ++++--- source3/smbd/dir.c | 2 +- source3/smbd/filename.c | 10 + source3/smbd/files.c | 33 ++++- source3/smbd/nttrans.c | 4 +- source3/smbd/open.c | 12 +- source3/smbd/oplock.c | 2 + source3/smbd/reply.c | 13 +- source3/smbd/smb2_create.c | 2 +- source3/smbd/smb2_getinfo.c | 6 +- source3/smbd/trans2.c | 26 +++- 15 files changed, 454 insertions(+), 163 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/include/proto.h b/source3/include/proto.h index 29dbcc9..4c7d4f3 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -3068,8 +3068,11 @@ struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, bool rename_share_filename(struct messaging_context *msg_ctx, struct share_mode_lock *lck, const char *servicepath, + uint32_t orig_name_hash, + uint32_t new_name_hash, const struct smb_filename *smb_fname); void get_file_infos(struct file_id id, + uint32_t name_hash, bool *delete_on_close, struct timespec *write_time); bool is_valid_share_mode_entry(const struct share_mode_entry *e); @@ -3086,9 +3089,13 @@ void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid, bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp); bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp); NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32 dosmode); -void set_delete_on_close_token(struct share_mode_lock *lck, const UNIX_USER_TOKEN *tok); -void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, const UNIX_USER_TOKEN *tok); +const UNIX_USER_TOKEN *get_delete_on_close_token(struct share_mode_lock *lck, uint32_t name_hash); +void set_delete_on_close_lck(files_struct *fsp, + struct share_mode_lock *lck, + bool delete_on_close, + const UNIX_USER_TOKEN *tok); bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const UNIX_USER_TOKEN *tok); +bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash); bool set_sticky_write_time(struct file_id fileid, struct timespec write_time); bool set_write_time(struct file_id fileid, struct timespec write_time); int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, @@ -4764,6 +4771,8 @@ files_struct *file_fsp(struct smb_request *req, uint16 fid); NTSTATUS dup_file_fsp(struct smb_request *req, files_struct *from, uint32 access_mask, uint32 share_access, uint32 create_options, files_struct *to); +NTSTATUS file_name_hash(connection_struct *conn, + const char *name, uint32_t *p_name_hash); NTSTATUS fsp_set_smb_fname(struct files_struct *fsp, const struct smb_filename *smb_fname_in); diff --git a/source3/include/smb.h b/source3/include/smb.h index 1a76691..95c1d62 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -346,6 +346,7 @@ typedef struct files_struct { bool posix_open; bool is_sparse; struct smb_filename *fsp_name; + uint32_t name_hash; /* Jenkins hash of full pathname. */ struct vfs_fsp_data *vfs_extension; struct fake_file_handle *fake_file_handle; @@ -684,6 +685,7 @@ struct share_mode_entry { unsigned long share_file_id; uint32 uid; /* uid of file opener. */ uint16 flags; /* See SHARE_MODE_XX above. */ + uint32_t name_hash; /* Jenkins hash of full pathname. */ }; /* oplock break message definition - linearization of share_mode_entry. @@ -703,7 +705,8 @@ Offset Data length. 58 unsigned long file_id 4 bytes 62 uint32 uid 4 bytes 66 uint16 flags 2 bytes -68 +68 uint32 name_hash 4 bytes +72 */ @@ -721,14 +724,21 @@ Offset Data length. #define OP_BREAK_MSG_FILE_ID_OFFSET 58 #define OP_BREAK_MSG_UID_OFFSET 62 #define OP_BREAK_MSG_FLAGS_OFFSET 66 +#define OP_BREAK_MSG_NAME_HASH_OFFSET 68 #ifdef CLUSTER_SUPPORT -#define OP_BREAK_MSG_VNN_OFFSET 68 -#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 72 +#define OP_BREAK_MSG_VNN_OFFSET 72 +#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 76 #else -#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 68 +#define MSG_SMB_SHARE_MODE_ENTRY_SIZE 72 #endif +struct delete_token_list { + struct delete_token_list *next, *prev; + uint32_t name_hash; + UNIX_USER_TOKEN *delete_token; +}; + struct share_mode_lock { const char *servicepath; /* canonicalized. */ const char *base_name; @@ -736,8 +746,7 @@ struct share_mode_lock { struct file_id id; int num_share_modes; struct share_mode_entry *share_modes; - UNIX_USER_TOKEN *delete_token; - bool delete_on_close; + struct delete_token_list *delete_tokens; struct timespec old_write_time; struct timespec changed_write_time; bool fresh; @@ -754,20 +763,23 @@ struct locking_data { union { struct { int num_share_mode_entries; - bool delete_on_close; struct timespec old_write_time; struct timespec changed_write_time; - uint32 delete_token_size; /* Only valid if either of - the two previous fields - are True. */ + uint32 num_delete_token_entries; } s; struct share_mode_entry dummy; /* Needed for alignment. */ } u; /* The following four entries are implicit - struct share_mode_entry modes[num_share_mode_entries]; - char unix_token[delete_token_size] (divisible by 4). - char share_name[]; - char file_name[]; + + (1) struct share_mode_entry modes[num_share_mode_entries]; + + (2) A num_delete_token_entries of structs { + uint32_t len_delete_token; + char unix_token[len_delete_token] (divisible by 4). + }; + + (3) char share_name[]; + (4) char file_name[]; */ }; diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c index 9f98550..9392349 100644 --- a/source3/libsmb/smb_share_modes.c +++ b/source3/libsmb/smb_share_modes.c @@ -155,7 +155,8 @@ static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, */ static void create_share_mode_entry(struct share_mode_entry *out, - const struct smb_share_mode_entry *in) + const struct smb_share_mode_entry *in, + uint32_t name_hash) { memset(out, '\0', sizeof(struct share_mode_entry)); @@ -170,6 +171,7 @@ static void create_share_mode_entry(struct share_mode_entry *out, out->id.extid = in->extid; out->uid = (uint32)geteuid(); out->flags = 0; + out->name_hash = name_hash; } /* @@ -255,12 +257,32 @@ int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx, return 0; } - *p_delete_on_close = ld->u.s.delete_on_close; + *p_delete_on_close = ld->u.s.num_delete_token_entries != 0; *pp_list = list; free(db_data.dptr); return list_num; } +static uint32_t smb_name_hash(const char *sharepath, const char *filename, int *err) +{ + TDB_DATA key; + char *fullpath = NULL; + int ret; + uint32_t name_hash; + + *err = 0; + ret = asprintf(&fullpath, "%s/%s", sharepath, filename); + if (ret == -1 || fullpath == NULL) { + *err = 1; + return 0; + } + key.dptr = (uint8_t *)fullpath; + key.dsize = strlen(fullpath); + name_hash = tdb_jenkins_hash(&key); + free(fullpath); + return name_hash; +} + /* * Create an entry in the Samba share mode db. */ @@ -281,6 +303,12 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, struct share_mode_entry *shares = NULL; uint8 *new_data_p = NULL; size_t new_data_size = 0; + int err = 0; + uint32_t name_hash = smb_name_hash(sharepath, filename, &err); + + if (err) { + return -1; + } db_data = tdb_fetch(db_ctx->smb_tdb, locking_key); if (!db_data.dptr) { @@ -296,10 +324,9 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, ld = (struct locking_data *)db_data.dptr; memset(ld, '\0', sizeof(struct locking_data)); ld->u.s.num_share_mode_entries = 1; - ld->u.s.delete_on_close = 0; - ld->u.s.delete_token_size = 0; + ld->u.s.num_delete_token_entries = 0; shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data)); - create_share_mode_entry(shares, new_entry); + create_share_mode_entry(shares, new_entry, name_hash); memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(struct share_mode_entry), sharepath, @@ -338,12 +365,12 @@ int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, shares = (struct share_mode_entry *)(new_data_p + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry))); - create_share_mode_entry(shares, new_entry); + create_share_mode_entry(shares, new_entry, name_hash); ld = (struct locking_data *)new_data_p; ld->u.s.num_share_mode_entries++; - /* Append the original delete_token and filenames. */ + /* Append the original delete_tokens and filenames. */ memcpy(new_data_p + sizeof(struct locking_data) + (ld->u.s.num_share_mode_entries * sizeof(struct share_mode_entry)), db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)), db_data.dsize - sizeof(struct locking_data) - (orig_num_share_modes * sizeof(struct share_mode_entry))); @@ -460,7 +487,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, return tdb_delete(db_ctx->smb_tdb, locking_key); } - /* Copy any delete token plus the terminating filenames. */ + /* Copy any delete tokens plus the terminating filenames. */ remaining_ptr = db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)); remaining_size = db_data.dsize - (remaining_ptr - db_data.dptr); @@ -521,7 +548,7 @@ int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx, } if (share_mode_entry_equal(set_entry, share)) { - create_share_mode_entry(share, new_entry); + create_share_mode_entry(share, new_entry, share->name_hash); found_entry = 1; break; } diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 4a61953..1942f44 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -492,7 +492,7 @@ char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e) return talloc_asprintf(ctx, "share_mode_entry[%d]: %s " "pid = %s, share_access = 0x%x, private_options = 0x%x, " "access_mask = 0x%x, mid = 0x%llx, type= 0x%x, gen_id = %lu, " - "uid = %u, flags = %u, file_id %s", + "uid = %u, flags = %u, file_id %s, name_hash = 0x%x", num, e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "", procid_str_static(&e->pid), @@ -500,7 +500,8 @@ char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e) e->access_mask, (unsigned long long)e->op_mid, e->op_type, e->share_file_id, (unsigned int)e->uid, (unsigned int)e->flags, - file_id_string_tos(&e->id)); + file_id_string_tos(&e->id), + (unsigned int)e->name_hash); } /******************************************************************* @@ -532,6 +533,104 @@ static void print_share_mode_table(struct locking_data *data) } } +static int parse_delete_tokens_list(struct share_mode_lock *lck, + struct locking_data *pdata, + const TDB_DATA dbuf) +{ + uint8_t *p = dbuf.dptr + sizeof(struct locking_data) + + (lck->num_share_modes * + sizeof(struct share_mode_entry)); + uint8_t *end_ptr = dbuf.dptr + (dbuf.dsize - 2); + int delete_tokens_size = 0; + int i; + + lck->delete_tokens = NULL; + + for (i = 0; i < pdata->u.s.num_delete_token_entries; i++) { + uint32_t token_len; + struct delete_token_list *pdtl; + + if (end_ptr - p < (sizeof(uint32_t) + sizeof(uint32_t) + + sizeof(uid_t) + sizeof(gid_t))) { + DEBUG(0,("parse_delete_tokens_list: " + "corrupt token list (%u)", + (unsigned int)(end_ptr - p))); + smb_panic("corrupt token list"); + return -1; + } + + memcpy(&token_len, p, sizeof(token_len)); + delete_tokens_size += token_len; + + if (p + token_len > end_ptr || token_len < sizeof(token_len) + + sizeof(pdtl->name_hash) + + sizeof(uid_t) + + sizeof(gid_t)) { + DEBUG(0,("parse_delete_tokens_list: " + "invalid token length (%u)\n", + (unsigned int)token_len )); + smb_panic("invalid token length"); + return -1; + } + + p += sizeof(token_len); + + pdtl = TALLOC_ZERO_P(lck, struct delete_token_list); + if (pdtl == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + /* Copy out the name_hash. */ + memcpy(&pdtl->name_hash, p, sizeof(pdtl->name_hash)); + p += sizeof(pdtl->name_hash); + + pdtl->delete_token = TALLOC_ZERO_P(pdtl, UNIX_USER_TOKEN); + if (pdtl->delete_token == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + + /* Copy out the uid and gid. */ + memcpy(&pdtl->delete_token->uid, p, sizeof(uid_t)); + p += sizeof(uid_t); + memcpy(&pdtl->delete_token->gid, p, sizeof(gid_t)); + p += sizeof(gid_t); + + token_len -= (sizeof(token_len) + sizeof(pdtl->name_hash) + + sizeof(uid_t) + sizeof(gid_t)); + + /* Any supplementary groups ? */ + if (token_len) { + int j; + + if (token_len % sizeof(gid_t) != 0) { + DEBUG(0,("parse_delete_tokens_list: " + "corrupt group list (%u)", + (unsigned int)(token_len % sizeof(gid_t)) )); + smb_panic("corrupt group list"); + return -1; + } + + pdtl->delete_token->ngroups = token_len / sizeof(gid_t); + pdtl->delete_token->groups = TALLOC_ARRAY(pdtl->delete_token, gid_t, + pdtl->delete_token->ngroups); + if (pdtl->delete_token->groups == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + + for (j = 0; j < pdtl->delete_token->ngroups; j++) { + memcpy(&pdtl->delete_token->groups[j], p, sizeof(gid_t)); + p += sizeof(gid_t); + } + } + /* Add to the list. */ + DLIST_ADD(lck->delete_tokens, pdtl); + } + + return delete_tokens_size; +} + /******************************************************************* Get all share mode entries for a dev/inode pair. ********************************************************************/ @@ -539,6 +638,7 @@ static void print_share_mode_table(struct locking_data *data) static bool parse_share_modes(const TDB_DATA dbuf, struct share_mode_lock *lck) { struct locking_data data; + int delete_tokens_size; int i; if (dbuf.dsize < sizeof(struct locking_data)) { @@ -547,20 +647,18 @@ static bool parse_share_modes(const TDB_DATA dbuf, struct share_mode_lock *lck) memcpy(&data, dbuf.dptr, sizeof(data)); - lck->delete_on_close = data.u.s.delete_on_close; lck->old_write_time = data.u.s.old_write_time; lck->changed_write_time = data.u.s.changed_write_time; lck->num_share_modes = data.u.s.num_share_mode_entries; - DEBUG(10, ("parse_share_modes: delete_on_close: %d, owrt: %s, " - "cwrt: %s, tok: %u, num_share_modes: %d\n", - lck->delete_on_close, + DEBUG(10, ("parse_share_modes: owrt: %s, " + "cwrt: %s, ntok: %u, num_share_modes: %d\n", timestring(talloc_tos(), convert_timespec_to_time_t(lck->old_write_time)), timestring(talloc_tos(), convert_timespec_to_time_t( lck->changed_write_time)), - (unsigned int)data.u.s.delete_token_size, + (unsigned int)data.u.s.num_delete_token_entries, lck->num_share_modes)); if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { @@ -590,66 +688,25 @@ static bool parse_share_modes(const TDB_DATA dbuf, struct share_mode_lock *lck) } } - /* Get any delete token. */ - if (data.u.s.delete_token_size) { - uint8 *p = dbuf.dptr + sizeof(struct locking_data) + - (lck->num_share_modes * - sizeof(struct share_mode_entry)); - - if ((data.u.s.delete_token_size < sizeof(uid_t) + sizeof(gid_t)) || - ((data.u.s.delete_token_size - sizeof(uid_t)) % sizeof(gid_t)) != 0) { - DEBUG(0, ("parse_share_modes: invalid token size %d\n", - data.u.s.delete_token_size)); - smb_panic("parse_share_modes: invalid token size"); - } - - lck->delete_token = TALLOC_P(lck, UNIX_USER_TOKEN); - if (!lck->delete_token) { - smb_panic("parse_share_modes: talloc failed"); - } - - /* Copy out the uid and gid. */ - memcpy(&lck->delete_token->uid, p, sizeof(uid_t)); - p += sizeof(uid_t); - memcpy(&lck->delete_token->gid, p, sizeof(gid_t)); - p += sizeof(gid_t); - - /* Any supplementary groups ? */ - lck->delete_token->ngroups = (data.u.s.delete_token_size > (sizeof(uid_t) + sizeof(gid_t))) ? - ((data.u.s.delete_token_size - - (sizeof(uid_t) + sizeof(gid_t)))/sizeof(gid_t)) : 0; - - if (lck->delete_token->ngroups) { - /* Make this a talloc child of lck->delete_token. */ - lck->delete_token->groups = TALLOC_ARRAY(lck->delete_token, gid_t, - lck->delete_token->ngroups); - if (!lck->delete_token) { - smb_panic("parse_share_modes: talloc failed"); - } - - for (i = 0; i < lck->delete_token->ngroups; i++) { - memcpy(&lck->delete_token->groups[i], p, sizeof(gid_t)); - p += sizeof(gid_t); - } - } - - } else { - lck->delete_token = NULL; + /* Get any delete tokens. */ + delete_tokens_size = parse_delete_tokens_list(lck, &data, dbuf); + if (delete_tokens_size < 0) { + smb_panic("parse_share_modes: parse_delete_tokens_list failed"); } /* Save off the associated service path and filename. */ lck->servicepath = (const char *)dbuf.dptr + sizeof(struct locking_data) + (lck->num_share_modes * sizeof(struct share_mode_entry)) + - data.u.s.delete_token_size; + delete_tokens_size; lck->base_name = (const char *)dbuf.dptr + sizeof(struct locking_data) + (lck->num_share_modes * sizeof(struct share_mode_entry)) + - data.u.s.delete_token_size + + delete_tokens_size + strlen(lck->servicepath) + 1; lck->stream_name = (const char *)dbuf.dptr + sizeof(struct locking_data) + (lck->num_share_modes * sizeof(struct share_mode_entry)) + - data.u.s.delete_token_size + + delete_tokens_size + strlen(lck->servicepath) + 1 + strlen(lck->base_name) + 1; @@ -685,7 +742,9 @@ static TDB_DATA unparse_share_modes(const struct share_mode_lock *lck) struct locking_data *data; ssize_t offset; ssize_t sp_len, bn_len, sn_len; - uint32 delete_token_size; + uint32_t delete_tokens_size = 0; + struct delete_token_list *pdtl = NULL; + uint32_t num_delete_token_entries = 0; result.dptr = NULL; result.dsize = 0; @@ -704,12 +763,18 @@ static TDB_DATA unparse_share_modes(const struct share_mode_lock *lck) bn_len = strlen(lck->base_name); -- Samba Shared Repository