Coverage Report

Created: 2026-05-30 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/proftpd/modules/mod_ctrls.c
Line
Count
Source
1
/*
2
 * ProFTPD: mod_ctrls -- a module implementing the ftpdctl local socket
3
 *          server, as well as several utility functions for other Controls
4
 *          modules
5
 * Copyright (c) 2000-2026 TJ Saunders
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
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_ctrls, 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
#include "mod_ctrls.h"
32
33
0
#define MOD_CTRLS_VERSION "mod_ctrls/0.9.5"
34
35
#ifndef PR_USE_CTRLS
36
# error "Controls support required (use --enable-ctrls)"
37
#endif
38
39
/* Master daemon in standalone mode? (from src/main.c) */
40
extern unsigned char is_master;
41
42
module ctrls_module;
43
static ctrls_acttab_t ctrls_acttab[];
44
45
static const char *trace_channel = "ctrls";
46
47
/* Hard-coded Controls timer IDs.  Need two, one for the initial timer, one
48
 * to identify the user-configured-interval timer
49
 */
50
0
#define CTRLS_TIMER_ID       24075
51
52
static unsigned int ctrls_interval = 10;
53
54
/* Controls listening socket fd */
55
static int ctrls_sockfd = -1;
56
57
0
#define MOD_CTRLS_DEFAULT_SOCK    PR_RUN_DIR "/proftpd.sock"
58
static char *ctrls_sock_file = MOD_CTRLS_DEFAULT_SOCK;
59
60
/* User/group ownership of the control socket */
61
static uid_t ctrls_sock_uid = 0;
62
static gid_t ctrls_sock_gid = 0;
63
64
/* Pool for this module's use */
65
static pool *ctrls_pool = NULL;
66
67
/* Required "freshness" of client credential sockets */
68
static unsigned int ctrls_cl_freshness = 10;
69
70
/* Start of the client list */
71
static pr_ctrls_cl_t *cl_list = NULL;
72
static unsigned int cl_listlen = 0;
73
static unsigned int cl_maxlistlen = 5;
74
75
/* Controls access control list.  This is for ACLs on the control socket
76
 * itself, rather than on individual actions.
77
 */
78
static ctrls_acl_t ctrls_sock_acl;
79
80
static unsigned char ctrls_engine = TRUE;
81
82
/* Necessary prototypes */
83
static int ctrls_setblock(int sockfd);
84
static int ctrls_setnonblock(int sockfd);
85
86
static const char *ctrls_logname = NULL;
87
88
/* Support routines
89
 */
90
91
/* Controls logging routines
92
 */
93
94
0
static int ctrls_closelog(void) {
95
0
  if (ctrls_logname != NULL) {
96
0
    pr_ctrls_set_logfd(-1);
97
0
    ctrls_logname = NULL;
98
0
  }
99
100
0
  return 0;
101
0
}
102
103
0
static int ctrls_openlog(void) {
104
0
  int logfd, res = 0, xerrno = 0;
105
106
  /* Sanity check */
107
0
  if (ctrls_logname == NULL) {
108
0
    return 0;
109
0
  }
110
111
0
  PRIVS_ROOT
112
0
  res = pr_log_openfile(ctrls_logname, &logfd, PR_LOG_SYSTEM_MODE);
113
0
  xerrno = errno;
114
0
  PRIVS_RELINQUISH
115
116
0
  if (res == 0) {
117
0
    pr_ctrls_set_logfd(logfd);
118
119
0
  } else {
120
0
    if (res == -1) {
121
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
122
0
        ": unable to open ControlsLog '%s': %s", ctrls_logname,
123
0
        strerror(xerrno));
124
125
0
    } else if (res == PR_LOG_WRITABLE_DIR) {
126
0
      pr_log_pri(PR_LOG_WARNING, MOD_CTRLS_VERSION
127
0
        ": unable to open ControlsLog '%s': "
128
0
        "parent directory is world-writable", ctrls_logname);
129
130
0
    } else if (res == PR_LOG_SYMLINK) {
131
0
      pr_log_pri(PR_LOG_WARNING, MOD_CTRLS_VERSION
132
0
        ": unable to open ControlsLog '%s': %s is a symbolic link",
133
0
        ctrls_logname, ctrls_logname);
134
0
    }
135
0
  }
136
137
0
  return res;
138
0
}
139
140
/* Controls client routines
141
 */
142
143
0
static pr_ctrls_cl_t *ctrls_new_cl(void) {
144
0
  pool *cl_pool = NULL;
145
146
0
  if (cl_list == NULL) {
147
148
    /* Our first client */
149
0
    cl_pool = make_sub_pool(ctrls_pool);
150
0
    pr_pool_tag(cl_pool, "Controls client pool");
151
152
0
    cl_list = (pr_ctrls_cl_t *) pcalloc(cl_pool, sizeof(pr_ctrls_cl_t));
153
154
0
    cl_list->cl_pool = cl_pool;
155
0
    cl_list->cl_fd = -1;
156
0
    cl_list->cl_uid = 0;
157
0
    cl_list->cl_user = NULL;
158
0
    cl_list->cl_gid = 0;
159
0
    cl_list->cl_group = NULL;
160
0
    cl_list->cl_pid = 0;
161
0
    cl_list->cl_ctrls = make_array(cl_pool, 0, sizeof(pr_ctrls_t *));
162
163
0
    cl_list->cl_next = NULL;
164
0
    cl_list->cl_prev = NULL;
165
166
0
    cl_listlen = 1;
167
168
0
  } else {
169
0
    pr_ctrls_cl_t *cl = NULL;
170
171
    /* Add another victim to the list */
172
0
    cl_pool = make_sub_pool(ctrls_pool);
173
0
    pr_pool_tag(cl_pool, "Controls client pool");
174
175
0
    cl = (pr_ctrls_cl_t *) pcalloc(cl_pool, sizeof(pr_ctrls_cl_t));
176
177
0
    cl->cl_pool = cl_pool;
178
0
    cl->cl_fd = -1;
179
0
    cl->cl_uid = 0;
180
0
    cl->cl_user = NULL;
181
0
    cl->cl_gid = 0;
182
0
    cl->cl_group = NULL;
183
0
    cl->cl_pid = 0;
184
0
    cl->cl_ctrls = make_array(cl->cl_pool, 0, sizeof(pr_ctrls_t *));
185
186
0
    cl->cl_next = cl_list;
187
0
    cl->cl_prev = NULL;
188
189
0
    cl_list->cl_prev = cl;
190
0
    cl_list = cl;
191
192
0
    cl_listlen++;
193
0
  }
194
195
0
  return cl_list;
196
0
}
197
198
/* Add a new client to the set */
199
static pr_ctrls_cl_t *ctrls_add_cl(int cl_fd, uid_t cl_uid, gid_t cl_gid,
200
0
    pid_t cl_pid, unsigned long cl_flags) {
201
0
  pr_ctrls_cl_t *cl = NULL;
202
203
  /* Make sure there's an empty entry available */
204
0
  cl = ctrls_new_cl();
205
206
0
  cl->cl_fd = cl_fd;
207
0
  cl->cl_uid = cl_uid;
208
0
  cl->cl_user = pr_auth_uid2name(cl->cl_pool, cl->cl_uid);
209
0
  cl->cl_gid = cl_gid;
210
0
  cl->cl_group = pr_auth_gid2name(cl->cl_pool, cl->cl_gid);
211
0
  cl->cl_pid = cl_pid;
212
0
  cl->cl_flags = cl_flags;
213
214
0
  pr_ctrls_log(MOD_CTRLS_VERSION,
215
0
    "accepted connection from %s/%s client", cl->cl_user, cl->cl_group);
216
217
0
  return cl;
218
0
}
219
220
/* Remove a client from the set */
221
0
static void ctrls_del_cl(pr_ctrls_cl_t *cl) {
222
223
  /* Remove this ctr_cl_t from the list, and free it */
224
0
  if (cl->cl_next) {
225
0
    cl->cl_next->cl_prev = cl->cl_prev;
226
0
  }
227
228
0
  if (cl->cl_prev) {
229
0
    cl->cl_prev->cl_next = cl->cl_next;
230
231
0
  } else {
232
0
    cl_list = cl->cl_next;
233
0
  }
234
235
0
  (void) close(cl->cl_fd);
236
0
  cl->cl_fd = -1;
237
238
0
  destroy_pool(cl->cl_pool);
239
0
  cl_listlen--;
240
0
}
241
242
/* Controls socket routines
243
 */
