1 /*****************************************************************************
2 * Written by Chris Dunlap <cdunlap@llnl.gov>.
3 * Copyright (C) 2007-2020 Lawrence Livermore National Security, LLC.
4 * Copyright (C) 2002-2007 The Regents of the University of California.
5 * UCRL-CODE-155910.
6 *
7 * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE).
8 * For details, see <https://dun.github.io/munge/>.
9 *
10 * MUNGE is free software: you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free
12 * Software Foundation, either version 3 of the License, or (at your option)
13 * any later version. Additionally for the MUNGE library (libmunge), you
14 * can redistribute it and/or modify it under the terms of the GNU Lesser
15 * General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * MUNGE is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * and GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * and GNU Lesser General Public License along with MUNGE. If not, see
25 * <http://www.gnu.org/licenses/>.
26 *****************************************************************************/
27
28
29 #if HAVE_CONFIG_H
30 # include <config.h>
31 #endif /* HAVE_CONFIG_H */
32
33 #include <arpa/inet.h> /* for inet_ntop() */
34 #include <assert.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/socket.h> /* for AF_INET */
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <munge.h>
47 #include "conf.h"
48 #include "license.h"
49 #include "lock.h"
50 #include "log.h"
51 #include "md.h"
52 #include "missing.h" /* for inet_ntop() */
53 #include "munge_defs.h"
54 #include "net.h"
55 #include "path.h"
56 #include "str.h"
57 #include "version.h"
58 #include "zip.h"
59
60
61 /*****************************************************************************
62 * Command-Line Options
63 *****************************************************************************/
64
65 #define OPT_ADVICE 256
66 #define OPT_KEY_FILE 257
67 #define OPT_NUM_THREADS 258
68 #define OPT_AUTH_SERVER 259
69 #define OPT_AUTH_CLIENT 260
70 #define OPT_GROUP_CHECK 261
71 #define OPT_GROUP_UPDATE 262
72 #define OPT_SYSLOG 263
73 #define OPT_BENCHMARK 264
74 #define OPT_MAX_TTL 265
75 #define OPT_PID_FILE 266
76 #define OPT_LOG_FILE 267
77 #define OPT_SEED_FILE 268
78 #define OPT_TRUSTED_GROUP 269
79 #define OPT_ORIGIN 270
80 #define OPT_LAST 271
81
82 const char * const short_opts = ":hLVfFMsS:v";
83
84 #include <getopt.h>
85 struct option long_opts[] = {
86 { "help", no_argument, NULL, 'h' },
87 { "license", no_argument, NULL, 'L' },
88 { "version", no_argument, NULL, 'V' },
89 { "force", no_argument, NULL, 'f' },
90 { "foreground", no_argument, NULL, 'F' },
91 { "mlockall", no_argument, NULL, 'M' },
92 { "stop", no_argument, NULL, 's' },
93 { "socket", required_argument, NULL, 'S' },
94 { "verbose", no_argument, NULL, 'v' },
95 { "advice", no_argument, NULL, OPT_ADVICE },
96 #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD)
97 { "auth-server-dir", required_argument, NULL, OPT_AUTH_SERVER },
98 { "auth-client-dir", required_argument, NULL, OPT_AUTH_CLIENT },
99 #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */
100 { "benchmark", no_argument, NULL, OPT_BENCHMARK },
101 { "group-check-mtime", required_argument, NULL, OPT_GROUP_CHECK },
102 { "group-update-time", required_argument, NULL, OPT_GROUP_UPDATE },
103 { "key-file", required_argument, NULL, OPT_KEY_FILE },
104 { "log-file", required_argument, NULL, OPT_LOG_FILE },
105 { "max-ttl", required_argument, NULL, OPT_MAX_TTL },
106 { "num-threads", required_argument, NULL, OPT_NUM_THREADS },
107 { "origin", required_argument, NULL, OPT_ORIGIN },
108 { "pid-file", required_argument, NULL, OPT_PID_FILE },
109 { "seed-file", required_argument, NULL, OPT_SEED_FILE },
110 { "syslog", no_argument, NULL, OPT_SYSLOG },
111 { "trusted-group", required_argument, NULL, OPT_TRUSTED_GROUP },
112 { NULL, 0, NULL, 0 }
113 };
114
115
116 /*****************************************************************************
117 * Internal Prototypes
118 *****************************************************************************/
119
120 static void _conf_display_help (char *prog);
121
122 static void _conf_process_stop (conf_t conf);
123
124 static int _conf_send_signal (pid_t pid, int signum, int msecs);
125
126 static void _conf_set_origin_addr (conf_t conf);
127
128 static int _conf_open_keyfile (const char *keyfile, int got_force);
129
130
131 /*****************************************************************************
132 * Global Variables
133 *****************************************************************************/
134
135 conf_t conf = NULL; /* global configuration struct */
136
137
138 /*****************************************************************************
139 * External Functions
140 *****************************************************************************/
141
142 conf_t
create_conf(void)143 create_conf (void)
144 {
145 conf_t conf;
146
147 if (!(conf = malloc (sizeof (struct conf)))) {
148 log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf");
149 }
150 conf->ld = -1;
151 conf->got_benchmark = 0;
152 conf->got_clock_skew = 1;
153 conf->got_force = 0;
154 conf->got_foreground = 0;
155 conf->got_group_stat = !! MUNGE_GROUP_STAT_FLAG;
156 conf->got_stop = 0;
157 conf->got_mlockall = 0;
158 conf->got_root_auth = !! MUNGE_AUTH_ROOT_ALLOW_FLAG;
159 conf->got_socket_retry = !! MUNGE_SOCKET_RETRY_FLAG;
160 conf->got_syslog = 0;
161 conf->got_verbose = 0;
162 conf->def_cipher = MUNGE_DEFAULT_CIPHER;
163 conf->def_zip = zip_select_default_type (MUNGE_DEFAULT_ZIP);
164 conf->def_mac = MUNGE_DEFAULT_MAC;
165 conf->def_ttl = MUNGE_DEFAULT_TTL;
166 conf->max_ttl = MUNGE_MAXIMUM_TTL;
167 /*
168 * FIXME: Add support for default realm.
169 */
170 conf->config_name = NULL;
171 conf->lockfile_fd = -1;
172 conf->lockfile_name = NULL;
173
174 if (!(conf->logfile_name = strdup (MUNGE_LOGFILE_PATH))) {
175 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
176 "Failed to copy logfile name string");
177 }
178 if (!(conf->pidfile_name = strdup (MUNGE_PIDFILE_PATH))) {
179 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
180 "Failed to copy pidfile name string");
181 }
182 if (!(conf->socket_name = strdup (MUNGE_SOCKET_NAME))) {
183 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
184 "Failed to copy socket name string");
185 }
186 if (!(conf->seed_name = strdup (MUNGE_SEEDFILE_PATH))) {
187 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
188 "Failed to copy seed name string");
189 }
190 if (!(conf->key_name = strdup (MUNGE_KEYFILE_PATH))) {
191 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
192 "Failed to copy key name string");
193 }
194 conf->dek_key = NULL;
195 conf->dek_key_len = 0;
196 conf->mac_key = NULL;
197 conf->mac_key_len = 0;
198 conf->origin_name = NULL;
199 conf->origin_ifname = NULL;
200 memset (&conf->addr, 0, sizeof (conf->addr));
201 conf->gids = NULL;
202 conf->gids_update_secs = MUNGE_GROUP_UPDATE_SECS;
203 conf->nthreads = MUNGE_THREADS;
204 conf->auth_server_dir = NULL;
205 conf->auth_client_dir = NULL;
206 conf->auth_rnd_bytes = MUNGE_AUTH_RND_BYTES;
207
208 #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD)
209 if (!(conf->auth_server_dir = strdup (MUNGE_AUTH_SERVER_DIR))) {
210 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
211 "Failed to copy auth-server-dir default string");
212 }
213 if (!(conf->auth_client_dir = strdup (MUNGE_AUTH_CLIENT_DIR))) {
214 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
215 "Failed to copy auth-client-dir default string");
216 }
217 #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */
218
219 return (conf);
220 }
221
222
223 void
destroy_conf(conf_t conf,int do_unlink)224 destroy_conf (conf_t conf, int do_unlink)
225 {
226 assert (conf != NULL);
227 assert (conf->ld < 0); /* sock_destroy() already called */
228 assert (conf->lockfile_fd < 0);
229
230 if (conf->config_name) {
231 free (conf->config_name);
232 conf->config_name = NULL;
233 }
234 if (conf->lockfile_name) {
235 free (conf->lockfile_name);
236 conf->lockfile_name = NULL;
237 }
238 if (conf->logfile_name) {
239 free (conf->logfile_name);
240 conf->logfile_name = NULL;
241 }
242 if (conf->pidfile_name) {
243 if (do_unlink) {
244 (void) unlink (conf->pidfile_name);
245 }
246 free (conf->pidfile_name);
247 conf->pidfile_name = NULL;
248 }
249 if (conf->socket_name) {
250 free (conf->socket_name);
251 conf->socket_name = NULL;
252 }
253 if (conf->seed_name) {
254 free (conf->seed_name);
255 conf->seed_name = NULL;
256 }
257 if (conf->key_name) {
258 free (conf->key_name);
259 conf->key_name = NULL;
260 }
261 if (conf->dek_key) {
262 memburn (conf->dek_key, 0, conf->dek_key_len);
263 free (conf->dek_key);
264 conf->dek_key = NULL;
265 }
266 if (conf->mac_key) {
267 memburn (conf->mac_key, 0, conf->mac_key_len);
268 free (conf->mac_key);
269 conf->mac_key = NULL;
270 }
271 if (conf->origin_name) {
272 free (conf->origin_name);
273 conf->origin_name = NULL;
274 }
275 if (conf->origin_ifname) {
276 free (conf->origin_ifname);
277 conf->origin_ifname = NULL;
278 }
279 if (conf->auth_server_dir) {
280 free (conf->auth_server_dir);
281 conf->auth_server_dir = NULL;
282 }
283 if (conf->auth_client_dir) {
284 free (conf->auth_client_dir);
285 conf->auth_client_dir = NULL;
286 }
287 free (conf);
288
289 return;
290 }
291
292
293 void
parse_cmdline(conf_t conf,int argc,char ** argv)294 parse_cmdline (conf_t conf, int argc, char **argv)
295 {
296 char *prog;
297 int c;
298 long l;
299 char *p;
300
301 assert (conf != NULL);
302
303 opterr = 0; /* suppress default getopt err msgs */
304
305 prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0];
306
307 for (;;) {
308
309 c = getopt_long (argc, argv, short_opts, long_opts, NULL);
310
311 if (c == -1) { /* reached end of option list */
312 break;
313 }
314 switch (c) {
315 case 'h':
316 _conf_display_help (prog);
317 exit (EMUNGE_SUCCESS);
318 break;
319 case 'L':
320 display_license ();
321 exit (EMUNGE_SUCCESS);
322 break;
323 case 'V':
324 display_version ();
325 exit (EMUNGE_SUCCESS);
326 break;
327 case 'f':
328 conf->got_force = 1;
329 break;
330 case 'F':
331 conf->got_foreground = 1;
332 break;
333 case 'M':
334 conf->got_mlockall = 1;
335 break;
336 case 's':
337 conf->got_stop = 1;
338 break;
339 case 'S':
340 if (conf->socket_name)
341 free (conf->socket_name);
342 if (!(conf->socket_name = strdup (optarg)))
343 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
344 "Failed to copy socket name string");
345 break;
346 case 'v':
347 conf->got_verbose = 1;
348 break;
349 case OPT_ADVICE:
350 printf ("Don't Panic!\n");
351 exit (42);
352 #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD)
353 case OPT_AUTH_SERVER:
354 if (conf->auth_server_dir)
355 free (conf->auth_server_dir);
356 if (!(conf->auth_server_dir = strdup (optarg)))
357 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
358 "Failed to copy auth-server-dir cmdline string");
359 break;
360 case OPT_AUTH_CLIENT:
361 if (conf->auth_client_dir)
362 free (conf->auth_client_dir);
363 if (!(conf->auth_client_dir = strdup (optarg)))
364 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
365 "Failed to copy auth-client-dir cmdline string");
366 break;
367 #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */
368 case OPT_BENCHMARK:
369 conf->got_benchmark = 1;
370 break;
371 case OPT_GROUP_CHECK:
372 errno = 0;
373 l = strtol (optarg, &p, 10);
374 if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX)))
375 || (optarg == p) || (*p != '\0')) {
376 log_err (EMUNGE_SNAFU, LOG_ERR,
377 "Invalid value \"%s\" for group-check-mtime", optarg);
378 }
379 conf->got_group_stat = !! l;
380 break;
381 case OPT_GROUP_UPDATE:
382 errno = 0;
383 l = strtol (optarg, &p, 10);
384 if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX)))
385 || (optarg == p) || (*p != '\0')
386 || (l < INT_MIN) || (l > INT_MAX)) {
387 log_err (EMUNGE_SNAFU, LOG_ERR,
388 "Invalid value \"%s\" for group-update-time", optarg);
389 }
390 conf->gids_update_secs = l;
391 break;
392 case OPT_KEY_FILE:
393 if (conf->key_name)
394 free (conf->key_name);
395 if (!(conf->key_name = strdup (optarg)))
396 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
397 "Failed to copy key-file name string");
398 break;
399 case OPT_LOG_FILE:
400 if (conf->logfile_name)
401 free (conf->logfile_name);
402 if (!(conf->logfile_name = strdup (optarg)))
403 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
404 "Failed to copy log-file name string");
405 break;
406 case OPT_MAX_TTL:
407 l = strtol (optarg, &p, 10);
408 if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX)))
409 || (optarg == p) || (*p != '\0')
410 || (l < 1) || (l > MUNGE_MAXIMUM_TTL)) {
411 log_err (EMUNGE_SNAFU, LOG_ERR,
412 "Invalid value \"%s\" for max-ttl", optarg);
413 }
414 conf->max_ttl = l;
415 break;
416 case OPT_NUM_THREADS:
417 errno = 0;
418 l = strtol (optarg, &p, 10);
419 if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX)))
420 || (optarg == p) || (*p != '\0')
421 || (l <= 0) || (l > INT_MAX)) {
422 log_err (EMUNGE_SNAFU, LOG_ERR,
423 "Invalid value \"%s\" for num-threads", optarg);
424 }
425 conf->nthreads = l;
426 break;
427 case OPT_ORIGIN:
428 if (conf->origin_name)
429 free (conf->origin_name);
430 if (!(conf->origin_name = strdup (optarg)))
431 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
432 "Failed to copy origin string");
433 break;
434 case OPT_PID_FILE:
435 if (conf->pidfile_name)
436 free (conf->pidfile_name);
437 if (!(conf->pidfile_name = strdup (optarg)))
438 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
439 "Failed to copy pid-file name string");
440 break;
441 case OPT_SEED_FILE:
442 if (conf->seed_name)
443 free (conf->seed_name);
444 if (!(conf->seed_name = strdup (optarg)))
445 log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
446 "Failed to copy seed-file name string");
447 break;
448 case OPT_SYSLOG:
449 conf->got_syslog = 1;
450 break;
451 case OPT_TRUSTED_GROUP:
452 if (path_set_trusted_group (optarg) < 0) {
453 log_err (EMUNGE_SNAFU, LOG_ERR,
454 "Invalid value \"%s\" for trusted-group", optarg);
455 }
456 break;
457 case '?':
458 if (optopt > 0) {
459 log_err (EMUNGE_SNAFU, LOG_ERR,
460 "Invalid option \"-%c\"", optopt);
461 }
462 else if (optind > 1) {
463 log_err (EMUNGE_SNAFU, LOG_ERR,
464 "Invalid option \"%s\"", argv[optind - 1]);
465 }
466 else {
467 log_err (EMUNGE_SNAFU, LOG_ERR,
468 "Failed to process command-line");
469 }
470 break;
471 case ':':
472 if ((optind > 1)
473 && (strncmp (argv[optind - 1], "--", 2) == 0)) {
474 log_err (EMUNGE_SNAFU, LOG_ERR,
475 "Missing argument for option \"%s\"",
476 argv[optind - 1]);
477 }
478 else if (optopt > 0) {
479 log_err (EMUNGE_SNAFU, LOG_ERR,
480 "Missing argument for option \"-%c\"", optopt);
481 }
482 else {
483 log_err (EMUNGE_SNAFU, LOG_ERR,
484 "Failed to process command-line");
485 }
486 break;
487 default:
488 if ((optind > 1)
489 && (strncmp (argv[optind - 1], "--", 2) == 0)) {
490 log_err (EMUNGE_SNAFU, LOG_ERR,
491 "Unimplemented option \"%s\"", argv[optind - 1]);
492 }
493 else {
494 log_err (EMUNGE_SNAFU, LOG_ERR,
495 "Unimplemented option \"-%c\"", c);
496 }
497 break;
498 }
499 }
500 if (argv[optind]) {
501 log_err (EMUNGE_SNAFU, LOG_ERR,
502 "Unrecognized parameter \"%s\"", argv[optind]);
503 }
504 }
505
506
507 void
process_conf(conf_t conf)508 process_conf (conf_t conf)
509 {
510 /* Process the configuration.
511 */
512 assert (conf != NULL);
513
514 if (conf->got_stop) {
515 _conf_process_stop (conf);
516 }
517 _conf_set_origin_addr (conf);
518 return;
519 }
520
521
522 void
write_origin_addr(conf_t conf)523 write_origin_addr (conf_t conf)
524 {
525 /* Write a log message indicating the origin address that will be encoded into
526 * the credential metadata.
527 */
528 char buf[INET_ADDRSTRLEN];
529
530 assert (conf != NULL);
531
532 if (!inet_ntop (AF_INET, &conf->addr, buf, sizeof (buf))) {
533 log_msg (LOG_WARNING, "Failed to convert origin address to a string");
534 }
535 else if (conf->origin_ifname != NULL) {
536 log_msg (LOG_INFO, "Set origin address to %s (%s)", buf,
537 conf->origin_ifname);
538 }
539 else {
540 log_msg (LOG_INFO, "Set origin address to %s", buf);
541 }
542 return;
543 }
544
545
546 void
create_subkeys(conf_t conf)547 create_subkeys (conf_t conf)
548 {
549 int fd;
550 int n;
551 int n_total;
552 unsigned char buf[1024];
553 md_ctx dek_ctx;
554 md_ctx mac_ctx;
555
556 assert (conf != NULL);
557 assert (conf->dek_key == NULL);
558 assert (conf->mac_key == NULL);
559
560 /* Allocate memory for subkeys.
561 */
562 if ((conf->dek_key_len = md_size (MUNGE_MAC_SHA1)) <= 0) {
563 log_err (EMUNGE_NO_MEMORY, LOG_ERR,
564 "Failed to determine DEK key length");
565 }
566 if (!(conf->dek_key = malloc (conf->dek_key_len))) {
567 log_err (EMUNGE_NO_MEMORY, LOG_ERR,
568 "Failed to allocate %d bytes for cipher subkey",
569 conf->dek_key_len);
570 }
571 if ((conf->mac_key_len = md_size (MUNGE_MAC_SHA1)) <= 0) {
572 log_err (EMUNGE_NO_MEMORY, LOG_ERR,
573 "Failed to determine MAC key length");
574 }
575 if (!(conf->mac_key = malloc (conf->mac_key_len))) {
576 log_err (EMUNGE_NO_MEMORY, LOG_ERR,
577 "Failed to allocate %d bytes for MAC subkey",
578 conf->mac_key_len);
579 }
580 if (md_init (&dek_ctx, MUNGE_MAC_SHA1) < 0) {
581 log_err (EMUNGE_SNAFU, LOG_ERR,
582 "Failed to compute subkeys: Cannot init md ctx");
583 }
584 /* Compute keyfile's message digest.
585 */
586 fd = _conf_open_keyfile (conf->key_name, conf->got_force);
587 assert (fd >= 0);
588
589 n_total = 0;
590 for (;;) {
591 n = read (fd, buf, sizeof (buf));
592 if (n == 0)
593 break;
594 if ((n < 0) && (errno == EINTR))
595 continue;
596 if (n < 0)
597 log_errno (EMUNGE_SNAFU, LOG_ERR,
598 "Failed to read keyfile \"%s\"", conf->key_name);
599 if (md_update (&dek_ctx, buf, n) < 0)
600 log_err (EMUNGE_SNAFU, LOG_ERR,
601 "Failed to compute subkeys: Cannot update md ctx");
602 n_total += n;
603 }
604 if (close (fd) < 0) {
605 log_errno (EMUNGE_SNAFU, LOG_ERR,
606 "Failed to close keyfile \"%s\"", conf->key_name);
607 }
608 if (n_total < MUNGE_KEY_LEN_MIN_BYTES) {
609 log_err (EMUNGE_SNAFU, LOG_ERR,
610 "Keyfile must be at least %d bytes", MUNGE_KEY_LEN_MIN_BYTES);
611 }
612 if (md_copy (&mac_ctx, &dek_ctx) < 0) {
613 log_err (EMUNGE_SNAFU, LOG_ERR,
614 "Failed to compute subkeys: Cannot copy md ctx");
615 }
616 /* Append "1" to keyfile in order to compute cipher subkey.
617 */
618 n = conf->dek_key_len;
619 if ( (md_update (&dek_ctx, "1", 1) < 0)
620 || (md_final (&dek_ctx, conf->dek_key, &n) < 0)
621 || (md_cleanup (&dek_ctx) < 0) ) {
622 log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute cipher subkey");
623 }
624 assert (n <= conf->dek_key_len);
625
626 /* Append "2" to keyfile in order to compute mac subkey.
627 */
628 n = conf->mac_key_len;
629 if ( (md_update (&mac_ctx, "2", 1) < 0)
630 || (md_final (&mac_ctx, conf->mac_key, &n) < 0)
631 || (md_cleanup (&mac_ctx) < 0) ) {
632 log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute MAC subkey");
633 }
634 assert (n <= conf->mac_key_len);
635
636 return;
637 }
638
639
640 /*****************************************************************************
641 * Internal Functions
642 *****************************************************************************/
643
644 static void
_conf_display_help(char * prog)645 _conf_display_help (char *prog)
646 {
647 /* Displays a help message describing the command-line options.
648 */
649 const int w = -24; /* pad for width of option string */
650
651 assert (prog != NULL);
652
653 printf ("Usage: %s [OPTIONS]\n", prog);
654 printf ("\n");
655
656 printf (" %*s %s\n", w, "-h, --help",
657 "Display this help");
658
659 printf (" %*s %s\n", w, "-L, --license",
660 "Display license information");
661
662 printf (" %*s %s\n", w, "-V, --version",
663 "Display version information");
664
665 printf ("\n");
666
667 printf (" %*s %s\n", w, "-f, --force",
668 "Force daemon to run if possible");
669
670 printf (" %*s %s\n", w, "-F, --foreground",
671 "Run daemon in the foreground (do not fork)");
672
673 printf (" %*s %s\n", w, "-M, --mlockall",
674 "Lock all pages in memory");
675
676 printf (" %*s %s\n", w, "-s, --stop",
677 "Stop daemon bound to socket");
678
679 printf (" %*s %s [%s]\n", w, "-S, --socket=PATH",
680 "Specify local socket", MUNGE_SOCKET_NAME);
681
682 printf (" %*s %s\n", w, "-v, --verbose",
683 "Be verbose");
684
685 printf ("\n");
686
687 #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD)
688 printf (" %*s %s [%s]\n", w, "--auth-server-dir=DIR",
689 "Specify auth-server directory", MUNGE_AUTH_SERVER_DIR);
690
691 printf (" %*s %s [%s]\n", w, "--auth-client-dir=DIR",
692 "Specify auth-client directory", MUNGE_AUTH_CLIENT_DIR);
693 #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */
694
695 printf (" %*s %s\n", w, "--benchmark",
696 "Disable timers to reduce noise while benchmarking");
697
698 printf (" %*s Specify whether to check \"%s\" mtime [%d]\n",
699 w, "--group-check-mtime=BOOL", GIDS_GROUP_FILE,
700 MUNGE_GROUP_STAT_FLAG);
701
702 printf (" %*s %s [%d]\n", w, "--group-update-time=INT",
703 "Specify seconds between group info updates",
704 MUNGE_GROUP_UPDATE_SECS);
705
706 printf (" %*s %s [%s]\n", w, "--key-file=PATH",
707 "Specify key file", MUNGE_KEYFILE_PATH);
708
709 printf (" %*s %s [%s]\n", w, "--log-file=PATH",
710 "Specify log file", MUNGE_LOGFILE_PATH);
711
712 printf (" %*s %s [%d]\n", w, "--max-ttl=INT",
713 "Specify maximum time-to-live (in seconds)", MUNGE_MAXIMUM_TTL);
714
715 printf (" %*s %s [%d]\n", w, "--num-threads=INT",
716 "Specify number of threads to spawn", MUNGE_THREADS);
717
718 printf (" %*s %s\n", w, "--origin=ADDRESS",
719 "Specify origin address via hostname/IPaddr/interface");
720
721 printf (" %*s %s [%s]\n", w, "--pid-file=PATH",
722 "Specify PID file", MUNGE_PIDFILE_PATH);
723
724 printf (" %*s %s [%s]\n", w, "--seed-file=PATH",
725 "Specify PRNG seed file", MUNGE_SEEDFILE_PATH);
726
727 printf (" %*s %s\n", w, "--syslog",
728 "Redirect log messages to syslog");
729
730 printf (" %*s %s\n", w, "--trusted-group=GROUP",
731 "Specify trusted group/GID for directory checks");
732
733 printf ("\n");
734 return;
735 }
736
737
738 static void
_conf_process_stop(conf_t conf)739 _conf_process_stop (conf_t conf)
740 {
741 /* Processes the -s/--stop option.
742 * A series of SIGTERMs are sent to the process holding the write-lock.
743 * If the process fails to terminate, a final SIGKILL is sent.
744 */
745 pid_t pid;
746 int signum;
747 int msecs;
748 int i;
749 int rv;
750
751 assert (conf != NULL);
752 assert (MUNGE_SIGNAL_ATTEMPTS > 0);
753 assert (MUNGE_SIGNAL_DELAY_MSECS > 0);
754
755 pid = lock_query (conf);
756 if (pid <= 0) {
757 if (conf->got_verbose) {
758 log_err (EMUNGE_SNAFU, LOG_ERR,
759 "Failed to query socket lockfile \"%s\": %s",
760 conf->lockfile_name,
761 (pid == 0) ? "Lock not held" : strerror (errno));
762 }
763 exit (EXIT_FAILURE);
764 }
765 rv = kill (pid, 0);
766 if (rv < 0) {
767 if (conf->got_verbose) {
768 log_errno (EMUNGE_SNAFU, LOG_ERR,
769 "Failed to signal daemon bound to socket \"%s\" (pid %d)",
770 conf->socket_name, pid);
771 }
772 exit (EXIT_FAILURE);
773 }
774 signum = SIGTERM;
775 msecs = 0;
776 for (i = 0; i < (MUNGE_SIGNAL_ATTEMPTS + 1); i++) {
777 if (i == MUNGE_SIGNAL_ATTEMPTS) {
778 signum = SIGKILL; /* Kill me harder! */
779 }
780 msecs += MUNGE_SIGNAL_DELAY_MSECS;
781 rv = _conf_send_signal (pid, signum, msecs);
782 if (rv == 0) {
783 if (conf->got_verbose) {
784 log_msg (LOG_NOTICE,
785 "%s daemon bound to socket \"%s\" (pid %d)",
786 (signum == SIGTERM) ? "Terminated" : "Killed",
787 conf->socket_name, pid);
788 }
789 exit (EXIT_SUCCESS);
790 }
791 }
792 if (conf->got_verbose) {
793 log_err (EMUNGE_SNAFU, LOG_ERR,
794 "Failed to terminate daemon bound to socket \"%s\" (pid %d)",
795 conf->socket_name, pid);
796 }
797 exit (EXIT_FAILURE);
798 }
799
800
801 static int
_conf_send_signal(pid_t pid,int signum,int msecs)802 _conf_send_signal (pid_t pid, int signum, int msecs)
803 {
804 /* Sends the signal [signum] to the process specified by [pid].
805 * Returns 1 if the process is still running after a delay of [msecs],
806 * or 0 if the process cannot be found.
807 */
808 struct timespec ts;
809 int rv;
810
811 assert (pid > 0);
812 assert (signum > 0);
813 assert (msecs > 0);
814
815 log_msg (LOG_DEBUG, "Signaling pid %d with sig %d and %dms delay",
816 pid, signum, msecs);
817
818 rv = kill (pid, signum);
819 if (rv < 0) {
820 if (errno == ESRCH) {
821 return (0);
822 }
823 log_errno (EMUNGE_SNAFU, LOG_ERR,
824 "Failed to signal daemon (pid %d, sig %d)", pid, signum);
825 }
826 ts.tv_sec = msecs / 1000;
827 ts.tv_nsec = (msecs % 1000) * 1000 * 1000;
828 retry:
829 rv = nanosleep (&ts, &ts);
830 if (rv < 0) {
831 if (errno == EINTR) {
832 goto retry;
833 }
834 log_errno (EMUNGE_SNAFU, LOG_ERR,
835 "Failed to sleep while awaiting signal result");
836 }
837 rv = kill (pid, 0);
838 if (rv < 0) {
839 if (errno == ESRCH) {
840 return (0);
841 }
842 log_errno (EMUNGE_SNAFU, LOG_ERR,
843 "Failed to check daemon (pid %d, sig 0)", pid);
844 }
845 return (1);
846 }
847
848
849 static void
_conf_set_origin_addr(conf_t conf)850 _conf_set_origin_addr (conf_t conf)
851 {
852 /* Set the origin address to be encoded into credential metadata.
853 * If an origin is explicitly specified, failure to lookup its network address
854 * results in an error which can be overridden.
855 * If an orgin is not specified or the error is overridden, a warning is
856 * logged and the origin address is set to the null address.
857 */
858 int is_origin_specified;
859 int rv = 0;
860
861 assert (conf != NULL);
862
863 memset (&conf->addr, 0, sizeof (conf->addr));
864 conf->origin_ifname = NULL;
865
866 is_origin_specified = (conf->origin_name != NULL) ? 1 : 0;
867
868 if (conf->origin_name == NULL) {
869 rv = net_get_hostname (&conf->origin_name);
870 if (rv < 0) {
871 log_msg (LOG_WARNING, "Failed to get name of current host");
872 }
873 }
874 if (conf->origin_name != NULL) {
875 errno = 0;
876 rv = net_get_hostaddr (conf->origin_name, &conf->addr,
877 &conf->origin_ifname);
878 if (rv < 0) {
879 log_err_or_warn (conf->got_force || !is_origin_specified,
880 "Failed to lookup origin \"%s\"%s%s", conf->origin_name,
881 (errno != 0) ? ": " : "",
882 (errno != 0) ? strerror (errno) : "");
883 }
884 }
885 if (rv != 0) {
886 log_msg (LOG_WARNING, "Continuing with origin set to null address");
887 }
888 return;
889 }
890
891
892 static int
_conf_open_keyfile(const char * keyfile,int got_force)893 _conf_open_keyfile (const char *keyfile, int got_force)
894 {
895 /* Returns a valid file-descriptor to the opened [keyfile], or dies trying.
896 */
897 int is_symlink;
898 struct stat st;
899 int n;
900 char keydir [PATH_MAX];
901 char ebuf [1024];
902 int fd;
903
904 if ((keyfile == NULL) || (*keyfile == '\0')) {
905 log_err (EMUNGE_SNAFU, LOG_ERR, "Keyfile name is undefined");
906 }
907 is_symlink = (lstat (keyfile, &st) == 0) ? S_ISLNK (st.st_mode) : 0;
908
909 if (stat (keyfile, &st) < 0) {
910 log_errno (EMUNGE_SNAFU, LOG_ERR,
911 "Failed to check keyfile \"%s\"", keyfile);
912 }
913 if (!S_ISREG (st.st_mode)) {
914 log_err (EMUNGE_SNAFU, LOG_ERR,
915 "Keyfile is insecure: \"%s\" must be a regular file (type=%07o)",
916 keyfile, (st.st_mode & S_IFMT));
917 }
918 if (is_symlink) {
919 log_err_or_warn (got_force,
920 "Keyfile is insecure: \"%s\" should not be a symbolic link",
921 keyfile);
922 }
923 if (st.st_uid != geteuid ()) {
924 log_err_or_warn (got_force,
925 "Keyfile is insecure: \"%s\" should be owned by UID %u instead of "
926 "UID %u", keyfile, (unsigned) geteuid (), (unsigned) st.st_uid);
927 }
928 if (st.st_mode & (S_IRGRP | S_IWGRP)) {
929 log_err_or_warn (got_force,
930 "Keyfile is insecure: \"%s\" should not be readable or writable "
931 "by group (perms=%04o)", keyfile, (st.st_mode & ~S_IFMT));
932 }
933 if (st.st_mode & (S_IROTH | S_IWOTH)) {
934 log_err_or_warn (got_force,
935 "Keyfile is insecure: \"%s\" should not be readable or writable "
936 "by other (perms=%04o)", keyfile, (st.st_mode & ~S_IFMT));
937 }
938 /* Ensure keyfile dir is secure against modification by others.
939 */
940 if (path_dirname (keyfile, keydir, sizeof (keydir)) < 0) {
941 log_err (EMUNGE_SNAFU, LOG_ERR,
942 "Failed to determine dirname of keyfile \"%s\"", keyfile);
943 }
944 n = path_is_secure (keydir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS);
945 if (n < 0) {
946 log_err (EMUNGE_SNAFU, LOG_ERR,
947 "Failed to check keyfile dir \"%s\": %s", keydir, ebuf);
948 }
949 else if (n == 0) {
950 log_err_or_warn (got_force, "Keyfile is insecure: %s", ebuf);
951 }
952 /* Open keyfile for reading only.
953 */
954 if ((fd = open (keyfile, O_RDONLY)) < 0) {
955 log_errno (EMUNGE_SNAFU, LOG_ERR,
956 "Failed to open keyfile \"%s\"", keyfile);
957 }
958 return (fd);
959 }
960