Coverage Report

Created: 2025-08-26 07:05

/src/proftpd/modules/mod_delay.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * ProFTPD: mod_delay -- a module for adding arbitrary delays to the FTP
3
 *                       session lifecycle
4
 * Copyright (c) 2004-2025 TJ Saunders
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, TJ Saunders and other respective copyright holders
21
 * give permission to link this program with OpenSSL, and distribute the
22
 * resulting executable, without including the source code for OpenSSL in the
23
 * source distribution.
24
 *
25
 * This is mod_delay, contrib software for proftpd 1.3.x and above.
26
 * For more information contact TJ Saunders <tj@castaglia.org>.
27
 */
28
29
#include "conf.h"
30
#include "privs.h"
31
32
0
#define MOD_DELAY_VERSION   "mod_delay/0.8"
33
34
/* Make sure the version of proftpd is as necessary. */
35
#if PROFTPD_VERSION_NUMBER < 0x0001021001
36
# error "ProFTPD 1.2.10rc1 or later required"
37
#endif
38
39
#ifdef HAVE_SYS_MMAN_H
40
# include <sys/mman.h>
41
#endif
42
43
/* On some platforms, this may not be defined.  On AIX, for example, this
44
 * symbol is only defined when _NO_PROTO is defined, and _XOPEN_SOURCE is 500.
45
 * How annoying.
46
 */
47
#ifndef MAP_FAILED
48
# define MAP_FAILED ((void *) -1)
49
#endif
50
51
#if defined(PR_USE_CTRLS)
52
# include <mod_ctrls.h>
53
#endif /* PR_USE_CTRLS */
54
55
/* Number of values to keep in a row. */
56
#ifndef DELAY_NVALUES
57
0
# define DELAY_NVALUES      256
58
#endif
59
60
/* Fraction of total values that are accepted from a single session. */
61
#ifndef DELAY_SESS_NVALUES
62
0
# define DELAY_SESS_NVALUES   16
63
#endif
64
65
/* The mod_delay tables have separate entries for different protocols;
66
 * the implementation/handling of one protocol means that that protocol can
67
 * have different timings from others.  For example, due to the encryption
68
 * overhead, authentication via SSL can take longer than without SSL.  Thus
69
 * we need to keep the per-protocol timings separate.
70
 *
71
 * We currently allocate space for three protocols:
72
 *
73
 *  ftp
74
 *  ftps
75
 *  ssh2
76
 *
77
 * If more protocols are supported by proftpd, this this DELAY_NPROTO value
78
 * should be increased accordingly.  The delay_table_reset() function will
79
 * also need updating, to include the new protocol, as well.
80
 */
81
0
#define DELAY_NPROTO      3
82
83
/* Define an absolute upper limit on the delay values selected, in usecs.
84
 *
85
 * I originally wanted a ceiling of 1 hour, but when converted to usecs, the
86
 * value exceeded LONG_MAX.  So instead, we use 1800000000 usecs (30 min).
87
 */
88
0
#define DELAY_MAX_DELAY_USECS     1800000000L
89
90
/* Define an upper bound on the interval we will use, between time of connect
91
 * and time of USER command.  This is currently limited to 60 seconds.
92
 */
93
0
#define DELAY_MAX_CONNECT_INTERVAL_USECS  60000000L
94
95
#if defined(PR_USE_CTRLS)
96
static ctrls_acttab_t delay_acttab[];
97
#endif /* PR_USE_CTRLS */
98
99
extern xaset_t *server_list;
100
101
module delay_module;
102
103
struct delay_vals_rec {
104
  char dv_proto[16];
105
  unsigned int dv_nvals;
106
  long dv_vals[DELAY_NVALUES];
107
};
108
109
struct delay_rec {
110
  unsigned int d_sid;
111
  char d_addr[80];
112
  unsigned int d_port;
113
  struct delay_vals_rec d_vals[DELAY_NPROTO];
114
};
115
116
struct {
117
  int dt_enabled;
118
  const char *dt_path;
119
  int dt_fd;
120
  size_t dt_size;
121
  void *dt_data;
122
  size_t dt_lookupsz;
123
  unsigned int *dt_lookup;
124
125
} delay_tab;
126
127
static unsigned int delay_engine = TRUE;
128
static unsigned int delay_nuser = 0;
129
static unsigned int delay_npass = 0;
130
static unsigned long delay_user_delayed = 0L;
131
static unsigned long delay_pass_delayed = 0L;
132
static pool *delay_pool = NULL;
133
static struct timeval delay_tv;
134
135
/* DelayOnEvent events */
136
0
#define DELAY_EVENT_USER_CMD    1
137
0
#define DELAY_EVENT_PASS_CMD    2
138
0
#define DELAY_EVENT_FAILED_LOGIN  3
139
0
#define DELAY_EVENT_CONNECT   4
140
141
/* DelayOnEvent Connect */
142
static unsigned long delay_failed_login_min_delay = 0UL;
143
static unsigned long delay_failed_login_max_delay = 0UL;
144
145
/* DelayOnEvent FailedLogin */
146
static unsigned long delay_connect_min_delay = 0UL;
147
static unsigned long delay_connect_max_delay = 0UL;
148
149
/* DelayOnEvent USER */
150
static unsigned long delay_user_min_delay = 0UL;
151
static unsigned long delay_user_max_delay = 0UL;
152
153
/* DelayOnEvent PASS */
154
static unsigned long delay_pass_min_delay = 0UL;
155
static unsigned long delay_pass_max_delay = 0UL;
156
157
static int delay_sess_init(void);
158
static void delay_table_reset(void);
159
160
#define delay_swap(a, b) \
161
0
  tmp = (a); \
162
0
  (a) = (b); \
163
0
  (b) = tmp;
164
165
static const char *trace_channel = "delay";
166
167
0
static long delay_select_k(unsigned long k, array_header *values) {
168
0
  unsigned long l, ir, tmp = 0;
169
0
  long *elts = (long *) values->elts;
170
0
  unsigned int nelts = values->nelts;
171
172
  /* This is from "Numeric Recipes in C", Ch. 8.5, as the select()
173
   * algorithm, an in-place sorting algorithm for finding the Kth
174
   * element in an array, where all elements to the left of K are
175
   * smaller than K, and all elements to the right are larger.
176
   */
177
178
0
  l = 1;
179
0
  ir = values->nelts - 1;
180
181
0
  while (TRUE) {
182
0
    unsigned int i, j;
183
0
    long p;
184
0
    unsigned long mid;
185
186
0
    pr_signals_handle();
187
188
0
    if (ir <= l+1) {
189
0
      if (ir == l+1 &&
190
0
          elts[ir] < elts[l]) {
191
0
        delay_swap(elts[l], elts[ir]);
192
0
      }
193
194
0
      return elts[k];
195
0
    }
196
197
0
    mid = (l + ir) >> 1;
198
199
0
    delay_swap(elts[mid], elts[l+1]);
200
0
    if (elts[l] > elts[ir]) {
201
0
      delay_swap(elts[l], elts[ir]);
202
0
    }
203
204
0
    if (elts[l+1] > elts[ir]) {
205
0
      delay_swap(elts[l+1], elts[ir]);
206
0
    }
207
208
0
    if (elts[l] > elts[l+1]) {
209
0
      delay_swap(elts[l], elts[l+1]);
210
0
    }
211
212
0
    i = l + 1;
213
0
    j = ir;
214
0
    p = elts[l+1];
215
216
0
    while (TRUE) {
217
0
      pr_signals_handle();
218
219
0
      do {
220
0
        i++;
221
0
      } while (i < nelts && elts[i] < p);
222
223
0
      do {
224
0
        j--;
225
0
      } while (elts[j] > p);
226
227
0
      if (j < i) {
228
0
        break;
229
0
      }
230
231
0
      delay_swap(elts[i], elts[j]);
232
0
    }
233
234
0
    elts[l+1] = elts[j];
235
0
    elts[j] = p;
236
237
0
    if ((unsigned long) p >= k) {
238
0
      ir = j - 1;
239
0
    }
240
241
0
    if ((unsigned long) p <= k) {
242
0
      l = i;
243
0
    }
244
245
0
    if (l >= (nelts - 1) ||
246
0
        ir >= nelts) {
247
0
      break;
248
0
    }
249
0
  }
250
251
0
  return -1;
252
0
}
253
254
static long delay_get_median(pool *p, unsigned int rownum, const char *protocol,
255
0
    long interval) {
256
0
  register unsigned int i;
257
0
  struct delay_rec *row;
258
0
  struct delay_vals_rec *dv = NULL;
259
0
  long *tab_vals = NULL, median;
260
0
  array_header *list = make_array(p, 1, sizeof(long));
261
262
  /* Calculate the median value of the current command's recorded values,
263
   * taking the protocol (e.g. "ftp", "ftps", "ssh2") into account.
264
   *
265
   * When calculating the median, we use the current interval as well
266
   * as the recorded intervals in the table, giving us an odd number of
267
   * values.
268
   *
269
   * If the number of values in this row is less than the watermark
270
   * value, we'll actually return the maximum value, rather than the
271
   * median.  Below the watermark, the server is "cold" and has not
272
   * yet accumulated enough data to make the median a useful value.
273
   */
274
275
0
  row = &((struct delay_rec *) delay_tab.dt_data)[rownum];
276
277
  /* Find the list of delay values that match the given protocol. */
278
0
  for (i = 0; i < DELAY_NPROTO; i++) {
279
0
    dv = &(row->d_vals[i]);
280
0
    if (strcmp(dv->dv_proto, protocol) == 0) {
281
0
      tab_vals = dv->dv_vals;
282
0
      break;
283
0
    }
284
0
  }
285
286
  /* Start at the end of the row and work backward, as values are
287
   * always added at the end of the row, shifting everything to the left.
288
   */
289
0
  if (tab_vals != NULL) {
290
0
    for (i = 1; i < dv->dv_nvals; i++) {
291
      /* Ignore any possible garbage (i.e. negative) values in the
292
       * DelayTable.
293
       */
294
0
      if (tab_vals[DELAY_NVALUES - 1 - i] >= 0) {
295
0
        *((long *) push_array(list)) = tab_vals[DELAY_NVALUES - 1 - i];
296
0
      }
297
0
    }
298
0
  }
299
0
  *((long *) push_array(list)) = interval;
300
301
0
  pr_trace_msg(trace_channel, 6, "selecting median interval from %d %s",
302
0
    list->nelts, list->nelts != 1 ? "values" : "value");
303
304
0
  median = delay_select_k(((list->nelts + 1) / 2), list);
305
0
  if (median >= 0) {
306
307
    /* Enforce an additional restriction: no delays over a hard limit. */
308
0
    if (median >= DELAY_MAX_DELAY_USECS) {
309
0
      pr_trace_msg(trace_channel, 1,
310
0
        "selected median (%ld usecs) exceeds max delay (%ld usecs), ignoring",
311
0
        median, (long) DELAY_MAX_DELAY_USECS);
312
0
      pr_log_debug(DEBUG5, MOD_DELAY_VERSION
313
0
        ": selected median (%ld usecs) exceeds max delay (%ld usecs), ignoring",
314
0
        median, (long) DELAY_MAX_DELAY_USECS);
315
0
      median = -1;
316
317
0
    } else {
318
0
      pr_trace_msg(trace_channel, 7, "selected median interval of %ld usecs",
319
0
        median);
320
0
    }
321
0
  }
322
323
0
  return median;
324
0
}
325
326
0
static int delay_mask_signals(unsigned char block) {
327
0
  static sigset_t mask_sigset;
328
0
  int res = -1;
329
330
0
  if (block) {
331
0
    sigemptyset(&mask_sigset);
332
333
0
    sigaddset(&mask_sigset, SIGCHLD);
334
0
    sigaddset(&mask_sigset, SIGUSR1);
335
0
    sigaddset(&mask_sigset, SIGINT);
336
0
    sigaddset(&mask_sigset, SIGQUIT);
337
0
#ifdef SIGIO
338
0
    sigaddset(&mask_sigset, SIGIO);
339
0
#endif
340
0
#ifdef SIGBUS
341
0
    sigaddset(&mask_sigset, SIGBUS);
342
0
#endif
343
0
    sigaddset(&mask_sigset, SIGHUP);
344
345
0
    res = sigprocmask(SIG_BLOCK, &mask_sigset, NULL);
346
347
0
  } else {
348
0
    res = sigprocmask(SIG_UNBLOCK, &mask_sigset, NULL);
349
0
  }
350
351
0
  return res;
352
0
}
353
354
0
static void delay_signals_block(void) {
355
0
  if (delay_mask_signals(TRUE) < 0) {
356
0
    pr_trace_msg(trace_channel, 1,
357
0
      "error blocking signals: %s", strerror(errno));
358
0
  }
359
0
}
360
361
0
static void delay_signals_unblock(void) {
362
0
  if (delay_mask_signals(FALSE) < 0) {
363
0
    pr_trace_msg(trace_channel, 1,
364
0
      "error unblocking signals: %s", strerror(errno));
365
0
  }
366
0
}
367
368
0
static unsigned long delay_inject_delay(unsigned long interval) {
369
0
  struct timeval tv;
370
0
  int res, xerrno;
371
372
0
  tv.tv_sec = interval / 1000000;
373
0
  tv.tv_usec = interval % 1000000;
374
375
0
  pr_trace_msg(trace_channel, 8, "delaying for %ld usecs",
376
0
    (long int) ((tv.tv_sec * 1000000) + tv.tv_usec));
377
378
0
  delay_signals_block();
379
0
  res = select(0, NULL, NULL, NULL, &tv);
380
0
  xerrno = errno;
381
0
  delay_signals_unblock();
382
383
0
  if (res < 0 &&
384
0
      xerrno == EINTR) {
385
386
    /* If we were interrupted, handle the interrupting signal. */
387
0
    pr_signals_handle();
388
0
  }
389
390
0
  return interval;
391
0
}
392
393
static unsigned long delay_inject_delay_with_jitter(long interval,
394
0
    long max_jitter) {
395
0
  long jitter_usec;
396
397
0
  if (max_jitter <= 0) {
398
    /* Assume a max additional jitter of half of the given interval. */
399
0
    max_jitter = (interval / 2);
400
0
  }
401
402
  /* Add an additional delay of a random number of usecs of jitter. */
403
0
  jitter_usec = pr_random_next(0, max_jitter);
404
405
0
  pr_trace_msg(trace_channel, 8, "additional random delay of %ld usecs added",
406
0
    (long int) jitter_usec);
407
0
  interval += jitter_usec;
408
409
0
  if (interval > DELAY_MAX_DELAY_USECS) {
410
0
    interval = DELAY_MAX_DELAY_USECS;
411
0
  }
412
413
0
  return delay_inject_delay(interval);
414
0
}
415
416
/* Similar to the pr_str_get_duration() function, but parses millisecond
417
 * values, not seconds.
418
 *
419
 * In addition, it can parse a min-max textual range.
420
 */