244
245
/* Iterate through any readable descriptors, reading each into appropriate
246
 * client objects
247
 */
248
0
static void ctrls_cls_read(void) {
249
0
  pr_ctrls_cl_t *cl;
250
251
0
  cl = cl_list;
252
0
  while (cl != NULL) {
253
0
    int res, xerrno;
254
255
0
    pr_signals_handle();
256
257
0
    res = pr_ctrls_recv_request(cl);
258
0
    xerrno = errno;
259
260
0
    if (res < 0) {
261
0
      switch (xerrno) {
262
0
        case EOF:
263
0
          break;
264
265
0
        case EINVAL:
266
          /* Unsupported action requested */
267
0
          if (cl->cl_flags == 0) {
268
0
            cl->cl_flags = PR_CTRLS_CL_NOACTION;
269
0
          }
270
271
0
          pr_ctrls_log(MOD_CTRLS_VERSION,
272
0
            "recvd from %s/%s client: (invalid action)", cl->cl_user,
273
0
            cl->cl_group);
274
0
          break;
275
276
0
        case EAGAIN:
277
#if defined(EAGAIN) && \
278
    defined(EWOULDBLOCK) && \
279
    EWOULDBLOCK != EAGAIN
280
        case EWOULDBLOCK:
281
#endif
282
          /* Malicious/blocked client */
283
0
          if (cl->cl_flags == 0) {
284
0
            cl->cl_flags = PR_CTRLS_CL_BLOCKED;
285
0
          }
286
0
          break;
287
288
0
        default:
289
0
          pr_ctrls_log(MOD_CTRLS_VERSION,
290
0
            "error: unable to receive client request: %s", strerror(errno));
291
0
          break;
292
0
      }
293
294
0
    } else {
295
0
      pr_ctrls_t *ctrl;
296
0
      char *request;
297
298
0
      ctrl = *((pr_ctrls_t **) cl->cl_ctrls->elts);
299
0
      request = (char *) ctrl->ctrls_action;
300
301
      /* Request successfully read.  Flag this client as being in such a
302
       * state.
303
       */
304
0
      if (cl->cl_flags == 0) {
305
0
        cl->cl_flags = PR_CTRLS_CL_HAVEREQ;
306
0
      }
307
308
0
      if (ctrl->ctrls_cb_args != NULL) {
309
0
        unsigned int reqargc;
310
0
        char **reqargv;
311
312
        /* Reconstruct the original request string from the client for
313
         * logging.
314
         */
315
316
0
        reqargc = ctrl->ctrls_cb_args->nelts;
317
0
        reqargv = ctrl->ctrls_cb_args->elts;
318
319
0
        while (reqargc--) {
320
0
          request = pstrcat(cl->cl_pool, request, " ", *reqargv++, NULL);
321
0
        }
322
323
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
324
0
          "recvd from %s/%s client: '%s'", cl->cl_user, cl->cl_group,
325
0
          request);
326
0
      }
327
0
    }
328
329
0
    cl = cl->cl_next;
330
0
  }
331
0
}
332
333
/* Iterate through any writable descriptors, writing out the responses to the
334
 * appropriate client objects
335
 */
336
0
static int ctrls_cls_write(void) {
337
0
  pr_ctrls_cl_t *cl;
338
339
0
  cl = cl_list;
340
0
  while (cl != NULL) {
341
0
    pr_ctrls_cl_t *tmp_cl;
342
343
    /* Necessary to keep track of the next client in the list while
344
     * the list is being modified.
345
     */
346
0
    tmp_cl = cl->cl_next;
347
348
0
    pr_signals_handle();
349
350
    /* This client has something to hear */
351
0
    if (cl->cl_flags == PR_CTRLS_CL_NOACCESS) {
352
0
      char *msg = "access denied";
353
354
      /* ACL-denied access */
355
0
      if (pr_ctrls_send_response(ctrls_pool, cl->cl_fd,
356
0
          PR_CTRLS_STATUS_ACCESS_DENIED, 1, &msg) < 0) {
357
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
358
0
          "error: unable to send response to %s/%s client: %s",
359
0
          cl->cl_user, cl->cl_group, strerror(errno));
360
361
0
      } else {
362
0
        pr_ctrls_log(MOD_CTRLS_VERSION, "sent to %s/%s client: '%s'",
363
0
          cl->cl_user, cl->cl_group, msg);
364
0
      }
365
366
0
    } else if (cl->cl_flags == PR_CTRLS_CL_NOACTION) {
367
0
      char *msg = "unsupported action requested";
368
369
      /* Unsupported action -- no matching controls */
370
0
      if (pr_ctrls_send_response(ctrls_pool, cl->cl_fd,
371
0
          PR_CTRLS_STATUS_UNSUPPORTED_OPERATION, 1, &msg) < 0) {
372
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
373
0
          "error: unable to send response to %s/%s client: %s",
374
0
          cl->cl_user, cl->cl_group, strerror(errno));
375
376
0
      } else {
377
0
        pr_ctrls_log(MOD_CTRLS_VERSION, "sent to %s/%s client: '%s'",
378
0
          cl->cl_user, cl->cl_group, msg);
379
0
      }
380
381
0
    } else if (cl->cl_flags == PR_CTRLS_CL_BLOCKED) {
382
0
      char *msg = "blocked connection";
383
384
0
      if (pr_ctrls_send_response(ctrls_pool, cl->cl_fd,
385
0
          PR_CTRLS_STATUS_INTERNAL_ERROR, 1, &msg) < 0) {
386
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
387
0
          "error: unable to send response to %s/%s client: %s",
388
0
          cl->cl_user, cl->cl_group, strerror(errno));
389
390
0
      } else {
391
0
        pr_ctrls_log(MOD_CTRLS_VERSION, "sent to %s/%s client: '%s'",
392
0
          cl->cl_user, cl->cl_group, msg);
393
0
      }
