Line data Source code
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 1544 : 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 : {
56 : struct server_id_db *names_db;
57 : struct notify_context *ctx;
58 : NTSTATUS status;
59 :
60 1544 : ctx = talloc(mem_ctx, struct notify_context);
61 1544 : if (ctx == NULL) {
62 0 : return NULL;
63 : }
64 1544 : ctx->msg_ctx = msg;
65 :
66 1544 : ctx->sconn = sconn;
67 1544 : ctx->callback = callback;
68 :
69 1544 : names_db = messaging_names_db(msg);
70 1544 : if (!server_id_db_lookup_one(names_db, "notify-daemon",
71 : &ctx->notifyd)) {
72 0 : DBG_WARNING("No notify daemon around\n");
73 0 : TALLOC_FREE(ctx);
74 0 : return NULL;
75 : }
76 :
77 : {
78 : struct server_id_buf tmp;
79 1544 : DBG_DEBUG("notifyd=%s\n",
80 : server_id_str_buf(ctx->notifyd, &tmp));
81 : }
82 :
83 1544 : if (callback != NULL) {
84 1544 : status = messaging_register(msg, ctx, MSG_PVFS_NOTIFY,
85 : notify_handler);
86 1544 : if (!NT_STATUS_IS_OK(status)) {
87 0 : DBG_WARNING("messaging_register failed: %s\n",
88 : nt_errstr(status));
89 0 : TALLOC_FREE(ctx);
90 0 : return NULL;
91 : }
92 : }
93 :
94 1544 : talloc_set_destructor(ctx, notify_context_destructor);
95 :
96 1544 : return ctx;
97 : }
98 :
99 1544 : static int notify_context_destructor(struct notify_context *ctx)
100 : {
101 1544 : if (ctx->callback != NULL) {
102 1544 : messaging_deregister(ctx->msg_ctx, MSG_PVFS_NOTIFY, ctx);
103 : }
104 :
105 1544 : return 0;
106 : }
107 :
108 52 : 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 : {
112 52 : struct notify_context *ctx = talloc_get_type_abort(
113 : private_data, struct notify_context);
114 : struct notify_event_msg *event_msg;
115 : struct notify_event event;
116 :
117 52 : 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 : }
121 52 : if (data->data[data->length-1] != 0) {
122 0 : DBG_WARNING("path not 0-terminated\n");
123 0 : return;
124 : }
125 :
126 52 : event_msg = (struct notify_event_msg *)data->data;
127 :
128 52 : event.action = event_msg->action;
129 52 : event.path = event_msg->path;
130 52 : event.private_data = event_msg->private_data;
131 :
132 52 : DBG_DEBUG("Got notify_event action=%"PRIu32", private_data=%p, "
133 : "path=%s\n",
134 : event.action,
135 : event.private_data,
136 : event.path);
137 :
138 52 : ctx->callback(ctx->sconn, event.private_data, event_msg->when, &event);
139 : }
140 :
141 30 : NTSTATUS notify_add(struct notify_context *ctx,
142 : const char *path, uint32_t filter, uint32_t subdir_filter,
143 : void *private_data)
144 : {
145 30 : struct notify_rec_change_msg msg = {};
146 : struct iovec iov[2];
147 : size_t pathlen;
148 : NTSTATUS status;
149 :
150 30 : if (ctx == NULL) {
151 0 : return NT_STATUS_NOT_IMPLEMENTED;
152 : }
153 :
154 30 : DBG_DEBUG("path=[%s], filter=%"PRIu32", subdir_filter=%"PRIu32", "
155 : "private_data=%p\n",
156 : path,
157 : filter,
158 : subdir_filter,
159 : private_data);
160 :
161 30 : pathlen = strlen(path)+1;
162 :
163 30 : clock_gettime_mono(&msg.instance.creation_time);
164 30 : msg.instance.filter = filter;
165 30 : msg.instance.subdir_filter = subdir_filter;
166 30 : msg.instance.private_data = private_data;
167 :
168 30 : iov[0].iov_base = &msg;
169 30 : iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
170 30 : iov[1].iov_base = discard_const_p(char, path);
171 30 : iov[1].iov_len = pathlen;
172 :
173 30 : status = messaging_send_iov(
174 : ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
175 : iov, ARRAY_SIZE(iov), NULL, 0);
176 :
177 30 : if (!NT_STATUS_IS_OK(status)) {
178 0 : DBG_DEBUG("messaging_send_iov returned %s\n",
179 : nt_errstr(status));
180 0 : return status;
181 : }
182 :
183 30 : return NT_STATUS_OK;
184 : }
185 :
186 30 : NTSTATUS notify_remove(struct notify_context *ctx, void *private_data,
187 : char *path)
188 : {
189 30 : struct notify_rec_change_msg msg = {};
190 : struct iovec iov[2];
191 : NTSTATUS status;
192 :
193 : /* see if change notify is enabled at all */
194 30 : if (ctx == NULL) {
195 0 : return NT_STATUS_NOT_IMPLEMENTED;
196 : }
197 :
198 30 : msg.instance.private_data = private_data;
199 :
200 30 : iov[0].iov_base = &msg;
201 30 : iov[0].iov_len = offsetof(struct notify_rec_change_msg, path);
202 30 : iov[1].iov_base = path;
203 30 : iov[1].iov_len = strlen(path)+1;
204 :
205 30 : status = messaging_send_iov(
206 : ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE,
207 : iov, ARRAY_SIZE(iov), NULL, 0);
208 :
209 30 : return status;
210 : }
211 :
212 3382 : void notify_trigger(struct notify_context *ctx,
213 : uint32_t action, uint32_t filter,
214 : const char *dir, const char *name)
215 : {
216 : struct notify_trigger_msg msg;
217 : struct iovec iov[4];
218 3382 : char slash = '/';
219 :
220 3382 : DBG_DEBUG("notify_trigger called action=0x%"PRIx32", "
221 : "filter=0x%"PRIx32", dir=%s, name=%s\n",
222 : action,
223 : filter,
224 : dir,
225 : name);
226 :
227 3382 : if (ctx == NULL) {
228 0 : return;
229 : }
230 :
231 3382 : msg.when = timespec_current();
232 3382 : msg.action = action;
233 3382 : msg.filter = filter;
234 :
235 3382 : iov[0].iov_base = &msg;
236 3382 : iov[0].iov_len = offsetof(struct notify_trigger_msg, path);
237 3382 : iov[1].iov_base = discard_const_p(char, dir);
238 3382 : iov[1].iov_len = strlen(dir);
239 3382 : iov[2].iov_base = &slash;
240 3382 : iov[2].iov_len = 1;
241 3382 : iov[3].iov_base = discard_const_p(char, name);
242 3382 : iov[3].iov_len = strlen(name)+1;
243 :
244 3382 : messaging_send_iov(
245 : ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_TRIGGER,
246 : iov, ARRAY_SIZE(iov), NULL, 0);
247 : }
|