421
static int delay_str_get_duration_ms(const char *str, long *min_duration,
422
0
    long *max_duration) {
423
0
  unsigned int mins, secs;
424
0
  long min_msecs, max_msecs;
425
0
  int flags = PR_STR_FL_IGNORE_CASE, has_suffix = FALSE;
426
0
  size_t len;
427
0
  char *ptr = NULL;
428
429
0
  if (str == NULL) {
430
0
    errno = EINVAL;
431
0
    return -1;
432
0
  }
433
434
0
  if (sscanf(str, "%2u:%2u.%4lu", &mins, &secs, &min_msecs) == 3) {
435
0
    if (mins > INT_MAX ||
436
0
        secs > INT_MAX ||
437
0
        min_msecs > INT_MAX) {
438
0
      errno = ERANGE;
439
0
      return -1;
440
0
    }
441
442
0
    if (min_duration != NULL) {
443
0
      *min_duration = (mins * 60 * 1000) + (secs * 1000) + min_msecs;
444
0
    }
445
446
0
    if (max_duration != NULL) {
447
0
      *max_duration = (mins * 60 * 1000) + (secs * 1000) + min_msecs;
448
0
    }
449
450
0
    return 0;
451
0
  }
452
453
0
  if (sscanf(str, "%ld-%ld", &min_msecs, &max_msecs) == 2) {
454
0
    if (min_msecs > INT_MAX ||
455
0
        max_msecs > INT_MAX) {
456
0
      errno = ERANGE;
457
0
      return -1;
458
0
    }
459
460
0
    if (min_msecs >= max_msecs) {
461
0
      errno = EINVAL;
462
0
      return -1;
463
0
    }
464
465
0
    if (min_duration != NULL) {
466
0
      *min_duration = min_msecs;
467
0
    }
468
469
0
    if (max_duration != NULL) {
470
0
      *max_duration = max_msecs;
471
0
    }
472
473
0
    return 0;
474
0
  }
475
476
0
  len = strlen(str);
477
0
  if (len == 0) {
478
0
    errno = EINVAL;
479
0
    return -1;
480
0
  }
481
482
0
  has_suffix = pr_strnrstr(str, len, "ms", 2, flags);
483
0
  if (has_suffix == TRUE) {
484
    /* Parse millisecs */
485
486
0
    if (sscanf(str, "%ld", &min_msecs) == 1) {
487
0
      if (min_msecs > INT_MAX) {
488
0
        errno = ERANGE;
489
0
        return -1;
490
0
      }
491
492
0
      if (min_duration != NULL) {
493
0
        *min_duration = min_msecs;
494
0
      }
495
496
0
      if (max_duration != NULL) {
497
0
        *max_duration = min_msecs;
498
0
      }
499
500
0
      return 0;
501
0
    }
502
503
0
    if (sscanf(str, "%ld-%ld", &min_msecs, &max_msecs) == 2) {
504
0
      if (min_msecs > INT_MAX ||
505
0
          max_msecs > INT_MAX) {
506
0
        errno = ERANGE;
507
0
        return -1;
508
0
      }
509
510
0
      if (min_msecs >= max_msecs) {
511
0
        errno = EINVAL;
512
0
        return -1;
513
0
      }
514
515
0
      if (min_duration != NULL) {
516
0
        *min_duration = min_msecs;
517
0
      }
518
519
0
      if (max_duration != NULL) {
520
0
        *max_duration = max_msecs;
521
0
      }
522
523
0
      return 0;
524
0
    }
525
526
0
    errno = EINVAL;
527
0
    return -1;
528
0
  }
529
530
0
  has_suffix = pr_strnrstr(str, len, "s", 1, flags);
531
0
  if (has_suffix == FALSE) {
532
0
    has_suffix = pr_strnrstr(str, len, "sec", 3, flags);
533
0
  }
534
535
0
  if (has_suffix == TRUE) {
536
0
    unsigned int max_secs;
537
538
    /* Parse seconds */
539
540
0
    if (sscanf(str, "%u", &secs) == 1) {
541
0
      if (secs > INT_MAX) {
542
0
        errno = ERANGE;
543
0
        return -1;
544
0
      }
545
546
0
      if (min_duration != NULL) {
547
0
        *min_duration = (secs * 1000);
548
0
      }
549
550
0
      if (max_duration != NULL) {
551
0
        *max_duration = (secs * 1000);
552
0
      }
553
554
0
      return 0;
555
0
    }
556
557
0
    if (sscanf(str, "%u-%u", &secs, &max_secs) == 2) {
558
0
      if (secs > INT_MAX ||
559
0
          max_secs > INT_MAX) {
560
0
        errno = ERANGE;
561
0
        return -1;
562
0
      }
563
564
0
      if (secs >= max_secs) {
565
0
        errno = EINVAL;
566
0
        return -1;
567
0
      }
568
569
0
      if (min_duration != NULL) {
570
0
        *min_duration = (secs * 1000);
571
0
      }
572
573
0
      if (max_duration != NULL) {
574
0
        *max_duration = (max_secs * 1000);
575
0
      }
576
577
0
      return 0;
578
0
    }
579
580
0
    errno = EINVAL;
581
0
    return -1;
582
0
  }
583
584
  /* Use strtol(3) here, check for trailing garbage, etc. */
585
0
  min_msecs = strtol(str, &ptr, 10);
586
0
  if (ptr && *ptr) {
587
    /* Not a bare number, but a string with non-numeric characters. */
588
0
    errno = EINVAL;
589
0
    return -1;
590
0
  }
591
592
0
  if (min_msecs < 0 ||
593
0
      min_msecs > INT_MAX) {
594
0
    errno = ERANGE;
595
0
    return -1;
596
0
  }
597
598
0
  if (min_duration != NULL) {
599
0
    *min_duration = min_msecs;
600
0
  }
601
602
0
  if (max_duration != NULL) {
603
0
    *max_duration = min_msecs;
604
0
  }
605
606
0
  return 0;
607
0
}
608
609
/* There are two rows (USER and PASS) for each server ID (SID).
610
 *
611
 * To find the row number, we scan the lookup table by SID.  The USER row
612
 * number is then the next value in the lookup table after the SID, the PASS
613
 * row number is the next value in the lookup table after the USER row number.
614
 */
615
0
static unsigned int delay_get_user_rownum(unsigned int sid) {
616
0
  unsigned int i, r = -1;
617
618
0
  for (i = 0; i < delay_tab.dt_lookupsz; i = i + 3) {
619
0
    if (delay_tab.dt_lookup[i] == sid) {
620
0
      r = delay_tab.dt_lookup[i+1];
621
0
      break;
622
0
    }
623
0
  }
624
625
0
  return r;
626
0
}
627
628
0
static unsigned int delay_get_pass_rownum(unsigned int sid) {
629
0
  unsigned int i, r = -1;
630
631
0
  for (i = 0; i < delay_tab.dt_lookupsz; i = i + 3) {
632
0
    if (delay_tab.dt_lookup[i] == sid) {
633
0
      r = delay_tab.dt_lookup[i+2];
634
0
      break;
635
0
    }
636
0
  }
637
638
0
  return r;
639
0
}
640
641
static void delay_table_add_interval(unsigned int rownum, const char *protocol,
642
0
    long interval) {
643
0
  register unsigned int i;
644
0
  struct delay_rec *row;
645
0
  struct delay_vals_rec *dv = NULL;
646
647
0
  row = &((struct delay_rec *) delay_tab.dt_data)[rownum];
648
649
0
  for (i = 0; i < DELAY_NPROTO; i++) {
650
0
    dv = &(row->d_vals[i]);
651
0
    if (strcmp(dv->dv_proto, protocol) == 0) {
652
0
      break;
653
0
    }
654
0
  }
655
656
  /* Shift all existing values to the left one position. */
657
0
  memmove(&(dv->dv_vals[0]), &(dv->dv_vals[1]),
658
0
    sizeof(long) * (DELAY_NVALUES - 1));
659
660
  /* Add the given value to the end. */
661
662
0
  if (interval > DELAY_MAX_DELAY_USECS) {
663
    /* Truncate the interval to the maximum allowed value. */
664
0
    interval = DELAY_MAX_DELAY_USECS;
665
0
  }
666
667
0
  dv->dv_vals[DELAY_NVALUES-1] = interval;
668
0
  if (dv->dv_nvals < DELAY_NVALUES) {
669
0
    dv->dv_nvals++;
670
0
  }
671
0
}
672
673
/* Create a lookup table, of SID to USER/PASS row number.  We do this
674
 * dynamically, since there is no guarantee that all SIDs will be present
675
 * in the server_list; some virtual hosts (SIDs) may be omitted from that
676
 * list due to misconfigurations (see Issue #1746).
677
 */
678
0
static void delay_table_init_lookup(void) {
679
0
  off_t lookupsz;
680
0
  server_rec *s;
681
0
  unsigned int i, *lookup, r, server_count = 0;
682
683
0
  for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
684
0
    server_count++;
685
0
  }