394
395
0
    } else if (cl->cl_flags == PR_CTRLS_CL_HAVEREQ) {
396
0
      if (cl->cl_ctrls != NULL &&
397
0
          cl->cl_ctrls->nelts > 0) {
398
0
        register unsigned int i = 0;
399
0
        pr_ctrls_t **ctrlv = NULL;
400
401
0
        ctrlv = (pr_ctrls_t **) cl->cl_ctrls->elts;
402
403
0
        for (i = 0; i < cl->cl_ctrls->nelts; i++) {
404
0
          if ((ctrlv[i])->ctrls_cb_retval < 1) {
405
406
            /* Make sure the callback(s) added responses */
407
0
            if ((ctrlv[i])->ctrls_cb_resps != NULL) {
408
0
              if (pr_ctrls_send_response(ctrls_pool, cl->cl_fd,
409
0
                  (ctrlv[i])->ctrls_cb_retval,
410
0
                  (ctrlv[i])->ctrls_cb_resps->nelts,
411
0
                  (char **) (ctrlv[i])->ctrls_cb_resps->elts) < 0) {
412
0
                pr_ctrls_log(MOD_CTRLS_VERSION,
413
0
                  "error: unable to send response to %s/%s "
414
0
                  "client: %s", cl->cl_user, cl->cl_group, strerror(errno));
415
416
0
              } else {
417
                /* For logging/accounting purposes */
418
0
                register unsigned int j = 0;
419
0
                int respval = (ctrlv[i])->ctrls_cb_retval;
420
0
                unsigned int respargc = (ctrlv[i])->ctrls_cb_resps->nelts;
421
0
                char **respargv = (ctrlv[i])->ctrls_cb_resps->elts;
422
423
0
                pr_ctrls_log(MOD_CTRLS_VERSION,
424
0
                  "sent to %s/%s client: return value: %d",
425
0
                  cl->cl_user, cl->cl_group, respval);
426
427
0
                for (j = 0; j < respargc; j++) {
428
0
                  pr_ctrls_log(MOD_CTRLS_VERSION,
429
0
                    "sent to %s/%s client: '%s'", cl->cl_user, cl->cl_group,
430
0
                    respargv[j]);
431
0
                }
432
0
              }
433
434
0
            } else {
435
              /* No responses added by callbacks */
436
0
              pr_ctrls_log(MOD_CTRLS_VERSION,
437
0
                "notice: no responses given for %s/%s client: "
438
0
                "check controls handlers", cl->cl_user, cl->cl_group);
439
0
            }
440
0
          }
441
0
        }
442
0
      }
443
0
    }
444
445
0
    pr_ctrls_log(MOD_CTRLS_VERSION,
446
0
      "closed connection to %s/%s client", cl->cl_user, cl->cl_group);
447
448
    /* Remove the client from the list */
449
0
    ctrls_del_cl(cl);
450
0
    cl = tmp_cl;
451
0
  }
452
453
0
  return 0;
454
0
}
455
456
/* Create a listening local socket */
457
0
static int ctrls_listen(const char *sock_file) {
458
0
  int sockfd = -1, len = 0;
459
0
  struct sockaddr_un sock;
460
#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
461
    !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
462
  int opt = 1;
463
  socklen_t optlen = sizeof(opt);
464
#endif /* !LOCAL_CREDS */
465
466
  /* No interruptions */
467
0
  pr_signals_block();
468
469
  /* Create the Unix domain socket */
470
0
  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
471
0
  if (sockfd < 0) {
472
0
    int xerrno = errno;
473
474
0
    pr_signals_unblock();
475
0
    pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
476
0
      ": error: unable to create local socket: %s", strerror(xerrno));
477
478
0
    errno = xerrno;
479
0
    return -1;
480
0
  }
481
482
  /* Ensure that the socket used is not one of the major three fds (stdin,
483
   * stdout, or stderr).
484
   */
485
0
  if (sockfd <= STDERR_FILENO) {
486
0
    int res;
487
488
0
    res = pr_fs_get_usable_fd(sockfd);
489
0
    if (res < 0) {
490
0
      int xerrno = errno;
491
492
0
      pr_signals_unblock();
493
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
494
0
        ": error duplicating ctrls socket: %s", strerror(xerrno));
495
0
      (void) close(sockfd);
496
497
0
      errno = xerrno;
498
0
      return -1;
499
0
    }
500
501
0
    (void) close(sockfd);
502
0
    sockfd = res;
503
0
  }
504
505
0
  if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
506
0
    int xerrno = errno;
507
508
0
    pr_signals_unblock();
509
0
    pr_log_pri(PR_LOG_WARNING,
510
0
      "unable to set CLO_EXEC on ctrls socket fd %d: %s", sockfd,
511
0
      strerror(xerrno));
512
513
0
    (void) close(sockfd);
514
0
    errno = xerrno;
515
0
    return -1;
516
0
  }
517
518
  /* Make sure the path to which we want to bind this socket doesn't already
519
   * exist.
520
   */
521
0
  (void) unlink(sock_file);
522
523
  /* Fill in the socket structure fields */
524
0
  memset(&sock, 0, sizeof(sock));
525
526
0
  sock.sun_family = AF_UNIX;
527
0
  sstrncpy(sock.sun_path, sock_file, sizeof(sock.sun_path));
528
529
0
  len = sizeof(sock);
530
531
  /* Bind the name to the descriptor */
532
0
  pr_trace_msg(trace_channel, 1, "binding ctrls socket fd %d to path '%s'",
533
0
    sockfd, sock.sun_path);
534
0
  if (bind(sockfd, (struct sockaddr *) &sock, len) < 0) {
535
0
    int xerrno = errno;
536
537
0
    pr_signals_unblock();
538
0
    (void) close(sockfd);
539
540
0
    errno = xerrno;
541
0
    pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
542
0
      ": error: unable to bind to local socket: %s", strerror(xerrno));
