Coverage Report

Created: 2024-05-20 06:26

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