1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2001-2017 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Controls API routines */
26 
27 #include "conf.h"
28 #include "privs.h"
29 
30 #ifdef HAVE_UCRED_H
31 # include <ucred.h>
32 #endif /* !HAVE_UCRED_H */
33 
34 #ifdef HAVE_SYS_UCRED_H
35 # include <sys/ucred.h>
36 #endif /* !HAVE_SYS_UCRED_H */
37 
38 #ifdef HAVE_SYS_UIO_H
39 # include <sys/uio.h>
40 #endif /* !HAVE_SYS_UIO_H */
41 
42 #ifdef PR_USE_CTRLS
43 
44 #include "mod_ctrls.h"
45 
46 /* Maximum number of request arguments. */
47 #define CTRLS_MAX_NREQARGS	32
48 
49 /* Maximum number of response arguments. */
50 #define CTRLS_MAX_NRESPARGS	1024
51 
52 /* Maximum length of a single request argument. */
53 #define CTRLS_MAX_REQARGLEN	256
54 
55 typedef struct ctrls_act_obj {
56   struct ctrls_act_obj *prev, *next;
57   pool *pool;
58   unsigned int id;
59   const char *action;
60   const char *desc;
61   const module *module;
62   volatile unsigned int flags;
63   int (*action_cb)(pr_ctrls_t *, int, char **);
64 } ctrls_action_t;
65 
66 static unsigned char ctrls_blocked = FALSE;
67 
68 static pool *ctrls_pool = NULL;
69 static ctrls_action_t *ctrls_action_list = NULL;
70 
71 static pr_ctrls_t *ctrls_active_list = NULL;
72 static pr_ctrls_t *ctrls_free_list = NULL;
73 
74 static int ctrls_use_isfifo = FALSE;
75 
76 static const char *trace_channel = "ctrls";
77 
78 /* lookup/lookup_next indices */
79 static ctrls_action_t *action_lookup_next = NULL;
80 static const char *action_lookup_action = NULL;
81 static module *action_lookup_module = NULL;
82 
83 /* Logging */
84 static int ctrls_logfd = -1;
85 
86 /* necessary prototypes */
87 static ctrls_action_t *ctrls_action_new(void);
88 static pr_ctrls_t *ctrls_new(void);
89 static pr_ctrls_t *ctrls_lookup_action(module *, const char *, unsigned char);
90 static pr_ctrls_t *ctrls_lookup_next_action(module *, unsigned char);
91 
ctrls_prepare(ctrls_action_t * act)92 static pr_ctrls_t *ctrls_prepare(ctrls_action_t *act) {
93   pr_ctrls_t *ctrl = NULL;
94 
95   /* Sanity check */
96   if (!act)
97     return NULL;
98 
99   pr_block_ctrls();
100 
101   /* Get a blank ctrl object */
102   ctrl = ctrls_new();
103 
104   /* Fill in the fields from the action object. */
105   ctrl->ctrls_id = act->id;
106   ctrl->ctrls_module = act->module;
107   ctrl->ctrls_action = act->action;
108   ctrl->ctrls_desc = act->desc;
109   ctrl->ctrls_cb = act->action_cb;
110   ctrl->ctrls_flags = act->flags;
111 
112   /* Add this to the "in use" list */
113   ctrl->ctrls_next = ctrls_active_list;
114   ctrls_active_list = ctrl;
115 
116   pr_unblock_ctrls();
117   return ctrl;
118 }
119 
ctrls_free(pr_ctrls_t * ctrl)120 static void ctrls_free(pr_ctrls_t *ctrl) {
121 
122   /* Make sure that ctrls are blocked while we're doing this */
123   pr_block_ctrls();
124 
125   /* Remove this object from the active list */
126   if (ctrl->ctrls_prev)
127     ctrl->ctrls_prev->ctrls_next = ctrl->ctrls_next;
128 
129   else
130     ctrls_active_list = ctrl->ctrls_next;
131 
132   if (ctrl->ctrls_next)
133     ctrl->ctrls_next->ctrls_prev = ctrl->ctrls_prev;
134 
135   /* Clear its fields, and add it to the free list */
136   ctrl->ctrls_next = NULL;
137   ctrl->ctrls_prev = NULL;
138   ctrl->ctrls_id = 0;
139   ctrl->ctrls_module = NULL;
140   ctrl->ctrls_action = NULL;
141   ctrl->ctrls_cb = NULL;
142   ctrl->ctrls_cb_retval = 1;
143   ctrl->ctrls_flags = 0;
144 
145   if (ctrl->ctrls_tmp_pool) {
146     destroy_pool(ctrl->ctrls_tmp_pool);
147     ctrl->ctrls_tmp_pool = NULL;
148   }
149 
150   ctrl->ctrls_cb_args = NULL;
151   ctrl->ctrls_cb_resps = NULL;
152   ctrl->ctrls_data = NULL;
153 
154   ctrl->ctrls_next = ctrls_free_list;
155   ctrls_free_list = ctrl;
156 
157   pr_unblock_ctrls();
158   return;
159 }
160 
ctrls_action_new(void)161 static ctrls_action_t *ctrls_action_new(void) {
162   ctrls_action_t *act = NULL;
163   pool *sub_pool = make_sub_pool(ctrls_pool);
164 
165   pr_pool_tag(sub_pool, "ctrls action subpool");
166   act = pcalloc(sub_pool, sizeof(ctrls_action_t));
167   act->pool = sub_pool;
168 
169   return act;
170 }
171 
ctrls_new(void)172 static pr_ctrls_t *ctrls_new(void) {
173   pr_ctrls_t *ctrl = NULL;
174 
175   /* Check for a free ctrl first */
176   if (ctrls_free_list) {
177 
178     /* Take one from the top */
179     ctrl = ctrls_free_list;
180     ctrls_free_list = ctrls_free_list->ctrls_next;
181 
182     if (ctrls_free_list)
183       ctrls_free_list->ctrls_prev = NULL;
184 
185   } else {
186 
187     /* Have to allocate a new one. */
188     ctrl = (pr_ctrls_t *) pcalloc(ctrls_pool, sizeof(pr_ctrls_t));
189 
190     /* It's important that a new ctrl object have the retval initialized
191      * to 1; this tells the Controls layer that it is "pending", not yet
192      * handled.
193      */
194     ctrl->ctrls_cb_retval = 1;
195   }
196 
197   return ctrl;
198 }
199 
ctrls_sep(char ** str)200 static char *ctrls_sep(char **str) {
201   char *ret = NULL, *dst = NULL;
202   unsigned char quoted = FALSE;
203 
204   /* Sanity checks */
205   if (!str || !*str || !**str)
206     return NULL;
207 
208   while (**str && PR_ISSPACE(**str)) {
209     (*str)++;
210   }
211 
212   if (!**str)
213     return NULL;
214 
215   ret = dst = *str;
216 
217   if (**str == '\"') {
218     quoted = TRUE;
219     (*str)++;
220   }
221 
222   while (**str &&
223          (quoted ? (**str != '\"') : !PR_ISSPACE(**str))) {
224 
225     if (**str == '\\' && quoted) {
226 
227       /* Escaped char */
228       if (*((*str) + 1))
229         *dst = *(++(*str));
230     }
231 
232     *dst++ = **str;
233     ++(*str);
234   }
235 
236   if (**str)
237     (*str)++;
238   *dst = '\0';
239 
240   return ret;
241 }
242 
pr_ctrls_register(const module * mod,const char * action,const char * desc,int (* cb)(pr_ctrls_t *,int,char **))243 int pr_ctrls_register(const module *mod, const char *action,
244     const char *desc, int (*cb)(pr_ctrls_t *, int, char **)) {
245   ctrls_action_t *act = NULL, *acti = NULL;
246   unsigned int act_id = 0;
247 
248   /* sanity checks */
249   if (action == NULL ||
250       desc == NULL ||
251       cb == NULL) {
252     errno = EINVAL;
253     return -1;
254   }
255 
256   pr_trace_msg("ctrls", 3,
257     "module '%s' registering handler for ctrl action '%s' (at %p)",
258     mod ? mod->name : "(none)", action, cb);
259 
260   /* Block ctrls while we're doing this */
261   pr_block_ctrls();
262 
263   /* Get a ctrl action object */
264   act = ctrls_action_new();
265 
266   /* Randomly generate a unique random ID for this object */
267   while (TRUE) {
268     unsigned char have_id = FALSE;
269     act_id = (unsigned int) pr_random_next(1L, RAND_MAX);
270 
271     /* Check the list for this ID */
272     for (acti = ctrls_action_list; acti; acti = acti->next) {
273       if (acti->id == act_id) {
274         have_id = TRUE;
275         break;
276       }
277     }
278 
279     if (!have_id)
280       break;
281   }
282 
283   act->next = NULL;
284   act->id = act_id;
285   act->action = pstrdup(ctrls_pool, action);
286   act->desc = desc;
287   act->module = mod;
288   act->action_cb = cb;
289 
290   /* Add this to the list of "registered" actions */
291 
292   if (ctrls_action_list) {
293     act->next = ctrls_action_list;
294     ctrls_action_list->prev = act;
295   }
296 
297   ctrls_action_list = act;
298 
299   pr_unblock_ctrls();
300 
301   return act_id;
302 }
303 
pr_ctrls_unregister(module * mod,const char * action)304 int pr_ctrls_unregister(module *mod, const char *action) {
305   ctrls_action_t *act = NULL;
306   unsigned char have_action = FALSE;
307 
308   /* Make sure that ctrls are blocked while we're doing this */
309   pr_block_ctrls();
310 
311   for (act = ctrls_action_list; act; act = act->next) {
312     if ((action == NULL || strcmp(act->action, action) == 0) &&
313         (act->module == mod || mod == ANY_MODULE || mod == NULL)) {
314       have_action = TRUE;
315 
316       /* Remove this object from the list of registered actions */
317       if (act->prev) {
318         act->prev->next = act->next;
319 
320       } else {
321         ctrls_action_list = act->next;
322       }
323 
324       if (act->next) {
325         act->next->prev = act->prev;
326       }
327 
328       pr_trace_msg("ctrls", 3,
329         "module '%s' unregistering handler for ctrl action '%s'",
330         mod ? mod->name : "(none)", act->action);
331 
332       /* Destroy this action. */
333       destroy_pool(act->pool);
334     }
335   }
336 
337   pr_unblock_ctrls();
338 
339   if (!have_action) {
340     errno = ENOENT;
341     return -1;
342   }
343 
344   return 0;
345 }
346 
pr_ctrls_add_arg(pr_ctrls_t * ctrl,char * ctrls_arg,size_t ctrls_arglen)347 int pr_ctrls_add_arg(pr_ctrls_t *ctrl, char *ctrls_arg, size_t ctrls_arglen) {
348   register unsigned int i;
349 
350   /* Sanity checks */
351   if (ctrl == NULL ||
352       ctrls_arg == NULL) {
353     errno = EINVAL;
354     return -1;
355   }
356 
357   /* Scan for non-printable characters. */
358   for (i = 0; i < ctrls_arglen; i++) {
359     if (!PR_ISPRINT((int) ctrls_arg[i])) {
360       errno = EPERM;
361       return -1;
362     }
363   }
364 
365   /* Make sure the pr_ctrls_t has a temporary pool, from which the args will
366    * be allocated.
367    */
368   if (ctrl->ctrls_tmp_pool == NULL) {
369     ctrl->ctrls_tmp_pool = make_sub_pool(ctrls_pool);
370     pr_pool_tag(ctrl->ctrls_tmp_pool, "ctrls tmp pool");
371   }
372 
373   if (ctrl->ctrls_cb_args == NULL) {
374     ctrl->ctrls_cb_args = make_array(ctrl->ctrls_tmp_pool, 0, sizeof(char *));
375   }
376 
377   /* Add the given argument */
378   *((char **) push_array(ctrl->ctrls_cb_args)) = pstrndup(ctrl->ctrls_tmp_pool,
379     ctrls_arg, ctrls_arglen);
380 
381   return 0;
382 }
383 
pr_ctrls_copy_args(pr_ctrls_t * src_ctrl,pr_ctrls_t * dst_ctrl)384 int pr_ctrls_copy_args(pr_ctrls_t *src_ctrl, pr_ctrls_t *dst_ctrl) {
385 
386   /* Sanity checks */
387   if (src_ctrl == NULL ||
388       dst_ctrl == NULL) {
389     errno = EINVAL;
390     return -1;
391   }
392 
393   /* If source ctrl has no ctrls_cb_args member, there's nothing to be
394    * done.
395    */
396   if (src_ctrl->ctrls_cb_args == NULL) {
397     return 0;
398   }
399 
400   /* Make sure the pr_ctrls_t has a temporary pool, from which the args will
401    * be allocated.
402    */
403   if (dst_ctrl->ctrls_tmp_pool == NULL) {
404     dst_ctrl->ctrls_tmp_pool = make_sub_pool(ctrls_pool);
405     pr_pool_tag(dst_ctrl->ctrls_tmp_pool, "ctrls tmp pool");
406   }
407 
408   /* Overwrite any existing dst_ctrl->ctrls_cb_args.  This is OK, as
409    * the ctrl will be reset (cleared) once it has been processed.
410    */
411   dst_ctrl->ctrls_cb_args = copy_array(dst_ctrl->ctrls_tmp_pool,
412     src_ctrl->ctrls_cb_args);
413 
414   return 0;
415 }
416 
pr_ctrls_copy_resps(pr_ctrls_t * src_ctrl,pr_ctrls_t * dst_ctrl)417 int pr_ctrls_copy_resps(pr_ctrls_t *src_ctrl, pr_ctrls_t *dst_ctrl) {
418 
419   /* sanity checks */
420   if (!src_ctrl || !dst_ctrl) {
421     errno = EINVAL;
422     return -1;
423   }
424 
425   /* The source ctrl must have a ctrls_cb_resps member, and the destination
426    * ctrl must not have a ctrls_cb_resps member.
427    */
428   if (!src_ctrl->ctrls_cb_resps || dst_ctrl->ctrls_cb_resps) {
429     errno = EINVAL;
430     return -1;
431   }
432 
433   dst_ctrl->ctrls_cb_resps = copy_array(dst_ctrl->ctrls_tmp_pool,
434     src_ctrl->ctrls_cb_resps);
435 
436   return 0;
437 }
438 
pr_ctrls_add_response(pr_ctrls_t * ctrl,char * fmt,...)439 int pr_ctrls_add_response(pr_ctrls_t *ctrl, char *fmt, ...) {
440   char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
441   va_list resp;
442 
443   /* Sanity check */
444   if (!ctrl || !fmt) {
445     errno = EINVAL;
446     return -1;
447   }
448 
449   /* Make sure the pr_ctrls_t has a temporary pool, from which the responses
450    * will be allocated
451    */
452   if (!ctrl->ctrls_tmp_pool) {
453     ctrl->ctrls_tmp_pool = make_sub_pool(ctrls_pool);
454     pr_pool_tag(ctrl->ctrls_tmp_pool, "ctrls tmp pool");
455   }
456 
457   if (!ctrl->ctrls_cb_resps)
458     ctrl->ctrls_cb_resps = make_array(ctrl->ctrls_tmp_pool, 0,
459       sizeof(char *));
460 
461   /* Affix the message */
462   va_start(resp, fmt);
463   pr_vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, resp);
464   va_end(resp);
465 
466   buf[sizeof(buf) - 1] = '\0';
467 
468   /* add the given response */
469   *((char **) push_array(ctrl->ctrls_cb_resps)) =
470     pstrdup(ctrl->ctrls_tmp_pool, buf);
471 
472   return 0;
473 }
474 
pr_ctrls_flush_response(pr_ctrls_t * ctrl)475 int pr_ctrls_flush_response(pr_ctrls_t *ctrl) {
476 
477   /* Sanity check */
478   if (!ctrl) {
479     errno = EINVAL;
480     return -1;
481   }
482 
483   /* Make sure the callback(s) added responses */
484   if (ctrl->ctrls_cb_resps) {
485     if (pr_ctrls_send_msg(ctrl->ctrls_cl->cl_fd, ctrl->ctrls_cb_retval,
486         ctrl->ctrls_cb_resps->nelts,
487         (char **) ctrl->ctrls_cb_resps->elts) < 0)
488       return -1;
489   }
490 
491   return 0;
492 }
493 
pr_ctrls_parse_msg(pool * msg_pool,char * msg,unsigned int * msgargc,char *** msgargv)494 int pr_ctrls_parse_msg(pool *msg_pool, char *msg, unsigned int *msgargc,
495     char ***msgargv) {
496   char *tmp = msg, *str = NULL;
497   pool *tmp_pool = NULL;
498   array_header *msgs = NULL;
499 
500   /* Sanity checks */
501   if (!msg_pool || !msgargc || !msgargv) {
502     errno = EINVAL;
503     return -1;
504   }
505 
506   tmp_pool = make_sub_pool(msg_pool);
507 
508   /* Allocate an array_header, and push each space-delimited string
509    * (respecting quotes and escapes) into the array.  Once done,
510    * destroy the array.
511    */
512 
513   msgs = make_array(tmp_pool, 0, sizeof(char *));
514 
515   while ((str = ctrls_sep(&tmp)) != NULL)
516     *((char **) push_array(msgs)) = pstrdup(msg_pool, str);
517 
518   *msgargc = msgs->nelts;
519   *msgargv = (char **) msgs->elts;
520 
521   destroy_pool(tmp_pool);
522 
523   return 0;
524 }
525 
pr_ctrls_recv_request(pr_ctrls_cl_t * cl)526 int pr_ctrls_recv_request(pr_ctrls_cl_t *cl) {
527   pr_ctrls_t *ctrl = NULL, *next_ctrl = NULL;
528   char reqaction[128] = {'\0'}, *reqarg = NULL;
529   size_t reqargsz = 0;
530   unsigned int nreqargs = 0, reqarglen = 0;
531   int bread, status = 0;
532   register unsigned int i = 0;
533 
534   if (cl == NULL) {
535     errno = EINVAL;
536     return -1;
537   }
538 
539   if (cl->cl_fd < 0) {
540     errno = EBADF;
541     return -1;
542   }
543 
544   /* No interruptions */
545   pr_signals_block();
546 
547   /* Read in the incoming number of args, including the action. */
548 
549   /* First, read the status (but ignore it).  This is necessary because
550    * the same function, pr_ctrls_send_msg(), is used to send requests
551    * as well as responses, and the status is a necessary part of a response.
552    */
553   bread = read(cl->cl_fd, &status, sizeof(int));
554   if (bread < 0) {
555     int xerrno = errno;
556 
557     pr_signals_unblock();
558 
559     errno = xerrno;
560     return -1;
561   }
562 
563   /* Watch for short reads. */
564   if (bread != sizeof(int)) {
565     (void) pr_trace_msg(trace_channel, 3,
566       "short read (%d of %u bytes) of status, unable to receive request",
567       bread, (unsigned int) sizeof(int));
568     pr_signals_unblock();
569     errno = EPERM;
570     return -1;
571   }
572 
573   /* Read in the args, length first, then string. */
574   bread = read(cl->cl_fd, &nreqargs, sizeof(unsigned int));
575   if (bread < 0) {
576     int xerrno = errno;
577 
578     pr_signals_unblock();
579 
580     errno = xerrno;
581     return -1;
582   }
583 
584   /* Watch for short reads. */
585   if (bread != sizeof(unsigned int)) {
586     (void) pr_trace_msg(trace_channel, 3,
587       "short read (%d of %u bytes) of nreqargs, unable to receive request",
588       bread, (unsigned int) sizeof(unsigned int));
589     pr_signals_unblock();
590     errno = EPERM;
591     return -1;
592   }
593 
594   if (nreqargs > CTRLS_MAX_NREQARGS) {
595     (void) pr_trace_msg(trace_channel, 3,
596       "nreqargs (%u) exceeds max (%u), rejecting", nreqargs,
597       CTRLS_MAX_NREQARGS);
598     pr_signals_unblock();
599     errno = ENOMEM;
600     return -1;
601   }
602 
603   /* Next, read in the requested number of arguments.  The client sends
604    * the arguments in pairs: first the length of the argument, then the
605    * argument itself.  The first argument is the action, so get the first
606    * matching pr_ctrls_t (if present), and add the remaining arguments to it.
607    */
608 
609   bread = read(cl->cl_fd, &reqarglen, sizeof(unsigned int));
610   if (bread < 0) {
611     int xerrno = errno;
612 
613     pr_signals_unblock();
614 
615     errno = xerrno;
616     return -1;
617   }
618 
619   /* Watch for short reads. */
620   if (bread != sizeof(unsigned int)) {
621     (void) pr_trace_msg(trace_channel, 3,
622       "short read (%d of %u bytes) of reqarglen, unable to receive request",
623       bread, (unsigned int) sizeof(unsigned int));
624     pr_signals_unblock();
625     errno = EPERM;
626     return -1;
627   }
628 
629   if (reqarglen >= sizeof(reqaction)) {
630     pr_signals_unblock();
631     errno = ENOMEM;
632     return -1;
633   }
634 
635   memset(reqaction, '\0', sizeof(reqaction));
636 
637   bread = read(cl->cl_fd, reqaction, reqarglen);
638   if (bread < 0) {
639     int xerrno = errno;
640 
641     pr_signals_unblock();
642 
643     errno = xerrno;
644     return -1;
645   }
646 
647   /* Watch for short reads. */
648   if ((size_t) bread != reqarglen) {
649     (void) pr_trace_msg(trace_channel, 3,
650       "short read (%d of %u bytes) of reqaction, unable to receive request",
651       bread, reqarglen);
652     pr_signals_unblock();
653     errno = EPERM;
654     return -1;
655   }
656 
657   reqaction[sizeof(reqaction)-1] = '\0';
658   nreqargs--;
659 
660   /* Find a matching action object, and use it to populate a ctrl object,
661    * preparing the ctrl object for dispatching to the action handlers.
662    */
663   ctrl = ctrls_lookup_action(NULL, reqaction, TRUE);
664   if (ctrl == NULL) {
665     pr_signals_unblock();
666 
667     /* XXX This is where we could also add "did you mean" functionality. */
668     errno = EINVAL;
669     return -1;
670   }
671 
672   for (i = 0; i < nreqargs; i++) {
673     memset(reqarg, '\0', reqargsz);
674 
675     bread = read(cl->cl_fd, &reqarglen, sizeof(unsigned int));
676     if (bread < 0) {
677       int xerrno = errno;
678 
679       pr_signals_unblock();
680 
681       errno = xerrno;
682       return -1;
683     }
684 
685     /* Watch for short reads. */
686     if (bread != sizeof(unsigned int)) {
687       (void) pr_trace_msg(trace_channel, 3,
688         "short read (%d of %u bytes) of reqarglen (#%u), skipping",
689         bread, i+1, (unsigned int) sizeof(unsigned int));
690       continue;
691     }
692 
693     if (reqarglen == 0) {
694       /* Skip any zero-length arguments. */
695       continue;
696     }
697 
698     if (reqarglen > CTRLS_MAX_REQARGLEN) {
699       (void) pr_trace_msg(trace_channel, 3,
700         "reqarglen (#%u) of %u bytes exceeds max (%u bytes), rejecting",
701         i+1, reqarglen, CTRLS_MAX_REQARGLEN);
702       pr_signals_unblock();
703       errno = ENOMEM;
704       return -1;
705     }
706 
707     /* Make sure reqarg is large enough to handle the given argument.  If
708      * it is too small, allocate one of the necessary size.
709      */
710 
711     if (reqargsz < reqarglen) {
712       reqargsz = reqarglen + 1;
713 
714       if (!ctrl->ctrls_tmp_pool) {
715         ctrl->ctrls_tmp_pool = make_sub_pool(ctrls_pool);
716         pr_pool_tag(ctrl->ctrls_tmp_pool, "ctrls tmp pool");
717       }
718 
719       reqarg = pcalloc(ctrl->ctrls_tmp_pool, reqargsz);
720     }
721 
722     bread = read(cl->cl_fd, reqarg, reqarglen);
723     if (bread < 0) {
724       int xerrno = errno;
725 
726       pr_signals_unblock();
727 
728       errno = xerrno;
729       return -1;
730     }
731 
732     /* Watch for short reads. */
733     if ((size_t) bread != reqarglen) {
734       (void) pr_trace_msg(trace_channel, 3,
735         "short read (%d of %u bytes) of reqarg (#%u), skipping",
736         bread, i+1, reqarglen);
737       continue;
738     }
739 
740     if (pr_ctrls_add_arg(ctrl, reqarg, reqarglen)) {
741       int xerrno = errno;
742 
743       pr_signals_unblock();
744 
745       errno = xerrno;
746       return -1;
747     }
748   }
749 
750   /* Add this ctrls object to the client object. */
751   *((pr_ctrls_t **) push_array(cl->cl_ctrls)) = ctrl;
752 
753   /* Set the flag that this control is ready to go */
754   ctrl->ctrls_flags |= PR_CTRLS_REQUESTED;
755   ctrl->ctrls_cl = cl;
756 
757   /* Copy the populated ctrl object args to ctrl objects for all other
758    * matching action objects.
759    */
760   next_ctrl = ctrls_lookup_next_action(NULL, TRUE);
761 
762   while (next_ctrl != NULL) {
763     if (pr_ctrls_copy_args(ctrl, next_ctrl) < 0) {
764       int xerrno = errno;
765 
766       pr_signals_unblock();
767 
768       errno = xerrno;
769       return -1;
770     }
771 
772     /* Add this ctrl object to the client object. */
773     *((pr_ctrls_t **) push_array(cl->cl_ctrls)) = next_ctrl;
774 
775     /* Set the flag that this control is ready to go. */
776     next_ctrl->ctrls_flags |= PR_CTRLS_REQUESTED;
777     next_ctrl->ctrls_cl = cl;
778 
779     next_ctrl = ctrls_lookup_next_action(NULL, TRUE);
780   }
781 
782   pr_signals_unblock();
783   return 0;
784 }
785 
pr_ctrls_recv_response(pool * resp_pool,int ctrls_sockfd,int * status,char *** respargv)786 int pr_ctrls_recv_response(pool *resp_pool, int ctrls_sockfd,
787     int *status, char ***respargv) {
788   register unsigned int i = 0;
789   array_header *resparr = NULL;
790   unsigned int respargc = 0, resparglen = 0;
791   char response[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
792 
793   /* Sanity checks */
794   if (resp_pool == NULL ||
795       ctrls_sockfd < 0 ||
796       status == NULL) {
797     errno = EINVAL;
798     return -1;
799   }
800 
801   resparr = make_array(resp_pool, 0, sizeof(char *));
802 
803   /* No interruptions. */
804   pr_signals_block();
805 
806   /* First, read the status, which is the return value of the control handler.
807    */
808   if (read(ctrls_sockfd, status, sizeof(int)) != sizeof(int)) {
809     pr_signals_unblock();
810     return -1;
811   }
812 
813   /* Next, read the number of responses to be received */
814   if (read(ctrls_sockfd, &respargc, sizeof(unsigned int)) !=
815       sizeof(unsigned int)) {
816     pr_signals_unblock();
817     return -1;
818   }
819 
820   if (respargc > CTRLS_MAX_NRESPARGS) {
821     (void) pr_trace_msg(trace_channel, 3,
822       "respargc (%u) exceeds max (%u), rejecting", respargc,
823       CTRLS_MAX_NRESPARGS);
824     pr_signals_unblock();
825     errno = ENOMEM;
826     return -1;
827   }
828 
829   /* Read each response, and add it to the array */
830   for (i = 0; i < respargc; i++) {
831     int bread = 0, blen = 0;
832 
833     if (read(ctrls_sockfd, &resparglen,
834         sizeof(unsigned int)) != sizeof(unsigned int)) {
835       pr_signals_unblock();
836       return -1;
837     }
838 
839     /* Make sure resparglen is not too big */
840     if (resparglen >= sizeof(response)) {
841       pr_signals_unblock();
842       errno = ENOMEM;
843       return -1;
844     }
845 
846     memset(response, '\0', sizeof(response));
847 
848     bread = read(ctrls_sockfd, response, resparglen);
849     while ((size_t) bread != resparglen) {
850       if (bread < 0) {
851         pr_signals_unblock();
852         return -1;
853       }
854 
855       blen += bread;
856       bread = read(ctrls_sockfd, response + blen, resparglen - blen);
857     }
858 
859     /* Always make sure the buffer is zero-terminated */
860     response[sizeof(response)-1] = '\0';
861 
862     *((char **) push_array(resparr)) = pstrdup(resp_pool, response);
863   }
864 
865   if (respargv) {
866     *respargv = ((char **) resparr->elts);
867   }
868 
869   pr_signals_unblock();
870   return respargc;
871 }
872 
pr_ctrls_send_msg(int sockfd,int msgstatus,unsigned int msgargc,char ** msgargv)873 int pr_ctrls_send_msg(int sockfd, int msgstatus, unsigned int msgargc,
874     char **msgargv) {
875   register unsigned int i = 0;
876   unsigned int msgarglen = 0;
877 
878   /* Sanity checks */
879   if (sockfd < 0) {
880     errno = EINVAL;
881     return -1;
882   }
883 
884   if (msgargc < 1) {
885     return 0;
886   }
887 
888   if (msgargv == NULL) {
889     return 0;
890   }
891 
892   /* No interruptions */
893   pr_signals_block();
894 
895   /* Send the message status first */
896   if (write(sockfd, &msgstatus, sizeof(int)) != sizeof(int)) {
897     pr_signals_unblock();
898     return -1;
899   }
900 
901   /* Send the strings, one argument at a time.  First, send the number
902    * of arguments to be sent; then send, for each argument, first the
903    * length of the argument string, then the argument itself.
904    */
905   if (write(sockfd, &msgargc, sizeof(unsigned int)) !=
906       sizeof(unsigned int)) {
907     pr_signals_unblock();
908     return -1;
909   }
910 
911   for (i = 0; i < msgargc; i++) {
912     int res = 0;
913 
914     msgarglen = strlen(msgargv[i]);
915 
916     while (TRUE) {
917       res = write(sockfd, &msgarglen, sizeof(unsigned int));
918 
919       if (res != sizeof(unsigned int)) {
920         if (errno == EAGAIN) {
921           continue;
922         }
923 
924         pr_signals_unblock();
925         return -1;
926       }
927 
928       break;
929     }
930 
931     while (TRUE) {
932       res = write(sockfd, msgargv[i], msgarglen);
933       if ((size_t) res != msgarglen) {
934         if (errno == EAGAIN) {
935           continue;
936         }
937 
938         pr_signals_unblock();
939         return -1;
940 
941       }
942 
943       break;
944     }
945   }
946 
947   pr_signals_unblock();
948   return 0;
949 }
950 
ctrls_lookup_action(module * mod,const char * action,unsigned char skip_disabled)951 static pr_ctrls_t *ctrls_lookup_action(module *mod, const char *action,
952     unsigned char skip_disabled) {
953 
954   /* (Re)set the current indices */
955   action_lookup_next = ctrls_action_list;
956   action_lookup_action = action;
957   action_lookup_module = mod;
958 
959   /* Wrapper around ctrls_lookup_next_action() */
960   return ctrls_lookup_next_action(mod, skip_disabled);
961 }
962 
ctrls_lookup_next_action(module * mod,unsigned char skip_disabled)963 static pr_ctrls_t *ctrls_lookup_next_action(module *mod,
964     unsigned char skip_disabled) {
965   ctrls_action_t *act = NULL;
966 
967   /* Sanity check */
968   if (!action_lookup_action) {
969     errno = EINVAL;
970     return NULL;
971   }
972 
973   if (mod != action_lookup_module)
974     return ctrls_lookup_action(mod, action_lookup_action, skip_disabled);
975 
976   for (act = action_lookup_next; act; act = act->next) {
977 
978     if (skip_disabled && (act->flags & PR_CTRLS_ACT_DISABLED))
979       continue;
980 
981     if (strcmp(act->action, action_lookup_action) == 0 &&
982         (act->module == mod || mod == ANY_MODULE || mod == NULL)) {
983 
984       action_lookup_next = act->next;
985 
986       /* Use this action object to prepare a ctrl object. */
987       return ctrls_prepare(act);
988     }
989   }
990 
991   return NULL;
992 }
993 
pr_get_registered_actions(pr_ctrls_t * ctrl,int flags)994 int pr_get_registered_actions(pr_ctrls_t *ctrl, int flags) {
995   ctrls_action_t *act = NULL;
996 
997   /* Are ctrls blocked? */
998   if (ctrls_blocked) {
999     errno = EPERM;
1000     return -1;
1001   }
1002 
1003   for (act = ctrls_action_list; act; act = act->next) {
1004     switch (flags) {
1005       case CTRLS_GET_ACTION_ALL:
1006         pr_ctrls_add_response(ctrl, "%s (mod_%s.c)", act->action,
1007           act->module->name);
1008         break;
1009 
1010       case CTRLS_GET_ACTION_ENABLED:
1011         if (act->flags & PR_CTRLS_ACT_DISABLED)
1012           break;
1013         pr_ctrls_add_response(ctrl, "%s (mod_%s.c)", act->action,
1014           act->module->name);
1015         break;
1016 
1017       case CTRLS_GET_DESC:
1018         pr_ctrls_add_response(ctrl, "%s: %s", act->action,
1019           act->desc);
1020         break;
1021     }
1022   }
1023 
1024   return 0;
1025 }
1026 
pr_set_registered_actions(module * mod,const char * action,unsigned char skip_disabled,unsigned int flags)1027 int pr_set_registered_actions(module *mod, const char *action,
1028     unsigned char skip_disabled, unsigned int flags) {
1029   ctrls_action_t *act = NULL;
1030   unsigned char have_action = FALSE;
1031 
1032   /* Is flags a valid combination of settable flags? */
1033   if (flags && flags != PR_CTRLS_ACT_DISABLED) {
1034     errno = EINVAL;
1035     return -1;
1036   }
1037 
1038   /* Are ctrls blocked? */
1039   if (ctrls_blocked) {
1040     errno = EPERM;
1041     return -1;
1042   }
1043 
1044   for (act = ctrls_action_list; act; act = act->next) {
1045     if (skip_disabled && (act->flags & PR_CTRLS_ACT_DISABLED))
1046       continue;
1047 
1048     if ((!action ||
1049          strncmp(action, "all", 4) == 0 ||
1050          strcmp(act->action, action) == 0) &&
1051         (act->module == mod || mod == ANY_MODULE || mod == NULL)) {
1052       have_action = TRUE;
1053       act->flags = flags;
1054     }
1055   }
1056 
1057   if (!have_action) {
1058     errno = ENOENT;
1059     return -1;
1060   }
1061 
1062   return 0;
1063 }
1064 
1065 #if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1066     !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
ctrls_connect_local_creds(int sockfd)1067 static int ctrls_connect_local_creds(int sockfd) {
1068   char buf[1] = {'\0'};
1069   int res;
1070 
1071   /* The backend doesn't care what we send here, but it wants
1072    * exactly one character to force recvmsg() to block and wait
1073    * for us.
1074    */
1075 
1076   res = write(sockfd, buf, 1);
1077   while (res < 0) {
1078     if (errno == EINTR) {
1079       pr_signals_handle();
1080 
1081       res = write(sockfd, buf, 1);
1082       continue;
1083     }
1084 
1085     pr_trace_msg(trace_channel, 5,
1086       "error writing credentials byte for LOCAL_CREDS to fd %d: %s", sockfd,
1087       strerror(errno));
1088     return -1;
1089   }
1090 
1091   return res;
1092 }
1093 #endif /* !SCM_CREDS */
1094 
pr_ctrls_connect(const char * socket_file)1095 int pr_ctrls_connect(const char *socket_file) {
1096   int sockfd = -1, len = 0;
1097   struct sockaddr_un cl_sock, ctrl_sock;
1098 
1099   /* No interruptions */
1100   pr_signals_block();
1101 
1102   /* Create a Unix domain socket */
1103   sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
1104   if (sockfd < 0) {
1105     int xerrno = errno;
1106 
1107     pr_signals_unblock();
1108 
1109     errno = xerrno;
1110     return -1;
1111   }
1112 
1113   if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
1114     int xerrno = errno;
1115 
1116     (void) close(sockfd);
1117     pr_signals_unblock();
1118 
1119     errno = xerrno;
1120     return -1;
1121   }
1122 
1123   /* Fill in the socket address */
1124   memset(&cl_sock, 0, sizeof(cl_sock));
1125 
1126   /* This first part is clever.  First, this process creates a socket in
1127    * the file system.  It _then_ connect()s to the server.  Upon accept()ing
1128    * the connection, the server examines the created socket to see that it
1129    * is indeed a socket, with the proper mode and time.  Clever, but not
1130    * ideal.
1131    */
1132 
1133   cl_sock.sun_family = AF_UNIX;
1134   pr_snprintf(cl_sock.sun_path, sizeof(cl_sock.sun_path) - 1, "%s%05u",
1135     "/tmp/ftp.cl", (unsigned int) getpid());
1136   len = sizeof(cl_sock);
1137 
1138   /* Make sure the file doesn't already exist */
1139   (void) unlink(cl_sock.sun_path);
1140 
1141   /* Make it a socket */
1142   if (bind(sockfd, (struct sockaddr *) &cl_sock, len) < 0) {
1143     int xerrno = errno;
1144 
1145     (void) unlink(cl_sock.sun_path);
1146     (void) close(sockfd);
1147     pr_signals_unblock();
1148 
1149     errno = xerrno;
1150     return -1;
1151   }
1152 
1153   /* Set the proper mode */
1154   if (chmod(cl_sock.sun_path, PR_CTRLS_CL_MODE) < 0) {
1155     int xerrno = errno;
1156 
1157     (void) unlink(cl_sock.sun_path);
1158     (void) close(sockfd);
1159     pr_signals_unblock();
1160 
1161     errno = xerrno;
1162     return -1;
1163   }
1164 
1165   /* Now connect to the real server */
1166   memset(&ctrl_sock, 0, sizeof(ctrl_sock));
1167 
1168   ctrl_sock.sun_family = AF_UNIX;
1169   sstrncpy(ctrl_sock.sun_path, socket_file, sizeof(ctrl_sock.sun_path));
1170   len = sizeof(ctrl_sock);
1171 
1172   if (connect(sockfd, (struct sockaddr *) &ctrl_sock, len) < 0) {
1173     int xerrno = errno;
1174 
1175     (void) unlink(cl_sock.sun_path);
1176     (void) close(sockfd);
1177     pr_signals_unblock();
1178 
1179     errno = xerrno;
1180     return -1;
1181   }
1182 
1183 #if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1184     !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
1185   if (ctrls_connect_local_creds(sockfd) < 0) {
1186     int xerrno = errno;
1187 
1188     (void) unlink(cl_sock.sun_path);
1189     (void) close(sockfd);
1190     pr_signals_unblock();
1191 
1192     errno = xerrno;
1193     return -1;
1194   }
1195 #endif /* LOCAL_CREDS */
1196 
1197   pr_signals_unblock();
1198   return sockfd;
1199 }
1200 
pr_ctrls_issock_unix(mode_t sock_mode)1201 int pr_ctrls_issock_unix(mode_t sock_mode) {
1202 
1203   if (ctrls_use_isfifo) {
1204 #ifdef S_ISFIFO
1205     if (S_ISFIFO(sock_mode)) {
1206       return 0;
1207     }
1208 #endif /* S_ISFIFO */
1209   } else {
1210 #ifdef S_ISSOCK
1211     if (S_ISSOCK(sock_mode)) {
1212       return 0;
1213     }
1214 #endif /* S_ISSOCK */
1215   }
1216 
1217   errno = ENOSYS;
1218   return -1;
1219 }
1220 
1221 #if defined(SO_PEERCRED)
ctrls_get_creds_peercred(int sockfd,uid_t * uid,gid_t * gid,pid_t * pid)1222 static int ctrls_get_creds_peercred(int sockfd, uid_t *uid, gid_t *gid,
1223     pid_t *pid) {
1224 # if defined(HAVE_STRUCT_SOCKPEERCRED)
1225   struct sockpeercred cred;
1226 # else
1227   struct ucred cred;
1228 # endif /* HAVE_STRUCT_SOCKPEERCRED */
1229   socklen_t cred_len;
1230 
1231   cred_len = sizeof(cred);
1232   if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) < 0) {
1233     int xerrno = errno;
1234 
1235     pr_trace_msg(trace_channel, 2,
1236       "error obtaining peer credentials using SO_PEERCRED: %s",
1237       strerror(xerrno));
1238 
1239     errno = EPERM;
1240     return -1;
1241   }
1242 
1243   if (uid) {
1244     *uid = cred.uid;
1245   }
1246 
1247   if (gid) {
1248     *gid = cred.gid;
1249   }
1250 
1251   if (pid) {
1252     *pid = cred.pid;
1253   }
1254 
1255   return 0;
1256 }
1257 #endif /* SO_PEERCRED */
1258 
1259 #if !defined(SO_PEERCRED) && defined(HAVE_GETPEEREID)
ctrls_get_creds_peereid(int sockfd,uid_t * uid,gid_t * gid)1260 static int ctrls_get_creds_peereid(int sockfd, uid_t *uid, gid_t *gid) {
1261   if (getpeereid(sockfd, uid, gid) < 0) {
1262     int xerrno = errno;
1263 
1264     pr_trace_msg(trace_channel, 7, "error obtaining credentials using "
1265       "getpeereid(2) on fd %d: %s", sockfd, strerror(xerrno));
1266 
1267     errno = xerrno;
1268     return -1;
1269   }
1270 
1271   return 0;
1272 }
1273 #endif /* !HAVE_GETPEEREID */
1274 
1275 #if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1276     defined(HAVE_GETPEERUCRED)
ctrls_get_creds_peerucred(int sockfd,uid_t * uid,gid_t * gid)1277 static int ctrls_get_creds_peerucred(int sockfd, uid_t *uid, gid_t *gid) {
1278   ucred_t *cred = NULL;
1279 
1280   if (getpeerucred(sockfd, &cred) < 0) {
1281     int xerrno = errno;
1282 
1283     pr_trace_msg(trace_channel, 7, "error obtaining credentials using "
1284       "getpeerucred(3) on fd %d: %s", sockfd, strerror(xerrno));
1285 
1286     errno = xerrno;
1287     return -1;
1288   }
1289 
1290   if (uid)
1291     *uid = ucred_getruid(cred);
1292 
1293   if (gid)
1294     *gid = ucred_getrgid(cred);
1295 
1296   ucred_free(cred);
1297   return 0;
1298 }
1299 #endif /* !HAVE_GETPEERUCRED */
1300 
1301 #if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1302     !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
ctrls_get_creds_local(int sockfd,uid_t * uid,gid_t * gid,pid_t * pid)1303 static int ctrls_get_creds_local(int sockfd, uid_t *uid, gid_t *gid,
1304     pid_t *pid) {
1305   int res;
1306   char buf[1];
1307   struct iovec iov;
1308   struct msghdr msg;
1309 
1310 # if defined(SOCKCREDSIZE)
1311 #  define MINCREDSIZE		(sizeof(struct cmsghdr) + SOCKCREDSIZE(0))
1312 # else
1313 #  if defined(HAVE_STRUCT_CMSGCRED)
1314 #   define MINCREDSIZE		(sizeof(struct cmsghdr) + sizeof(struct cmsgcred))
1315 #  elif defined(HAVE_STRUCT_SOCKCRED)
1316 #   define MINCREDSIZE		(sizeof(struct cmsghdr) + sizeof(struct sockcred))
1317 #  endif
1318 # endif /* !SOCKCREDSIZE */
1319 
1320   char control[MINCREDSIZE];
1321 
1322   iov.iov_base = buf;
1323   iov.iov_len = 1;
1324 
1325   memset(&msg, 0, sizeof(msg));
1326   msg.msg_iov = &iov;
1327   msg.msg_iovlen = 1;
1328   msg.msg_control = control;
1329   msg.msg_controllen = sizeof(control);
1330   msg.msg_flags = 0;
1331 
1332   res = recvmsg(sockfd, &msg, 0);
1333   while (res < 0) {
1334     int xerrno = errno;
1335 
1336     if (xerrno == EINTR) {
1337       pr_signals_handle();
1338 
1339       res = recvmsg(sockfd, &msg, 0);
1340       continue;
1341     }
1342 
1343     pr_trace_msg(trace_channel, 6,
1344       "error calling recvmsg() on fd %d: %s", sockfd, strerror(xerrno));
1345 
1346     errno = xerrno;
1347     return -1;
1348   }
1349 
1350   if (msg.msg_controllen > 0) {
1351 #if defined(HAVE_STRUCT_CMSGCRED)
1352     struct cmsgcred cred;
1353 #elif defined(HAVE_STRUCT_SOCKCRED)
1354     struct sockcred cred;
1355 #endif /* !CMSGCRED and !SOCKCRED */
1356 
1357     struct cmsghdr *hdr = (struct cmsghdr *) control;
1358 
1359     if (hdr->cmsg_level != SOL_SOCKET) {
1360       pr_trace_msg(trace_channel, 5,
1361         "message received via recvmsg() on fd %d was not a SOL_SOCKET message",
1362         sockfd);
1363 
1364       errno = EINVAL;
1365       return -1;
1366     }
1367 
1368     if (hdr->cmsg_len < MINCREDSIZE) {
1369       pr_trace_msg(trace_channel, 5,
1370         "message received via recvmsg() on fd %d was not of proper "
1371         "length (%u bytes)", sockfd, MINCREDSIZE);
1372 
1373       errno = EINVAL;
1374       return -1;
1375     }
1376 
1377     if (hdr->cmsg_type != SCM_CREDS) {
1378       pr_trace_msg(trace_channel, 5,
1379         "message received via recvmsg() on fd %d was not of type SCM_CREDS",
1380         sockfd);
1381 
1382       errno = EINVAL;
1383       return -1;
1384     }
1385 
1386 #if defined(HAVE_STRUCT_CMSGCRED)
1387     memcpy(&cred, CMSG_DATA(hdr), sizeof(struct cmsgcred));
1388 
1389     if (uid)
1390       *uid = cred.cmcred_uid;
1391 
1392     if (gid)
1393       *gid = cred.cmcred_gid;
1394 
1395     if (pid)
1396       *pid = cred.cmcred_pid;
1397 
1398 #elif defined(HAVE_STRUCT_SOCKCRED)
1399     memcpy(&cred, CMSG_DATA(hdr), sizeof(struct sockcred));
1400 
1401     if (uid)
1402       *uid = cred.sc_uid;
1403 
1404     if (gid)
1405       *gid = cred.sc_gid;
1406 #endif
1407 
1408     return 0;
1409   }
1410 
1411   return -1;
1412 }
1413 #endif /* !SCM_CREDS */
1414 
ctrls_get_creds_basic(struct sockaddr_un * sock,int cl_fd,unsigned int max_age,uid_t * uid,gid_t * gid,pid_t * pid)1415 static int ctrls_get_creds_basic(struct sockaddr_un *sock, int cl_fd,
1416     unsigned int max_age, uid_t *uid, gid_t *gid, pid_t *pid) {
1417   pid_t cl_pid = 0;
1418   char *tmp = NULL;
1419   time_t stale_time;
1420   struct stat st;
1421 
1422   /* Check the path -- hmmm... */
1423   PRIVS_ROOT
1424   while (stat(sock->sun_path, &st) < 0) {
1425     int xerrno = errno;
1426 
1427     if (xerrno == EINTR) {
1428       pr_signals_handle();
1429       continue;
1430     }
1431 
1432     PRIVS_RELINQUISH
1433     pr_trace_msg(trace_channel, 2, "error: unable to stat %s: %s",
1434       sock->sun_path, strerror(xerrno));
1435     (void) close(cl_fd);
1436 
1437     errno = xerrno;
1438     return -1;
1439   }
1440   PRIVS_RELINQUISH
1441 
1442   /* Is it a socket? */
1443   if (pr_ctrls_issock_unix(st.st_mode) < 0) {
1444     (void) close(cl_fd);
1445     errno = ENOTSOCK;
1446     return -1;
1447   }
1448 
1449   /* Are the perms _not_ rwx------? */
1450   if (st.st_mode & (S_IRWXG|S_IRWXO) ||
1451       ((st.st_mode & S_IRWXU) != PR_CTRLS_CL_MODE)) {
1452     pr_trace_msg(trace_channel, 3,
1453       "error: unable to accept connection: incorrect mode");
1454     (void) close(cl_fd);
1455     errno = EPERM;
1456     return -1;
1457   }
1458 
1459   /* Is it new enough? */
1460   stale_time = time(NULL) - max_age;
1461 
1462   if (st.st_atime < stale_time ||
1463       st.st_ctime < stale_time ||
1464       st.st_mtime < stale_time) {
1465     char *msg = "error: stale connection";
1466 
1467     pr_trace_msg(trace_channel, 3,
1468       "unable to accept connection: stale connection");
1469 
1470     /* Log the times being compared, to aid in debugging this situation. */
1471     if (st.st_atime < stale_time) {
1472       time_t age = stale_time - st.st_atime;
1473 
1474       pr_trace_msg(trace_channel, 3,
1475          "last access time of '%s' is %lu secs old (must be less than %u secs)",
1476          sock->sun_path, (unsigned long) age, max_age);
1477     }
1478 
1479     if (st.st_ctime < stale_time) {
1480       time_t age = stale_time - st.st_ctime;
1481 
1482       pr_trace_msg(trace_channel, 3,
1483          "last change time of '%s' is %lu secs old (must be less than %u secs)",
1484          sock->sun_path, (unsigned long) age, max_age);
1485     }
1486 
1487     if (st.st_mtime < stale_time) {
1488       time_t age = stale_time - st.st_mtime;
1489 
1490       pr_trace_msg(trace_channel, 3,
1491          "last modified time of '%s' is %lu secs old (must be less than %u "
1492          "secs)", sock->sun_path, (unsigned long) age, max_age);
1493     }
1494 
1495     if (pr_ctrls_send_msg(cl_fd, -1, 1, &msg) < 0) {
1496       pr_trace_msg(trace_channel, 2, "error sending message: %s",
1497         strerror(errno));
1498     }
1499 
1500     (void) close(cl_fd);
1501 
1502     errno = ETIMEDOUT;
1503     return -1;
1504   }
1505 
1506   /* Parse the PID out of the path */
1507   tmp = sock->sun_path;
1508   tmp += strlen("/tmp/ftp.cl");
1509   cl_pid = atol(tmp);
1510 
1511   /* Return the IDs of the caller */
1512   if (uid)
1513     *uid = st.st_uid;
1514 
1515   if (gid)
1516     *gid = st.st_gid;
1517 
1518   if (pid)
1519     *pid = cl_pid;
1520 
1521   return 0;
1522 }
1523 
pr_ctrls_accept(int sockfd,uid_t * uid,gid_t * gid,pid_t * pid,unsigned int max_age)1524 int pr_ctrls_accept(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid,
1525     unsigned int max_age) {
1526   socklen_t len = 0;
1527   struct sockaddr_un sock;
1528   int cl_fd = -1;
1529   int res = -1;
1530 
1531   len = sizeof(sock);
1532 
1533   while ((cl_fd = accept(sockfd, (struct sockaddr *) &sock, &len)) < 0) {
1534     int xerrno = errno;
1535 
1536     if (xerrno == EINTR) {
1537       pr_signals_handle();
1538       continue;
1539     }
1540 
1541     pr_trace_msg(trace_channel, 3,
1542       "error: unable to accept on local socket: %s", strerror(xerrno));
1543 
1544     errno = xerrno;
1545     return -1;
1546   }
1547 
1548   /* NULL terminate the name */
1549   sock.sun_path[sizeof(sock.sun_path)-1] = '\0';
1550 
1551 #if defined(SO_PEERCRED)
1552   pr_trace_msg(trace_channel, 5,
1553     "checking client credentials using SO_PEERCRED");
1554   res = ctrls_get_creds_peercred(cl_fd, uid, gid, pid);
1555 
1556 #elif !defined(SO_PEERCRED) && defined(HAVE_GETPEEREID)
1557   pr_trace_msg(trace_channel, 5,
1558     "checking client credentials using getpeereid(2)");
1559   res = ctrls_get_creds_peereid(cl_fd, uid, gid);
1560 
1561 #elif !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1562       defined(HAVE_GETPEERUCRED)
1563   pr_trace_msg(trace_channel, 5,
1564     "checking client credentials using getpeerucred(3)");
1565   res = ctrls_get_creds_peerucred(cl_fd, uid, gid);
1566 
1567 #elif !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID) && \
1568       !defined(HAVE_GETPEERUCRED) && defined(LOCAL_CREDS)
1569   pr_trace_msg(trace_channel, 5,
1570     "checking client credentials using SCM_CREDS");
1571   res = ctrls_get_creds_local(cl_fd, uid, gid, pid);
1572 
1573 #endif
1574 
1575   /* Fallback to the Stevens method of determining connection credentials,
1576    * if the kernel-enforced methods did not pan out.
1577    */
1578   if (res < 0) {
1579     pr_trace_msg(trace_channel, 5,
1580       "checking client credentials using Stevens' method");
1581     res = ctrls_get_creds_basic(&sock, cl_fd, max_age, uid, gid, pid);
1582 
1583     if (res < 0)
1584       return res;
1585   }
1586 
1587   /* Done with the path now */
1588   PRIVS_ROOT
1589   unlink(sock.sun_path);
1590   PRIVS_RELINQUISH
1591 
1592   return cl_fd;
1593 }
1594 
pr_block_ctrls(void)1595 void pr_block_ctrls(void) {
1596   ctrls_blocked = TRUE;
1597 }
1598 
pr_unblock_ctrls(void)1599 void pr_unblock_ctrls(void) {
1600   ctrls_blocked = FALSE;
1601 }
1602 
pr_check_actions(void)1603 int pr_check_actions(void) {
1604   ctrls_action_t *act = NULL;
1605 
1606   for (act = ctrls_action_list; act; act = act->next) {
1607 
1608     if (act->flags & PR_CTRLS_ACT_SOLITARY) {
1609       /* This is a territorial action -- only one instance allowed */
1610       if (ctrls_lookup_action(NULL, act->action, FALSE)) {
1611         pr_log_pri(PR_LOG_NOTICE,
1612           "duplicate controls for '%s' action not allowed",
1613           act->action);
1614         return -1;
1615       }
1616     }
1617   }
1618 
1619   return 0;
1620 }
1621 
pr_run_ctrls(module * mod,const char * action)1622 int pr_run_ctrls(module *mod, const char *action) {
1623   pr_ctrls_t *ctrl = NULL;
1624 
1625   /* Are ctrls blocked? */
1626   if (ctrls_blocked) {
1627     errno = EPERM;
1628     return -1;
1629   }
1630 
1631   for (ctrl = ctrls_active_list; ctrl; ctrl = ctrl->ctrls_next) {
1632 
1633     /* Be watchful of the various client-side flags.  Note: if
1634      * ctrl->ctrls_cl is ever NULL, it means there's a bug in the code.
1635      */
1636     if (ctrl->ctrls_cl->cl_flags != PR_CTRLS_CL_HAVEREQ)
1637       continue;
1638 
1639     /* Has this control been disabled? */
1640     if (ctrl->ctrls_flags & PR_CTRLS_ACT_DISABLED)
1641       continue;
1642 
1643     /* Is it time to trigger this ctrl? */
1644     if (!(ctrl->ctrls_flags & PR_CTRLS_REQUESTED))
1645       continue;
1646 
1647     if (ctrl->ctrls_when > time(NULL)) {
1648       ctrl->ctrls_flags |= PR_CTRLS_PENDING;
1649       pr_ctrls_add_response(ctrl, "request pending");
1650       continue;
1651     }
1652 
1653     if (action &&
1654         strcmp(ctrl->ctrls_action, action) == 0) {
1655       pr_trace_msg(trace_channel, 7, "calling '%s' control handler",
1656         ctrl->ctrls_action);
1657 
1658       /* Invoke the callback, if the ctrl's action matches.  Unblock
1659        * ctrls before invoking the callback, then re-block them after the
1660        * callback returns.  This will allow the action handlers to use some
1661        * of the Controls API functions correctly.
1662        */
1663       pr_unblock_ctrls();
1664       ctrl->ctrls_cb_retval = ctrl->ctrls_cb(ctrl,
1665         (ctrl->ctrls_cb_args ? ctrl->ctrls_cb_args->nelts : 0),
1666         (ctrl->ctrls_cb_args ? (char **) ctrl->ctrls_cb_args->elts : NULL));
1667       pr_block_ctrls();
1668 
1669       if (ctrl->ctrls_cb_retval < 1) {
1670         ctrl->ctrls_flags &= ~PR_CTRLS_REQUESTED;
1671         ctrl->ctrls_flags &= ~PR_CTRLS_PENDING;
1672         ctrl->ctrls_flags |= PR_CTRLS_HANDLED;
1673       }
1674 
1675     } else if (!action) {
1676       pr_trace_msg(trace_channel, 7, "calling '%s' control handler",
1677         ctrl->ctrls_action);
1678 
1679       /* If no action was given, invoke every callback */
1680       pr_unblock_ctrls();
1681       ctrl->ctrls_cb_retval = ctrl->ctrls_cb(ctrl,
1682         (ctrl->ctrls_cb_args ? ctrl->ctrls_cb_args->nelts : 0),
1683         (ctrl->ctrls_cb_args ? (char **) ctrl->ctrls_cb_args->elts : NULL));
1684       pr_block_ctrls();
1685 
1686       if (ctrl->ctrls_cb_retval < 1) {
1687         ctrl->ctrls_flags &= ~PR_CTRLS_REQUESTED;
1688         ctrl->ctrls_flags &= ~PR_CTRLS_PENDING;
1689         ctrl->ctrls_flags |= PR_CTRLS_HANDLED;
1690       }
1691     }
1692   }
1693 
1694   return 0;
1695 }
1696 
pr_reset_ctrls(void)1697 int pr_reset_ctrls(void) {
1698   pr_ctrls_t *ctrl = NULL;
1699 
1700   /* NOTE: need a clean_ctrls() or somesuch that will, after sending any
1701    * responses, iterate through the list and "free" any ctrls whose
1702    * ctrls_cb_retval is zero.  This feature is used to handle things like
1703    * shutdown requests in the future -- the request is only considered
1704    * "processed" when the callback returns zero.  Any non-zero requests are
1705    * not cleared, and are considered "pending".  However, this brings up the
1706    * complication of an additional request for that action being issued by the
1707    * client before the request is processed.  Simplest solution: remove the
1708    * old request args, and replace them with the new ones.
1709    *
1710    * This requires that the return value of the ctrl callback be explicitly
1711    * documented.
1712    *
1713    * How about: ctrls_cb_retval = 1  pending
1714    *                              0  processed, OK    (reset)
1715    *                             -1  processed, error (reset)
1716    */
1717 
1718   for (ctrl = ctrls_active_list; ctrl; ctrl = ctrl->ctrls_next) {
1719     if (ctrl->ctrls_cb_retval < 1)
1720       ctrls_free(ctrl);
1721   }
1722 
1723   return 0;
1724 }
1725 
1726 /* From include/mod_ctrls.h */
1727 
1728 /* Returns TRUE if the given cl_gid is allowed by the group ACL, FALSE
1729  * otherwise. Note that the default is to deny everyone, unless an ACL has
1730  * been configured.
1731  */
pr_ctrls_check_group_acl(gid_t cl_gid,const ctrls_grp_acl_t * grp_acl)1732 unsigned char pr_ctrls_check_group_acl(gid_t cl_gid,
1733     const ctrls_grp_acl_t *grp_acl) {
1734   register unsigned int i = 0;
1735   unsigned char res = FALSE;
1736 
1737   /* Note: the special condition of ngids of 1 and gids of NULL signals
1738    * that all groups are to be treated according to the allow member.
1739    */
1740   if (grp_acl->gids) {
1741     for (i = 0; i < grp_acl->ngids; i++) {
1742       if ((grp_acl->gids)[i] == cl_gid) {
1743         res = TRUE;
1744       }
1745     }
1746 
1747   } else if (grp_acl->ngids == 1) {
1748     res = TRUE;
1749   }
1750 
1751   if (!grp_acl->allow) {
1752     res = !res;
1753   }
1754 
1755   return res;
1756 }
1757 
1758 /* Returns TRUE if the given cl_uid is allowed by the user ACL, FALSE
1759  * otherwise. Note that the default is to deny everyone, unless an ACL has
1760  * been configured.
1761  */
pr_ctrls_check_user_acl(uid_t cl_uid,const ctrls_usr_acl_t * usr_acl)1762 unsigned char pr_ctrls_check_user_acl(uid_t cl_uid,
1763     const ctrls_usr_acl_t *usr_acl) {
1764   register unsigned int i = 0;
1765   unsigned char res = FALSE;
1766 
1767   /* Note: the special condition of nuids of 1 and uids of NULL signals
1768    * that all users are to be treated according to the allow member.
1769    */
1770   if (usr_acl->uids) {
1771     for (i = 0; i < usr_acl->nuids; i++) {
1772       if ((usr_acl->uids)[i] == cl_uid) {
1773         res = TRUE;
1774       }
1775     }
1776 
1777   } else if (usr_acl->nuids == 1) {
1778     res = TRUE;
1779   }
1780 
1781   if (!usr_acl->allow) {
1782     res = !res;
1783   }
1784 
1785   return res;
1786 }
1787 
1788 /* Returns TRUE for allowed, FALSE for denied. */
pr_ctrls_check_acl(const pr_ctrls_t * ctrl,const ctrls_acttab_t * acttab,const char * action)1789 unsigned char pr_ctrls_check_acl(const pr_ctrls_t *ctrl,
1790     const ctrls_acttab_t *acttab, const char *action) {
1791   register unsigned int i = 0;
1792 
1793   for (i = 0; acttab[i].act_action; i++) {
1794     if (strcmp(acttab[i].act_action, action) == 0) {
1795 
1796       if (!pr_ctrls_check_user_acl(ctrl->ctrls_cl->cl_uid,
1797             &(acttab[i].act_acl->acl_usrs)) &&
1798           !pr_ctrls_check_group_acl(ctrl->ctrls_cl->cl_gid,
1799             &(acttab[i].act_acl->acl_grps))) {
1800 
1801         /* Access denied */
1802         return FALSE;
1803       }
1804     }
1805   }
1806 
1807   return TRUE;
1808 }
1809 
pr_ctrls_init_acl(ctrls_acl_t * acl)1810 void pr_ctrls_init_acl(ctrls_acl_t *acl) {
1811 
1812   /* Sanity check */
1813   if (!acl)
1814     return;
1815 
1816   memset(acl, 0, sizeof(ctrls_acl_t));
1817   acl->acl_usrs.allow = acl->acl_grps.allow = TRUE;
1818 }
1819 
ctrls_argsep(char ** arg)1820 static char *ctrls_argsep(char **arg) {
1821   char *ret = NULL, *dst = NULL;
1822   char quote_mode = 0;
1823 
1824   if (!arg || !*arg || !**arg)
1825     return NULL;
1826 
1827   while (**arg && PR_ISSPACE(**arg))
1828     (*arg)++;
1829 
1830   if (!**arg)
1831     return NULL;
1832 
1833   ret = dst = *arg;
1834 
1835   if (**arg == '\"') {
1836     quote_mode++;
1837     (*arg)++;
1838   }
1839 
1840   while (**arg && **arg != ',' &&
1841       (quote_mode ? (**arg != '\"') : (!PR_ISSPACE(**arg)))) {
1842 
1843     if (**arg == '\\' && quote_mode) {
1844 
1845       /* escaped char */
1846       if (*((*arg) + 1))
1847         *dst = *(++(*arg));
1848     }
1849 
1850     *dst++ = **arg;
1851     ++(*arg);
1852   }
1853 
1854   if (**arg)
1855     (*arg)++;
1856 
1857   *dst = '\0';
1858   return ret;
1859 }
1860 
pr_ctrls_parse_acl(pool * acl_pool,char * acl_str)1861 char **pr_ctrls_parse_acl(pool *acl_pool, char *acl_str) {
1862   char *name = NULL, *acl_str_dup = NULL, **acl_list = NULL;
1863   array_header *acl_arr = NULL;
1864   pool *tmp_pool = NULL;
1865 
1866   /* Sanity checks */
1867   if (!acl_pool || !acl_str)
1868     return NULL;
1869 
1870   tmp_pool = make_sub_pool(acl_pool);
1871   acl_str_dup = pstrdup(tmp_pool, acl_str);
1872 
1873   /* Allocate an array */
1874   acl_arr = make_array(acl_pool, 0, sizeof(char **));
1875 
1876   /* Add each name to the array */
1877   while ((name = ctrls_argsep(&acl_str_dup)) != NULL) {
1878     char *tmp = pstrdup(acl_pool, name);
1879 
1880     /* Push the name into the ACL array */
1881     *((char **) push_array(acl_arr)) = tmp;
1882   }
1883 
1884   /* Terminate the temp array with a NULL, as is proper. */
1885   *((char **) push_array(acl_arr)) = NULL;
1886 
1887   acl_list = (char **) acl_arr->elts;
1888   destroy_pool(tmp_pool);
1889 
1890   /* return the array of names */
1891   return acl_list;
1892 }
1893 
pr_ctrls_set_group_acl(pool * grp_acl_pool,ctrls_grp_acl_t * grp_acl,const char * allow,char * grouplist)1894 void pr_ctrls_set_group_acl(pool *grp_acl_pool, ctrls_grp_acl_t *grp_acl,
1895     const char *allow, char *grouplist) {
1896   char *group = NULL, **groups = NULL;
1897   array_header *gid_list = NULL;
1898   gid_t gid = 0;
1899   pool *tmp_pool = NULL;
1900 
1901   if (grp_acl_pool == NULL ||
1902       grp_acl == NULL ||
1903       allow == NULL ||
1904       grouplist == NULL) {
1905     return;
1906   }
1907 
1908   tmp_pool = make_sub_pool(grp_acl_pool);
1909 
1910   if (strncmp(allow, "allow", 6) == 0) {
1911     grp_acl->allow = TRUE;
1912 
1913   } else {
1914     grp_acl->allow = FALSE;
1915   }
1916 
1917   /* Parse the given expression into an array, then retrieve the GID
1918    * for each given name.
1919    */
1920   groups = pr_ctrls_parse_acl(grp_acl_pool, grouplist);
1921 
1922   /* Allocate an array of gid_t's */
1923   gid_list = make_array(grp_acl_pool, 0, sizeof(gid_t));
1924 
1925   for (group = *groups; group != NULL; group = *++groups) {
1926 
1927     /* Handle a group name of "*" differently. */
1928     if (strncmp(group, "*", 2) == 0) {
1929       grp_acl->ngids = 1;
1930       grp_acl->gids = NULL;
1931       destroy_pool(tmp_pool);
1932       return;
1933 
1934     } else {
1935       gid = pr_auth_name2gid(tmp_pool, group);
1936       if (gid == (gid_t) -1)
1937         continue;
1938     }
1939 
1940     *((gid_t *) push_array(gid_list)) = gid;
1941   }
1942 
1943   grp_acl->ngids = gid_list->nelts;
1944   grp_acl->gids = (gid_t *) gid_list->elts;
1945 
1946   destroy_pool(tmp_pool);
1947 }
1948 
pr_ctrls_set_user_acl(pool * usr_acl_pool,ctrls_usr_acl_t * usr_acl,const char * allow,char * userlist)1949 void pr_ctrls_set_user_acl(pool *usr_acl_pool, ctrls_usr_acl_t *usr_acl,
1950     const char *allow, char *userlist) {
1951   char *user = NULL, **users = NULL;
1952   array_header *uid_list = NULL;
1953   uid_t uid = 0;
1954   pool *tmp_pool = NULL;
1955 
1956   /* Sanity checks */
1957   if (usr_acl_pool == NULL ||
1958       usr_acl == NULL ||
1959       allow == NULL ||
1960       userlist == NULL) {
1961     return;
1962   }
1963 
1964   tmp_pool = make_sub_pool(usr_acl_pool);
1965 
1966   if (strncmp(allow, "allow", 6) == 0) {
1967     usr_acl->allow = TRUE;
1968 
1969   } else {
1970     usr_acl->allow = FALSE;
1971   }
1972 
1973   /* Parse the given expression into an array, then retrieve the UID
1974    * for each given name.
1975    */
1976   users = pr_ctrls_parse_acl(usr_acl_pool, userlist);
1977 
1978   /* Allocate an array of uid_t's */
1979   uid_list = make_array(usr_acl_pool, 0, sizeof(uid_t));
1980 
1981   for (user = *users; user != NULL; user = *++users) {
1982 
1983     /* Handle a user name of "*" differently. */
1984     if (strncmp(user, "*", 2) == 0) {
1985       usr_acl->nuids = 1;
1986       usr_acl->uids = NULL;
1987       destroy_pool(tmp_pool);
1988       return;
1989 
1990     } else {
1991       uid = pr_auth_name2uid(tmp_pool, user);
1992       if (uid == (uid_t) -1)
1993         continue;
1994     }
1995 
1996     *((uid_t *) push_array(uid_list)) = uid;
1997   }
1998 
1999   usr_acl->nuids = uid_list->nelts;
2000   usr_acl->uids = (uid_t *) uid_list->elts;
2001 
2002   destroy_pool(tmp_pool);
2003 }
2004 
pr_ctrls_set_module_acls(ctrls_acttab_t * acttab,pool * acl_pool,char ** actions,const char * allow,const char * type,char * list)2005 char *pr_ctrls_set_module_acls(ctrls_acttab_t *acttab, pool *acl_pool,
2006     char **actions, const char *allow, const char *type, char *list) {
2007   register unsigned int i = 0;
2008   unsigned char all_actions = FALSE;
2009 
2010   /* First, sanity check the given list of actions against the actions
2011    * in the given table.
2012    */
2013   for (i = 0; actions[i]; i++) {
2014     register unsigned int j = 0;
2015     unsigned char valid_action = FALSE;
2016 
2017     if (strncmp(actions[i], "all", 4) == 0)
2018       continue;
2019 
2020     for (j = 0; acttab[j].act_action; j++) {
2021       if (strcmp(actions[i], acttab[j].act_action) == 0) {
2022         valid_action = TRUE;
2023         break;
2024       }
2025     }
2026 
2027     if (!valid_action)
2028       return actions[i];
2029   }
2030 
2031   for (i = 0; actions[i]; i++) {
2032     register unsigned int j = 0;
2033 
2034     if (!all_actions &&
2035         strncmp(actions[i], "all", 4) == 0)
2036       all_actions = TRUE;
2037 
2038     for (j = 0; acttab[j].act_action; j++) {
2039       if (all_actions || strcmp(actions[i], acttab[j].act_action) == 0) {
2040 
2041         /* Use the type parameter to determine whether the list is of users or
2042          * of groups.
2043          */
2044         if (strncmp(type, "user", 5) == 0) {
2045           pr_ctrls_set_user_acl(acl_pool, &(acttab[j].act_acl->acl_usrs),
2046             allow, list);
2047 
2048         } else if (strncmp(type, "group", 6) == 0) {
2049           pr_ctrls_set_group_acl(acl_pool, &(acttab[j].act_acl->acl_grps),
2050             allow, list);
2051         }
2052       }
2053     }
2054   }
2055 
2056   return NULL;
2057 }
2058 
pr_ctrls_unregister_module_actions(ctrls_acttab_t * acttab,char ** actions,module * mod)2059 char *pr_ctrls_unregister_module_actions(ctrls_acttab_t *acttab,
2060     char **actions, module *mod) {
2061   register unsigned int i = 0;
2062 
2063   /* First, sanity check the given actions against the actions supported by
2064    * this module.
2065    */
2066   for (i = 0; actions[i]; i++) {
2067     register unsigned int j = 0;
2068     unsigned char valid_action = FALSE;
2069 
2070     for (j = 0; acttab[j].act_action; j++) {
2071       if (strcmp(actions[i], acttab[j].act_action) == 0) {
2072         valid_action = TRUE;
2073         break;
2074       }
2075     }
2076 
2077     if (!valid_action)
2078       return actions[i];
2079   }
2080 
2081   /* Next, iterate through both lists again, looking for actions of the
2082    * module _not_ in the given list.
2083    */
2084   for (i = 0; acttab[i].act_action; i++) {
2085     register unsigned int j = 0;
2086     unsigned char have_action = FALSE;
2087 
2088     for (j = 0; actions[j]; j++) {
2089       if (strcmp(acttab[i].act_action, actions[j]) == 0) {
2090         have_action = TRUE;
2091         break;
2092       }
2093     }
2094 
2095     if (have_action) {
2096       pr_trace_msg(trace_channel, 4, "mod_%s.c: removing '%s' control",
2097         mod->name, acttab[i].act_action);
2098       pr_ctrls_unregister(mod, acttab[i].act_action);
2099       destroy_pool(acttab[i].act_acl->acl_pool);
2100     }
2101   }
2102 
2103   return NULL;
2104 }
2105 
pr_ctrls_set_logfd(int fd)2106 int pr_ctrls_set_logfd(int fd) {
2107 
2108   /* Close any existing log fd. */
2109   if (ctrls_logfd >= 0) {
2110     (void) close(ctrls_logfd);
2111   }
2112 
2113   ctrls_logfd = fd;
2114   return 0;
2115 }
2116 
pr_ctrls_log(const char * module_version,const char * fmt,...)2117 int pr_ctrls_log(const char *module_version, const char *fmt, ...) {
2118   va_list msg;
2119   int res;
2120 
2121   /* sanity check */
2122   if (ctrls_logfd < 0)
2123     return 0;
2124 
2125   va_start(msg, fmt);
2126   res = pr_log_vwritefile(ctrls_logfd, module_version, fmt, msg);
2127   va_end(msg);
2128 
2129   return res;
2130 }
2131 
2132 /* Initialize the Controls API. */
init_ctrls(void)2133 void init_ctrls(void) {
2134   struct stat st;
2135   int sockfd;
2136   struct sockaddr_un sockun;
2137   size_t socklen;
2138   char *sockpath = PR_RUN_DIR "/test.sock";
2139 
2140   if (ctrls_pool) {
2141     destroy_pool(ctrls_pool);
2142   }
2143 
2144   ctrls_pool = make_sub_pool(permanent_pool);
2145   pr_pool_tag(ctrls_pool, "Controls Pool");
2146 
2147   /* Make sure all of the lists are zero'd out. */
2148   ctrls_action_list = NULL;
2149   ctrls_active_list = NULL;
2150   ctrls_free_list = NULL;
2151 
2152    /* And that the lookup indices are (re)set as well... */
2153   action_lookup_next = NULL;
2154   action_lookup_action = NULL;
2155   action_lookup_module = NULL;
2156 
2157   /* Run-time check to find out whether this platform identifies a
2158    * Unix domain socket file descriptor via the S_ISFIFO macro, or
2159    * the S_ISSOCK macro.
2160    */
2161 
2162   sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2163   if (sockfd < 0) {
2164     pr_log_debug(DEBUG10, "unable to create Unix domain socket: %s",
2165       strerror(errno));
2166     return;
2167   }
2168 
2169   memset(&sockun, 0, sizeof(sockun));
2170   sockun.sun_family = AF_UNIX;
2171   sstrncpy(sockun.sun_path, sockpath, sizeof(sockun.sun_path));
2172   socklen = sizeof(struct sockaddr_un);
2173 
2174   if (bind(sockfd, (struct sockaddr *) &sockun, socklen) < 0) {
2175     pr_log_debug(DEBUG10, "unable to bind to Unix domain socket at '%s': %s",
2176       sockpath, strerror(errno));
2177     (void) close(sockfd);
2178     (void) unlink(sockpath);
2179     return;
2180   }
2181 
2182   if (fstat(sockfd, &st) < 0) {
2183     pr_log_debug(DEBUG10, "unable to stat Unix domain socket at '%s': %s",
2184       sockpath, strerror(errno));
2185     (void) close(sockfd);
2186     (void) unlink(sockpath);
2187     return;
2188   }
2189 
2190 #ifdef S_ISFIFO
2191   pr_log_debug(DEBUG10, "testing Unix domain socket using S_ISFIFO");
2192   if (S_ISFIFO(st.st_mode)) {
2193     ctrls_use_isfifo = TRUE;
2194   }
2195 #else
2196   pr_log_debug(DEBUG10, "cannot test Unix domain socket using S_ISFIFO: "
2197     "macro undefined");
2198 #endif
2199 
2200 #ifdef S_ISSOCK
2201   pr_log_debug(DEBUG10, "testing Unix domain socket using S_ISSOCK");
2202   if (S_ISSOCK(st.st_mode)) {
2203     ctrls_use_isfifo = FALSE;
2204   }
2205 #else
2206   pr_log_debug(DEBUG10, "cannot test Unix domain socket using S_ISSOCK: "
2207     "macro undefined");
2208 #endif
2209 
2210   pr_log_debug(DEBUG10, "using %s macro for Unix domain socket detection",
2211     ctrls_use_isfifo ? "S_ISFIFO" : "S_ISSOCK");
2212 
2213   (void) close(sockfd);
2214   (void) unlink(sockpath);
2215   return;
2216 }
2217 
2218 #endif /* PR_USE_CTRLS */
2219