543
0
    pr_trace_msg(trace_channel, 1, "unable to bind to local socket: %s",
544
0
      strerror(xerrno));
545
546
0
    errno = xerrno;
547
0
    return -1;
548
0
  }
549
550
  /* Start listening to the socket */
551
0
  if (listen(sockfd, 5) < 0) {
552
0
    int xerrno = errno;
553
554
0
    pr_signals_unblock();
555
0
    (void) close(sockfd);
556
557
0
    errno = xerrno;
558
0
    pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
559
0
      ": error: unable to listen on local socket '%s': %s", sock.sun_path,
560
0
      strerror(xerrno));
561
0
    pr_trace_msg(trace_channel, 1, "unable to listen on local socket '%s': %s",
562
0
      sock.sun_path, strerror(xerrno));
563
564
0
    errno = xerrno;
565
0
    return -1;
566
0
  }
567
568
#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
569
    !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
570
  /* Set the LOCAL_CREDS socket option. */
571
  if (setsockopt(sockfd, 0, LOCAL_CREDS, &opt, optlen) < 0) {
572
    pr_log_debug(DEBUG0, MOD_CTRLS_VERSION ": error enabling LOCAL_CREDS: %s",
573
      strerror(errno));
574
  }
575
#endif /* !LOCAL_CREDS */
576
577
  /* Change the permissions on the socket, so that users can connect */
578
0
  if (chmod(sock.sun_path, (mode_t) PR_CTRLS_MODE) < 0) {
579
0
    int xerrno = errno;
580
581
0
    pr_signals_unblock();
582
0
    (void) close(sockfd);
583
584
0
    errno = xerrno;
585
0
    pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
586
0
      ": error: unable to chmod local socket: %s", strerror(xerrno));
587
0
    pr_trace_msg(trace_channel, 1, "unable to chmod local socket: %s",
588
0
      strerror(xerrno));
589
590
0
    errno = xerrno;
591
0
    return -1;
592
0
  }
593
594
0
  pr_signals_unblock();
595
0
  return sockfd;
596
0
}
597
598
0
static int ctrls_recv_cl_reqs(void) {
599
0
  fd_set cl_rset;
600
0
  struct timeval timeout;
601
0
  uid_t cl_uid;
602
0
  gid_t cl_gid;
603
0
  pid_t cl_pid;
604
0
  unsigned long cl_flags = 0;
605
0
  int cl_fd, max_fd;
606
607
0
  timeout.tv_usec = 500L;
608
0
  timeout.tv_sec = 0L;
609
610
  /* look for any pending client connections */
611
0
  while (cl_listlen < cl_maxlistlen) {
612
0
    int res = 0, xerrno;
613
614
0
    pr_signals_handle();
615
616
0
    if (ctrls_sockfd < 0) {
617
0
      break;
618
0
    }
619
620
0
    FD_ZERO(&cl_rset);
621
0
    FD_SET(ctrls_sockfd, &cl_rset);
622
0
    max_fd = ctrls_sockfd + 1;
623
624
0
    res = select(max_fd + 1, &cl_rset, NULL, NULL, &timeout);
625
0
    xerrno = errno;
626
627
0
    if (res == 0) {
628
      /* Go through the client list */
629
0
      ctrls_cls_read();
630
631
0
      return 0;
632
0
    }
633
634
0
    if (res < 0) {
635
0
      if (xerrno == EINTR) {
636
0
        pr_signals_handle();
637
0
        continue;
638
0
      }
639
640
0
      pr_ctrls_log(MOD_CTRLS_VERSION,
641
0
        "error: unable to select on local socket: %s", strerror(xerrno));
642
643
0
      errno = xerrno;
644
0
      return res;
645
0
    }
646
647
0
    if (FD_ISSET(ctrls_sockfd, &cl_rset)) {
648
      /* Make sure the ctrl socket is non-blocking */
649
0
      if (ctrls_setnonblock(ctrls_sockfd) < 0) {
650
0
        xerrno = errno;
651
652
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
653
0
          "error: unable to set nonblocking on local socket: %s",
654
0
          strerror(xerrno));
655
656
0
        errno = xerrno;
657
0
        return -1;
658
0
      }
659
660
      /* Accept pending connections */
661
0
      cl_fd = pr_ctrls_accept(ctrls_sockfd, &cl_uid, &cl_gid, &cl_pid,
662
0
        ctrls_cl_freshness);
663
0
      xerrno = errno;
664
665
0
      if (cl_fd < 0) {
666
0
        if (xerrno != ETIMEDOUT) {
667
0
          pr_ctrls_log(MOD_CTRLS_VERSION,
668
0
            "error: unable to accept connection: %s", strerror(xerrno));
669
0
        }
670
671
0
        continue;
672
0
      }
673
674
      /* Restore blocking mode to the ctrl socket */
675
0
      if (ctrls_setblock(ctrls_sockfd) < 0) {
676
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
677
0
          "error: unable to set blocking on local socket: %s",
678
0
          strerror(errno));
679
0
      }
680
681
      /* Set this socket as non-blocking */
682
0
      if (ctrls_setnonblock(cl_fd) < 0) {
683
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
684
0
          "error: unable to set nonblocking on client socket: %s",
685
0
          strerror(errno));
686
0
        (void) close(cl_fd);
687
0
        continue;
688
0
      }
689
690
0
      if (pr_ctrls_check_user_acl(cl_uid, &ctrls_sock_acl.acl_users) != TRUE &&
691
0
          pr_ctrls_check_group_acl(cl_gid, &ctrls_sock_acl.acl_groups) != TRUE) {
692
0
        cl_flags = PR_CTRLS_CL_NOACCESS;
693
0
      }
694
695
      /* Add the client to the list */
696
0
      ctrls_add_cl(cl_fd, cl_uid, cl_gid, cl_pid, cl_flags);
697
0
    }
698
0
  }
699
700
  /* Go through the client list */
701
0
  ctrls_cls_read();
702
703
0
  return 0;
