/src/samba/source3/smbd/notify_msg.c
Line | Count | Source |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * |
4 | | * Copyright (C) Volker Lendecke 2014 |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "includes.h" |
21 | | #include "librpc/gen_ndr/notify.h" |
22 | | #include "librpc/gen_ndr/messaging.h" |
23 | | #include "lib/dbwrap/dbwrap.h" |
24 | | #include "lib/dbwrap/dbwrap_rbt.h" |
25 | | #include "lib/util/server_id.h" |
26 | | #include "messages.h" |
27 | | #include "proto.h" |
28 | | #include "globals.h" |
29 | | #include "tdb.h" |
30 | | #include "util_tdb.h" |
31 | | #include "lib/util/server_id_db.h" |
32 | | #include "smbd/notifyd/notifyd.h" |
33 | | |
34 | | struct notify_context { |
35 | | struct server_id notifyd; |
36 | | struct messaging_context *msg_ctx; |
37 | | |
38 | | struct smbd_server_connection *sconn; |
39 | | void (*callback)(struct smbd_server_connection *sconn, |
40 | | void *private_data, struct timespec when, |
41 | | const struct notify_event *ctx); |
42 | | }; |
43 | | |
44 | | static void notify_handler(struct messaging_context *msg, void *private_data, |
45 | | uint32_t msg_type, struct server_id src, |
46 | | DATA_BLOB *data); |
47 | | static int notify_context_destructor(struct notify_context *ctx); |
48 | | |
49 | | struct notify_context *notify_init( |
50 | | TALLOC_CTX *mem_ctx, struct messaging_context *msg, |
51 | | struct smbd_server_connection *sconn, |
52 | | void (*callback)(struct smbd_server_connection *sconn, |
53 | | void *, struct timespec, |
54 | | const struct notify_event *)) |
55 | 0 | { |
56 | 0 | struct server_id_db *names_db; |
57 | 0 | struct notify_context *ctx; |
58 | 0 | NTSTATUS status; |
59 | |
|
60 | 0 | ctx = talloc(mem_ctx, struct notify_context); |
61 | 0 | if (ctx == NULL) { |
62 | 0 | return NULL; |
63 | 0 | } |
64 | 0 | ctx->msg_ctx = msg; |
65 | |
|
66 | 0 | ctx->sconn = sconn; |
67 | 0 | ctx->callback = callback; |
68 | |
|
69 | 0 | names_db = messaging_names_db(msg); |
70 | 0 | if (!server_id_db_lookup_one(names_db, "notify-daemon", |
71 | 0 | &ctx->notifyd)) { |
72 | 0 | DBG_WARNING("No notify daemon around\n"); |
73 | 0 | TALLOC_FREE(ctx); |
74 | 0 | return NULL; |
75 | 0 | } |
76 | | |
77 | 0 | { |
78 | 0 | struct server_id_buf tmp; |
79 | 0 | DBG_DEBUG("notifyd=%s\n", |
80 | 0 | server_id_str_buf(ctx->notifyd, &tmp)); |
81 | 0 | } |
82 | |
|
83 | 0 | if (callback != NULL) { |
84 | 0 | status = messaging_register(msg, ctx, MSG_PVFS_NOTIFY, |
85 | 0 | notify_handler); |
86 | 0 | if (!NT_STATUS_IS_OK(status)) { |
87 | 0 | DBG_WARNING("messaging_register failed: %s\n", |
88 | 0 | nt_errstr(status)); |
89 | 0 | TALLOC_FREE(ctx); |
90 | 0 | return NULL; |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 0 | talloc_set_destructor(ctx, notify_context_destructor); |
95 | |
|
96 | 0 | return ctx; |
97 | 0 | } |
98 | | |
99 | | static int notify_context_destructor(struct notify_context *ctx) |
100 | 0 | { |
101 | 0 | if (ctx->callback != NULL) { |
102 | 0 | messaging_deregister(ctx->msg_ctx, MSG_PVFS_NOTIFY, ctx); |
103 | 0 | } |
104 | |
|
105 | 0 | return 0; |
106 | 0 | } |
107 | | |
108 | | static void notify_handler(struct messaging_context *msg, void *private_data, |
109 | | uint32_t msg_type, struct server_id src, |
110 | | DATA_BLOB *data) |
111 | 0 | { |
112 | 0 | struct notify_context *ctx = talloc_get_type_abort( |
113 | 0 | private_data, struct notify_context); |
114 | 0 | struct notify_event_msg *event_msg; |
115 | 0 | struct notify_event event; |
116 | |
|
117 | 0 | if (data->length < offsetof(struct notify_event_msg, path) + 1) { |
118 | 0 | DBG_WARNING("message too short: %zu\n", data->length); |
119 | 0 | return; |
120 | 0 | } |
121 | 0 | if (data->data[data->length-1] != 0) { |
122 | 0 | DBG_WARNING("path not 0-terminated\n"); |
123 | 0 | return; |
124 | 0 | } |
125 | | |
126 | 0 | event_msg = (struct notify_event_msg *)data->data; |
127 | |
|
128 | 0 | event.action = event_msg->action; |
129 | 0 | event.path = event_msg->path; |
130 | 0 | event.private_data = event_msg->private_data; |
131 | |
|
132 | 0 | DBG_DEBUG("Got notify_event action=%"PRIu32", private_data=%p, " |
133 | 0 | "path=%s\n", |
134 | 0 | event.action, |
135 | 0 | event.private_data, |
136 | 0 | event.path); |
137 | |
|
138 | 0 | ctx->callback(ctx->sconn, event.private_data, event_msg->when, &event); |
139 | 0 | } |
140 | | |
141 | | NTSTATUS notify_add(struct notify_context *ctx, |
142 | | const char *path, uint32_t filter, uint32_t subdir_filter, |
143 | | void *private_data) |
144 | 0 | { |
145 | 0 | struct notify_rec_change_msg msg = {}; |
146 | 0 | struct iovec iov[2]; |
147 | 0 | size_t pathlen; |
148 | 0 | NTSTATUS status; |
149 | |
|
150 | 0 | if (ctx == NULL) { |
151 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
152 | 0 | } |
153 | | |
154 | 0 | DBG_DEBUG("path=[%s], filter=%"PRIu32", subdir_filter=%"PRIu32", " |
155 | 0 | "private_data=%p\n", |
156 | 0 | path, |
157 | 0 | filter, |
158 | 0 | subdir_filter, |
159 | 0 | private_data); |
160 | |
|
161 | 0 | pathlen = strlen(path)+1; |
162 | |
|
163 | 0 | clock_gettime_mono(&msg.instance.creation_time); |
164 | 0 | msg.instance.filter = filter; |
165 | 0 | msg.instance.subdir_filter = subdir_filter; |
166 | 0 | msg.instance.private_data = private_data; |
167 | |
|
168 | 0 | iov[0].iov_base = &msg; |
169 | 0 | iov[0].iov_len = offsetof(struct notify_rec_change_msg, path); |
170 | 0 | iov[1].iov_base = discard_const_p(char, path); |
171 | 0 | iov[1].iov_len = pathlen; |
172 | |
|
173 | 0 | status = messaging_send_iov( |
174 | 0 | ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE, |
175 | 0 | iov, ARRAY_SIZE(iov), NULL, 0); |
176 | |
|
177 | 0 | if (!NT_STATUS_IS_OK(status)) { |
178 | 0 | DBG_DEBUG("messaging_send_iov returned %s\n", |
179 | 0 | nt_errstr(status)); |
180 | 0 | return status; |
181 | 0 | } |
182 | | |
183 | 0 | return NT_STATUS_OK; |
184 | 0 | } |
185 | | |
186 | | NTSTATUS notify_remove(struct notify_context *ctx, void *private_data, |
187 | | char *path) |
188 | 0 | { |
189 | 0 | struct notify_rec_change_msg msg = {}; |
190 | 0 | struct iovec iov[2]; |
191 | 0 | NTSTATUS status; |
192 | | |
193 | | /* see if change notify is enabled at all */ |
194 | 0 | if (ctx == NULL) { |
195 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
196 | 0 | } |
197 | | |
198 | 0 | msg.instance.private_data = private_data; |
199 | |
|
200 | 0 | iov[0].iov_base = &msg; |
201 | 0 | iov[0].iov_len = offsetof(struct notify_rec_change_msg, path); |
202 | 0 | iov[1].iov_base = path; |
203 | 0 | iov[1].iov_len = strlen(path)+1; |
204 | |
|
205 | 0 | status = messaging_send_iov( |
206 | 0 | ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE, |
207 | 0 | iov, ARRAY_SIZE(iov), NULL, 0); |
208 | |
|
209 | 0 | return status; |
210 | 0 | } |
211 | | |
212 | | void notify_trigger(struct notify_context *ctx, |
213 | | uint32_t action, uint32_t filter, |
214 | | const char *dir, const char *name) |
215 | 0 | { |
216 | 0 | struct notify_trigger_msg msg; |
217 | 0 | struct iovec iov[4]; |
218 | 0 | char slash = '/'; |
219 | |
|
220 | 0 | DBG_DEBUG("notify_trigger called action=0x%"PRIx32", " |
221 | 0 | "filter=0x%"PRIx32", dir=%s, name=%s\n", |
222 | 0 | action, |
223 | 0 | filter, |
224 | 0 | dir, |
225 | 0 | name); |
226 | |
|
227 | 0 | if (ctx == NULL) { |
228 | 0 | return; |
229 | 0 | } |
230 | | |
231 | 0 | msg.when = timespec_current(); |
232 | 0 | msg.action = action; |
233 | 0 | msg.filter = filter; |
234 | |
|
235 | 0 | iov[0].iov_base = &msg; |
236 | 0 | iov[0].iov_len = offsetof(struct notify_trigger_msg, path); |
237 | 0 | iov[1].iov_base = discard_const_p(char, dir); |
238 | 0 | iov[1].iov_len = strlen(dir); |
239 | 0 | iov[2].iov_base = &slash; |
240 | 0 | iov[2].iov_len = 1; |
241 | 0 | iov[3].iov_base = discard_const_p(char, name); |
242 | 0 | iov[3].iov_len = strlen(name)+1; |
243 | |
|
244 | 0 | messaging_send_iov( |
245 | 0 | ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_TRIGGER, |
246 | 0 | iov, ARRAY_SIZE(iov), NULL, 0); |
247 | 0 | } |