Coverage Report

Created: 2023-03-26 06:19

/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
650
      /* Make sure the ctrl socket is non-blocking */
651
0
      if (ctrls_setnonblock(ctrls_sockfd) < 0) {
652
0
        xerrno = errno;
653
654
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
655
0
          "error: unable to set nonblocking on local socket: %s",
656
0
          strerror(xerrno));
657
658
0
        errno = xerrno;
659
0
        return -1;
660
0
      }
661
662
      /* Accept pending connections */
663
0
      cl_fd = pr_ctrls_accept(ctrls_sockfd, &cl_uid, &cl_gid, &cl_pid,
664
0
        ctrls_cl_freshness);
665
0
      xerrno = errno;
666
667
0
      if (cl_fd < 0) {
668
0
        if (xerrno != ETIMEDOUT) {
669
0
          pr_ctrls_log(MOD_CTRLS_VERSION,
670
0
            "error: unable to accept connection: %s", strerror(xerrno));
671
0
        }
672
673
0
        continue;
674
0
      }
675
676
      /* Restore blocking mode to the ctrl socket */
677
0
      if (ctrls_setblock(ctrls_sockfd) < 0) {
678
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
679
0
          "error: unable to set blocking on local socket: %s",
680
0
          strerror(errno));
681
0
      }
682
683
      /* Set this socket as non-blocking */
684
0
      if (ctrls_setnonblock(cl_fd) < 0) {
685
0
        pr_ctrls_log(MOD_CTRLS_VERSION,
686
0
          "error: unable to set nonblocking on client socket: %s",
687
0
          strerror(errno));
688
0
        (void) close(cl_fd);
689
0
        continue;
690
0
      }
691
692
0
      if (pr_ctrls_check_user_acl(cl_uid, &ctrls_sock_acl.acl_users) != TRUE &&
693
0
          pr_ctrls_check_group_acl(cl_gid, &ctrls_sock_acl.acl_groups) != TRUE) {
694
0
        cl_flags = PR_CTRLS_CL_NOACCESS;
695
0
      }
696
697
      /* Add the client to the list */
698
0
      ctrls_add_cl(cl_fd, cl_uid, cl_gid, cl_pid, cl_flags);
699
0
    }
700
0
  }
701
702
  /* Go through the client list */
703
0
  ctrls_cls_read();
704
705
0
  return 0; 
706
0
}
707
708
0
static int ctrls_send_cl_resps(void) {
709
710
  /* Go through the client list */
711
0
  ctrls_cls_write();
712
713
0
  return 0;
714
0
}
715
716
0
static int ctrls_setblock(int sockfd) {
717
0
  int flags = 0;
718
0
  int res = -1;
719
720
  /* default error */
721
0
  errno = EBADF;
722
723
0
  flags = fcntl(sockfd, F_GETFL);
724
0
  res = fcntl(sockfd, F_SETFL, flags & (U32BITS ^ O_NONBLOCK));
725
726
0
  return res;
727
0
}
728
729
0
static int ctrls_setnonblock(int sockfd) {
730
0
  int flags = 0;
731
0
  int res = -1;
732
733
  /* default error */
734
0
  errno = EBADF;
735
736
0
  flags = fcntl(sockfd, F_GETFL);
737
0
  res = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
738
739
0
  return res;
740
0
}
741
742
0
static int ctrls_timer_cb(CALLBACK_FRAME) {
743
0
  static unsigned char first_time = TRUE;
744
745
  /* If the ControlsEngine is not to run, do nothing from here on out */
746
0
  if (ctrls_engine == FALSE) {
747
0
    (void) close(ctrls_sockfd);
748
0
    ctrls_sockfd = -1;
749
750
0
    if (is_master) {
751
      /* Remove the local socket path as well */
752
0
      (void) unlink(ctrls_sock_file);
753
0
    }
754
755
0
    return 0;
756
0
  }
757
758
0
  if (first_time == TRUE) {
759
    /* Change the ownership on the socket to that configured by the admin */
760
0
    PRIVS_ROOT
761
0
    if (chown(ctrls_sock_file, ctrls_sock_uid, ctrls_sock_gid) < 0) {
762
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
763
0
        ": unable to chown local socket %s: %s", ctrls_sock_file,
764
0
        strerror(errno));
765
0
    }
766
0
    PRIVS_RELINQUISH
767
768
0
    first_time = FALSE;
769
0
  }