704
0
}
705
706
0
static int ctrls_send_cl_resps(void) {
707
708
  /* Go through the client list */
709
0
  ctrls_cls_write();
710
711
0
  return 0;
712
0
}
713
714
0
static int ctrls_setblock(int sockfd) {
715
0
  int flags = 0;
716
0
  int res = -1;
717
718
  /* default error */
719
0
  errno = EBADF;
720
721
0
  flags = fcntl(sockfd, F_GETFL);
722
0
  res = fcntl(sockfd, F_SETFL, flags & (U32BITS ^ O_NONBLOCK));
723
724
0
  return res;
725
0
}
726
727
0
static int ctrls_setnonblock(int sockfd) {
728
0
  int flags = 0;
729
0
  int res = -1;
730
731
  /* default error */
732
0
  errno = EBADF;
733
734
0
  flags = fcntl(sockfd, F_GETFL);
735
0
  res = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
736
737
0
  return res;
738
0
}
739
740
0
static int ctrls_timer_cb(CALLBACK_FRAME) {
741
0
  static unsigned char first_time = TRUE;
742
743
  /* If the ControlsEngine is not to run, do nothing from here on out */
744
0
  if (ctrls_engine == FALSE) {
745
0
    (void) close(ctrls_sockfd);
746
0
    ctrls_sockfd = -1;
747
748
0
    if (is_master) {
749
      /* Remove the local socket path as well */
750
0
      (void) unlink(ctrls_sock_file);
751
0
    }
752
753
0
    return 0;
754
0
  }
755
756
0
  if (first_time == TRUE) {
757
    /* Change the ownership on the socket to that configured by the admin */
758
0
    PRIVS_ROOT
759
0
    if (chown(ctrls_sock_file, ctrls_sock_uid, ctrls_sock_gid) < 0) {
760
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
761
0
        ": unable to chown local socket %s: %s", ctrls_sock_file,
762
0
        strerror(errno));
763
0
    }
764
0
    PRIVS_RELINQUISH
765
766
0
    first_time = FALSE;
767
0
  }
768
769
  /* Please no alarms while doing this. */
770
0
  pr_alarms_block();
771
772
  /* Process pending requests. */
773
0
  ctrls_recv_cl_reqs();
774
775
  /* Run through the controls */
776
0
  pr_run_ctrls(NULL, NULL);
777
778
  /* Process pending responses */
779
0
  ctrls_send_cl_resps();
780
781
  /* Reset controls */
782
0
  pr_ctrls_reset();
783
784
0
  pr_alarms_unblock();
785
0
  return 1;
786
0
}
787
788
/* Controls handlers
789
 */
790
791
0
static int respcmp(const void *a, const void *b) {
792
0
  return strcmp(*((char **) a), *((char **) b));
793
0
}
794
795
static int ctrls_handle_help(pr_ctrls_t *ctrl, int reqargc,
796
0
    char **reqargv) {
797
798
  /* Run through the list of registered controls, and add them to the
799
   * response, including the module in which they appear.
800
   */
801
802
0
  if (reqargc != 0) {
803
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
804
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
805
0
  }
806
807
0
  if (pr_get_registered_actions(ctrl, CTRLS_GET_DESC) < 0) {
808
0
    pr_ctrls_add_response(ctrl, "unable to get actions: %s", strerror(errno));
809
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
810
0
  }
811
812
  /* Be nice, and sort the directives lexicographically */
813
0
  qsort(ctrl->ctrls_cb_resps->elts, ctrl->ctrls_cb_resps->nelts,
814
0
    sizeof(char *), respcmp);
815
816
0
  return PR_CTRLS_STATUS_OK;
817
0
}
818
819
static int ctrls_handle_insctrl(pr_ctrls_t *ctrl, int reqargc,
820
0
    char **reqargv) {
821
0
  module *m = ANY_MODULE;
822
0
  int res, xerrno;
823
824
  /* Enable a control into the registered controls list. This requires the
825
   * action and, optionally, the module of the control to be enabled.
826
   */
827
828
  /* Check the insctrl ACL */
829
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "insctrl") != TRUE) {
830
831
    /* Access denied */
832
0
    pr_ctrls_add_response(ctrl, "access denied");
833
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
834
0
  }
835
836
0
  if (reqargc < 1 ||
837
0
      reqargc > 2) {
838
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
839
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
840
0
  }
841
842
  /* If the optional second parameter, a module name, is used, lookup
843
   * the module pointer matching the name.
844
   */
845
0
  if (reqargc == 2) {
846
0
    m = pr_module_get(reqargv[1]);
847
0
  }
848
849
0
  res = pr_set_registered_actions(m, reqargv[0], FALSE, 0);
850
0
  xerrno = errno;
851
852
0
  if (res < 0) {
853
0
    if (xerrno == ENOENT) {
854
0
      pr_ctrls_add_response(ctrl, "no such control: '%s'", reqargv[0]);
855
0
      return PR_CTRLS_STATUS_SUBJECT_NOT_FOUND;
856
0
    }
857
858
0
    pr_ctrls_add_response(ctrl, "unable to enable '%s': %s", reqargv[0],
859
0
      strerror(errno));
860
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
861
0
  }
862
863
0
  pr_ctrls_add_response(ctrl, "'%s' control enabled", reqargv[0]);
864
0
  return PR_CTRLS_STATUS_OK;
865
0
}
866
867
static int ctrls_handle_lsctrl(pr_ctrls_t *ctrl, int reqargc,
868
0
    char **reqargv) {
869
870
  /* Run through the list of registered controls, and add them to the
871
   * response, including the module in which they appear.
872
   */
873
874
  /* Check the lsctrl ACL */
875
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "lsctrl") != TRUE) {
876
877
    /* Access denied */
878
0
    pr_ctrls_add_response(ctrl, "access denied");
879
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
880
0
  }
881
882
0
  if (reqargc != 0) {
883
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
884
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
885
0
  }
886
887
0
  if (pr_get_registered_actions(ctrl, CTRLS_GET_ACTION_ENABLED) < 0) {
888
0
    pr_ctrls_add_response(ctrl, "unable to get actions: %s", strerror(errno));
889
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
890
0
  }
891
892
  /* Be nice, and sort the actions lexicographically */
893
0
  qsort(ctrl->ctrls_cb_resps->elts, ctrl->ctrls_cb_resps->nelts,
894
0
    sizeof(char *), respcmp);
895
896
0
  return PR_CTRLS_STATUS_OK;
897
0
}
898
899
static int ctrls_handle_rmctrl(pr_ctrls_t *ctrl, int reqargc,
900
0
    char **reqargv) {
901
0
  module *m = ANY_MODULE;
902
0
  int res, xerrno;
903
904
  /* Disable a control from the registered controls list. This requires the
905
   * action and, optionally, the module of the control to be removed.
906
   */
907
908
  /* Check the rmctrl ACL */
909
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "rmctrl") != TRUE) {
910
911
    /* Access denied */
912
0
    pr_ctrls_add_response(ctrl, "access denied");
913
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
914
0
  }
915
916
0
  if (reqargc < 1 ||
917
0
      reqargc > 2) {
918
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
919
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
920
0
  }
921
922
  /* The three controls added by this module _cannot_ be removed (at least
923
   * not via this control handler).
924
   */
925
0
  if (strcmp(reqargv[0], "insctrl") == 0 ||
926
0
      strcmp(reqargv[0], "lsctrl") == 0 ||
927
0
      strcmp(reqargv[0], "rmctrl") == 0) {
928
0
    pr_ctrls_add_response(ctrl, "'%s' control cannot be removed", reqargv[0]);
929
0
    return PR_CTRLS_STATUS_OPERATION_DENIED;
930
0
  }
