diff options
-rw-r--r-- | source3/include/smb.h | 11 | ||||
-rw-r--r-- | source3/smbd/notify.c | 82 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 39 |
3 files changed, 72 insertions, 60 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index b4cb5bd611..71ff656385 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -448,6 +448,7 @@ struct notify_change { struct notify_mid_map; struct notify_entry; struct notify_event; +struct notify_change_request; struct sys_notify_backend; struct sys_notify_context { struct event_context *ev; @@ -455,16 +456,6 @@ struct sys_notify_context { void *private_data; /* For use by the system backend */ }; -struct notify_change_request { - struct notify_change_request *prev, *next; - struct files_struct *fsp; /* backpointer for cancel by mid */ - char request_buf[smb_size]; - uint32 filter; - uint32 max_param_count; - struct notify_mid_map *mid_map; - void *backend_data; -}; - struct notify_change_buf { /* * If no requests are pending, changes are queued here. Simple array, diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 8719c83bba..cf60720bc7 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -22,6 +22,19 @@ #include "includes.h" +struct notify_change_request { + struct notify_change_request *prev, *next; + struct files_struct *fsp; /* backpointer for cancel by mid */ + char request_buf[smb_size]; + uint32 filter; + uint32 max_param_count; + uint32 current_bufsize; + struct notify_mid_map *mid_map; + void *backend_data; +}; + +static void notify_fsp(files_struct *fsp, uint32 action, const char *name); + static struct notify_mid_map *notify_changes_by_mid; /* @@ -114,19 +127,20 @@ static void change_notify_reply_packet(const char *request_buf, } void change_notify_reply(const char *request_buf, uint32 max_param_count, - int num_changes, struct notify_change *changes) + struct notify_change_buf *notify_buf) { char *outbuf = NULL; prs_struct ps; size_t buflen = smb_size+38+max_param_count; - if (num_changes == -1) { + if (notify_buf->num_changes == -1) { change_notify_reply_packet(request_buf, NT_STATUS_OK); return; } if (!prs_init(&ps, 0, NULL, False) - || !notify_marshall_changes(num_changes, changes, &ps)) { + || !notify_marshall_changes(notify_buf->num_changes, + notify_buf->changes, &ps)) { change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY); goto done; } @@ -155,6 +169,49 @@ void change_notify_reply(const char *request_buf, uint32 max_param_count, done: SAFE_FREE(outbuf); prs_mem_free(&ps); + + TALLOC_FREE(notify_buf->changes); + notify_buf->num_changes = 0; +} + +static void notify_callback(void *private_data, const struct notify_event *e) +{ + files_struct *fsp = (files_struct *)private_data; + DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name)); + notify_fsp(fsp, e->action, e->path); +} + +NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, + BOOL recursive) +{ + char *fullpath; + struct notify_entry e; + NTSTATUS status; + + SMB_ASSERT(fsp->notify == NULL); + + if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) { + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, + fsp->fsp_name) == -1) { + DEBUG(0, ("asprintf failed\n")); + return NT_STATUS_NO_MEMORY; + } + + e.path = fullpath; + e.filter = filter; + e.subdir_filter = 0; + if (recursive) { + e.subdir_filter = filter; + } + + status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp); + SAFE_FREE(fullpath); + + return status; } NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count, @@ -175,6 +232,7 @@ NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count, memcpy(request->request_buf, inbuf, sizeof(request->request_buf)); request->max_param_count = max_param_count; + request->current_bufsize = 0; request->filter = filter; request->fsp = fsp; request->backend_data = NULL; @@ -275,7 +333,7 @@ void notify_fname(connection_struct *conn, uint32 action, uint32 filter, SAFE_FREE(fullpath); } -void notify_fsp(files_struct *fsp, uint32 action, const char *name) +static void notify_fsp(files_struct *fsp, uint32 action, const char *name) { struct notify_change *change, *changes; char *name2; @@ -290,19 +348,19 @@ void notify_fsp(files_struct *fsp, uint32 action, const char *name) if (!(name2 = talloc_strdup(fsp->notify, name))) { DEBUG(0, ("talloc_strdup failed\n")); return; - } + } string_replace(name2, '/', '\\'); /* * Someone has triggered a notify previously, queue the change for - * later. TODO: Limit the number of changes queued, test how filters - * apply here. Do we have to store them? + * later. */ - if ((fsp->notify->num_changes > 30) || (name == NULL)) { + if ((fsp->notify->num_changes > 1000) || (name == NULL)) { /* - * W2k3 seems to store at most 30 changes. + * The real number depends on the client buf, just provide a + * guard against a DoS here. */ TALLOC_FREE(fsp->notify->changes); TALLOC_FREE(name2); @@ -353,13 +411,9 @@ void notify_fsp(files_struct *fsp, uint32 action, const char *name) change_notify_reply(fsp->notify->requests->request_buf, fsp->notify->requests->max_param_count, - fsp->notify->num_changes, - fsp->notify->changes); + fsp->notify); change_notify_remove_request(fsp->notify->requests); - - TALLOC_FREE(fsp->notify->changes); - fsp->notify->num_changes = 0; } char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 7483073a58..543f393c89 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1787,13 +1787,6 @@ int reply_ntrename(connection_struct *conn, don't allow a directory to be opened. ****************************************************************************/ -static void notify_callback(void *private_data, const struct notify_event *e) -{ - files_struct *fsp = (files_struct *)private_data; - DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name)); - notify_fsp(fsp, e->action, e->path); -} - static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, @@ -1843,33 +1836,11 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, } if (fsp->notify == NULL) { - char *fullpath; - struct notify_entry e; - - if (!(fsp->notify = TALLOC_ZERO_P( - NULL, struct notify_change_buf))) { - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, - fsp->fsp_name) == -1) { - DEBUG(0, ("asprintf failed\n")); - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - - e.path = fullpath; - e.filter = filter; - e.subdir_filter = 0; - if (recursive) { - e.subdir_filter = filter; - } - - status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, - fsp); - SAFE_FREE(fullpath); + status = change_notify_create(fsp, filter, recursive); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("notify_add returned %s\n", + DEBUG(10, ("change_notify_create returned %s\n", nt_errstr(status))); return ERROR_NT(status); } @@ -1887,11 +1858,7 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, */ change_notify_reply(inbuf, max_param_count, - fsp->notify->num_changes, - fsp->notify->changes); - - TALLOC_FREE(fsp->notify->changes); - fsp->notify->num_changes = 0; + fsp->notify); /* * change_notify_reply() above has independently sent its |