770
771
  /* Please no alarms while doing this. */
772
0
  pr_alarms_block();
773
774
  /* Process pending requests. */
775
0
  ctrls_recv_cl_reqs();
776
777
  /* Run through the controls */
778
0
  pr_run_ctrls(NULL, NULL);
779
780
  /* Process pending responses */
781
0
  ctrls_send_cl_resps();
782
783
  /* Reset controls */
784
0
  pr_ctrls_reset();
785
786
0
  pr_alarms_unblock();
787
0
  return 1;
788
0
}
789
790
/* Controls handlers
791
 */
792
793
0
static int respcmp(const void *a, const void *b) {
794
0
  return strcmp(*((char **) a), *((char **) b));
795
0
}
796
797
static int ctrls_handle_help(pr_ctrls_t *ctrl, int reqargc,
798
0
    char **reqargv) {
799
800
  /* Run through the list of registered controls, and add them to the
801
   * response, including the module in which they appear.
802
   */
803
804
0
  if (reqargc != 0) {
805
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
806
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
807
0
  }
808
809
0
  if (pr_get_registered_actions(ctrl, CTRLS_GET_DESC) < 0) {
810
0
    pr_ctrls_add_response(ctrl, "unable to get actions: %s", strerror(errno));
811
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
812
0
  }
813
814
  /* Be nice, and sort the directives lexicographically */
815
0
  qsort(ctrl->ctrls_cb_resps->elts, ctrl->ctrls_cb_resps->nelts,
816
0
    sizeof(char *), respcmp);
817
818
0
  return PR_CTRLS_STATUS_OK;
819
0
}
820
821
static int ctrls_handle_insctrl(pr_ctrls_t *ctrl, int reqargc,
822
0
    char **reqargv) {
823
0
  module *m = ANY_MODULE;
824
0
  int res, xerrno;
825
826
  /* Enable a control into the registered controls list. This requires the
827
   * action and, optionally, the module of the control to be enabled.
828
   */
829
830
  /* Check the insctrl ACL */
831
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "insctrl") != TRUE) {
832
833
    /* Access denied */
834
0
    pr_ctrls_add_response(ctrl, "access denied");
835
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
836
0
  }
837
838
0
  if (reqargc < 1 ||
839
0
      reqargc > 2) {
840
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
841
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
842
0
  }
843
844
  /* If the optional second parameter, a module name, is used, lookup
845
   * the module pointer matching the name.
846
   */
847
0
  if (reqargc == 2) {
848
0
    m = pr_module_get(reqargv[1]);
849
0
  }
850
851
0
  res = pr_set_registered_actions(m, reqargv[0], FALSE, 0);
852
0
  xerrno = errno;
853
854
0
  if (res < 0) {
855
0
    if (xerrno == ENOENT) {
856
0
      pr_ctrls_add_response(ctrl, "no such control: '%s'", reqargv[0]);
857
0
      return PR_CTRLS_STATUS_SUBJECT_NOT_FOUND;
858
0
    }
859
860
0
    pr_ctrls_add_response(ctrl, "unable to enable '%s': %s", reqargv[0],
861
0
      strerror(errno));
862
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
863
0
  }
864
865
0
  pr_ctrls_add_response(ctrl, "'%s' control enabled", reqargv[0]);
866
0
  return PR_CTRLS_STATUS_OK;
