diff options
author | Andrew Bartlett <abartlet@samba.org> | 2009-04-20 16:53:02 +0200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2009-04-20 16:53:02 +0200 |
commit | 6c9caed48187a0d18becf59ab636af44cbe521b0 (patch) | |
tree | c47170169077be6f8ae60aed739803ab4ba861b7 /source3/smbd | |
parent | 53765c81f726a8c056cc4e57004592dd489975c9 (diff) | |
parent | 31120c9eacafd93e0f2c6b0f906af21adadd318a (diff) | |
download | samba-6c9caed48187a0d18becf59ab636af44cbe521b0.tar.gz samba-6c9caed48187a0d18becf59ab636af44cbe521b0.tar.bz2 samba-6c9caed48187a0d18becf59ab636af44cbe521b0.zip |
Merge commit 'origin/master' into libcli-auth-merge-without-netlogond
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/conn.c | 2 | ||||
-rw-r--r-- | source3/smbd/filename.c | 30 | ||||
-rw-r--r-- | source3/smbd/files.c | 4 | ||||
-rw-r--r-- | source3/smbd/lanman.c | 6 | ||||
-rw-r--r-- | source3/smbd/notify.c | 10 | ||||
-rw-r--r-- | source3/smbd/notify_internal.c | 307 | ||||
-rw-r--r-- | source3/smbd/uid.c | 11 |
7 files changed, 350 insertions, 20 deletions
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c index a52f2d2e96..3800643769 100644 --- a/source3/smbd/conn.c +++ b/source3/smbd/conn.c @@ -212,7 +212,7 @@ bool conn_idle_all(time_t t) for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist)) { - if (plist->pipe_handles && plist->pipe_handles->count) { + if (num_pipe_handles(plist->pipe_handles) != 0) { return False; } } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 80722a7cd0..e35f23ef37 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -33,6 +33,9 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, const char *streamname, SMB_STRUCT_STAT *pst, char **path); +static int get_real_filename_mangled(connection_struct *conn, const char *path, + const char *name, TALLOC_CTX *mem_ctx, + char **found_name); /**************************************************************************** Mangle the 2nd name and check if it is then equal to the first name. @@ -447,7 +450,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, */ if (name_has_wildcard || - (SMB_VFS_GET_REAL_FILENAME( + (get_real_filename_mangled( conn, dirpath, start, talloc_tos(), &found_name) == -1)) { char *unmangled; @@ -789,15 +792,12 @@ static bool fname_equal(const char *name1, const char *name2, If the name looks like a mangled name then try via the mangling functions ****************************************************************************/ -int get_real_filename(connection_struct *conn, const char *path, - const char *name, TALLOC_CTX *mem_ctx, - char **found_name) +static int get_real_filename_mangled(connection_struct *conn, const char *path, + const char *name, TALLOC_CTX *mem_ctx, + char **found_name) { - struct smb_Dir *cur_dir; - const char *dname; bool mangled; char *unmangled_name = NULL; - long curpos; mangled = mangle_is_mangled(name, conn->params); @@ -838,8 +838,24 @@ int get_real_filename(connection_struct *conn, const char *path, /* Name is now unmangled. */ name = unmangled_name; } + return get_real_filename(conn, path, name, mem_ctx, + found_name); } + return SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, + found_name); +} + +int get_real_filename(connection_struct *conn, const char *path, + const char *name, TALLOC_CTX *mem_ctx, + char **found_name) +{ + struct smb_Dir *cur_dir; + const char *dname; + bool mangled; + char *unmangled_name = NULL; + long curpos; + /* open the directory */ if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) { DEBUG(3,("scan dir didn't open dir [%s]\n",path)); diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 36e80a086a..d2ea520146 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -433,6 +433,10 @@ void file_free(struct smb_request *req, files_struct *fsp) } if (fsp->notify) { + if (fsp->is_directory) { + notify_remove_onelevel(fsp->conn->notify_ctx, + &fsp->file_id, fsp); + } notify_remove(fsp->conn->notify_ctx, fsp); TALLOC_FREE(fsp->notify); } diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 6f8f8ed5e4..979e5b57a4 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -2073,7 +2073,7 @@ static bool api_RNetGroupEnum(connection_struct *conn,uint16 vuid, } status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(), - SAMR_ACCESS_OPEN_DOMAIN, &samr_handle); + SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", nt_errstr(status))); @@ -2254,7 +2254,7 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid, } status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(), - SAMR_ACCESS_OPEN_DOMAIN, &samr_handle); + SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", nt_errstr(status))); @@ -2409,7 +2409,7 @@ static bool api_RNetUserEnum(connection_struct *conn, uint16 vuid, } status = rpccli_samr_Connect2(samr_pipe, talloc_tos(), global_myname(), - SAMR_ACCESS_OPEN_DOMAIN, &samr_handle); + SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", nt_errstr(status))); diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index d141fb2180..12a75cc9f6 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -339,6 +339,9 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, const char *path) { char *fullpath; + char *parent; + const char *name; + SMB_STRUCT_STAT sbuf; if (path[0] == '.' && path[1] == '/') { path += 2; @@ -348,6 +351,13 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, return; } + if (parent_dirname(talloc_tos(), path, &parent, &name) + && (SMB_VFS_STAT(conn, parent, &sbuf) != -1)) { + notify_onelevel(conn->notify_ctx, action, filter, + SMB_VFS_FILE_ID_CREATE(conn, &sbuf), + name); + } + notify_trigger(conn->notify_ctx, action, filter, fullpath); SAFE_FREE(fullpath); } diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c index 1e45c54cbb..a42404db3e 100644 --- a/source3/smbd/notify_internal.c +++ b/source3/smbd/notify_internal.c @@ -27,7 +27,8 @@ #include "librpc/gen_ndr/ndr_notify.h" struct notify_context { - struct db_context *db; + struct db_context *db_recursive; + struct db_context *db_onelevel; struct server_id server; struct messaging_context *messaging_ctx; struct notify_list *list; @@ -91,10 +92,18 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, return NULL; } - notify->db = db_open(notify, lock_path("notify.tdb"), - 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, - O_RDWR|O_CREAT, 0644); - if (notify->db == NULL) { + notify->db_recursive = db_open(notify, lock_path("notify.tdb"), + 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, + O_RDWR|O_CREAT, 0644); + if (notify->db_recursive == NULL) { + talloc_free(notify); + return NULL; + } + + notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"), + 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, + O_RDWR|O_CREAT, 0644); + if (notify->db_onelevel == NULL) { talloc_free(notify); return NULL; } @@ -103,7 +112,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, notify->messaging_ctx = messaging_ctx; notify->list = NULL; notify->array = NULL; - notify->seqnum = notify->db->get_seqnum(notify->db); + notify->seqnum = notify->db_recursive->get_seqnum( + notify->db_recursive); notify->key = string_term_tdb_data(NOTIFY_KEY); talloc_set_destructor(notify, notify_destructor); @@ -123,7 +133,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, */ static NTSTATUS notify_fetch_locked(struct notify_context *notify, struct db_record **rec) { - *rec = notify->db->fetch_locked(notify->db, notify, notify->key); + *rec = notify->db_recursive->fetch_locked(notify->db_recursive, + notify, notify->key); if (*rec == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } @@ -140,7 +151,7 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec NTSTATUS status; int seqnum; - seqnum = notify->db->get_seqnum(notify->db); + seqnum = notify->db_recursive->get_seqnum(notify->db_recursive); if (seqnum == notify->seqnum && notify->array != NULL) { return NT_STATUS_OK; @@ -153,7 +164,8 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec NT_STATUS_HAVE_NO_MEMORY(notify->array); if (!rec) { - if (notify->db->fetch(notify->db, notify, notify->key, &dbuf) != 0) { + if (notify->db_recursive->fetch(notify->db_recursive, notify, + notify->key, &dbuf) != 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else { @@ -344,6 +356,96 @@ static NTSTATUS notify_add_array(struct notify_context *notify, struct db_record } /* + Add a non-recursive watch +*/ + +static void notify_add_onelevel(struct notify_context *notify, + struct notify_entry *e, void *private_data) +{ + struct notify_entry_array *array; + struct db_record *rec; + DATA_BLOB blob; + TDB_DATA dbuf; + enum ndr_err_code ndr_err; + NTSTATUS status; + + array = talloc_zero(talloc_tos(), struct notify_entry_array); + if (array == NULL) { + return; + } + + rec = notify->db_onelevel->fetch_locked( + notify->db_onelevel, talloc_tos(), + make_tdb_data((uint8_t *)&e->dir_id, sizeof(e->dir_id))); + if (rec == NULL) { + DEBUG(10, ("notify_add_onelevel: fetch_locked for %s failed" + "\n", file_id_string_tos(&e->dir_id))); + TALLOC_FREE(array); + return; + } + + blob.data = (uint8_t *)rec->value.dptr; + blob.length = rec->value.dsize; + + if (blob.length > 0) { + ndr_err = ndr_pull_struct_blob( + &blob, array, NULL, array, + (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(array); + return; + } + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_add_onelevel:\n")); + NDR_PRINT_DEBUG(notify_entry_array, array); + } + } + + array->entries = talloc_realloc(array, array->entries, + struct notify_entry, + array->num_entries+1); + if (array->entries == NULL) { + TALLOC_FREE(array); + return; + } + array->entries[array->num_entries] = *e; + array->entries[array->num_entries].private_data = private_data; + array->entries[array->num_entries].server = notify->server; + array->num_entries += 1; + + ndr_err = ndr_push_struct_blob( + &blob, rec, NULL, array, + (ndr_push_flags_fn_t)ndr_push_notify_entry_array); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(array); + return; + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_add_onelevel:\n")); + NDR_PRINT_DEBUG(notify_entry_array, array); + } + + dbuf.dptr = blob.data; + dbuf.dsize = blob.length; + + status = rec->store(rec, dbuf, TDB_REPLACE); + TALLOC_FREE(array); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("notify_add_onelevel: store failed: %s\n", + nt_errstr(status))); + return; + } + e->filter = 0; + return; +} + + +/* add a notify watch. This is called when a notify is first setup on a open directory handle. */ @@ -411,6 +513,11 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0, } } + if (e.filter != 0) { + notify_add_onelevel(notify, &e, private_data); + status = NT_STATUS_OK; + } + /* if the system notify handler couldn't handle some of the filter bits, or couldn't handle a request for recursion then we need to install it in the array used for the @@ -426,6 +533,102 @@ done: return status; } +NTSTATUS notify_remove_onelevel(struct notify_context *notify, + const struct file_id *fid, + void *private_data) +{ + struct notify_entry_array *array; + struct db_record *rec; + DATA_BLOB blob; + TDB_DATA dbuf; + enum ndr_err_code ndr_err; + NTSTATUS status; + int i; + + array = talloc_zero(talloc_tos(), struct notify_entry_array); + if (array == NULL) { + return NT_STATUS_NO_MEMORY; + } + + rec = notify->db_onelevel->fetch_locked( + notify->db_onelevel, talloc_tos(), + make_tdb_data((uint8_t *)fid, sizeof(*fid))); + if (rec == NULL) { + DEBUG(10, ("notify_remove_onelevel: fetch_locked for %s failed" + "\n", file_id_string_tos(fid))); + TALLOC_FREE(array); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + blob.data = (uint8_t *)rec->value.dptr; + blob.length = rec->value.dsize; + + if (blob.length > 0) { + ndr_err = ndr_pull_struct_blob( + &blob, array, NULL, array, + (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(array); + return ndr_map_error2ntstatus(ndr_err); + } + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_remove_onelevel:\n")); + NDR_PRINT_DEBUG(notify_entry_array, array); + } + } + + for (i=0; i<array->num_entries; i++) { + if ((private_data == array->entries[i].private_data) && + cluster_id_equal(¬ify->server, + &array->entries[i].server)) { + break; + } + } + + if (i == array->num_entries) { + TALLOC_FREE(array); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + array->entries[i] = array->entries[array->num_entries-1]; + array->num_entries -= 1; + + if (array->num_entries == 0) { + rec->delete_rec(rec); + TALLOC_FREE(array); + return NT_STATUS_OK; + } + + ndr_err = ndr_push_struct_blob( + &blob, rec, NULL, array, + (ndr_push_flags_fn_t)ndr_push_notify_entry_array); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(array); + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_add_onelevel:\n")); + NDR_PRINT_DEBUG(notify_entry_array, array); + } + + dbuf.dptr = blob.data; + dbuf.dsize = blob.length; + + status = rec->store(rec, dbuf, TDB_REPLACE); + TALLOC_FREE(array); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("notify_add_onelevel: store failed: %s\n", + nt_errstr(status))); + return status; + } + return NT_STATUS_OK; +} + /* remove a notify watch. Called when the directory handle is closed */ @@ -574,6 +777,92 @@ static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry * return status; } +void notify_onelevel(struct notify_context *notify, uint32_t action, + uint32_t filter, struct file_id fid, const char *name) +{ + struct notify_entry_array *array; + TDB_DATA dbuf; + DATA_BLOB blob; + bool have_dead_entries = false; + int i; + + array = talloc_zero(talloc_tos(), struct notify_entry_array); + if (array == NULL) { + return; + } + + if (notify->db_onelevel->fetch( + notify->db_onelevel, array, + make_tdb_data((uint8_t *)&fid, sizeof(fid)), + &dbuf) == -1) { + TALLOC_FREE(array); + return; + } + + blob.data = (uint8 *)dbuf.dptr; + blob.length = dbuf.dsize; + + if (blob.length > 0) { + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_struct_blob( + &blob, array, NULL, array, + (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(array); + return; + } + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_onelevel:\n")); + NDR_PRINT_DEBUG(notify_entry_array, array); + } + } + + for (i=0; i<array->num_entries; i++) { + struct notify_entry *e = &array->entries[i]; + + if ((e->filter & filter) != 0) { + NTSTATUS status; + + status = notify_send(notify, e, name, action); + if (NT_STATUS_EQUAL( + status, NT_STATUS_INVALID_HANDLE)) { + /* + * Mark the entry as dead. All entries have a + * path set. The marker used here is setting + * that to NULL. + */ + e->path = NULL; + have_dead_entries = true; + } + } + } + + if (!have_dead_entries) { + TALLOC_FREE(array); + return; + } + + for (i=0; i<array->num_entries; i++) { + struct notify_entry *e = &array->entries[i]; + if (e->path != NULL) { + continue; + } + DEBUG(10, ("Deleting notify entries for process %s because " + "it's gone\n", procid_str_static(&e->server))); + /* + * Potential TODO: This might need optimizing, + * notify_remove_onelevel() does a fetch_locked() operation at + * every call. But this would only matter if a process with + * MANY notifies has died without shutting down properly. + */ + notify_remove_onelevel(notify, &e->dir_id, e->private_data); + } + + TALLOC_FREE(array); + return; +} /* trigger a notify message for anyone waiting on a matching event diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index f8c55b1b8f..b8ed321a45 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -164,6 +164,10 @@ void conn_clear_vuid_cache(connection_struct *conn, uint16_t vuid) if (ent->vuid == vuid) { ent->vuid = UID_FIELD_INVALID; + /* Ensure we're not freeing an active pointer. */ + if (conn->server_info == ent->server_info) { + conn->server_info = NULL; + } TALLOC_FREE(ent->server_info); ent->read_only = False; ent->admin_user = False; @@ -216,6 +220,13 @@ bool change_to_user(connection_struct *conn, uint16 vuid) server_info = vuser ? vuser->server_info : conn->server_info; + if (!server_info) { + /* Invalid vuid sent - even with security = share. */ + DEBUG(2,("change_to_user: Invalid vuid %d used on " + "share %s.\n",vuid, lp_servicename(snum) )); + return false; + } + if (!check_user_ok(conn, vuid, server_info, snum)) { DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) " "not permitted access to share %s.\n", |