931
932
  /* If the optional second parameter, a module name, is used, lookup
933
   * the module pointer matching the name.
934
   */
935
0
  if (reqargc == 2) {
936
0
    m = pr_module_get(reqargv[1]);
937
0
  }
938
939
0
  res = pr_set_registered_actions(m, reqargv[0], FALSE, PR_CTRLS_ACT_DISABLED);
940
0
  xerrno = errno;
941
942
0
  if (res < 0) {
943
0
    if (xerrno == ENOENT) {
944
0
      pr_ctrls_add_response(ctrl, "no such control: '%s'", reqargv[0]);
945
0
      return PR_CTRLS_STATUS_SUBJECT_NOT_FOUND;
946
0
    }
947
948
0
    pr_ctrls_add_response(ctrl, "unable to disable '%s': %s", reqargv[0],
949
0
      strerror(xerrno));
950
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
951
0
  }
952
953
0
  if (strcmp(reqargv[0], "all") != 0) {
954
0
    pr_ctrls_add_response(ctrl, "'%s' control disabled", reqargv[0]);
955
956
0
  } else {
957
    /* If all actions have been disabled, stop listening on the local
958
     * socket, and turn off this module's engine.
959
     */
960
0
    pr_ctrls_add_response(ctrl, "all controls disabled");
961
0
    pr_ctrls_add_response(ctrl, "restart the daemon to re-enable controls");
962
963
0
    (void) close(ctrls_sockfd);
964
0
    ctrls_sockfd = -1;
965
966
0
    ctrls_engine = FALSE;
967
0
  }
968
969
0
  return PR_CTRLS_STATUS_OK;
970
0
}
971
972
/* Configuration handlers
973
 */
974
975
/* Default behavior is to deny everyone unless an ACL has been configured */
976
0
MODRET set_ctrlsacls(cmd_rec *cmd) {
977
0
  int res;
978
0
  char **actions = NULL;
979
0
  const char *bad_action = NULL;
980
981
0
  CHECK_ARGS(cmd, 4);
982
0
  CHECK_CONF(cmd, CONF_ROOT);
983
984
  /* Parse the given string of actions into a char **.  Then iterate
985
   * through the acttab, checking to see if a given control is _not_ in
986
   * the list.  If not in the list, unregister that control.
987
   */
988
989
0
  actions = pr_ctrls_parse_acl(cmd->tmp_pool, cmd->argv[1]);
990
991
  /* Check the second parameter to make sure it is "allow" or "deny" */
992
0
  if (strcmp(cmd->argv[2], "allow") != 0 &&
993
0
      strcmp(cmd->argv[2], "deny") != 0) {
994
0
    CONF_ERROR(cmd, "second parameter must be 'allow' or 'deny'");
995
0
  }
996
997
  /* Check the third parameter to make sure it is "user" or "group" */
998
0
  if (strcmp(cmd->argv[3], "user") != 0 &&
999
0
      strcmp(cmd->argv[3], "group") != 0) {
1000
0
    CONF_ERROR(cmd, "third parameter must be 'user' or 'group'");
1001
0
  }
1002
1003
0
  res = pr_ctrls_set_module_acls2(ctrls_acttab, ctrls_pool, actions,
1004
0
    cmd->argv[2], cmd->argv[3], cmd->argv[4], &bad_action);
1005
0
  if (res < 0) {
1006
0
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown action: '",
1007
0
      bad_action, "'", NULL));
1008
0
  }
1009
1010
0
  return PR_HANDLED(cmd);
1011
0
}
1012
1013
/* default: 10 secs */
1014
0
MODRET set_ctrlsauthfreshness(cmd_rec *cmd) {
1015
0
  int freshness = 0;
1016
1017
0
  CHECK_ARGS(cmd, 1);
1018
0
  CHECK_CONF(cmd, CONF_ROOT);
1019
1020
0
  freshness = atoi(cmd->argv[1]);
1021
0
  if (freshness <= 0) {
1022
0
    CONF_ERROR(cmd, "must be a positive number");
1023
0
  }
1024
1025
0
  ctrls_cl_freshness = freshness;
1026
0
  return PR_HANDLED(cmd);
1027
0
}
1028
1029
0
MODRET set_ctrlsengine(cmd_rec *cmd) {
1030
0
  int engine = -1;
1031
1032
0
  CHECK_ARGS(cmd, 1);
1033
0
  CHECK_CONF(cmd, CONF_ROOT);
1034
1035
0
  engine = get_boolean(cmd, 1);
1036
0
  if (engine == -1) {
1037
0
    CONF_ERROR(cmd, "expected Boolean parameter");
1038
0
  }
1039
1040
0
  ctrls_engine = engine;
1041
0
  return PR_HANDLED(cmd);
1042
0
}
1043
1044
/* default: 10 secs */
1045
0
MODRET set_ctrlsinterval(cmd_rec *cmd) {
1046
0
  int nsecs = 0;
1047
1048
0
  CHECK_ARGS(cmd, 1);
1049
0
  CHECK_CONF(cmd, CONF_ROOT);
1050
1051
0
  nsecs = atoi(cmd->argv[1]);
1052
0
  if (nsecs <= 0) {
1053
0
    CONF_ERROR(cmd, "must be a positive number");
1054
0
  }
1055
1056
  /* Remove the existing timer, and re-install it with this new interval. */
1057
0
  ctrls_interval = nsecs;
1058
1059
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1060
0
  pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
1061
0
    "Controls polling");
1062
1063
0
  return PR_HANDLED(cmd);
1064
0
}
1065
1066
0
MODRET set_ctrlslog(cmd_rec *cmd) {
1067
0
  int res = 0;
1068
1069
0
  CHECK_ARGS(cmd, 1);
1070
0
  CHECK_CONF(cmd, CONF_ROOT);
1071
1072
0
  ctrls_logname = pstrdup(ctrls_pool, cmd->argv[1]);
1073
1074
0
  res = ctrls_openlog();
1075
0
  if (res < 0) {
1076
0
    if (res == -1) {
1077
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to open '",
1078
0
        (char *) cmd->argv[1], "': ", strerror(errno), NULL));
1079
0
    }
1080
1081
0
    if (res == -2) {
1082
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1083
0
        "unable to log to a world-writable directory", NULL));
1084
0
    }
1085
0
  }
1086
1087
0
  return PR_HANDLED(cmd);