867
0
}
868
869
static int ctrls_handle_lsctrl(pr_ctrls_t *ctrl, int reqargc,
870
0
    char **reqargv) {
871
872
  /* Run through the list of registered controls, and add them to the
873
   * response, including the module in which they appear.
874
   */
875
876
  /* Check the lsctrl ACL */
877
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "lsctrl") != TRUE) {
878
879
    /* Access denied */
880
0
    pr_ctrls_add_response(ctrl, "access denied");
881
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
882
0
  }
883
884
0
  if (reqargc != 0) {
885
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
886
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
887
0
  }
888
889
0
  if (pr_get_registered_actions(ctrl, CTRLS_GET_ACTION_ENABLED) < 0) {
890
0
    pr_ctrls_add_response(ctrl, "unable to get actions: %s", strerror(errno));
891
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
892
0
  }
893
894
  /* Be nice, and sort the actions lexicographically */
895
0
  qsort(ctrl->ctrls_cb_resps->elts, ctrl->ctrls_cb_resps->nelts,
896
0
    sizeof(char *), respcmp);
897
898
0
  return PR_CTRLS_STATUS_OK;
899
0
}
900
901
static int ctrls_handle_rmctrl(pr_ctrls_t *ctrl, int reqargc,
902
0
    char **reqargv) {
903
0
  module *m = ANY_MODULE;
904
0
  int res, xerrno;
905
906
  /* Disable a control from the registered controls list. This requires the
907
   * action and, optionally, the module of the control to be removed.
908
   */
909
910
  /* Check the rmctrl ACL */
911
0
  if (pr_ctrls_check_acl(ctrl, ctrls_acttab, "rmctrl") != TRUE) {
912
913
    /* Access denied */
914
0
    pr_ctrls_add_response(ctrl, "access denied");
915
0
    return PR_CTRLS_STATUS_ACCESS_DENIED;
916
0
  }
917
918
0
  if (reqargc < 1 ||
919
0
      reqargc > 2) {
920
0
    pr_ctrls_add_response(ctrl, "wrong number of parameters");
921
0
    return PR_CTRLS_STATUS_WRONG_PARAMETERS;
922
0
  }
923
924
  /* The three controls added by this module _cannot_ be removed (at least
925
   * not via this control handler).
926
   */
927
0
  if (strcmp(reqargv[0], "insctrl") == 0 ||
928
0
      strcmp(reqargv[0], "lsctrl") == 0 ||
929
0
      strcmp(reqargv[0], "rmctrl") == 0) {
930
0
    pr_ctrls_add_response(ctrl, "'%s' control cannot be removed", reqargv[0]);
931
0
    return PR_CTRLS_STATUS_OPERATION_DENIED;
932
0
  }
933
934
  /* If the optional second parameter, a module name, is used, lookup
935
   * the module pointer matching the name.
936
   */
937
0
  if (reqargc == 2) {
938
0
    m = pr_module_get(reqargv[1]);
939
0
  }
940
941
0
  res = pr_set_registered_actions(m, reqargv[0], FALSE, PR_CTRLS_ACT_DISABLED);
942
0
  xerrno = errno;
943
944
0
  if (res < 0) {
945
0
    if (xerrno == ENOENT) {
946
0
      pr_ctrls_add_response(ctrl, "no such control: '%s'", reqargv[0]);
947
0
      return PR_CTRLS_STATUS_SUBJECT_NOT_FOUND;
948
0
    }
949
950
0
    pr_ctrls_add_response(ctrl, "unable to disable '%s': %s", reqargv[0],
951
0
      strerror(xerrno));
952
0
    return PR_CTRLS_STATUS_INTERNAL_ERROR;
953
0
  }
954
955
0
  if (strcmp(reqargv[0], "all") != 0) {
956
0
    pr_ctrls_add_response(ctrl, "'%s' control disabled", reqargv[0]);
957
958
0
  } else {
959
    /* If all actions have been disabled, stop listening on the local
960
     * socket, and turn off this module's engine.
961
     */
962
0
    pr_ctrls_add_response(ctrl, "all controls disabled");
963
0
    pr_ctrls_add_response(ctrl, "restart the daemon to re-enable controls");
964
965
0
    (void) close(ctrls_sockfd);
966
0
    ctrls_sockfd = -1;
967
968
0
    ctrls_engine = FALSE;
969
0
  }
970
971
0
  return PR_CTRLS_STATUS_OK;
972
0
}
973
974
/* Configuration handlers
975
 */
