Coverage Report

Created: 2026-08-13 06:52

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