1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 1997, 1998 Public Flood Software
4  * Copyright (c) 2001-2016 The ProFTPD Project team
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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
19  *
20  * As a special exemption, Public Flood Software/MacGyver aka Habeeb J. Dihu
21  * and other respective copyright holders give permission to link this program
22  * with OpenSSL, and distribute the resulting executable, without including
23  * the source code for OpenSSL in the source distribution.
24  */
25 
26 /* Timer system, based on alarm() and SIGALRM. */
27 
28 #include "conf.h"
29 
30 /* From src/main.c */
31 extern volatile unsigned int recvd_signal_flags;
32 
33 struct timer {
34   struct timer *next, *prev;
35 
36   long count;                   /* Amount of time remaining */
37   long interval;                /* Original length of timer */
38 
39   int timerno;                  /* Caller dependent timer number */
40   module *mod;                  /* Module owning this timer */
41   callback_t callback;          /* Function to callback */
42   char remove;                  /* Internal use */
43 
44   const char *desc;		/* Description of timer, provided by caller */
45 };
46 
47 #define PR_TIMER_DYNAMIC_TIMERNO	1024
48 
49 static int _current_timeout = 0;
50 static int _total_time = 0;
51 static int _sleep_sem = 0;
52 static int alarms_blocked = 0, alarm_pending = 0;
53 static xaset_t *timers = NULL;
54 static xaset_t *recycled = NULL;
55 static xaset_t *free_timers = NULL;
56 static int _indispatch = 0;
57 static int dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO;
58 static unsigned int nalarms = 0;
59 static time_t _alarmed_time = 0;
60 
61 static pool *timer_pool = NULL;
62 
63 static const char *trace_channel = "timer";
64 
timer_cmp(struct timer * t1,struct timer * t2)65 static int timer_cmp(struct timer *t1, struct timer *t2) {
66   if (t1->count < t2->count) {
67     return -1;
68   }
69 
70   if (t1->count > t2->count) {
71     return 1;
72   }
73 
74   return 0;
75 }
76 
77 /* This function does the work of iterating through the list of registered
78  * timers, checking to see if their callbacks should be invoked and whether
79  * they should be removed from the registration list. Its return value is
80  * the amount of time remaining on the first timer in the list.
81  */
process_timers(int elapsed)82 static int process_timers(int elapsed) {
83   struct timer *t = NULL, *next = NULL;
84   int res = 0;
85 
86   if (recycled == NULL) {
87     recycled = xaset_create(timer_pool, NULL);
88   }
89 
90   if (elapsed == 0 &&
91       recycled->xas_list == NULL) {
92     if (timers == NULL) {
93       return 0;
94     }
95 
96     if (timers->xas_list != NULL) {
97       /* The value we return is a proposed timeout, for the next call to
98        * alarm(3).  We start with the simple count of timers in our list.
99        *
100        * But then we reduce the number; some of the timers' intervals may
101        * less than the number of total timers.
102        */
103       res = ((struct timer *) timers->xas_list)->count;
104       if (res > 5) {
105         res = 5;
106       }
107     }
108 
109     return res;
110   }
111 
112   /* Critical code, no interruptions please */
113   if (_indispatch) {
114     return 0;
115   }
116 
117   pr_alarms_block();
118   _indispatch++;
119 
120   if (elapsed) {
121     for (t = (struct timer *) timers->xas_list; t; t = next) {
122       /* If this timer has already been handled, skip */
123       next = t->next;
124 
125       if (t->remove) {
126         /* Move the timer onto the free_timers chain, for later reuse. */
127         xaset_remove(timers, (xasetmember_t *) t);
128         xaset_insert(free_timers, (xasetmember_t *) t);
129 
130       } else if ((t->count -= elapsed) <= 0) {
131         /* This timer's interval has elapsed, so trigger its callback. */
132 
133         pr_trace_msg(trace_channel, 4,
134           "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking "
135           "callback (%p)", t->interval,
136           t->interval != 1 ? "seconds" : "second", t->timerno,
137           t->desc ? t->desc : "<unknown>",
138           t->mod ? t->mod->name : "<none>", t->callback);
139 
140         if (t->callback(t->interval, t->timerno, t->interval - t->count,
141             t->mod) == 0) {
142 
143           /* A return value of zero means this timer is done, and can be
144            * removed.
145            */
146           xaset_remove(timers, (xasetmember_t *) t);
147           xaset_insert(free_timers, (xasetmember_t *) t);
148 
149         } else {
150           /* A non-zero return value from a timer callback signals that
151            * the timer should be reused/restarted.
152            */
153           pr_trace_msg(trace_channel, 6,
154             "restarting timer ID %d ('%s'), as per callback", t->timerno,
155             t->desc ? t->desc : "<unknown>");
156 
157           xaset_remove(timers, (xasetmember_t *) t);
158           t->count = t->interval;
159           xaset_insert(recycled, (xasetmember_t *) t);
160         }
161       }
162     }
163   }
164 
165   /* Put the recycled timers back into the main timer list. */
166   t = (struct timer *) recycled->xas_list;
167   while (t != NULL) {
168     xaset_remove(recycled, (xasetmember_t *) t);
169     xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
170     t = (struct timer *) recycled->xas_list;
171   }
172 
173   _indispatch--;
174   pr_alarms_unblock();
175 
176   /* If no active timers remain in the list, there is no reason to set the
177    * SIGALRM handle.
178    */
179 
180   if (timers->xas_list != NULL) {
181     /* The value we return is a proposed timeout, for the next call to
182      * alarm(3).  We start with the simple count of timers in our list.
183      *
184      * But then we reduce the number; some of the timers' intervals may
185      * less than the number of total timers.
186      */
187     res = ((struct timer *) timers->xas_list)->count;
188     if (res > 5) {
189       res = 5;
190     }
191   }
192 
193   return res;
194 }
195 
sig_alarm(int signo)196 static RETSIGTYPE sig_alarm(int signo) {
197   struct sigaction act;
198 
199   act.sa_handler = sig_alarm;
200   sigemptyset(&act.sa_mask);
201   act.sa_flags = 0;
202 
203 #ifdef SA_INTERRUPT
204   act.sa_flags |= SA_INTERRUPT;
205 #endif
206 
207   /* Install this handler for SIGALRM. */
208   if (sigaction(SIGALRM, &act, NULL) < 0) {
209     pr_log_pri(PR_LOG_WARNING,
210       "unable to install SIGALRM handler via sigaction(2): %s",
211       strerror(errno));
212   }
213 
214 #ifdef HAVE_SIGINTERRUPT
215   if (siginterrupt(SIGALRM, 1) < 0) {
216     pr_log_pri(PR_LOG_WARNING,
217       "unable to allow SIGALRM to interrupt system calls: %s", strerror(errno));
218   }
219 #endif
220 
221   recvd_signal_flags |= RECEIVED_SIG_ALRM;
222   nalarms++;
223 
224   /* Reset the alarm */
225   _total_time += _current_timeout;
226   if (_current_timeout) {
227     _alarmed_time = time(NULL);
228     alarm(_current_timeout);
229   }
230 }
231 
set_sig_alarm(void)232 static void set_sig_alarm(void) {
233   struct sigaction act;
234 
235   act.sa_handler = sig_alarm;
236   sigemptyset(&act.sa_mask);
237   act.sa_flags = 0;
238 #ifdef SA_INTERRUPT
239   act.sa_flags |= SA_INTERRUPT;
240 #endif
241 
242   /* Install this handler for SIGALRM. */
243   if (sigaction(SIGALRM, &act, NULL) < 0) {
244     pr_log_pri(PR_LOG_WARNING,
245       "unable to install SIGALRM handler via sigaction(2): %s",
246       strerror(errno));
247   }
248 
249 #ifdef HAVE_SIGINTERRUPT
250   if (siginterrupt(SIGALRM, 1) < 0) {
251     pr_log_pri(PR_LOG_WARNING,
252       "unable to allow SIGALRM to interrupt system calls: %s", strerror(errno));
253   }
254 #endif
255 }
256 
handle_alarm(void)257 void handle_alarm(void) {
258   int new_timeout = 0;
259 
260   /* We need to adjust for any time that might be remaining on the alarm,
261    * in case we were called in order to change alarm durations.  Note
262    * that rapid-fire calling of this function will probably screw
263    * up the already poor resolution of alarm() _horribly_.  Oh well,
264    * this shouldn't be used for any precise work anyway, it's only
265    * for modules to perform approximate timing.
266    */
267 
268   /* It's possible that alarms are blocked when this function is
269    * called, if so, increment alarm_pending and exit swiftly.
270    */
271   while (nalarms) {
272     nalarms = 0;
273 
274     if (!alarms_blocked) {
275       int alarm_elapsed;
276       time_t now;
277 
278       /* Clear any pending ALRM signals. */
279       alarm(0);
280 
281       /* Determine how much time has elapsed since we last processed timers. */
282       time(&now);
283       alarm_elapsed = _alarmed_time > 0 ? (int) (now - _alarmed_time) : 0;
284 
285       new_timeout = _total_time + alarm_elapsed;
286       _total_time = 0;
287       new_timeout = process_timers(new_timeout);
288 
289       _alarmed_time = now;
290       alarm(_current_timeout = new_timeout);
291 
292     } else {
293       alarm_pending++;
294     }
295   }
296 }
297 
pr_timer_reset(int timerno,module * mod)298 int pr_timer_reset(int timerno, module *mod) {
299   struct timer *t = NULL;
300 
301   if (timers == NULL) {
302     errno = EPERM;
303     return -1;
304   }
305 
306   if (_indispatch) {
307     errno = EINTR;
308     return -1;
309   }
310 
311   pr_alarms_block();
312 
313   if (recycled == NULL) {
314     recycled = xaset_create(timer_pool, NULL);
315   }
316 
317   for (t = (struct timer *) timers->xas_list; t; t = t->next) {
318     if (t->timerno == timerno &&
319         (t->mod == mod || mod == ANY_MODULE)) {
320       t->count = t->interval;
321       xaset_remove(timers, (xasetmember_t *) t);
322       xaset_insert(recycled, (xasetmember_t *) t);
323       nalarms++;
324 
325       /* The handle_alarm() function also readjusts the timers lists
326        * as part of its processing, so it needs to be called when a timer
327        * is reset.
328        */
329       handle_alarm();
330       break;
331     }
332   }
333 
334   pr_alarms_unblock();
335 
336   if (t != NULL) {
337     pr_trace_msg(trace_channel, 7, "reset timer ID %d ('%s', for module '%s')",
338       t->timerno, t->desc, t->mod ? t->mod->name : "[none]");
339     return t->timerno;
340   }
341 
342   return 0;
343 }
344 
pr_timer_remove(int timerno,module * mod)345 int pr_timer_remove(int timerno, module *mod) {
346   struct timer *t = NULL, *tnext = NULL;
347   int nremoved = 0;
348 
349   /* If there are no timers currently registered, do nothing. */
350   if (!timers)
351     return 0;
352 
353   pr_alarms_block();
354 
355   for (t = (struct timer *) timers->xas_list; t; t = tnext) {
356     tnext = t->next;
357 
358     if ((timerno < 0 || t->timerno == timerno) &&
359         (mod == ANY_MODULE || t->mod == mod)) {
360       nremoved++;
361 
362       if (_indispatch) {
363         t->remove++;
364 
365       } else {
366         xaset_remove(timers, (xasetmember_t *) t);
367         xaset_insert(free_timers, (xasetmember_t *) t);
368 	nalarms++;
369 
370         /* The handle_alarm() function also readjusts the timers lists
371          * as part of its processing, so it needs to be called when a timer
372          * is removed.
373          */
374         handle_alarm();
375       }
376 
377       pr_trace_msg(trace_channel, 7,
378         "removed timer ID %d ('%s', for module '%s')", t->timerno, t->desc,
379         t->mod ? t->mod->name : "[none]");
380     }
381 
382     /* If we are removing a specific timer, break out of the loop now.
383      * Otherwise, keep removing any matching timers.
384      */
385     if (nremoved > 0 &&
386         timerno >= 0) {
387       break;
388     }
389   }
390 
391   pr_alarms_unblock();
392 
393   if (nremoved == 0) {
394     errno = ENOENT;
395     return -1;
396   }
397 
398   /* If we removed a specific timer because of the given timerno, return
399    * that timerno value.
400    */
401   if (timerno >= 0) {
402     return timerno;
403   }
404 
405   return nremoved;
406 }
407 
pr_timer_add(int seconds,int timerno,module * mod,callback_t cb,const char * desc)408 int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb,
409     const char *desc) {
410   struct timer *t = NULL;
411 
412   if (seconds <= 0 ||
413       cb == NULL ||
414       desc == NULL) {
415     errno = EINVAL;
416     return -1;
417   }
418 
419   if (!timers)
420     timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp);
421 
422   /* Check to see that, if specified, the timerno is not already in use. */
423   if (timerno >= 0) {
424     for (t = (struct timer *) timers->xas_list; t; t = t->next) {
425       if (t->timerno == timerno) {
426         errno = EPERM;
427         return -1;
428       }
429     }
430   }
431 
432   if (!free_timers)
433     free_timers = xaset_create(timer_pool, NULL);
434 
435   /* Try to use an old timer first */
436   pr_alarms_block();
437   t = (struct timer *) free_timers->xas_list;
438   if (t != NULL) {
439     xaset_remove(free_timers, (xasetmember_t *) t);
440 
441   } else {
442     if (timer_pool == NULL) {
443       timer_pool = make_sub_pool(permanent_pool);
444       pr_pool_tag(timer_pool, "Timer Pool");
445     }
446 
447     /* Must allocate a new one */
448     t = palloc(timer_pool, sizeof(struct timer));
449   }
450 
451   if (timerno < 0) {
452     /* Dynamic timer */
453     if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) {
454       dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO;
455     }
456 
457     timerno = dynamic_timerno++;
458   }
459 
460   t->timerno = timerno;
461   t->count = t->interval = seconds;
462   t->callback = cb;
463   t->mod = mod;
464   t->remove = 0;
465   t->desc = desc;
466 
467   /* If called while _indispatch, add to the recycled list to prevent
468    * list corruption
469    */
470 
471   if (_indispatch) {
472     if (!recycled)
473       recycled = xaset_create(timer_pool, NULL);
474     xaset_insert(recycled, (xasetmember_t *) t);
475 
476   } else {
477     xaset_insert_sort(timers, (xasetmember_t *) t, TRUE);
478     nalarms++;
479     set_sig_alarm();
480 
481     /* The handle_alarm() function also readjusts the timers lists
482      * as part of its processing, so it needs to be called when a timer
483      * is added.
484      */
485     handle_alarm();
486   }
487 
488   pr_alarms_unblock();
489 
490   pr_trace_msg(trace_channel, 7, "added timer ID %d ('%s', for module '%s'), "
491     "triggering in %ld %s", t->timerno, t->desc,
492     t->mod ? t->mod->name : "[none]", t->interval,
493     t->interval != 1 ? "seconds" : "second");
494   return timerno;
495 }
496 
497 /* Alarm blocking.  This is done manually rather than with syscalls,
498  * so as to allow for easier signal handling, portability and
499  * detecting the number of blocked alarms, as well as nesting the
500  * block/unblock functions.
501  */
502 
pr_alarms_block(void)503 void pr_alarms_block(void) {
504   ++alarms_blocked;
505 }
506 
pr_alarms_unblock(void)507 void pr_alarms_unblock(void) {
508   --alarms_blocked;
509   if (alarms_blocked == 0 && alarm_pending) {
510     alarm_pending = 0;
511     nalarms++;
512     handle_alarm();
513   }
514 }
515 
sleep_cb(CALLBACK_FRAME)516 static int sleep_cb(CALLBACK_FRAME) {
517   _sleep_sem++;
518   return 0;
519 }
520 
pr_timer_sleep(int seconds)521 int pr_timer_sleep(int seconds) {
522   int timerno = 0;
523   sigset_t oset;
524 
525   _sleep_sem = 0;
526 
527   if (alarms_blocked || _indispatch) {
528     errno = EPERM;
529     return -1;
530   }
531 
532   timerno = pr_timer_add(seconds, -1, NULL, sleep_cb, "sleep");
533   if (timerno == -1)
534     return -1;
535 
536   sigemptyset(&oset);
537   while (!_sleep_sem) {
538     sigsuspend(&oset);
539     handle_alarm();
540   }
541 
542   return 0;
543 }
544 
pr_timer_usleep(unsigned long usecs)545 int pr_timer_usleep(unsigned long usecs) {
546   struct timeval tv;
547 
548   if (usecs == 0) {
549     errno = EINVAL;
550     return -1;
551   }
552 
553   tv.tv_sec = (usecs / 1000000);
554   tv.tv_usec = (usecs - (tv.tv_sec * 1000000));
555 
556   pr_signals_block();
557   (void) select(0, NULL, NULL, NULL, &tv);
558   pr_signals_unblock();
559 
560   return 0;
561 }
562 
timers_init(void)563 void timers_init(void) {
564 
565   /* Reset some of the key static variables. */
566   _current_timeout = 0;
567   _total_time = 0;
568   nalarms = 0;
569   _alarmed_time = 0;
570   dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO;
571 
572   /* Don't inherit the parent's timer lists. */
573   timers = NULL;
574   recycled = NULL;
575   free_timers = NULL;
576 
577   /* Reset the timer pool. */
578   if (timer_pool) {
579     destroy_pool(timer_pool);
580   }
581 
582   timer_pool = make_sub_pool(permanent_pool);
583   pr_pool_tag(timer_pool, "Timer Pool");
584 
585   return;
586 }
587