686
687
0
  lookupsz = server_count * 3 * sizeof(unsigned int);
688
0
  lookup = pcalloc(delay_pool, lookupsz);
689
690
0
  i = r = 0;
691
0
  for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
692
    /* SID */
693
0
    lookup[i] = s->sid;
694
695
    /* SID-specific USER row */
696
0
    lookup[i+1] = r;
697
698
    /* SID-specific PASS row */
699
0
    lookup[i+2] = r + 1;
700
701
0
    i += 3;
702
0
    r += 2;
703
0
  }
704
705
0
  delay_tab.dt_lookupsz = lookupsz;
706
0
  delay_tab.dt_lookup = lookup;
707
0
}
708
709
0
static int delay_table_init(void) {
710
0
  pr_fh_t *fh;
711
0
  struct stat st;
712
0
  server_rec *s;
713
0
  unsigned int server_count = 0;
714
0
  off_t tab_size;
715
0
  int flags = O_RDWR|O_CREAT;
716
0
  int reset_table = FALSE, xerrno = 0;
717
718
  /* We only want to create the table if it does not already exist.
719
   *
720
   * If the ServerType is inetd, we want to leave the current contents
721
   * alone (don't we want to check to see that it's appropriate, sid-wise,
722
   * for the current server_list?), otherwise, we reset the table.
723
   *
724
   * The size of the table should be:
725
   *
726
   *  number of vhosts * 2 * row size
727
   */
728
729
0
  for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
730
0
    server_count++;
731
0
  }
732
733
0
  tab_size = server_count * 2 * sizeof(struct delay_rec);
734
735
0
  PRIVS_ROOT
736
0
  fh = pr_fsio_open(delay_tab.dt_path, flags);
737
0
  xerrno = errno;
738
0
  PRIVS_RELINQUISH
739
740
0
  if (fh == NULL) {
741
0
    pr_log_debug(DEBUG0, MOD_DELAY_VERSION
742
0
      ": error opening DelayTable '%s': %s", delay_tab.dt_path,
743
0
      strerror(xerrno));
744
0
    pr_trace_msg(trace_channel, 1, "error opening DelayTable '%s': %s",
745
0
      delay_tab.dt_path, strerror(xerrno));
746
0
    errno = xerrno;
747
0
    return -1;
748
0
  }
749
750
  /* Find a usable fd for the just-opened DelayTable fd. */
751
0
  if (pr_fs_get_usable_fd2(&(fh->fh_fd)) < 0) {
752
0
    pr_log_debug(DEBUG0, MOD_DELAY_VERSION
753
0
      ": warning: unable to find good fd for DelayTable %d: %s",
754
0
      fh->fh_fd, strerror(errno));
755
0
  }
756
757
  /* Set the close-on-exec flag, for safety. */
758
0
  if (fcntl(fh->fh_fd, F_SETFD, FD_CLOEXEC) < 0) {
759
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
760
0
      ": unable to set CLO_EXEC on DelayTable fd %d: %s", fh->fh_fd,
761
0
      strerror(errno));
762
0
  }
763
764
0
  if (pr_fsio_fstat(fh, &st) < 0) {
765
0
    xerrno = errno;
766
767
0
    pr_trace_msg(trace_channel, 1, "error stat'ing DelayTable '%s': %s",
768
0
      delay_tab.dt_path, strerror(xerrno));
769
0
    pr_fsio_close(fh);
770
771
0
    errno = xerrno;
772
0
    return -1;
773
0
  }
774
775
0
  if (S_ISDIR(st.st_mode)) {
776
0
    xerrno = EISDIR;
777
778
0
    pr_trace_msg(trace_channel, 1, "error using DelayTable '%s': %s",
779
0
      delay_tab.dt_path, strerror(xerrno));
780
0
    pr_fsio_close(fh);
781
782
0
    errno = xerrno;
783
0
    return -1;
784
0
  }
785
786
0
  if (st.st_size != tab_size) {
787
    /* This check is for cases when the ServerType is inetd, and the
788
     * current DelayTable has the wrong size, which can happen if the
789
     * configuration has changed by having vhosts added or removed.
790
     */
791
792
0
    pr_trace_msg(trace_channel, 3,
793
0
      "expected table size %" PR_LU ", found %" PR_LU ", resetting table",
794
0
      (pr_off_t) tab_size, (pr_off_t) st.st_size);
795
0
    reset_table = TRUE;
796
0
  }
797
798
  /* Initialize the lookup table before we possibly reset the table, as the
799
   * reset process requires looking up the row numbers.
800
   */
801
0
  delay_table_init_lookup();
802
803
0
  if (reset_table == TRUE) {
804
0
    struct flock lock;
805
806
0
    lock.l_type = F_WRLCK;
807
0
    lock.l_whence = 0;
808
0
    lock.l_start = 0;
809
0
    lock.l_len = 0;
810
811
0
    pr_trace_msg(trace_channel, 8, "write-locking DelayTable '%s'",
812
0
      fh->fh_path);
813
0
    while (fcntl(fh->fh_fd, F_SETLKW, &lock) < 0) {
814
0
      xerrno = errno;
815
816
0
      if (errno == EINTR) {
817
0
        pr_signals_handle();
818
0
        continue;
819
0
      }
820
821
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
822
0
        ": unable to obtain write lock on DelayTable '%s': %s",
823
0
        fh->fh_path, strerror(xerrno));
824
0
      pr_trace_msg(trace_channel, 1,
825
0
        "unable to obtain write lock on DelayTable '%s': %s", fh->fh_path,
826
0
        strerror(xerrno));
827
0
      pr_fsio_close(fh);
828
829
0
      errno = xerrno;
830
0
      return -1;
831
0
    }
832
833
    /* Seek to the desired table size (actually, one byte less than the
834
     * desired size) and write a single byte, so that there's enough
835
     * allocated backing store on the filesystem to support the ensuing
836
     * mmap() call.
837
     */
838
0
    if (lseek(fh->fh_fd, tab_size-1, SEEK_SET) < 0) {
839
0
      xerrno = errno;
840
841
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
842
0
        ": error seeking to %lu in DelayTable '%s': %s",
843
0
        (unsigned long) tab_size-1, fh->fh_path, strerror(xerrno));
844
0
      pr_trace_msg(trace_channel, 1,
845
0
        "error seeking to %lu in DelayTable '%s': %s",
846
0
        (unsigned long) tab_size-1, fh->fh_path, strerror(xerrno));
847
848
0
      pr_fsio_close(fh);
849
850
0
      errno = xerrno;
851
0
      return -1;
852
0
    }
853
854
0
    if (write(fh->fh_fd, "", 1) != 1) {
855
0
      xerrno = errno;
856
857
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
858
0
        ": error writing single byte to DelayTable '%s': %s", fh->fh_path,
859
0
        strerror(xerrno));
860
0
      pr_trace_msg(trace_channel, 1,
861
0
        "error writing single byte to DelayTable '%s': %s", fh->fh_path,
862
0
        strerror(xerrno));
863
864
0
      pr_fsio_close(fh);
865
866
0
      errno = xerrno;
867
0
      return -1;
868
0
    }
869
870
    /* Truncate the table, in case we're shrinking an existing table. */
871
0
    pr_fsio_ftruncate(fh, tab_size);
872
873
0
    lock.l_type = F_UNLCK;
874
875
0
    pr_trace_msg(trace_channel, 8, "unlocking DelayTable '%s'", fh->fh_path);
876
0
    if (fcntl(fh->fh_fd, F_SETLK, &lock) < 0) {
877
0
      pr_trace_msg(trace_channel, 3,
878
0
        "error unlocking fd %d: %s", fh->fh_fd, strerror(errno));
879
0
    }
880
0
  }
881
882
0
  delay_tab.dt_fd = fh->fh_fd;
883
0
  delay_tab.dt_size = (size_t) tab_size;
884
885
0
  pr_trace_msg(trace_channel, 8, "mapping DelayTable '%s' (%lu bytes, fd %d) "
886
0
    "into memory", fh->fh_path, (unsigned long) delay_tab.dt_size,
887
0
    delay_tab.dt_fd);
888
0
  delay_tab.dt_data = mmap(NULL, delay_tab.dt_size, PROT_READ|PROT_WRITE,
889
0
    MAP_SHARED, delay_tab.dt_fd, 0);
890
891
0
  if (delay_tab.dt_data == MAP_FAILED) {
892
0
    xerrno = errno;
893
894
0
    delay_tab.dt_data = NULL;
895
896
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
897
0
      ": error mapping DelayTable '%s' into memory: %s", delay_tab.dt_path,
898
0
      strerror(xerrno));
899
0
    pr_trace_msg(trace_channel, 1,
900
0
      "error mapping DelayTable '%s' into memory: %s", delay_tab.dt_path,
901
0
      strerror(xerrno));
902
903
0
    pr_fsio_close(fh);
904
0
    delay_tab.dt_fd = -1;
905
906
0
    errno = xerrno;
907
0
    return -1;
908
0
  }
909
910
0
  if (reset_table == FALSE) {
911
0
    struct delay_rec *row;
912
913
0
    for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
914
0
      unsigned int r;
915
0
      const char *ip_str;
916
917
      /* Row for USER values */
918
0
      r = delay_get_user_rownum(s->sid);
919
0
      row = &((struct delay_rec *) delay_tab.dt_data)[r];
920
0
      ip_str = pr_netaddr_get_ipstr(s->addr);
921
0
      if (ip_str == NULL) {
922
0
        continue;
923
0
      }
924
925
0
      if (strcmp(ip_str, row->d_addr) != 0) {
926
0
        reset_table = TRUE;
927
0
        break;
928
0
      }
929
930
0
      if (s->ServerPort != row->d_port) {
931
0
        reset_table = TRUE;
932
0
        break;
933
0
      }
934
935
      /* Row for PASS values */
936
0
      r = delay_get_pass_rownum(s->sid);
937
0
      row = &((struct delay_rec *) delay_tab.dt_data)[r];
938
0
      if (strcmp(ip_str, row->d_addr) != 0) {
939
0
        reset_table = TRUE;
940
0
        break;
941
0
      }
942
943
0
      if (s->ServerPort != row->d_port) {
944
0
        reset_table = TRUE;
945
0
        break;
946
0
      }
947
0
    }
948
0
  }
949
950
0
  if (reset_table == TRUE) {
951
0
    struct flock lock;
952
953
0
    lock.l_type = F_WRLCK;
954
0
    lock.l_whence = 0;
955
0
    lock.l_start = 0;
956
0
    lock.l_len = 0;
957
958
0
    pr_trace_msg(trace_channel, 8, "write-locking DelayTable '%s'",
959
0
      fh->fh_path);
960
0
    while (fcntl(fh->fh_fd, F_SETLKW, &lock) < 0) {
961
0
      xerrno = errno;
962
963
0
      if (errno == EINTR) {
964
0
        pr_signals_handle();
965
0
        continue;
966
0
      }
967
968
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
969
0
        ": unable to obtain write lock on DelayTable '%s': %s",
970
0
        fh->fh_path, strerror(xerrno));
971
0
      pr_trace_msg(trace_channel, 1,
972
0
        "unable to obtain write lock on DelayTable '%s': %s", fh->fh_path,
973
0
        strerror(xerrno));
974
0
      pr_fsio_close(fh);
975
976
0
      errno = xerrno;
977
0
      return -1;
978
0
    }
979
980
    /* Seek to the desired table size (actually, one byte less than the
981
     * desired size) and write a single byte, so that there's enough
982
     * allocated backing store on the filesystem to support the ensuing
983
     * mmap() call.
984
     */
985
0
    if (lseek(fh->fh_fd, tab_size-1, SEEK_SET) < 0) {
986
0
      xerrno = errno;
987
988
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
989
0
        ": error seeking to %lu in DelayTable '%s': %s",
990
0
        (unsigned long) tab_size-1, fh->fh_path, strerror(xerrno));
991
0
      pr_trace_msg(trace_channel, 1,
992
0
        "error seeking to %lu in DelayTable '%s': %s",
993
0
        (unsigned long) tab_size-1, fh->fh_path, strerror(xerrno));