976
977
/* Default behavior is to deny everyone unless an ACL has been configured */
978
0
MODRET set_ctrlsacls(cmd_rec *cmd) {
979
0
  int res;
980
0
  char **actions = NULL;
981
0
  const char *bad_action = NULL;
982
983
0
  CHECK_ARGS(cmd, 4);
984
0
  CHECK_CONF(cmd, CONF_ROOT);
985
986
  /* Parse the given string of actions into a char **.  Then iterate
987
   * through the acttab, checking to see if a given control is _not_ in
988
   * the list.  If not in the list, unregister that control.
989
   */
990
991
0
  actions = pr_ctrls_parse_acl(cmd->tmp_pool, cmd->argv[1]);
992
993
  /* Check the second parameter to make sure it is "allow" or "deny" */
994
0
  if (strcmp(cmd->argv[2], "allow") != 0 &&
995
0
      strcmp(cmd->argv[2], "deny") != 0) {
996
0
    CONF_ERROR(cmd, "second parameter must be 'allow' or 'deny'");
997
0
  }
998
999
  /* Check the third parameter to make sure it is "user" or "group" */
1000
0
  if (strcmp(cmd->argv[3], "user") != 0 &&
1001
0
      strcmp(cmd->argv[3], "group") != 0) {
1002
0
    CONF_ERROR(cmd, "third parameter must be 'user' or 'group'");
1003
0
  }
1004
1005
0
  res = pr_ctrls_set_module_acls2(ctrls_acttab, ctrls_pool, actions,
1006
0
    cmd->argv[2], cmd->argv[3], cmd->argv[4], &bad_action);
1007
0
  if (res < 0) {
1008
0
    CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown action: '",
1009
0
      bad_action, "'", NULL));
1010
0
  }
1011
1012
0
  return PR_HANDLED(cmd);
1013
0
}
1014
1015
/* default: 10 secs */
1016
0
MODRET set_ctrlsauthfreshness(cmd_rec *cmd) {
1017
0
  int freshness = 0;
1018
1019
0
  CHECK_ARGS(cmd, 1);
1020
0
  CHECK_CONF(cmd, CONF_ROOT);
1021
1022
0
  freshness = atoi(cmd->argv[1]);
1023
0
  if (freshness <= 0) {
1024
0
    CONF_ERROR(cmd, "must be a positive number");
1025
0
  }
1026
1027
0
  ctrls_cl_freshness = freshness;
1028
0
  return PR_HANDLED(cmd);
1029
0
}
1030
1031
0
MODRET set_ctrlsengine(cmd_rec *cmd) {
1032
0
  int bool = -1;
1033
1034
0
  CHECK_ARGS(cmd, 1);
1035
0
  CHECK_CONF(cmd, CONF_ROOT);
1036
1037
0
  bool = get_boolean(cmd, 1);
1038
0
  if (bool == -1) {
1039
0
    CONF_ERROR(cmd, "expected Boolean parameter");
1040
0
  }
1041
1042
0
  ctrls_engine = bool;
1043
0
  return PR_HANDLED(cmd);
1044
0
}
1045
1046
/* default: 10 secs */
1047
0
MODRET set_ctrlsinterval(cmd_rec *cmd) {
1048
0
  int nsecs = 0;
1049
1050
0
  CHECK_ARGS(cmd, 1);
1051
0
  CHECK_CONF(cmd, CONF_ROOT);
1052
1053
0
  nsecs = atoi(cmd->argv[1]);
1054
0
  if (nsecs <= 0) {
1055
0
    CONF_ERROR(cmd, "must be a positive number");
1056
0
  }
1057
1058
  /* Remove the existing timer, and re-install it with this new interval. */
1059
0
  ctrls_interval = nsecs;
1060
1061
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1062
0
  pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
1063
0
    "Controls polling");
