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