994
995
0
      pr_fsio_close(fh);
996
997
0
      errno = xerrno;
998
0
      return -1;
999
0
    }
1000
1001
0
    if (write(fh->fh_fd, "", 1) != 1) {
1002
0
      xerrno = errno;
1003
1004
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1005
0
        ": error writing single byte to DelayTable '%s': %s", fh->fh_path,
1006
0
        strerror(xerrno));
1007
0
      pr_trace_msg(trace_channel, 1,
1008
0
        "error writing single byte to DelayTable '%s': %s", fh->fh_path,
1009
0
        strerror(xerrno));
1010
1011
0
      pr_fsio_close(fh);
1012
1013
0
      errno = xerrno;
1014
0
      return -1;
1015
0
    }
1016
1017
    /* Truncate the table, in case we're shrinking an existing table. */
1018
0
    pr_fsio_ftruncate(fh, tab_size);
1019
1020
0
    pr_trace_msg(trace_channel, 6, "resetting DelayTable '%s'",
1021
0
      delay_tab.dt_path);
1022
0
    delay_table_reset();
1023
1024
0
    lock.l_type = F_UNLCK;
1025
1026
0
    pr_trace_msg(trace_channel, 8, "unlocking DelayTable '%s'", fh->fh_path);
1027
0
    if (fcntl(fh->fh_fd, F_SETLK, &lock) < 0) {
1028
0
      pr_trace_msg(trace_channel, 3,
1029
0
        "error unlocking fd %d: %s", fh->fh_fd, strerror(errno));
1030
0
    }
1031
0
  }
1032
1033
  /* Done */
1034
0
  pr_trace_msg(trace_channel, 8, "unmapping DelayTable '%s' from memory",
1035
0
    delay_tab.dt_path);
1036
0
  if (munmap(delay_tab.dt_data, delay_tab.dt_size) < 0) {
1037
0
    xerrno = errno;
1038
0
    pr_fsio_close(fh);
1039
1040
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1041
0
      ": error unmapping DelayTable '%s': %s", delay_tab.dt_path,
1042
0
      strerror(xerrno));
1043
0
    pr_trace_msg(trace_channel, 1, "error unmapping DelayTable '%s': %s",
1044
0
      delay_tab.dt_path, strerror(xerrno));
1045
1046
0
    errno = xerrno;
1047
0
    return -1;
1048
0
  }
1049
1050
0
  delay_tab.dt_data = NULL;
1051
0
  delay_tab.dt_fd = -1;
1052
1053
0
  if (pr_fsio_close(fh) < 0) {
1054
0
    xerrno = errno;
1055
1056
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1057
0
      ": error closing DelayTable '%s': %s", delay_tab.dt_path,
1058
0
      strerror(xerrno));
1059
0
    pr_trace_msg(trace_channel, 1, "error closing DelayTable '%s': %s",
1060
0
      delay_tab.dt_path, strerror(xerrno));
1061
1062
0
    errno = xerrno;
1063
0
    return -1;
1064
0
  }
1065
1066
0
  return 0;
1067
0
}
1068
1069
0
static int delay_table_load(int lock_table) {
1070
0
  struct flock lock;
1071
1072
0
  if (lock_table == TRUE) {
1073
0
    lock.l_type = F_WRLCK;
1074
0
    lock.l_whence = 0;
1075
0
    lock.l_start = 0;
1076
0
    lock.l_len = 0;
1077
1078
0
    pr_trace_msg(trace_channel, 8, "write-locking DelayTable '%s'",
1079
0
      delay_tab.dt_path);
1080
0
    while (fcntl(delay_tab.dt_fd, F_SETLKW, &lock) < 0) {
1081
0
      if (errno == EINTR) {
1082
0
        pr_signals_handle();
1083
0
        continue;
1084
0
      }
1085
1086
0
      return -1;
1087
0
    }
1088
0
  }
1089
1090
0
  if (delay_tab.dt_data == NULL) {
1091
0
    pr_trace_msg(trace_channel, 8, "mapping DelayTable '%s' (%lu bytes, fd %d) "
1092
0
      "into memory", delay_tab.dt_path, (unsigned long) delay_tab.dt_size,
1093
0
      delay_tab.dt_fd);
1094
0
    delay_tab.dt_data = mmap(NULL, delay_tab.dt_size, PROT_READ|PROT_WRITE,
1095
0
      MAP_SHARED, delay_tab.dt_fd, 0);
1096
1097
0
    if (delay_tab.dt_data == MAP_FAILED) {
1098
0
      int xerrno = errno;
1099
1100
0
      delay_tab.dt_data = NULL;
1101
1102
0
      if (lock_table) {
1103
        /* Make sure we release the lock before returning. */
1104
0
        lock.l_type = F_UNLCK;
1105
0
        lock.l_whence = 0;
1106
0
        lock.l_start = 0;
1107
0
        lock.l_len = 0;
1108
1109
0
        pr_trace_msg(trace_channel, 8, "unlocking DelayTable '%s'",
1110
0
          delay_tab.dt_path);
1111
0
        while (fcntl(delay_tab.dt_fd, F_SETLKW, &lock) < 0) {
1112
0
          if (errno == EINTR) {
1113
0
            pr_signals_handle();
1114
0
            continue;
1115
0
          }
1116
0
        }
1117
0
      }
1118
1119
0
      errno = xerrno;
1120
0
      return -1;
1121
0
    }
1122
0
  }
1123
1124
0
  return 0;
1125
0
}
1126
1127
0
static void delay_table_reset(void) {
1128
0
  server_rec *s;
1129
1130
0
  for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
1131
0
    unsigned int r;
1132
0
    struct delay_rec *row;
1133
0
    struct delay_vals_rec *dv;
1134
0
    const char *ip_str;
1135
1136
0
    ip_str = pr_netaddr_get_ipstr(s->addr);
1137
0
    if (ip_str == NULL) {
1138
0
      continue;
1139
0
    }
1140
1141
    /* Row for USER values */
1142
0
    r = delay_get_user_rownum(s->sid);
1143
0
    row = &((struct delay_rec *) delay_tab.dt_data)[r];
1144
0
    row->d_sid = s->sid;
1145
0
    sstrncpy(row->d_addr, ip_str, sizeof(row->d_addr));
1146
0
    row->d_port = s->ServerPort;
1147
0
    memset(row->d_vals, 0, sizeof(row->d_vals));
1148
1149
    /* Initialize value subsets for "ftp", "ftps", and "ssh2". */
1150
0
    dv = &(row->d_vals[0]);
1151
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1152
0
    sstrcat(dv->dv_proto, "ftp", sizeof(dv->dv_proto));
1153
0
    dv->dv_nvals = 0;
1154
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1155
1156
0
    dv = &(row->d_vals[1]);
1157
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1158
0
    sstrcat(dv->dv_proto, "ftps", sizeof(dv->dv_proto));
1159
0
    dv->dv_nvals = 0;
1160
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1161
1162
0
    dv = &(row->d_vals[2]);
1163
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1164
0
    sstrcat(dv->dv_proto, "ssh2", sizeof(dv->dv_proto));
1165
0
    dv->dv_nvals = 0;
1166
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1167
1168
    /* Row for PASS values */
1169
0
    r = delay_get_pass_rownum(s->sid);
1170
0
    row = &((struct delay_rec *) delay_tab.dt_data)[r];
1171
0
    row->d_sid = s->sid;
1172
0
    sstrncpy(row->d_addr, ip_str, sizeof(row->d_addr));
1173
0
    row->d_port = s->ServerPort;
1174
0
    memset(row->d_vals, 0, sizeof(row->d_vals));
1175
1176
0
    dv = &(row->d_vals[0]);
1177
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1178
0
    sstrcat(dv->dv_proto, "ftp", sizeof(dv->dv_proto));
1179
0
    dv->dv_nvals = 0;
1180
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1181
1182
0
    dv = &(row->d_vals[1]);
1183
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1184
0
    sstrcat(dv->dv_proto, "ftps", sizeof(dv->dv_proto));
1185
0
    dv->dv_nvals = 0;
1186
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1187
1188
0
    dv = &(row->d_vals[2]);
1189
0
    memset(dv->dv_proto, 0, sizeof(dv->dv_proto));
1190
0
    sstrcat(dv->dv_proto, "ssh2", sizeof(dv->dv_proto));
1191
0
    dv->dv_nvals = 0;
1192
0
    memset(dv->dv_vals, -1, sizeof(dv->dv_vals));
1193
0
  }
1194
0
}
1195
1196
0
static int delay_table_wlock(unsigned int rownum) {
1197
0
  struct flock lock;
1198
1199
0
  lock.l_type = F_WRLCK;
1200
0
  lock.l_whence = 0;
1201
0
  lock.l_start = sizeof(struct delay_rec) * rownum;
1202
0
  lock.l_len = sizeof(struct delay_rec);
1203
1204
0
  pr_trace_msg(trace_channel, 8, "write-locking DelayTable '%s', row %u",
1205
0
    delay_tab.dt_path, rownum + 1);
1206
0
  while (fcntl(delay_tab.dt_fd, F_SETLKW, &lock) < 0) {
1207
0
    int xerrno = errno;
1208
1209
0
    if (xerrno == EINTR) {
1210
0
      pr_signals_handle();
1211
0
      continue;
1212
0
    }
1213
1214
0
    pr_trace_msg(trace_channel, 1, "error locking row: %s", strerror(xerrno));
1215
1216
0
    errno = xerrno;
1217
0
    return -1;
1218
0
  }
1219
1220
0
  return 0;
1221
0
}
1222
1223
0
static int delay_table_unload(int unlock_table) {
1224
1225
0
  if (delay_tab.dt_data != NULL) {
1226
0
    pr_trace_msg(trace_channel, 8, "unmapping DelayTable '%s' from memory",
1227
0
      delay_tab.dt_path);
1228
0
    if (munmap(delay_tab.dt_data, delay_tab.dt_size) < 0) {
1229
0
      int xerrno = errno;
1230
1231
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1232
0
        ": error unmapping DelayTable '%s': %s", delay_tab.dt_path,
1233
0
        strerror(xerrno));
1234
0
      pr_trace_msg(trace_channel, 1, "error unmapping DelayTable '%s': %s",
1235
0
        delay_tab.dt_path, strerror(xerrno));
1236
1237
0
      errno = xerrno;
1238
0
      return -1;
1239
0
    }
1240
1241
0
    delay_tab.dt_data = NULL;
1242
0
  }
1243
1244
0
  if (unlock_table == TRUE) {
1245
0
    struct flock lock;
1246
0
    lock.l_type = F_UNLCK;
1247
0
    lock.l_whence = SEEK_SET;
1248
0
    lock.l_start = 0;
1249
0
    lock.l_len = 0;
1250
1251
0
    pr_trace_msg(trace_channel, 8, "unlocking DelayTable '%s'",
1252
0
      delay_tab.dt_path);
1253
0
    while (fcntl(delay_tab.dt_fd, F_SETLK, &lock) < 0) {
1254
0
      if (errno == EINTR) {
1255
0
        pr_signals_handle();
1256
0
        continue;
1257
0
      }
1258
1259
0
      return -1;
1260
0
    }
1261
0
  }
1262
1263
0
  return 0;
1264
0
}
1265
1266
0
static int delay_table_unlock(unsigned int rownum) {
1267
0
  struct flock lock;
1268
1269
0
  lock.l_type = F_UNLCK;
1270
0
  lock.l_whence = 0;
1271
0
  lock.l_start = sizeof(struct delay_rec) * rownum;
1272
0
  lock.l_len = sizeof(struct delay_rec);
1273
1274
0
  pr_trace_msg(trace_channel, 8, "unlocking DelayTable '%s', row %u",
1275
0
    delay_tab.dt_path, rownum + 1);
1276
0
  while (fcntl(delay_tab.dt_fd, F_SETLKW, &lock) < 0) {
1277
0
    int xerrno = errno;
1278
1279
0
    if (xerrno == EINTR) {
1280
0
      pr_signals_handle();
1281
0
      continue;
1282
0
    }
1283
1284
0
    pr_trace_msg(trace_channel, 1, "error unlocking row: %s", strerror(xerrno));
1285
1286
0
    errno = xerrno;
1287
0
    return -1;
1288
0
  }
1289
1290
0
  return 0;
1291
0
}
1292
1293
#if defined(PR_USE_CTRLS)
1294
1295
/* Control handlers
1296
 */
