1 /*
2 * ProFTPD - FTP server daemon
3 * Copyright (c) 2003-2020 The ProFTPD Project team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, The ProFTPD Project team and other respective
20 * copyright holders give permission to link this program with OpenSSL, and
21 * distribute the resulting executable, without including the source code for
22 * OpenSSL in the source distribution.
23 */
24
25 /* Event management code */
26
27 #include "conf.h"
28
29 /* Note: as more events are added, and as this API grows more and more used
30 * by the core code, look into using a different ADT for storage/retrieval
31 * of these objects, such as hash tables.
32 */
33
34 struct event_handler {
35 struct event_handler *next, *prev;
36 module *module;
37 void (*cb)(const void *, void *);
38 void *user_data;
39 unsigned long flags;
40 };
41
42 struct event_list {
43 struct event_list *next;
44 pool *pool;
45 const char *event;
46 size_t event_len;
47 struct event_handler *handlers;
48 };
49
50 static pool *event_pool = NULL;
51 static struct event_list *events = NULL;
52
53 static const char *curr_event = NULL;
54 static struct event_list *curr_evl = NULL;
55 static struct event_handler *curr_evh = NULL;
56
57 /* Certain events are NOT logged via Trace logging (in order to prevent
58 * event/trace loops).
59 */
60 static const char *untraced_events[] = {
61 PR_LOG_NAME_UNSPEC,
62 PR_LOG_NAME_XFERLOG,
63 PR_LOG_NAME_SYSLOG,
64 PR_LOG_NAME_SYSTEMLOG,
65 PR_LOG_NAME_EXTLOG,
66 PR_LOG_NAME_TRACELOG,
67 NULL
68 };
69
70 #define PR_EVENT_FL_UNTRACED 0x001
71
72 static const char *trace_channel = "event";
73
74 #define EVENT_POOL_SZ 256
75
event_cleanup_cb(void * user_data)76 static void event_cleanup_cb(void *user_data) {
77 event_pool = NULL;
78 events = NULL;
79
80 curr_event = NULL;
81 curr_evl = NULL;
82 curr_evh = NULL;
83 }
84
pr_event_register(module * m,const char * event,void (* cb)(const void *,void *),void * user_data)85 int pr_event_register(module *m, const char *event,
86 void (*cb)(const void *, void *), void *user_data) {
87 register unsigned int i;
88 struct event_handler *evh;
89 struct event_list *evl;
90 pool *evl_pool;
91 unsigned long flags = 0;
92
93 if (event == NULL ||
94 cb == NULL) {
95 errno = EINVAL;
96 return -1;
97 }
98
99 if (event_pool == NULL) {
100 event_pool = make_sub_pool(permanent_pool);
101 pr_pool_tag(event_pool, "Event Pool");
102
103 register_cleanup2(event_pool, NULL, event_cleanup_cb);
104 }
105
106 pr_trace_msg(trace_channel, 3,
107 "module '%s' (%p) registering handler for event '%s' (at %p)",
108 m ? m->name : "(none)", m, event, cb);
109
110 evh = pcalloc(event_pool, sizeof(struct event_handler));
111
112 evh->module = m;
113 evh->cb = cb;
114 evh->user_data = user_data;
115
116 /* Is this an untraced event? */
117 for (i = 0; untraced_events[i] != NULL; i++) {
118 if (strcmp(event, untraced_events[i]) == 0) {
119 flags = PR_EVENT_FL_UNTRACED;
120 break;
121 }
122 }
123
124 evh->flags = flags;
125
126 /* Scan the currently registered lists, looking for where to add this
127 * registration.
128 */
129
130 for (evl = events; evl; evl = evl->next) {
131 if (strncmp(evl->event, event, evl->event_len + 1) == 0) {
132 struct event_handler *evhi, *evhl = NULL;
133
134 evhi = evl->handlers;
135 if (evhi) {
136 /* Make sure this event handler is added to the START of the list,
137 * in order to preserve module load order handling of events (i.e.
138 * last module loaded, first module handled). The exception to this
139 * rule are core callbacks (i.e. where m == NULL); these will always
140 * be invoked last.
141 *
142 * Before that, though, check for duplicate registration/subscription.
143 */
144 while (evhi) {
145 pr_signals_handle();
146
147 if (evhi->cb == evh->cb) {
148 /* Duplicate callback */
149 errno = EEXIST;
150 return -1;
151 }
152
153 evhl = evhi;
154
155 if (evhi->next == NULL) {
156 break;
157 }
158
159 evhi = evhi->next;
160 }
161
162 if (evh->module != NULL) {
163 if (evl->handlers->next != NULL) {
164 evl->handlers->next->prev = evh;
165 }
166
167 evh->next = evl->handlers;
168 evl->handlers = evh;
169
170 } else {
171 /* Core event listeners go at the end. */
172 evhl->next = evh;
173 evh->prev = evhl;
174 }
175
176 } else {
177 evl->handlers = evh;
178 }
179
180 /* All done */
181 return 0;
182 }
183 }
184
185 evl_pool = pr_pool_create_sz(event_pool, EVENT_POOL_SZ);
186 pr_pool_tag(evl_pool, "Event listener list pool");
187
188 evl = pcalloc(evl_pool, sizeof(struct event_list));
189 evl->pool = evl_pool;
190 evl->event = pstrdup(evl->pool, event);
191 evl->event_len = strlen(evl->event);
192 evl->handlers = evh;
193 evl->next = events;
194
195 events = evl;
196
197 /* Clear any cached data. */
198 curr_event = NULL;
199 curr_evl = NULL;
200 curr_evh = NULL;
201
202 return 0;
203 }
204
pr_event_unregister(module * m,const char * event,void (* cb)(const void *,void *))205 int pr_event_unregister(module *m, const char *event,
206 void (*cb)(const void *, void *)) {
207 struct event_list *evl;
208 int unregistered = FALSE;
209
210 if (events == NULL) {
211 return 0;
212 }
213
214 pr_trace_msg(trace_channel, 3,
215 "module '%s' (%p) unregistering handler for event '%s'",
216 m ? m->name : "(none)", m, event ? event : "(all)");
217
218 /* For now, simply remove the event_handler entry for this callback. In
219 * the future, add a static counter, and churn the event pool after a
220 * certain number of unregistrations, so that the memory pool doesn't
221 * grow unnecessarily.
222 */
223
224 for (evl = events; evl; evl = evl->next) {
225 pr_signals_handle();
226
227 if (event == NULL ||
228 strncmp(evl->event, event, evl->event_len + 1) == 0) {
229 struct event_handler *evh;
230
231 /* If there are no handlers for this event, there is nothing to
232 * unregister. Skip on to the next list.
233 */
234 if (evl->handlers == NULL) {
235 continue;
236 }
237
238 for (evh = evl->handlers; evh;) {
239
240 if ((m == NULL || evh->module == m) &&
241 (cb == NULL || evh->cb == cb)) {
242 struct event_handler *tmp = evh->next;
243
244 if (evh->next) {
245 evh->next->prev = evh->prev;
246 }
247
248 if (evh->prev) {
249 evh->prev->next = evh->next;
250
251 } else {
252 /* This is the head of the list. */
253 evl->handlers = evh->next;
254 }
255
256 evh->module = NULL;
257 evh = tmp;
258 unregistered = TRUE;
259
260 } else {
261 evh = evh->next;
262 }
263 }
264 }
265 }
266
267 /* Clear any cached data. */
268 curr_event = NULL;
269 curr_evl = NULL;
270 curr_evh = NULL;
271
272 if (!unregistered) {
273 errno = ENOENT;
274 return -1;
275 }
276
277 return 0;
278 }
279
pr_event_listening(const char * event)280 int pr_event_listening(const char *event) {
281 struct event_list *evl;
282 int count = 0;
283
284 if (event == NULL) {
285 errno = EINVAL;
286 return -1;
287 }
288
289 if (events == NULL) {
290 /* No registered listeners at all. */
291 return 0;
292 }
293
294 /* Lookup callbacks for this event. */
295 for (evl = events; evl; evl = evl->next) {
296
297 if (strncmp(evl->event, event, evl->event_len + 1) == 0) {
298 struct event_handler *evh;
299
300 /* If there are no registered callbacks for this event, be done. */
301 if (evl->handlers == NULL) {
302 return 0;
303 }
304
305 for (evh = evl->handlers; evh; evh = evh->next) {
306 count++;
307 }
308
309 break;
310 }
311 }
312
313 return count;
314 }
315
pr_event_generate(const char * event,const void * event_data)316 void pr_event_generate(const char *event, const void *event_data) {
317 int use_cache = FALSE;
318 struct event_list *evl;
319
320 if (event == NULL) {
321 return;
322 }
323
324 /* If there are no registered callbacks, be done. */
325 if (events == NULL) {
326 return;
327 }
328
329 /* If there is a cached event, see if the given event matches. */
330 if (curr_event != NULL &&
331 strcmp(curr_event, event) == 0) {
332 use_cache = TRUE;
333 }
334
335 /* Lookup callbacks for this event. */
336 for (evl = use_cache ? curr_evl : events; evl; evl = evl->next) {
337
338 if (strncmp(evl->event, event, evl->event_len + 1) == 0) {
339 struct event_handler *evh;
340
341 /* If there are no registered callbacks for this event, be done. */
342 if (!evl->handlers) {
343 pr_trace_msg(trace_channel, 8, "no event handlers registered for '%s'",
344 event);
345 return;
346 }
347
348 curr_event = event;
349 curr_evl = evl;
350
351 for (evh = use_cache ? curr_evh : evl->handlers; evh; evh = evh->next) {
352 /* Make sure that if the same event is generated by the current
353 * listener, the next time through we go to the next listener, rather
354 * sending the same event against to the same listener (Bug#3619).
355 */
356 curr_evh = evh->next;
357
358 if (!(evh->flags & PR_EVENT_FL_UNTRACED)) {
359 if (evh->module) {
360 pr_trace_msg(trace_channel, 8,
361 "dispatching event '%s' to mod_%s (at %p, use cache = %s)", event,
362 evh->module->name, evh->cb, use_cache ? "true" : "false");
363
364 } else {
365 pr_trace_msg(trace_channel, 8,
366 "dispatching event '%s' to core (at %p, use cache = %s)", event,
367 evh->cb, use_cache ? "true" : "false");
368 }
369 }
370
371 evh->cb(event_data, evh->user_data);
372 }
373
374 break;
375 }
376 }
377
378 /* Clear any cached data after publishing the event to all interested
379 * listeners.
380 */
381 curr_event = NULL;
382 curr_evl = NULL;
383 curr_evh = NULL;
384
385 return;
386 }
387
pr_event_dump(void (* dumpf)(const char *,...))388 void pr_event_dump(void (*dumpf)(const char *, ...)) {
389 struct event_list *evl;
390
391 if (dumpf == NULL) {
392 return;
393 }
394
395 if (events == NULL) {
396 dumpf("%s", "No events registered");
397 return;
398 }
399
400 for (evl = events; evl; evl = evl->next) {
401 pr_signals_handle();
402
403 if (evl->handlers == NULL) {
404 dumpf("No handlers registered for '%s'", evl->event);
405
406 } else {
407 struct event_handler *evh;
408
409 dumpf("Registered for '%s':", evl->event);
410 for (evh = evl->handlers; evh; evh = evh->next) {
411 if (evh->module != NULL) {
412 dumpf(" mod_%s.c", evh->module->name);
413
414 } else {
415 dumpf(" (core)");
416 }
417 }
418 }
419 }
420
421 return;
422 }
423