1064
1065
0
  return PR_HANDLED(cmd);
1066
0
}
1067
1068
0
MODRET set_ctrlslog(cmd_rec *cmd) {
1069
0
  int res = 0;
1070
1071
0
  CHECK_ARGS(cmd, 1);
1072
0
  CHECK_CONF(cmd, CONF_ROOT);
1073
1074
0
  ctrls_logname = pstrdup(ctrls_pool, cmd->argv[1]);
1075
1076
0
  res = ctrls_openlog();
1077
0
  if (res < 0) {
1078
0
    if (res == -1) {
1079
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to open '",
1080
0
        (char *) cmd->argv[1], "': ", strerror(errno), NULL));
1081
0
    }
1082
1083
0
    if (res == -2) {
1084
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1085
0
        "unable to log to a world-writable directory", NULL));
1086
0
    }
1087
0
  }
1088
1089
0
  return PR_HANDLED(cmd);
1090
0
}
1091
1092
/* Default: 5 max clients */
1093
0
MODRET set_ctrlsmaxclients(cmd_rec *cmd) {
1094
0
  int nclients = 0;
1095
1096
0
  CHECK_ARGS(cmd, 1);
1097
0
  CHECK_CONF(cmd, CONF_ROOT);
1098
1099
0
  nclients = atoi(cmd->argv[1]);
1100
0
  if (nclients <= 0) {
1101
0
    CONF_ERROR(cmd, "must be a positive number");
1102
0
  }
1103
1104
0
  cl_maxlistlen = nclients;
1105
0
  return PR_HANDLED(cmd);
1106
0
}
1107
1108
/* Default: var/run/proftpd.sock */
1109
0
MODRET set_ctrlssocket(cmd_rec *cmd) {
1110
0
  char *path;
1111
1112
0
  CHECK_ARGS(cmd, 1);
1113
0
  CHECK_CONF(cmd, CONF_ROOT);
1114
1115
0
  path = cmd->argv[1];
1116
0
  if (*path != '/') {
1117
0
    CONF_ERROR(cmd, "must be an absolute path");
1118
0
  }
1119
1120
  /* Close the socket. */
1121
0
  if (ctrls_sockfd >= 0) {
1122
0
    pr_trace_msg(trace_channel, 3, "closing ctrls socket '%s' (fd %d)",
1123
0
      ctrls_sock_file, ctrls_sockfd);
1124
0
    (void) unlink(ctrls_sock_file);
1125
0
    (void) close(ctrls_sockfd);
1126
0
    ctrls_sockfd = -1;
1127
0
  }
1128
1129
  /* Change the path. */
1130
0
  if (strcmp(path, ctrls_sock_file) != 0) {
1131
0
    ctrls_sock_file = pstrdup(ctrls_pool, path);
1132
0
  }
1133
1134
0
  return PR_HANDLED(cmd);
1135
0
}
1136
1137
/* Default behavior is to deny everyone unless an ACL has been configured */
1138
0
MODRET set_ctrlssocketacl(cmd_rec *cmd) {
1139
0
  CHECK_ARGS(cmd, 3);
1140
0
  CHECK_CONF(cmd, CONF_ROOT);
1141
1142
0
  pr_ctrls_init_acl(&ctrls_sock_acl);
1143
1144
  /* Check the first argument to make sure it either "allow" or "deny" */
1145
0
  if (strcasecmp(cmd->argv[1], "allow") != 0 &&
1146
0
      strcasecmp(cmd->argv[1], "deny") != 0) {
1147
0
    CONF_ERROR(cmd, "first parameter must be either 'allow' or 'deny'");
1148
0
  }
1149
1150
  /* Check the second argument to see how to handle the directive */
1151
0
  if (strcasecmp(cmd->argv[2], "user") == 0) {
1152
0
    if (pr_ctrls_set_user_acl(ctrls_pool, &ctrls_sock_acl.acl_users,
1153
0
        cmd->argv[1], cmd->argv[3]) < 0) {
1154
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1155
0
        "error configuring user socket ACL: ", strerror(errno), NULL));
1156
0
    }