1297
1298
static int delay_handle_info(pr_ctrls_t *ctrl, int reqargc,
1299
0
    char **reqargv) {
1300
0
  register server_rec *s;
1301
0
  pool *tmp_pool;
1302
0
  pr_fh_t *fh;
1303
0
  char *vals;
1304
0
  int xerrno = 0;
1305
1306
0
  PRIVS_ROOT
1307
0
  fh = pr_fsio_open(delay_tab.dt_path, O_RDWR);
1308
0
  xerrno = errno;
1309
0
  PRIVS_RELINQUISH
1310
1311
0
  if (fh == NULL) {
1312
0
    pr_ctrls_add_response(ctrl,
1313
0
      "warning: unable to open DelayTable '%s': %s", delay_tab.dt_path,
1314
0
      strerror(xerrno));
1315
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1316
0
  }
1317
1318
0
  delay_tab.dt_fd = fh->fh_fd;
1319
0
  delay_tab.dt_data = NULL;
1320
1321
0
  if (delay_table_load(TRUE) < 0) {
1322
0
    xerrno = errno;
1323
1324
0
    pr_ctrls_add_response(ctrl,
1325
0
      "unable to load DelayTable '%s' (fd %d) into memory: %s",
1326
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1327
0
    pr_trace_msg(trace_channel, 1,
1328
0
      "unable to load DelayTable '%s' (fd %d) into memory: %s",
1329
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1330
1331
0
    pr_fsio_close(fh);
1332
0
    delay_tab.dt_fd = -1;
1333
0
    delay_tab.dt_data = NULL;
1334
1335
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1336
0
  }
1337
1338
0
  tmp_pool = make_sub_pool(delay_pool);
1339
1340
0
  for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
1341
0
    unsigned int r;
1342
0
    register unsigned int i;
1343
0
    struct delay_rec *row;
1344
1345
    /* Row for USER values */
1346
0
    r = delay_get_user_rownum(s->sid);
1347
0
    row = &((struct delay_rec *) delay_tab.dt_data)[r];
1348
0
    pr_ctrls_add_response(ctrl, "Address %s#%u: USER values (usecs):",
1349
0
      row->d_addr, row->d_port);
1350
1351
0
    for (i = 0; i < DELAY_NPROTO; i++) {
1352
0
      struct delay_vals_rec *dv;
1353
0
      register unsigned int j;
1354
1355
0
      dv = &(row->d_vals[i]);
1356
1357
0
      if ((dv->dv_proto)[0] == '\0') {
1358
0
        continue;
1359
0
      }
1360
1361
0
      pr_ctrls_add_response(ctrl, " + Protocol %s, %u values:", dv->dv_proto,
1362
0
        dv->dv_nvals);
1363
1364
      /* Start at the end of the row and work backward, as values are
1365
       * always added at the end of the row, shifting everything to the left.
1366
       */
1367
0
      vals = "";
1368
0
      for (j = 0; j < dv->dv_nvals; j++) {
1369
0
        char buf[80];
1370
1371
0
        memset(buf, '\0', sizeof(buf));
1372
0
        pr_snprintf(buf, sizeof(buf)-1, "%10ld",
1373
0
          dv->dv_vals[DELAY_NVALUES - 1 - j]);
1374
1375
0
        vals = pstrcat(tmp_pool, vals, " ", buf, NULL);
1376
1377
0
        if (j != 0 &&
1378
0
            j % 4 == 0) {
1379
0
          pr_ctrls_add_response(ctrl, "    %s", vals);
1380
0
          vals = "";
1381
0
        }
1382
0
      }
1383
1384
0
      if (strlen(vals) > 0) {
1385
0
        pr_ctrls_add_response(ctrl, "    %s", vals);
1386
0
      }
1387
0
    }
1388
1389
0
    pr_ctrls_add_response(ctrl, "%s", "");
1390
1391
    /* Row for PASS values */
1392
0
    r = delay_get_pass_rownum(s->sid);
1393
0
    row = &((struct delay_rec *) delay_tab.dt_data)[r];
1394
0
    pr_ctrls_add_response(ctrl, "Address %s#%u: PASS values (usecs):",
1395
0
      row->d_addr, row->d_port);
1396
1397
0
    for (i = 0; i < DELAY_NPROTO; i++) {
1398
0
      struct delay_vals_rec *dv;
1399
0
      register unsigned int j;
1400
1401
0
      dv = &(row->d_vals[i]);
1402
1403
0
      if ((dv->dv_proto)[0] == '\0') {
1404
0
        continue;
1405
0
      }
1406
1407
0
      pr_ctrls_add_response(ctrl, " + Protocol %s, %u values:", dv->dv_proto,
1408
0
        dv->dv_nvals);
1409
1410
0
      vals = "";
1411
0
      for (j = 0; j < dv->dv_nvals; j++) {
1412
0
        char buf[80];
1413
1414
0
        memset(buf, '\0', sizeof(buf));
1415
0
        pr_snprintf(buf, sizeof(buf)-1, "%10ld",
1416
0
          dv->dv_vals[DELAY_NVALUES - 1 - j]);
1417
1418
0
        vals = pstrcat(tmp_pool, vals, " ", buf, NULL);
1419
1420
0
        if (j != 0 &&
1421
0
            j % 4 == 0) {
1422
0
          pr_ctrls_add_response(ctrl, "    %s", vals);
1423
0
          vals = "";
1424
0
        }
1425
0
      }
1426
1427
0
      if (strlen(vals) > 0) {
1428
0
        pr_ctrls_add_response(ctrl, "    %s", vals);
1429
0
      }
1430
0
    }
1431
1432
0
    pr_ctrls_add_response(ctrl, "%s", "");
1433
0
  }
1434
1435
0
  if (delay_table_unload(TRUE) < 0) {
1436
0
    pr_ctrls_add_response(ctrl,
1437
0
      "unable to unload DelayTable '%s' from memory: %s",
1438
0
      delay_tab.dt_path, strerror(errno));
1439
0
  }
1440
1441
0
  pr_fsio_close(fh);
1442
1443
0
  delay_tab.dt_fd = -1;
1444
0
  delay_tab.dt_data = NULL;
1445
1446
0
  destroy_pool(tmp_pool);
1447
0
  return PR_CTRLS_STATUS_OK;
1448
0
}
1449
1450
static int delay_handle_reset(pr_ctrls_t *ctrl, int reqargc,
1451
0
    char **reqarg) {
1452
0
  struct flock lock;
1453
0
  pr_fh_t *fh;
1454
0
  int xerrno = 0;
1455
1456
0
  PRIVS_ROOT
1457
0
  fh = pr_fsio_open(delay_tab.dt_path, O_RDWR);
1458
0
  xerrno = errno;
1459
0
  PRIVS_RELINQUISH
1460
1461
0
  if (fh == NULL) {
1462
0
    pr_ctrls_add_response(ctrl,
1463
0
      "unable to open DelayTable '%s': %s", delay_tab.dt_path,
1464
0
      strerror(xerrno));
1465
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1466
0
  }
1467
1468
0
  lock.l_type = F_WRLCK;
1469
0
  lock.l_whence = 0;
1470
0
  lock.l_start = 0;
1471
0
  lock.l_len = 0;
1472
1473
0
  while (fcntl(fh->fh_fd, F_SETLKW, &lock) < 0) {
1474
0
    xerrno = errno;
1475
1476
0
    if (xerrno == EINTR) {
1477
0
      pr_signals_handle();
1478
0
      continue;
1479
0
    }
1480
1481
0
    pr_ctrls_add_response(ctrl,
1482
0
      "unable to obtain write lock on DelayTable '%s': %s",
1483
0
       fh->fh_path, strerror(xerrno));
1484
0
    pr_fsio_close(fh);
1485
1486
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1487
0
  }
1488
1489
0
  if (pr_fsio_ftruncate(fh, 0) < 0) {
1490
0
    xerrno = errno;
1491
1492
0
    pr_ctrls_add_response(ctrl,
1493
0
      "error truncating DelayTable '%s': %s", fh->fh_path, strerror(xerrno));
1494
0
    pr_fsio_close(fh);
1495
1496
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1497
0
  }
1498
1499
0
  lock.l_type = F_UNLCK;
1500
0
  if (fcntl(fh->fh_fd, F_SETLK, &lock) < 0) {
1501
0
    pr_trace_msg(trace_channel, 3,
1502
0
      "error unlocking fd %d: %s", fh->fh_fd, strerror(errno));
1503
0
  }
1504
1505
0
  if (pr_fsio_close(fh) < 0) {
1506
0
    xerrno = errno;
1507
1508
0
    pr_ctrls_add_response(ctrl,
1509
0
      "error closing DelayTable '%s': %s", delay_tab.dt_path,
1510
0
      strerror(xerrno));
1511
1512
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
1513
0
  }
1514
1515
0
  pr_ctrls_add_response(ctrl, "DelayTable '%s' reset", delay_tab.dt_path);
1516
0
  return PR_CTRLS_STATUS_OK;
1517
0
}
1518
1519
static int delay_handle_delay(pr_ctrls_t *ctrl, int reqargc,
1520
0
    char **reqargv) {
1521
1522
0
  if (delay_tab.dt_enabled == FALSE) {
1523
0
    pr_ctrls_add_response(ctrl, "delay: DelayTable disabled");
1524
0
    return PR_CTRLS_STATUS_OPERATION_DENIED;
1525
0
  }
1526
1527
0
  if (reqargc == 0 ||
1528
0
      reqargv == NULL) {
1529
0
    pr_ctrls_add_response(ctrl, "delay: missing required parameters");
1530
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
1531
0
  }
1532
1533
0
  if (strcmp(reqargv[0], "info") == 0) {
1534
0
    if (pr_ctrls_check_acl(ctrl, delay_acttab, "info") != TRUE) {
1535
0
      pr_ctrls_add_response(ctrl, "access denied");
1536
0
      return PR_CTRLS_STATUS_ACCESS_DENIED;
1537
0
    }
1538
1539
0
    return delay_handle_info(ctrl, --reqargc, ++reqargv);
1540
1541
0
  } else if (strcmp(reqargv[0], "reset") == 0) {
1542
0
    if (pr_ctrls_check_acl(ctrl, delay_acttab, "reset") != TRUE) {
1543
0
      pr_ctrls_add_response(ctrl, "access denied");
1544
0
      return PR_CTRLS_STATUS_ACCESS_DENIED;
1545
0
    }
1546
1547
0
    return delay_handle_reset(ctrl, --reqargc, ++reqargv);
1548
0
  }
1549
1550
0
  pr_ctrls_add_response(ctrl, "unknown delay action: '%s'", reqargv[0]);
1551
0
  return PR_CTRLS_STATUS_UNSUPPORTED_OPERATION;
1552
0
}
1553
#endif /* PR_USE_CTRLS */
1554
1555
/* Configuration handlers
1556
 */
1557
1558
/* usage: DelayControlsACLs actions|all allow|deny user|group list */
1559
0
MODRET set_delayctrlsacls(cmd_rec *cmd) {
1560
0
#if defined(PR_USE_CTRLS)
1561
0
  char *bad_action = NULL, **actions = NULL;
1562
1563
0
  CHECK_ARGS(cmd, 4);
1564
0
  CHECK_CONF(cmd, CONF_ROOT);
1565
1566
0
  actions = pr_ctrls_parse_acl(cmd->tmp_pool, cmd->argv[1]);
1567
1568
  /* Check the second parameter to make sure it is "allow" or "deny" */
1569
0
  if (strcmp(cmd->argv[2], "allow") != 0 &&
1570
0
      strcmp(cmd->argv[2], "deny") != 0) {
1571
0
    CONF_ERROR(cmd, "second parameter must be 'allow' or 'deny'");
1572
0
  }
1573
1574
  /* Check the third parameter to make sure it is "user" or "group" */
1575
0
  if (strcmp(cmd->argv[3], "user") != 0 &&
1576
0
      strcmp(cmd->argv[3], "group") != 0) {
1577
0
    CONF_ERROR(cmd, "third parameter must be 'user' or 'group'");
1578
0
  }
1579
1580
0
  bad_action = pr_ctrls_set_module_acls(delay_acttab, delay_pool, actions,
1581
0
    cmd->argv[2], cmd->argv[3], cmd->argv[4]);
1582
0
  if (bad_action != NULL) {
1583
0
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown delay action: '",
1584
0
      bad_action, "'", NULL));
1585
0
  }
