Coverage Report

Created: 2024-09-30 06:24

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