1157
 
1158
0
  } else if (strcasecmp(cmd->argv[2], "group") == 0) {
1159
0
    if (pr_ctrls_set_group_acl(ctrls_pool, &ctrls_sock_acl.acl_groups,
1160
0
        cmd->argv[1], cmd->argv[3]) < 0) {
1161
0
      CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
1162
0
        "error configuring group socket ACL: ", strerror(errno), NULL));
1163
0
    }
1164
1165
0
  } else {
1166
0
    CONF_ERROR(cmd, "second parameter must be either 'user' or 'group'");
1167
0
  }
1168
1169
0
  return PR_HANDLED(cmd);
1170
0
}
1171
1172
/* Default: root root */
1173
0
MODRET set_ctrlssocketowner(cmd_rec *cmd) {
1174
0
  gid_t gid = 0;
1175
0
  uid_t uid = 0;
1176
1177
0
  CHECK_ARGS(cmd, 2);
1178
0
  CHECK_CONF(cmd, CONF_ROOT);
1179
1180
0
  uid = pr_auth_name2uid(cmd->tmp_pool, cmd->argv[1]);
1181
0
  if (uid == (uid_t) -1) {
1182
0
    if (errno != EINVAL) {
1183
0
      pr_log_debug(DEBUG0, "%s: %s has UID of -1", (char *) cmd->argv[0],
1184
0
        (char *) cmd->argv[1]);
1185
1186
0
    } else {
1187
0
      pr_log_debug(DEBUG0, "%s: no such user '%s'", (char *) cmd->argv[0],
1188
0
        (char *) cmd->argv[1]);
1189
0
    }
1190
1191
0
  } else {
1192
0
    ctrls_sock_uid = uid;
1193
0
  }
1194
1195
0
  gid = pr_auth_name2gid(cmd->tmp_pool, cmd->argv[2]);
1196
0
  if (gid == (gid_t) -1) {
1197
0
    if (errno != EINVAL) {
1198
0
      pr_log_debug(DEBUG0, "%s: %s has GID of -1", (char *) cmd->argv[0],
1199
0
        (char *) cmd->argv[2]);
1200
1201
0
    } else {
1202
0
      pr_log_debug(DEBUG0, "%s: no such group '%s'", (char *) cmd->argv[0],
1203
0
        (char *) cmd->argv[2]);
1204
0
    }
1205
1206
0
  } else {
1207
0
    ctrls_sock_gid = gid;
1208
0
  }
1209
1210
0
  return PR_HANDLED(cmd);
1211
0
}
1212
1213
/* Event handlers
1214
 */