1586
1587
0
  return PR_HANDLED(cmd);
1588
#else
1589
  CONF_ERROR(cmd, "requires Controls support (--enable-ctrls)")
1590
#endif /* PR_USE_CTRLS */
1591
0
}
1592
1593
/* usage: DelayEngine on|off */
1594
0
MODRET set_delayengine(cmd_rec *cmd) {
1595
0
  config_rec *c;
1596
0
  int engine;
1597
1598
0
  CHECK_ARGS(cmd, 1);
1599
0
  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1600
1601
0
  engine = get_boolean(cmd, 1);
1602
0
  if (engine == -1) {
1603
0
    CONF_ERROR(cmd, "expected Boolean parameter");
1604
0
  }
1605
1606
0
  c = add_config_param(cmd->argv[0], 1, NULL);
1607
0
  c->argv[0] = pcalloc(c->pool, sizeof(unsigned int));
1608
0
  *((unsigned int *) c->argv[0]) = engine;
1609
1610
0
  return PR_HANDLED(cmd);
1611
0
}
1612
1613
/* usage: DelayOnEvent event delay-millis|min-max */
1614
0
MODRET set_delayonevent(cmd_rec *cmd) {
1615
0
  config_rec *c;
1616
0
  long min_delay_ms = -1, max_delay_ms = -1;
1617
0
  int event;
1618
1619
0
  CHECK_ARGS(cmd, 2);
1620
0
  CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
1621
1622
0
  if (strcmp(cmd->argv[1], "USER") == 0) {
1623
0
    event = DELAY_EVENT_USER_CMD;
1624
1625
0
  } else if (strcmp(cmd->argv[1], "PASS") == 0) {
1626
0
    event = DELAY_EVENT_PASS_CMD;
1627
1628
0
  } else if (strcmp(cmd->argv[1], "FailedLogin") == 0) {
1629
0
    event = DELAY_EVENT_FAILED_LOGIN;
1630
1631
0
  } else if (strcmp(cmd->argv[1], "Connect") == 0) {
1632
0
    event = DELAY_EVENT_CONNECT;
1633
1634
0
  } else {
1635
0
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unknown/unsupported event: ",
1636
0
      cmd->argv[1], NULL));
1637
0
  }
1638
1639
0
  if (delay_str_get_duration_ms(cmd->argv[2], &min_delay_ms,
1640
0
      &max_delay_ms) < 0) {
1641
0
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "error parsing delay parameter '",
1642
0
      cmd->argv[2], "': ", strerror(errno), NULL));
1643
0
  }
1644
1645
0
  c = add_config_param(cmd->argv[0], 3, NULL, NULL, NULL);
1646
0
  c->argv[0] = palloc(c->pool, sizeof(int));
1647
0
  *((int *) c->argv[0]) = event;
1648
0
  c->argv[1] = palloc(c->pool, sizeof(unsigned long));
1649
0
  c->argv[2] = palloc(c->pool, sizeof(unsigned long));
1650
1651
  /* Note: Even though we parsed the delay parameter in millisec, we
1652
   * need to use microsecs internally, as that is the implemented interface.
1653
   */
1654
0
  *((unsigned long *) c->argv[1]) = (min_delay_ms * 1000);
1655
0
  *((unsigned long *) c->argv[2]) = (max_delay_ms * 1000);
1656
1657
0
  if (pr_module_exists("mod_ifsession.c")) {
1658
    /* These are needed in case this directive is used with mod_ifsession
1659
     * configuration.
1660
     */
1661
0
    c->flags |= CF_MULTI;
1662
0
  }
1663
1664
0
  return PR_HANDLED(cmd);
1665
0
}
1666
1667
/* usage: DelayTable path|"none" */
1668
0
MODRET set_delaytable(cmd_rec *cmd) {
1669
0
  const char *table = NULL;
1670
1671
0
  CHECK_ARGS(cmd, 1);
1672
0
  CHECK_CONF(cmd, CONF_ROOT);
1673
1674
0
  if (pr_fs_valid_path(cmd->argv[1]) < 0) {
1675
0
    if (strcasecmp(cmd->argv[1], "none") != 0) {
1676
0
      CONF_ERROR(cmd, "must be an absolute path");
1677
0
    }
1678
1679
0
  } else {
1680
0
    table = cmd->argv[1];
1681
0
  }
1682
1683
0
  add_config_param_str(cmd->argv[0], 1, table);
1684
0
  return PR_HANDLED(cmd);
1685
0
}
1686
1687
/* Command handlers
1688
 */
1689
1690
0
MODRET delay_log_pass(cmd_rec *cmd) {
1691
0
  if (delay_engine == FALSE) {
1692
0
    return PR_DECLINED(cmd);
1693
0
  }
1694
1695
0
  if (delay_pass_min_delay > 0) {
1696
0
    unsigned long interval = 0L;
1697
1698
0
    if (delay_pass_delayed < delay_pass_min_delay) {
1699
0
      interval = delay_pass_min_delay - delay_pass_delayed;
1700
0
    }
1701
1702
0
    if (interval > 0) {
1703
0
      pr_trace_msg(trace_channel, 9,
1704
0
        "enforcing minimum PASS delay (%lu usec), adding %ld usec delay",
1705
0
        delay_pass_min_delay, interval);
1706
0
      delay_inject_delay(interval);
1707
0
    }
1708
0
  }
1709
1710
0
  return PR_DECLINED(cmd);
1711
0
}
1712
1713
0
MODRET delay_log_pass_err(cmd_rec *cmd) {
1714
0
  if (delay_engine == FALSE) {
1715
0
    return PR_DECLINED(cmd);
1716
0
  }
1717
1718
0
  if (delay_failed_login_min_delay > 0 ||
1719
0
      delay_pass_min_delay > 0) {
1720
0
    unsigned long interval = 0L, min_delay;
1721
1722
0
    min_delay = delay_failed_login_min_delay;
1723
0
    if (delay_pass_min_delay > min_delay) {
1724
0
      min_delay = delay_pass_min_delay;
1725
0
    }
1726
1727
0
    if (delay_pass_delayed < min_delay) {
1728
0
      interval = min_delay - delay_pass_delayed;
1729
0
    }
1730
1731
0
    if (interval > 0) {
1732
0
      pr_trace_msg(trace_channel, 9,
1733
0
        "enforcing minimum failed login delay (%lu usec), adding %ld usec "
1734
0
        "delay", delay_failed_login_min_delay, interval);
1735
0
      delay_inject_delay(interval);
1736
0
    }
1737
0
  }
1738
1739
0
  return PR_DECLINED(cmd);
1740
0
}
1741
1742
0
MODRET delay_log_user(cmd_rec *cmd) {
1743
0
  if (delay_engine == FALSE) {
1744
0
    return PR_DECLINED(cmd);
1745
0
  }
1746
1747
0
  if (delay_user_min_delay > 0) {
1748
0
    long interval = 0L;
1749
1750
0
    if (delay_user_delayed < delay_user_min_delay) {
1751
0
      interval = delay_user_min_delay - delay_user_delayed;
1752
0
    }
1753
1754
0
    if (interval > 0) {
1755
0
      pr_trace_msg(trace_channel, 9,
1756
0
        "enforcing minimum USER delay (%lu usec), adding %ld usec delay",
1757
0
        delay_user_min_delay, interval);
1758
0
      delay_inject_delay(interval);
1759
0
    }
1760
0
  }
1761
1762
0
  return PR_DECLINED(cmd);
1763
0
}
1764
1765
0
MODRET delay_post_pass(cmd_rec *cmd) {
1766
0
  struct timeval tv;
1767
0
  unsigned int rownum;
1768
0
  long interval, median;
1769
0
  const char *proto;
1770
0
  unsigned char *authenticated;
1771
1772
0
  if (delay_engine == FALSE ||
1773
0
      delay_tab.dt_enabled == FALSE) {
1774
0
    return PR_DECLINED(cmd);
1775
0
  }
1776
1777
  /* Has the client already authenticated? */
1778
0
  authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
1779
0
  if (authenticated != NULL &&
1780
0
      *authenticated == TRUE) {
1781
0
    return PR_DECLINED(cmd);
1782
0
  }
1783
1784
0
  rownum = delay_get_pass_rownum(main_server->sid);
1785
1786
  /* Prepare for manipulating the table. */
1787
0
  if (delay_table_load(FALSE) < 0) {
1788
0
    int xerrno = errno;
1789
1790
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1791
0
      ": unable to load DelayTable '%s' (fd %d) into memory: %s",
1792
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1793
0
    pr_trace_msg(trace_channel, 1,
1794
0
      "unable to load DelayTable '%s' (fd %d) into memory: %s",
1795
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1796
1797
0
    errno = xerrno;
1798
0
    return PR_DECLINED(cmd);
1799
0
  }
1800
1801
0
  memset(&tv, 0, sizeof(tv));
1802
0
  gettimeofday(&tv, NULL);
1803
1804
0
  delay_table_wlock(rownum);
1805
1806
0
  interval = (tv.tv_sec - delay_tv.tv_sec) * 1000000 +
1807
0
    (tv.tv_usec - delay_tv.tv_usec);
1808
0
  pr_trace_msg(trace_channel, 9,
1809
0
    "interval between USER and PASS commands: %ld usecs", interval);
1810
1811
0
  proto = pr_session_get_protocol(0);
1812
1813
  /* Get the median interval value. */
1814
0
  median = delay_get_median(cmd->tmp_pool, rownum, proto, interval);
1815
1816
  /* Add the interval to the table. Only allow a single session to
1817
   * add a portion of the cache size, to prevent a single client from
1818
   * poisoning the cache.
1819
   */
1820
0
  if (delay_npass < (DELAY_NVALUES / DELAY_SESS_NVALUES)) {
1821
0
    pr_trace_msg(trace_channel, 8, "adding %ld usecs to PASS row", interval);
1822
0
    delay_table_add_interval(rownum, proto, interval);
1823
0
    delay_npass++;
1824
1825
0
  } else {
1826
    /* Generate an event, in case a module (i.e. mod_ban) might want
1827
     * to do something appropriate to such an ill-behaved client.
1828
     */
1829
0
    pr_event_generate("mod_delay.max-pass", session.c);
1830
0
  }
1831
1832
  /* Done with the table. */
1833
0
  delay_table_unlock(rownum);
1834
0
  if (delay_table_unload(FALSE) < 0) {
1835
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1836
0
      ": unable to unload DelayTable '%s' from memory: %s",
1837
0
      delay_tab.dt_path, strerror(errno));
1838
0
  }
1839
1840
  /* If this is a POST_CMD phase, then close the table.  If the phase is
1841
   * POST_CMD_ERR, then leave the table open; the client may send another
1842
   * set of USER/PASS commands.
1843
   */
1844
0
  if (session.curr_phase == POST_CMD) {
1845
0
    (void) close(delay_tab.dt_fd);
1846
0
    delay_tab.dt_fd = -1;
1847
0
  }
1848
1849
  /* If the current interval is less than the median interval (and a valid
1850
   * median interval was selected), we need to delay ourselves a little.
1851
   */
1852
0
  if (median >= 0) {
1853
0
    if (interval < median) {
1854
0
      pr_trace_msg(trace_channel, 9,
1855
0
        "interval (%ld usecs) less than selected median (%ld usecs), delaying",
1856
0
        interval, median);
1857
0
      delay_pass_delayed = delay_inject_delay_with_jitter(median - interval, 0);
1858
0
    }
1859
1860
0
  } else {
1861
0
    pr_trace_msg(trace_channel, 9,
1862
0
      "invalid median value (%ld usecs) selected, ignoring", median);
1863
0
  }
1864
1865
0
  return PR_DECLINED(cmd);
1866
0
}
1867
1868
0
MODRET delay_pre_pass(cmd_rec *cmd) {
1869
0
  if (delay_engine == FALSE) {
1870
0
    return PR_DECLINED(cmd);
1871
0
  }
1872
1873
  /* Always reset the USER delayed value. */
1874
0
  delay_pass_delayed = 0L;
1875
1876
0
  gettimeofday(&delay_tv, NULL);
1877
0
  return PR_DECLINED(cmd);
1878
0
}
1879
1880
0
MODRET delay_post_user(cmd_rec *cmd) {
1881
0
  struct timeval tv;
1882
0
  unsigned int rownum;
1883
0
  long interval = 0L, median = 0L;
1884
0
  const char *proto;
1885
0
  unsigned char *authenticated;
1886
1887
0
  if (delay_engine == FALSE ||
1888
0
      delay_tab.dt_enabled == FALSE) {
1889
0
    return PR_DECLINED(cmd);
1890
0
  }
1891
1892
  /* Has the client already authenticated? */
1893
0
  authenticated = get_param_ptr(cmd->server->conf, "authenticated", FALSE);
1894
0
  if (authenticated != NULL &&
1895
0
      *authenticated == TRUE) {
1896
0
    return PR_DECLINED(cmd);
1897
0
  }
1898
1899
0
  rownum = delay_get_user_rownum(main_server->sid);
1900
1901
  /* Prepare for manipulating the table. */
1902
0
  if (delay_table_load(FALSE) < 0) {
1903
0
    int xerrno = errno;
1904
1905
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1906
0
      ": unable to load DelayTable '%s' (fd %d) into memory: %s",
1907
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1908
0
    pr_trace_msg(trace_channel, 1,
1909
0
      "unable to load DelayTable '%s' (fd %d) into memory: %s",
1910
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
1911
1912
0
    errno = xerrno;
1913
0
    return PR_DECLINED(cmd);
1914
0
  }
1915
1916
0
  memset(&tv, 0, sizeof(tv));
1917
0
  gettimeofday(&tv, NULL);
1918
1919
0
  delay_table_wlock(rownum);
1920
1921
0
  interval = (tv.tv_sec - delay_tv.tv_sec) * 1000000 +
1922
0
    (tv.tv_usec - delay_tv.tv_usec);
1923
1924
  /* There can conceivably be quite a bit of time between connect and USER,
1925
   * e.g. for TLS handshakes, DNS lookups, user latency, etc.  Thus we put
1926
   * a bound on this interval at 60 seconds.  For the most part, this will
1927
   * not affect the selected median value -- expect when the DelayTable
1928
   * is empty, and this is the only value present.
1929
   */
1930
0
  if (interval > DELAY_MAX_CONNECT_INTERVAL_USECS) {
1931
0
    interval = DELAY_MAX_CONNECT_INTERVAL_USECS;
1932
0
  }
1933
1934
0
  pr_trace_msg(trace_channel, 9,
1935
0
    "interval between connect and USER command: %ld usecs", interval);
1936
1937
0
  proto = pr_session_get_protocol(0);
1938
1939
  /* Get the median interval value. */
1940
0
  median = delay_get_median(cmd->tmp_pool, rownum, proto, interval);
1941
1942
  /* Add the interval to the table. Only allow a single session to
1943
   * add a portion of the cache size, to prevent a single client from
1944
   * poisoning the cache.
1945
   */
1946
0
  if (delay_nuser < (DELAY_NVALUES / DELAY_SESS_NVALUES)) {
1947
0
    pr_trace_msg(trace_channel, 8, "adding %ld usecs to USER row", interval);
1948
0
    delay_table_add_interval(rownum, proto, interval);
1949
0
    delay_nuser++;
1950
1951
0
  } else {
1952
    /* Generate an event, in case a module (i.e. mod_ban) might want
1953
     * to do something appropriate to such an ill-behaved client.
1954
     */
1955
0
    pr_event_generate("mod_delay.max-user", session.c);
1956
0
  }
1957
1958
  /* Done with the table. */
1959
0
  delay_table_unlock(rownum);
1960
0
  if (delay_table_unload(FALSE) < 0) {
1961
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
1962
0
      ": unable to unload DelayTable '%s' from memory: %s",
1963
0
      delay_tab.dt_path, strerror(errno));
1964
0
  }
1965
1966
  /* If the current interval is less than the median interval (and a valid
1967
   * median interval was selected), we need to delay ourselves a little.
1968
   */
1969
0
  if (median >= 0) {
1970
0
    if (interval < median) {
1971
0
      pr_trace_msg(trace_channel, 9,
1972
0
        "interval (%ld usecs) less than selected median (%ld usecs), delaying",
1973
0
        interval, median);
1974
0
      delay_user_delayed = delay_inject_delay_with_jitter(median - interval, 0);
1975
0
    }
1976
1977
0
  } else {
1978
0
    pr_trace_msg(trace_channel, 9,
1979
0
      "invalid median value (%ld usecs) selected, ignoring", median);
1980
0
  }
1981
1982
0
  return PR_DECLINED(cmd);
1983
0
}
1984
1985
0
MODRET delay_pre_user(cmd_rec *cmd) {
1986
0
  if (delay_engine == FALSE) {
1987
0
    return PR_DECLINED(cmd);
1988
0
  }
1989
1990
  /* Always reset the USER delayed value. */
1991
0
  delay_user_delayed = 0L;
1992
1993
0
  gettimeofday(&delay_tv, NULL);
1994
0
  return PR_DECLINED(cmd);
1995
0
}
1996
1997
/* Event listeners
1998
 */