1088
0
}
1089
1090
/* Default: 5 max clients */
1091
0
MODRET set_ctrlsmaxclients(cmd_rec *cmd) {
1092
0
  int nclients = 0;
1093
1094
0
  CHECK_ARGS(cmd, 1);
1095
0
  CHECK_CONF(cmd, CONF_ROOT);
1096
1097
0
  nclients = atoi(cmd->argv[1]);
1098
0
  if (nclients <= 0) {
1099
0
    CONF_ERROR(cmd, "must be a positive number");
1100
0
  }
1101
1102
0
  cl_maxlistlen = nclients;
1103
0
  return PR_HANDLED(cmd);
1104
0
}
1105
1106
/* Default: var/run/proftpd.sock */
1107
0
MODRET set_ctrlssocket(cmd_rec *cmd) {
1108
0
  char *path;
1109
1110
0
  CHECK_ARGS(cmd, 1);
1111
0
  CHECK_CONF(cmd, CONF_ROOT);
1112
1113
0
  path = cmd->argv[1];
1114
0
  if (*path != '/') {
1115
0
    CONF_ERROR(cmd, "must be an absolute path");
1116
0
  }
1117
1118
  /* Close the socket. */
1119
0
  if (ctrls_sockfd >= 0) {
1120
0
    pr_trace_msg(trace_channel, 3, "closing ctrls socket '%s' (fd %d)",
1121
0
      ctrls_sock_file, ctrls_sockfd);
1122
0
    (void) unlink(ctrls_sock_file);
1123
0
    (void) close(ctrls_sockfd);
1124
0
    ctrls_sockfd = -1;
1125
0
  }
1126
1127
  /* Change the path. */
1128
0
  if (strcmp(path, ctrls_sock_file) != 0) {
1129
0
    ctrls_sock_file = pstrdup(ctrls_pool, path);
1130
0
  }
1131
1132
0
  return PR_HANDLED(cmd);
1133
0
}
1134
1135
/* Default behavior is to deny everyone unless an ACL has been configured */
1136
0
MODRET set_ctrlssocketacl(cmd_rec *cmd) {
1137
0
  CHECK_ARGS(cmd, 3);
1138
0
  CHECK_CONF(cmd, CONF_ROOT);
1139
1140
0
  pr_ctrls_init_acl(&ctrls_sock_acl);
1141
1142
  /* Check the first argument to make sure it either "allow" or "deny" */
1143
0
  if (strcasecmp(cmd->argv[1], "allow") != 0 &&
1144
0
      strcasecmp(cmd->argv[1], "deny") != 0) {
1145
0
    CONF_ERROR(cmd, "first parameter must be either 'allow' or 'deny'");
1146
0
  }
1147
1148
  /* Check the second argument to see how to handle the directive */
1149
0
  if (strcasecmp(cmd->argv[2], "user") == 0) {
1150
0
    if (pr_ctrls_set_user_acl(ctrls_pool, &ctrls_sock_acl.acl_users,
1151
0
        cmd->argv[1], cmd->argv[3]) < 0) {
1152
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1153
0
        "error configuring user socket ACL: ", strerror(errno), NULL));
1154
0
    }
1155
1156
0
  } else if (strcasecmp(cmd->argv[2], "group") == 0) {
1157
0
    if (pr_ctrls_set_group_acl(ctrls_pool, &ctrls_sock_acl.acl_groups,
1158
0
        cmd->argv[1], cmd->argv[3]) < 0) {
1159
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1160
0
        "error configuring group socket ACL: ", strerror(errno), NULL));
1161
0
    }
1162
1163
0
  } else {
1164
0
    CONF_ERROR(cmd, "second parameter must be either 'user' or 'group'");
1165
0
  }
1166
1167
0
  return PR_HANDLED(cmd);
1168
0
}
1169
1170
/* Default: root root */
1171
0
MODRET set_ctrlssocketowner(cmd_rec *cmd) {
1172
0
  gid_t gid = 0;
1173
0
  uid_t uid = 0;
1174
1175
0
  CHECK_ARGS(cmd, 2);
1176
0
  CHECK_CONF(cmd, CONF_ROOT);
1177
1178
0
  uid = pr_auth_name2uid(cmd->tmp_pool, cmd->argv[1]);
1179
0
  if (uid == (uid_t) -1) {
1180
0
    if (errno != EINVAL) {
1181
0
      pr_log_debug(DEBUG0, "%s: %s has UID of -1", (char *) cmd->argv[0],
1182
0
        (char *) cmd->argv[1]);
1183
1184
0
    } else {
1185
0
      pr_log_debug(DEBUG0, "%s: no such user '%s'", (char *) cmd->argv[0],
1186
0
        (char *) cmd->argv[1]);
1187
0
    }
1188
1189
0
  } else {
1190
0
    ctrls_sock_uid = uid;
1191
0
  }
1192
1193
0
  gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[2]);
1194
0
  if (gid == (gid_t) -1) {
1195
0
    if (errno != EINVAL) {
1196
0
      pr_log_debug(DEBUG0, "%s: %s has GID of -1", (char *) cmd->argv[0],
1197
0
        (char *) cmd->argv[2]);
1198
1199
0
    } else {
1200
0
      pr_log_debug(DEBUG0, "%s: no such group '%s'", (char *) cmd->argv[0],
1201
0
        (char *) cmd->argv[2]);
1202
0
    }
1203
1204
0
  } else {
1205
0
    ctrls_sock_gid = gid;
1206
0
  }
1207
1208
0
  return PR_HANDLED(cmd);
1209
0
}
1210
1211
/* Event handlers
1212
 */
1213
1214
0
static void ctrls_shutdown_ev(const void *event_data, void *user_data) {
1215
0
  if (!is_master || !ctrls_engine)
1216
0
    return;
1217
1218
  /* Close any connected clients */
1219
0
  if (cl_list != NULL) {
1220
0
    pr_ctrls_cl_t *cl = NULL;
1221
1222
0
    for (cl = cl_list; cl; cl = cl->cl_next) {
1223
0
      if (cl->cl_fd >= 0) {
1224
0
        (void) close(cl->cl_fd);
1225
0
        cl->cl_fd = -1;
1226
0
      }
1227
0
    }
1228
0
  }
1229
1230
0
  (void) close(ctrls_sockfd);
1231
0
  ctrls_sockfd = -1;
1232
1233
  /* Remove the local socket path as well */
1234
0
  (void) unlink(ctrls_sock_file);
1235
0
  return;
1236
0
}
1237
1238
0
static void ctrls_postparse_ev(const void *event_data, void *user_data) {
1239
0
  if (ctrls_engine == FALSE ||
1240
0
      ServerType == SERVER_INETD) {
1241
0
    return;
1242
0
  }
1243
1244
  /* Start listening on the ctrl socket */
1245
0
  PRIVS_ROOT
1246
0
  ctrls_sockfd = ctrls_listen(ctrls_sock_file);
1247
0
  PRIVS_RELINQUISH
1248
1249
  /* Start a timer for the checking/processing of the ctrl socket.  */
1250
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1251
0
  pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
1252
0
    "Controls polling");