1215
1216
0
static void ctrls_shutdown_ev(const void *event_data, void *user_data) {
1217
0
  if (!is_master || !ctrls_engine)
1218
0
    return;
1219
1220
  /* Close any connected clients */
1221
0
  if (cl_list != NULL) {
1222
0
    pr_ctrls_cl_t *cl = NULL;
1223
1224
0
    for (cl = cl_list; cl; cl = cl->cl_next) {
1225
0
      if (cl->cl_fd >= 0) {
1226
0
        (void) close(cl->cl_fd);
1227
0
        cl->cl_fd = -1;
1228
0
      }
1229
0
    }
1230
0
  }
1231
1232
0
  (void) close(ctrls_sockfd);
1233
0
  ctrls_sockfd = -1;
1234
1235
  /* Remove the local socket path as well */
1236
0
  (void) unlink(ctrls_sock_file);
1237
0
  return;
1238
0
}
1239
1240
0
static void ctrls_postparse_ev(const void *event_data, void *user_data) {
1241
0
  if (ctrls_engine == FALSE ||
1242
0
      ServerType == SERVER_INETD) {
1243
0
    return;
1244
0
  }
1245
1246
  /* Start listening on the ctrl socket */
1247
0
  PRIVS_ROOT
1248
0
  ctrls_sockfd = ctrls_listen(ctrls_sock_file);
1249
0
  PRIVS_RELINQUISH
1250
1251
  /* Start a timer for the checking/processing of the ctrl socket.  */
1252
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1253
0
  pr_timer_add(ctrls_interval, CTRLS_TIMER_ID, &ctrls_module, ctrls_timer_cb,
1254
0
    "Controls polling");
1255
0
}
1256
1257
0
static void ctrls_restart_ev(const void *event_data, void *user_data) {
1258
0
  register unsigned int i;
1259
1260
  /* Block alarms while we're preparing for the restart. */
1261
0
  pr_alarms_block();
1262
1263
  /* Close any connected clients */
1264
0
  if (cl_list != NULL) {
1265
0
    pr_ctrls_cl_t *cl = NULL;
1266
1267
0
    for (cl = cl_list; cl; cl = cl->cl_next) {
1268
0
      if (cl->cl_fd >= 0) {
1269
0
        (void) close(cl->cl_fd);
1270
0
        cl->cl_fd = -1;
1271
0
      }
1272
0
    }
1273
0
  }
1274
1275
  /* Reset the client list */
1276
0
  cl_list = NULL;
1277
0
  cl_listlen = 0;
1278
1279
0
  pr_trace_msg(trace_channel, 3, "closing ctrls socket '%s' (fd %d)",
1280
0
    ctrls_sock_file, ctrls_sockfd);
1281
0
  (void) close(ctrls_sockfd);
1282
0
  ctrls_sockfd = -1;
1283
1284
0
  ctrls_closelog();
1285
1286
  /* Clear the existing pool */
1287
0
  if (ctrls_pool != NULL) {
1288
0
    destroy_pool(ctrls_pool);
1289
1290
0
    ctrls_logname = NULL;
1291
0
    ctrls_sock_file = MOD_CTRLS_DEFAULT_SOCK;
1292
0
  }
1293
1294
  /* Allocate the pool for this module's use */
1295
0
  ctrls_pool = make_sub_pool(permanent_pool);
1296
0
  pr_pool_tag(ctrls_pool, MOD_CTRLS_VERSION);
1297
1298
  /* Register the control handlers */
1299
0
  for (i = 0; ctrls_acttab[i].act_action; i++) {
1300
1301
    /* Allocate and initialize the ACL for this control. */
1302
0
    ctrls_acttab[i].act_acl = pcalloc(ctrls_pool, sizeof(ctrls_acl_t));
1303
0
    pr_ctrls_init_acl(ctrls_acttab[i].act_acl);
1304
0
  }
1305
1306
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1307
0
  pr_alarms_unblock();
1308
0
  return;
1309
0
}
1310
1311
/* Initialization routines
1312
 */