1999
2000
0
static void delay_connect_ev(const void *event_data, void *user_data) {
2001
0
  config_rec *c;
2002
2003
0
  if (delay_engine == FALSE) {
2004
0
    return;
2005
0
  }
2006
2007
0
  c = find_config(main_server->conf, CONF_PARAM, "DelayOnEvent", FALSE);
2008
0
  while (c != NULL) {
2009
0
    int event;
2010
0
    unsigned long min_delay_usec, max_delay_usec;
2011
2012
0
    pr_signals_handle();
2013
2014
0
    event = *((int *) c->argv[0]);
2015
0
    min_delay_usec = *((unsigned long *) c->argv[1]);
2016
0
    max_delay_usec = *((unsigned long *) c->argv[2]);
2017
2018
0
    if (event == DELAY_EVENT_CONNECT) {
2019
0
      delay_connect_min_delay = min_delay_usec;
2020
0
      delay_connect_max_delay = max_delay_usec;
2021
0
    }
2022
2023
0
    c = find_config_next(c, c->next, CONF_PARAM, "DelayOnEvent", FALSE);
2024
0
  }
2025
2026
0
  (void) delay_inject_delay_with_jitter(delay_connect_min_delay,
2027
0
    (delay_connect_max_delay - delay_connect_min_delay));
2028
0
}
2029
2030
#if defined(PR_SHARED_MODULE)
2031
static void delay_mod_unload_ev(const void *event_data, void *user_data) {
2032
  if (strcmp("mod_delay.c", (const char *) event_data) != 0) {
2033
    return;
2034
  }
2035
2036
  /* Unregister ourselves from all events. */
2037
  pr_event_unregister(&delay_module, NULL, NULL);
2038
2039
# if defined(PR_USE_CTRLS)
2040
  pr_ctrls_unregister(&delay_module, "delay");
2041
# endif /* PR_USE_CTRLS */
2042
}
2043
#endif /* PR_SHARED_MODULE */
2044
2045
0
static void delay_postparse_ev(const void *event_data, void *user_data) {
2046
0
  config_rec *c;
2047
2048
0
  c = find_config(main_server->conf, CONF_PARAM, "DelayEngine", FALSE);
2049
0
  if (c != NULL &&
2050
0
      *((unsigned int *) c->argv[0]) == FALSE) {
2051
0
    delay_engine = FALSE;
2052
0
  }
2053
2054
0
  if (delay_engine == FALSE) {
2055
0
    return;
2056
0
  }
2057
2058
0
  c = find_config(main_server->conf, CONF_PARAM, "DelayTable", FALSE);
2059
0
  if (c != NULL) {
2060
0
    const char *table = NULL;
2061
2062
0
    table = c->argv[0];
2063
0
    if (table != NULL) {
2064
0
      delay_tab.dt_enabled = TRUE;
2065
0
      delay_tab.dt_path = table;
2066
2067
0
    } else {
2068
0
      delay_tab.dt_enabled = FALSE;
2069
0
    }
2070
0
  }
2071
2072
0
  if (delay_tab.dt_enabled == TRUE) {
2073
0
    (void) delay_table_init();
2074
0
  }
2075
0
}
2076
2077
0
static void delay_restart_ev(const void *event_data, void *user_data) {
2078
0
#if defined(PR_USE_CTRLS)
2079
0
    register unsigned int i;
2080
0
#endif /* PR_USE_CTRLS */
2081
2082
0
  delay_tab.dt_path = PR_RUN_DIR "/proftpd.delay";
2083
0
  delay_tab.dt_data = NULL;
2084
0
  delay_tab.dt_lookup = NULL;
2085
0
  delay_tab.dt_enabled = TRUE;
2086
2087
0
  if (delay_pool != NULL) {
2088
0
    destroy_pool(delay_pool);
2089
0
  }
2090
2091
0
  delay_pool = make_sub_pool(permanent_pool);
2092
0
  pr_pool_tag(delay_pool, MOD_DELAY_VERSION);
2093
2094
0
#if defined(PR_USE_CTRLS)
2095
0
  for (i = 0; delay_acttab[i].act_action; i++) {
2096
0
    delay_acttab[i].act_acl = pcalloc(delay_pool, sizeof(ctrls_acl_t));
2097
0
    pr_ctrls_init_acl(delay_acttab[i].act_acl);
2098
0
  }
2099
0
#endif /* PR_USE_CTRLS */
2100
0
}
2101
2102
0
static void delay_sess_reinit_ev(const void *event_data, void *user_data) {
2103
0
  int res;
2104
2105
  /* A HOST command changed the main_server pointer, reinitialize ourselves. */
2106
2107
0
  pr_event_unregister(&delay_module, "core.session-reinit",
2108
0
    delay_sess_reinit_ev);
2109
2110
0
  delay_engine = TRUE;
2111
2112
0
  if (delay_tab.dt_fd > 0) {
2113
0
    close(delay_tab.dt_fd);
2114
0
    delay_tab.dt_fd = -1;
2115
0
  }
2116
2117
0
  delay_nuser = 0;
2118
0
  delay_npass = 0;
2119
2120
0
  res = delay_sess_init();
2121
0
  if (res < 0) {
2122
0
    pr_session_disconnect(&delay_module,
2123
0
      PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
2124
0
  }
2125
0
}
2126
2127
0
static void delay_shutdown_ev(const void *event_data, void *user_data) {
2128
0
  pr_fh_t *fh = NULL;
2129
0
  char *data = NULL;
2130
0
  size_t datalen = 0;
2131
0
  int xerrno = 0;
2132
2133
0
  if (delay_engine == FALSE ||
2134
0
      delay_tab.dt_enabled == FALSE) {
2135
0
    return;
2136
0
  }
2137
2138
  /* Write out the DelayTable to the filesystem, thus updating the
2139
   * file metadata.
2140
   */
2141
2142
0
  PRIVS_ROOT
2143
0
  fh = pr_fsio_open(delay_tab.dt_path, O_RDWR);
2144
0
  xerrno = errno;
2145
0
  PRIVS_RELINQUISH
2146
2147
0
  if (fh == NULL) {
2148
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2149
0
      ": unable to open DelayTable '%s': %s", delay_tab.dt_path,
2150
0
      strerror(xerrno));
2151
0
    errno = xerrno;
2152
0
    return;
2153
0
  }
2154
2155
0
  delay_tab.dt_fd = fh->fh_fd;
2156
0
  delay_tab.dt_data = NULL;
2157
2158
0
  if (delay_table_load(TRUE) < 0) {
2159
0
    xerrno = errno;
2160
0
    pr_fsio_close(fh);
2161
2162
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2163
0
      ": unable to load DelayTable '%s' (fd %d) into memory: %s",
2164
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
2165
0
    pr_trace_msg(trace_channel, 1,
2166
0
      "unable to load DelayTable '%s' (fd %d) into memory: %s",
2167
0
      delay_tab.dt_path, delay_tab.dt_fd, strerror(xerrno));
2168
2169
0
    errno = xerrno;
2170
0
    return;
2171
0
  }
2172
2173
0
  datalen = delay_tab.dt_size;
2174
0
  data = palloc(delay_pool, datalen);
2175
0
  if (data != NULL &&
2176
0
      datalen > 0) {
2177
0
    memcpy(data, delay_tab.dt_data, datalen);
2178
0
  }
2179
2180
0
  if (delay_table_unload(TRUE) < 0) {
2181
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2182
0
      ": error unloading DelayTable '%s' from memory: %s",
2183
0
      delay_tab.dt_path, strerror(errno));
2184
0
  }