1253
0
}
1254
1255
0
static void ctrls_restart_ev(const void *event_data, void *user_data) {
1256
0
  register unsigned int i;
1257
1258
  /* Block alarms while we're preparing for the restart. */
1259
0
  pr_alarms_block();
1260
1261
  /* Close any connected clients */
1262
0
  if (cl_list != NULL) {
1263
0
    pr_ctrls_cl_t *cl = NULL;
1264
1265
0
    for (cl = cl_list; cl; cl = cl->cl_next) {
1266
0
      if (cl->cl_fd >= 0) {
1267
0
        (void) close(cl->cl_fd);
1268
0
        cl->cl_fd = -1;
1269
0
      }
1270
0
    }
1271
0
  }
1272
1273
  /* Reset the client list */
1274
0
  cl_list = NULL;
1275
0
  cl_listlen = 0;
1276
1277
0
  pr_trace_msg(trace_channel, 3, "closing ctrls socket '%s' (fd %d)",
1278
0
    ctrls_sock_file, ctrls_sockfd);
1279
0
  (void) close(ctrls_sockfd);
1280
0
  ctrls_sockfd = -1;
1281
1282
0
  ctrls_closelog();
1283
1284
  /* Clear the existing pool */
1285
0
  if (ctrls_pool != NULL) {
1286
0
    destroy_pool(ctrls_pool);
1287
1288
0
    ctrls_logname = NULL;
1289
0
    ctrls_sock_file = MOD_CTRLS_DEFAULT_SOCK;
1290
0
  }
1291
1292
  /* Allocate the pool for this module's use */
1293
0
  ctrls_pool = make_sub_pool(permanent_pool);
1294
0
  pr_pool_tag(ctrls_pool, MOD_CTRLS_VERSION);
1295
1296
  /* Register the control handlers */
1297
0
  for (i = 0; ctrls_acttab[i].act_action; i++) {
1298
1299
    /* Allocate and initialize the ACL for this control. */
1300
0
    ctrls_acttab[i].act_acl = pcalloc(ctrls_pool, sizeof(ctrls_acl_t));
1301
0
    pr_ctrls_init_acl(ctrls_acttab[i].act_acl);
1302
0
  }
1303
1304
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1305
0
  pr_alarms_unblock();
1306
0
  return;
1307
0
}
1308
1309
/* Initialization routines
1310
 */
1311
1312
0
static int ctrls_init(void) {
1313
0
  register unsigned int i = 0;
1314
1315
  /* Allocate the pool for this module's use */
1316
0
  ctrls_pool = make_sub_pool(permanent_pool);
1317
0
  pr_pool_tag(ctrls_pool, MOD_CTRLS_VERSION);
1318
1319
  /* Register the control handlers */
1320
0
  for (i = 0; ctrls_acttab[i].act_action; i++) {
1321
1322
    /* Allocate and initialize the ACL for this control. */
1323
0
    ctrls_acttab[i].act_acl = pcalloc(ctrls_pool, sizeof(ctrls_acl_t));
1324
0
    pr_ctrls_init_acl(ctrls_acttab[i].act_acl);
1325
1326
0
    if (pr_ctrls_register(&ctrls_module, ctrls_acttab[i].act_action,
1327
0
        ctrls_acttab[i].act_desc, ctrls_acttab[i].act_cb) < 0) {
1328
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
1329
0
        ": error registering '%s' control: %s",
1330
0
        ctrls_acttab[i].act_action, strerror(errno));
1331
0
    }
1332
0
  }
1333
1334
  /* Make certain the socket ACL is initialized. */
1335
0
  memset(&ctrls_sock_acl, '\0', sizeof(ctrls_acl_t));
1336
0
  ctrls_sock_acl.acl_users.allow = ctrls_sock_acl.acl_groups.allow = FALSE;
1337
1338
0
  pr_event_register(&ctrls_module, "core.restart", ctrls_restart_ev, NULL);
1339
0
  pr_event_register(&ctrls_module, "core.shutdown", ctrls_shutdown_ev, NULL);
1340
0
  pr_event_register(&ctrls_module, "core.postparse", ctrls_postparse_ev, NULL);
1341
1342
0
  return 0;
1343
0
}
1344
1345
0
static int ctrls_sess_init(void) {
1346
1347
  /* Children are not to listen for or handle control requests */
1348
0
  ctrls_engine = FALSE;
1349
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1350
1351
0
  pr_event_unregister(&ctrls_module, "core.restart", ctrls_restart_ev);
1352
1353
  /* Close the inherited socket */
1354
0
  close(ctrls_sockfd);
1355
0
  ctrls_sockfd = -1;
1356
1357
0
  return 0;
1358
0
}
1359
1360
static ctrls_acttab_t ctrls_acttab[] = {
1361
  { "help", "describe all registered controls", NULL,
1362
    ctrls_handle_help },
1363
  { "insctrl",  "enable a disabled control", NULL,
1364
    ctrls_handle_insctrl },
1365
  { "lsctrl", "list all registered controls", NULL,
1366
    ctrls_handle_lsctrl },
1367
  { "rmctrl", "disable a registered control", NULL,
1368
    ctrls_handle_rmctrl },
1369
  { NULL, NULL, NULL, NULL }
1370
};
1371
1372
/* Module API tables
1373
 */
1374
1375
static conftable ctrls_conftab[] = {
1376
  { "ControlsACLs",   set_ctrlsacls,    NULL },
1377
  { "ControlsAuthFreshness",  set_ctrlsauthfreshness, NULL },
1378
  { "ControlsEngine",   set_ctrlsengine,  NULL },
1379
  { "ControlsInterval",   set_ctrlsinterval,  NULL },
1380
  { "ControlsLog",    set_ctrlslog,   NULL },
1381
  { "ControlsMaxClients", set_ctrlsmaxclients,  NULL },
1382
  { "ControlsSocket",   set_ctrlssocket,  NULL },
1383
  { "ControlsSocketACL",  set_ctrlssocketacl, NULL },
1384
  { "ControlsSocketOwner",  set_ctrlssocketowner, NULL },
1385
  { NULL }
1386
};
1387
1388
module ctrls_module = {
1389
  NULL, NULL,
1390
1391
  /* Module API version 2.0 */
1392
  0x20,
1393
1394
  /* Module name */
1395
  "ctrls",
1396
1397
  /* Module configuration handler table */
1398
  ctrls_conftab,
1399
1400
  /* Module command handler table */
1401
  NULL,
1402
1403
  /* Module authentication handler table */
1404
  NULL,
1405
1406
  /* Module initialization function */
1407
  ctrls_init,
1408
1409
  /* Session initialization function */
1410
  ctrls_sess_init,
1411
1412
  /* Module version */
1413
  MOD_CTRLS_VERSION
1414
};