1313
1314
0
static int ctrls_init(void) {
1315
0
  register unsigned int i = 0; 
1316
1317
  /* Allocate the pool for this module's use */
1318
0
  ctrls_pool = make_sub_pool(permanent_pool);
1319
0
  pr_pool_tag(ctrls_pool, MOD_CTRLS_VERSION);
1320
1321
  /* Register the control handlers */
1322
0
  for (i = 0; ctrls_acttab[i].act_action; i++) {
1323
1324
    /* Allocate and initialize the ACL for this control. */
1325
0
    ctrls_acttab[i].act_acl = pcalloc(ctrls_pool, sizeof(ctrls_acl_t));
1326
0
    pr_ctrls_init_acl(ctrls_acttab[i].act_acl);
1327
1328
0
    if (pr_ctrls_register(&ctrls_module, ctrls_acttab[i].act_action,
1329
0
        ctrls_acttab[i].act_desc, ctrls_acttab[i].act_cb) < 0) {
1330
0
      pr_log_pri(PR_LOG_NOTICE, MOD_CTRLS_VERSION
1331
0
        ": error registering '%s' control: %s",
1332
0
        ctrls_acttab[i].act_action, strerror(errno));
1333
0
    }
1334
0
  }
1335
1336
  /* Make certain the socket ACL is initialized. */
1337
0
  memset(&ctrls_sock_acl, '\0', sizeof(ctrls_acl_t));
1338
0
  ctrls_sock_acl.acl_users.allow = ctrls_sock_acl.acl_groups.allow = FALSE;
1339
1340
0
  pr_event_register(&ctrls_module, "core.restart", ctrls_restart_ev, NULL);
1341
0
  pr_event_register(&ctrls_module, "core.shutdown", ctrls_shutdown_ev, NULL);
1342
0
  pr_event_register(&ctrls_module, "core.postparse", ctrls_postparse_ev, NULL);
1343
1344
0
  return 0;
1345
0
}
1346
1347
0
static int ctrls_sess_init(void) {
1348
1349
  /* Children are not to listen for or handle control requests */
1350
0
  ctrls_engine = FALSE;
1351
0
  pr_timer_remove(CTRLS_TIMER_ID, &ctrls_module);
1352
1353
0
  pr_event_unregister(&ctrls_module, "core.restart", ctrls_restart_ev);
1354
1355
  /* Close the inherited socket */
1356
0
  close(ctrls_sockfd);
1357
0
  ctrls_sockfd = -1;
1358
 
1359
0
  return 0;
1360
0
}
1361
1362
static ctrls_acttab_t ctrls_acttab[] = {
1363
  { "help", "describe all registered controls", NULL,
1364
    ctrls_handle_help },
1365
  { "insctrl",  "enable a disabled control", NULL, 
1366
    ctrls_handle_insctrl },
1367
  { "lsctrl", "list all registered controls", NULL, 
1368
    ctrls_handle_lsctrl },
1369
  { "rmctrl", "disable a registered control", NULL,
1370
    ctrls_handle_rmctrl },
1371
  { NULL, NULL, NULL, NULL }
1372
};
1373
1374
/* Module API tables
1375
 */
1376
1377
static conftable ctrls_conftab[] = {
1378
  { "ControlsACLs",   set_ctrlsacls,    NULL },
1379
  { "ControlsAuthFreshness",  set_ctrlsauthfreshness, NULL },
1380
  { "ControlsEngine",   set_ctrlsengine,  NULL },
1381
  { "ControlsInterval",   set_ctrlsinterval,  NULL },
1382
  { "ControlsLog",    set_ctrlslog,   NULL },
1383
  { "ControlsMaxClients", set_ctrlsmaxclients,  NULL },
1384
  { "ControlsSocket",   set_ctrlssocket,  NULL },
1385
  { "ControlsSocketACL",  set_ctrlssocketacl, NULL },
1386
  { "ControlsSocketOwner",  set_ctrlssocketowner, NULL },
1387
  { NULL }
1388
};
1389
1390
module ctrls_module = {
1391
  NULL, NULL,
1392
1393
  /* Module API version 2.0 */
1394
  0x20,
1395
1396
  /* Module name */
1397
  "ctrls",
1398
1399
  /* Module configuration handler table */
1400
  ctrls_conftab,
1401
1402
  /* Module command handler table */
1403
  NULL,
1404
1405
  /* Module authentication handler table */
1406
  NULL,
1407
1408
  /* Module initialization function */
1409
  ctrls_init,
1410
1411
  /* Session initialization function */
1412
  ctrls_sess_init,
1413
1414
  /* Module version */
1415
  MOD_CTRLS_VERSION
1416
};