2185
2186
0
  if (data != NULL &&
2187
0
      datalen > 0) {
2188
0
    if (pr_fsio_write(fh, data, datalen) < 0) {
2189
0
      pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2190
0
        ": error updating DelayTable '%s': %s", delay_tab.dt_path,
2191
0
        strerror(errno));
2192
0
    }
2193
0
  }
2194
2195
0
  delay_tab.dt_fd = -1;
2196
0
  if (pr_fsio_close(fh) < 0) {
2197
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2198
0
      ": error writing DelayTable '%s': %s", delay_tab.dt_path,
2199
0
      strerror(errno));
2200
0
  }
2201
0
}
2202
2203
/* Initialization functions
2204
 */
2205
2206
0
static int delay_init(void) {
2207
0
  delay_tab.dt_path = PR_RUN_DIR "/proftpd.delay";
2208
0
  delay_tab.dt_enabled = TRUE;
2209
0
  delay_tab.dt_data = NULL;
2210
2211
0
  pr_event_register(&delay_module, "core.connect", delay_connect_ev, NULL);
2212
#if defined(PR_SHARED_MODULE)
2213
  pr_event_register(&delay_module, "core.module-unload", delay_mod_unload_ev,
2214
    NULL);
2215
#endif
2216
0
  pr_event_register(&delay_module, "core.postparse", delay_postparse_ev, NULL);
2217
0
  pr_event_register(&delay_module, "core.restart", delay_restart_ev, NULL);
2218
0
  pr_event_register(&delay_module, "core.shutdown", delay_shutdown_ev, NULL);
2219
2220
0
  delay_pool = make_sub_pool(permanent_pool);
2221
0
  pr_pool_tag(delay_pool, MOD_DELAY_VERSION);
2222
2223
0
#if defined(PR_USE_CTRLS)
2224
0
  if (pr_ctrls_register(&delay_module, "delay", "tune mod_delay settings",
2225
0
      delay_handle_delay) < 0) {
2226
0
    pr_log_pri(PR_LOG_NOTICE, MOD_DELAY_VERSION
2227
0
      ": error registering 'delay' control: %s", strerror(errno));
2228
2229
0
  } else {
2230
0
    register unsigned int i;
2231
2232
0
    for (i = 0; delay_acttab[i].act_action; i++) {
2233
0
      delay_acttab[i].act_acl = pcalloc(delay_pool, sizeof(ctrls_acl_t));
2234
0
      pr_ctrls_init_acl(delay_acttab[i].act_acl);
2235
0
    }
2236
0
  }
2237
0
#endif /* PR_USE_CTRLS */
2238
2239
0
  return 0;
2240
0
}
2241
2242
0
static int delay_sess_init(void) {
2243
0
  pr_fh_t *fh;
2244
0
  config_rec *c;
2245
0
  int xerrno;
2246
2247
0
  pr_event_register(&delay_module, "core.session-reinit", delay_sess_reinit_ev,
2248
0
    NULL);
2249
2250
0
  if (delay_engine == FALSE) {
2251
0
    return 0;
2252
0
  }
2253
2254
  /* Look up DelayEngine again, as it may have been disabled in an
2255
   * <IfClass> section.
2256
   */
2257
0
  c = find_config(main_server->conf, CONF_PARAM, "DelayEngine", FALSE);
2258
0
  if (c != NULL &&
2259
0
      *((unsigned int *) c->argv[0]) == FALSE) {
2260
0
    delay_engine = FALSE;
2261
0
  }
2262
2263
0
  if (delay_engine == FALSE) {
2264
0
    return 0;
2265
0
  }
2266
2267
0
  c = find_config(main_server->conf, CONF_PARAM, "DelayOnEvent", FALSE);
2268
0
  while (c != NULL) {
2269
0
    int event;
2270
0
    unsigned long min_delay_usec, max_delay_usec;
2271
2272
0
    pr_signals_handle();
2273
2274
0
    event = *((int *) c->argv[0]);
2275
0
    min_delay_usec = *((unsigned long *) c->argv[1]);
2276
0
    max_delay_usec = *((unsigned long *) c->argv[2]);
2277
2278
0
    switch (event) {
2279
0
      case DELAY_EVENT_USER_CMD:
2280
0
        delay_user_min_delay = min_delay_usec;
2281
0
        delay_user_max_delay = max_delay_usec;
2282
0
        break;
2283
2284
0
      case DELAY_EVENT_PASS_CMD:
2285
0
        delay_pass_min_delay = min_delay_usec;
2286
0
        delay_pass_max_delay = max_delay_usec;
2287
0
        break;
2288
2289
0
      case DELAY_EVENT_FAILED_LOGIN:
2290
0
        delay_failed_login_min_delay = min_delay_usec;
2291
0
        delay_failed_login_max_delay = max_delay_usec;
2292
0
        break;
2293
2294
0
      case DELAY_EVENT_CONNECT:
2295
        /* We deliberately ignore the Connect event here, since it is
2296
         * handled already at connect time.
2297
         */
2298
0
        break;
2299
0
    }
2300
2301
0
    c = find_config_next(c, c->next, CONF_PARAM, "DelayOnEvent", FALSE);
2302
0
  }
2303
2304
0
  if (delay_tab.dt_enabled == FALSE) {
2305
    /* If the DelayTable has been disabled (but not DelayEngine), AND there
2306
     * are not DelayOnEvent rules set, log a warning since mod_delay will not
2307
     * be doing much; it's probably an unintentional misconfiguration.
2308
     */
2309
2310
0
    pr_log_debug(DEBUG0, MOD_DELAY_VERSION
2311
0
      ": no DelayOnEvent rules configured with \"DelayTable none\" in effect, "
2312
0
      "disabling module");
2313
0
    return 0;
2314
0
  }
2315
2316
0
  delay_nuser = 0;
2317
0
  delay_npass = 0;
2318
2319
0
  pr_trace_msg(trace_channel, 6, "opening DelayTable '%s'", delay_tab.dt_path);
2320
2321
0
  PRIVS_ROOT
2322
0
  fh = pr_fsio_open(delay_tab.dt_path, O_RDWR);
2323
0
  xerrno = errno;
2324
0
  PRIVS_RELINQUISH
2325
2326
0
  if (fh == NULL) {
2327
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2328
0
      ": unable to open DelayTable '%s': %s", delay_tab.dt_path,
2329
0
      strerror(xerrno));
2330
0
    pr_trace_msg(trace_channel, 1, "unable to open DelayTable '%s': %s",
2331
0
      delay_tab.dt_path, strerror(xerrno));
2332
0
    delay_engine = FALSE;
2333
0
    return 0;
2334
0
  }
2335
2336
  /* Find a usable fd for the just-opened DelayTable fd. */
2337
0
  if (pr_fs_get_usable_fd2(&(fh->fh_fd)) < 0) {
2338
0
    pr_log_debug(DEBUG0, MOD_DELAY_VERSION
2339
0
      ": warning: unable to find good fd for DelayTable %d: %s",
2340
0
      fh->fh_fd, strerror(errno));
2341
0
  }
2342
2343
  /* Set the close-on-exec flag, for safety. */
2344
0
  if (fcntl(fh->fh_fd, F_SETFD, FD_CLOEXEC) < 0) {
2345
0
    pr_log_pri(PR_LOG_WARNING, MOD_DELAY_VERSION
2346
0
      ": unable to set CLO_EXEC on DelayTable fd %d: %s", fh->fh_fd,
2347
0
      strerror(errno));
2348
0
  }
2349
2350
0
  delay_tab.dt_fd = fh->fh_fd;
2351
0
  delay_tab.dt_data = NULL;
2352
2353
0
  return 0;
2354
0
}
2355
2356
/* Module API tables
2357
 */
2358
2359
#if defined(PR_USE_CTRLS)
2360
static ctrls_acttab_t delay_acttab[] = {
2361
  { "info", NULL, NULL, NULL },
2362
  { "reset",  NULL, NULL, NULL },
2363
  { NULL, NULL, NULL, NULL }
2364
};
2365
#endif /* PR_USE_CTRLS */
2366
2367
static conftable delay_conftab[] = {
2368
  { "DelayControlsACLs",set_delayctrlsacls, NULL },
2369
  { "DelayEngine",  set_delayengine,  NULL },
2370
  { "DelayOnEvent", set_delayonevent, NULL },
2371
  { "DelayTable", set_delaytable,   NULL },
2372
  { NULL }
2373
};
2374
2375
static cmdtable delay_cmdtab[] = {
2376
  { PRE_CMD,    C_PASS, G_NONE, delay_pre_pass,   FALSE, FALSE },
2377
  { POST_CMD,   C_PASS, G_NONE, delay_post_pass,  FALSE, FALSE },
2378
  { POST_CMD_ERR, C_PASS, G_NONE, delay_post_pass,  FALSE, FALSE },
2379
  { PRE_CMD,    C_USER, G_NONE, delay_pre_user,   FALSE, FALSE },
2380
  { POST_CMD,   C_USER, G_NONE, delay_post_user,  FALSE, FALSE },
2381
  { POST_CMD_ERR, C_USER, G_NONE, delay_post_user,  FALSE, FALSE },
2382
  { LOG_CMD,    C_USER, G_NONE, delay_log_user,   FALSE, FALSE },
2383
  { LOG_CMD_ERR,  C_USER, G_NONE, delay_log_user,   FALSE, FALSE },
2384
  { LOG_CMD,    C_PASS, G_NONE, delay_log_pass,   FALSE, FALSE },
2385
  { LOG_CMD_ERR,  C_PASS, G_NONE, delay_log_pass_err, FALSE, FALSE },
2386
  { 0, NULL }
2387
};
2388
2389
module delay_module = {
2390
  NULL, NULL,
2391
2392
  /* Module API version 2.0 */
2393
  0x20,
2394
2395
  /* Module name */
2396
  "delay",
2397
2398
  /* Module configuration handler table */
2399
  delay_conftab,
2400
2401
  /* Module command handler table */
2402
  delay_cmdtab,
2403
2404
  /* Module authentication handler table */
2405
  NULL,
2406
2407
  /* Module initialization function */
2408
  delay_init,
2409
2410
  /* Session initialization function */
2411
  delay_sess_init,
2412
2413
  /* Module version */
2414
  MOD_DELAY_VERSION
2415
};