Signal cleanups.
[pwmd.git] / src / pwmd.c
blobaa9d990b3c897afcf363f01923baf855310d2ee7
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 Ben Kibbey <bjk@luxsci.net>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/un.h>
27 #include <signal.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <sys/wait.h>
31 #include <fcntl.h>
32 #include <pwd.h>
33 #include <glib.h>
34 #include <glib/gprintf.h>
35 #include <gcrypt.h>
36 #include <sys/mman.h>
37 #include <termios.h>
38 #include <assert.h>
39 #include <syslog.h>
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
45 #ifdef HAVE_SETRLIMIT
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #endif
50 #ifdef HAVE_ZLIB_H
51 #include <zlib.h>
52 #endif
54 #ifndef MEM_DEBUG
55 #include "mem.h"
56 #endif
58 #include "xml.h"
59 #include "common.h"
60 #include "commands.h"
61 #include "pwmd_error.h"
62 #include "cache.h"
63 #include "pwmd.h"
65 static void clear_rcfile_key()
67 gsize n;
68 gchar **groups;
69 gchar **p;
71 groups = g_key_file_get_groups(keyfileh, &n);
73 for (p = groups; *p; p++) {
74 GError *error = NULL;
76 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE)
77 g_key_file_set_string(keyfileh, *p, "key", "");
80 g_strfreev(groups);
83 static void reload_rcfile()
85 log_write(N_("reloading configuration file '%s'"), rcfile);
86 g_key_file_free(keyfileh);
87 keyfileh = parse_rcfile(0);
88 clear_rcfile_key();
91 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
93 gpg_error_t n = gpg_error_from_errno(e);
95 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
98 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
100 gpg_err_code_t n = gpg_err_code(e);
101 gpg_error_t code = gpg_err_make(GPG_ERR_SOURCE_USER_1, n);
103 if (!e)
104 return assuan_process_done(ctx, 0);
106 if (!ctx) {
107 log_write("%s\n", pwmd_strerror(e));
108 return e;
111 if (n == EPWMD_LIBXML_ERROR) {
112 xmlErrorPtr xml_error = xmlGetLastError();
113 return assuan_process_done(ctx, assuan_set_error(ctx, code, xml_error->message));
116 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
119 void log_write(const gchar *fmt, ...)
121 gchar *args, *line;
122 va_list ap;
123 struct tm *tm;
124 time_t now;
125 gchar tbuf[21];
126 gint fd = -1;
128 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
129 return;
131 if (logfile) {
132 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
133 warn(N_("logfile"));
134 return;
138 va_start(ap, fmt);
140 if (g_vasprintf(&args, fmt, ap) == -1) {
141 va_end(ap);
142 return;
145 if (log_syslog == TRUE)
146 syslog(LOG_INFO, "%s", args);
148 va_end(ap);
149 time(&now);
150 tm = localtime(&now);
151 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
152 tbuf[sizeof(tbuf) - 1] = 0;
153 line = g_strdup_printf("%s %i %s\n", tbuf, getpid(), args);
155 if (!line) {
156 if (logfile)
157 close(fd);
159 g_free(args);
160 return;
163 if (logfile) {
164 write(fd, line, strlen(line));
165 fsync(fd);
166 close(fd);
169 if (isatty(STDERR_FILENO)) {
170 fprintf(stderr, "%s", line);
171 fflush(stderr);
174 g_free(line);
175 g_free(args);
178 static void usage(gchar *pn)
180 g_printf(N_(
181 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
182 " -b run as a background process\n"
183 " -f load the specified rcfile (~/.pwmd/config)\n"
184 " -I import an XML file and write the encrypted data to stdout\n"
185 " -D disable use of the LIST and DUMP commands\n"
186 " -v version\n"
187 " -h this help text\n"
188 ), pn);
189 exit(EXIT_SUCCESS);
192 #ifndef MEM_DEBUG
193 static int gcry_SecureCheck(const void *ptr)
195 return 1;
197 #endif
199 static void setup_gcrypt()
201 gcry_check_version(NULL);
203 #ifndef MEM_DEBUG
204 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
205 xfree);
206 #endif
208 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
209 NULL) != 0)
210 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
212 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
213 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
216 static assuan_context_t new_connection(gint fd)
218 gpg_error_t rc;
219 gchar ver[ASSUAN_LINELENGTH];
220 assuan_context_t ctx;
222 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
224 if (rc)
225 goto fail;
227 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
228 assuan_set_hello_line(ctx, ver);
229 assuan_register_post_cmd_notify(ctx, command_finalize);
230 rc = register_commands(ctx);
232 if (rc)
233 goto fail;
235 rc = assuan_accept(ctx);
237 if (rc)
238 goto fail;
240 return ctx;
242 fail:
243 assuan_deinit_server(ctx);
244 log_write("%s", gpg_strerror(rc));
245 return NULL;
248 void send_cache_status_all()
250 guint i, t;
252 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
253 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
255 if (cn->tid == pth_self()) {
256 send_cache_status(cn->cl->ctx);
257 continue;
260 pth_raise(cn->tid, SIGUSR2);
264 static void *keepalive_thread(void *arg)
266 struct client_thread_s *thd = arg;
267 gint k = get_key_file_integer("default", "keepalive");
268 pth_event_t ev;
269 sigset_t set;
271 if (k <= 0)
272 pth_exit(NULL);
274 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k, 0));
275 sigemptyset(&set);
276 sigaddset(&set, SIGALRM);
278 for (;;) {
279 gint sig = 0;
280 gpg_error_t error;
282 pth_sigwait_ev(&set, &sig, ev);
283 pth_event_free(ev, PTH_FREE_THIS);
284 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k, 0));
286 if (sig)
287 break;
289 error = assuan_write_status(thd->cl->ctx, "KEEPALIVE", NULL);
291 if (error) {
292 pth_raise(thd->tid, SIGQUIT);
293 break;
297 pth_event_free(ev, PTH_FREE_THIS);
298 return NULL;
302 * Called every time a connection is made via pth_spawn(). This is the thread
303 * entry point.
305 static void *client_thread(void *data)
307 struct client_thread_s *thd = data;
308 gint fd = thd->fd;
309 pth_event_t ev;
310 struct client_s *cl = g_malloc0(sizeof(struct client_s));
311 sigset_t set;
313 if (!cl) {
314 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
315 goto fail;
318 thd->cl = cl;
321 * This is a "child" thread. Don't catch any signals. Let the master
322 * thread take care of signals in server_loop().
324 sigfillset(&set);
325 pth_sigmask(SIG_BLOCK, &set, NULL);
326 sigemptyset(&set);
327 /* Sends a cache status message to the client. */
328 sigaddset(&set, SIGUSR2);
329 /* Terminates this thread. Raised from keepalive_thread(). */
330 sigaddset(&set, SIGQUIT);
332 cl->ctx = new_connection(fd);
333 cl->fd = fd;
335 if (!cl->ctx)
336 goto fail;
338 assuan_set_pointer(cl->ctx, cl);
340 #ifdef HAVE_MLOCKALL
341 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
342 log_write("mlockall(): %s", strerror(errno));
343 goto fail;
345 #endif
347 send_cache_status(cl->ctx);
348 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
349 thd->keepalive_tid = pth_spawn(NULL, keepalive_thread, thd);
351 for (;;) {
352 gpg_error_t rc;
353 gint sig = 0;
355 pth_sigwait_ev(&set, &sig, ev);
357 if (sig > 0) {
358 switch (sig) {
359 case SIGUSR2:
360 send_cache_status(cl->ctx);
361 continue;
362 case SIGQUIT:
363 goto done;
364 default:
365 break;
369 if (pth_event_occurred(ev)) {
370 rc = assuan_process_next(cl->ctx);
372 if (rc) {
373 cl->inquire = INQUIRE_NONE;
375 if (gpg_err_code(rc) == GPG_ERR_EOF)
376 goto done;
378 log_write("assuan_process_next(): %s", gpg_strerror(rc));
379 rc = assuan_process_done(cl->ctx, rc);
381 if (rc) {
382 log_write("assuan_process_done(): %s", gpg_strerror(rc));
383 goto done;
386 else {
387 /* Set from store_command_finalize(). */
388 if (cl->inquire == INQUIRE_OK || cl->inquire_error) {
389 cl->inquire = INQUIRE_NONE;
390 rc = assuan_process_done(cl->ctx, gpg_err_make(GPG_ERR_SOURCE_ANY, cl->inquire_error));
391 cl->inquire_error = 0;
393 if (rc) {
394 log_write("assuan_process_done(): %s", gpg_strerror(rc));
395 goto done;
403 * Client cleanup (including XML data) is done in remove_connection() from
404 * the cleanup thread.
406 done:
407 pth_event_free(ev, PTH_FREE_ALL);
409 fail:
410 pth_exit(NULL);
411 return NULL;
415 * Make sure all settings are set to either the specified setting or a
416 * default.
418 static void set_rcfile_defaults(GKeyFile *kf)
420 gchar buf[PATH_MAX];
422 if (g_key_file_has_key(kf, "default", "socket_path", NULL) == FALSE) {
423 snprintf(buf, sizeof(buf), "~/.pwmd/socket");
424 g_key_file_set_string(kf, "default", "socket_path", buf);
427 if (g_key_file_has_key(kf, "default", "data_directory", NULL) == FALSE) {
428 snprintf(buf, sizeof(buf), "~/.pwmd/data");
429 g_key_file_set_string(kf, "default", "data_directory", buf);
432 if (g_key_file_has_key(kf, "default", "log_path", NULL) == FALSE) {
433 snprintf(buf, sizeof(buf), "~/.pwmd/log");
434 g_key_file_set_string(kf, "default", "log_path", buf);
437 if (g_key_file_has_key(kf, "default", "enable_logging", NULL) == FALSE)
438 g_key_file_set_boolean(kf, "default", "enable_logging", FALSE);
440 if (g_key_file_has_key(kf, "default", "cache_size", NULL) == FALSE)
441 g_key_file_set_integer(kf, "default", "cache_size", cache_size);
443 #ifdef HAVE_MLOCKALL
444 if (g_key_file_has_key(kf, "default", "disable_mlockall", NULL) == FALSE)
445 g_key_file_set_boolean(kf, "default", "disable_mlockall", TRUE);
446 #endif
448 if (g_key_file_has_key(kf, "default", "cache_timeout", NULL) == FALSE)
449 g_key_file_set_integer(kf, "default", "cache_timeout", -1);
451 if (g_key_file_has_key(kf, "default", "iterations", NULL) == FALSE)
452 g_key_file_set_integer(kf, "default", "iterations", 0);
454 if (g_key_file_has_key(kf, "default", "disable_list_and_dump", NULL) == FALSE)
455 g_key_file_set_boolean(kf, "default", "disable_list_and_dump", FALSE);
457 if (g_key_file_has_key(kf, "default", "iteration_progress", NULL) == FALSE)
458 g_key_file_set_integer(kf, "default", "iteration_progress", 0);
460 if (g_key_file_has_key(kf, "default", "compression_level", NULL) == FALSE)
461 g_key_file_set_integer(kf, "default", "compression_level", 6);
463 if (g_key_file_has_key(kf, "default", "recursion_depth", NULL) == FALSE)
464 g_key_file_set_integer(kf, "default", "recursion_depth", DEFAULT_RECURSION_DEPTH);
466 if (g_key_file_has_key(kf, "default", "zlib_bufsize", NULL) == FALSE)
467 g_key_file_set_integer(kf, "default", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
469 zlib_bufsize = g_key_file_get_integer(kf, "default", "zlib_bufsize", NULL);
471 max_recursion_depth = g_key_file_get_integer(kf, "default", "recursion_depth", NULL);
472 disable_list_and_dump = g_key_file_get_boolean(kf, "default", "disable_list_and_dump", NULL);
474 #ifdef HAVE_MLOCKALL
475 disable_mlock = g_key_file_get_boolean(kf, "default", "disable_mlockall", NULL);
476 #endif
478 if (g_key_file_has_key(kf, "default", "syslog", NULL) == FALSE)
479 g_key_file_set_boolean(kf, "default", "syslog", FALSE);
481 if (g_key_file_has_key(kf, "default", "keepalive", NULL) == FALSE)
482 g_key_file_set_integer(kf, "default", "keepalive", 5);
485 static GKeyFile *parse_rcfile(int cmdline)
487 GKeyFile *kf = g_key_file_new();
488 GError *error = NULL;
490 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &error) == FALSE) {
491 log_write("%s: %s", rcfile, error->message);
493 if (cmdline)
494 exit(EXIT_FAILURE);
496 if (error->code == G_FILE_ERROR_NOENT) {
497 g_clear_error(&error);
498 set_rcfile_defaults(kf);
499 return kf;
502 g_clear_error(&error);
503 return NULL;
505 else
506 set_rcfile_defaults(kf);
508 return kf;
511 static gchar *get_password(const gchar *prompt)
513 gchar buf[LINE_MAX], *p;
514 struct termios told, tnew;
515 gchar *key;
517 if (tcgetattr(STDIN_FILENO, &told) == -1)
518 err(EXIT_FAILURE, "tcgetattr()");
520 memcpy(&tnew, &told, sizeof(struct termios));
521 tnew.c_lflag &= ~(ECHO);
522 tnew.c_lflag |= ICANON|ECHONL;
524 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
525 tcsetattr(STDIN_FILENO, TCSANOW, &told);
526 err(EXIT_FAILURE, "tcsetattr()");
529 fprintf(stderr, "%s", prompt);
531 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
532 tcsetattr(STDIN_FILENO, TCSANOW, &told);
533 return NULL;
536 tcsetattr(STDIN_FILENO, TCSANOW, &told);
537 p[strlen(p) - 1] = 0;
539 if (!p || !*p)
540 return NULL;
542 key = gcry_malloc(strlen(p) + 1);
543 sprintf(key, "%s", p);
544 memset(&buf, 0, sizeof(buf));
545 return key;
548 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
550 int fd;
551 struct stat st;
552 gpg_error_t error;
554 if ((fd = open_file(filename, &st)) == -1) {
555 warn("%s", filename);
556 return FALSE;
559 if (st.st_size == 0) {
560 warnx(N_("%s: skipping empty file"), filename);
561 close(fd);
562 return FALSE;
565 error = try_xml_decrypt(NULL, fd, st, key);
566 close(fd);
567 return error ? FALSE : TRUE;
570 static gboolean get_input(const gchar *filename, guchar *key)
572 gint try = 0;
573 gchar *password;
574 gchar *prompt;
576 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
578 again:
579 if ((password = get_password(prompt)) == NULL) {
580 warnx(N_("%s: skipping file"), filename);
581 g_free(prompt);
582 return FALSE;
585 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password));
586 gcry_free(password);
588 if (do_try_xml_decrypt(filename, key) == FALSE) {
589 if (try++ == 2) {
590 warnx(N_("%s: invalid password, skipping"), filename);
591 g_free(prompt);
592 return FALSE;
594 else {
595 warnx(N_("%s: invalid password"), filename);
596 goto again;
600 g_free(prompt);
601 return TRUE;
604 static gboolean xml_import(const gchar *filename, gint iter)
606 xmlDocPtr doc;
607 gint fd;
608 struct stat st;
609 gint len;
610 xmlChar *xmlbuf;
611 xmlChar *xml;
612 gchar *key = NULL;
613 gchar *key2 = NULL;
614 guchar shakey[gcrykeysize];
615 gcry_cipher_hd_t gh;
616 gpg_error_t error;
617 gint level;
618 glong outsize;
619 gpointer outbuf;
620 gint zerror;
622 if (stat(filename, &st) == -1) {
623 warn("%s", filename);
624 return FALSE;
627 if ((gcryerrno = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
628 send_error(NULL, gcryerrno);
629 gcry_cipher_close(gh);
630 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
631 return FALSE;
634 if ((key = get_password(N_("New password: "))) == NULL) {
635 fprintf(stderr, "%s\n", N_("Invalid password."));
636 gcry_cipher_close(gh);
637 return FALSE;
640 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
641 fprintf(stderr, "%s\n", N_("Passwords do not match."));
642 gcry_free(key);
643 gcry_cipher_close(gh);
644 return FALSE;
647 if (g_utf8_collate(key, key2) != 0) {
648 fprintf(stderr, "%s\n", N_("Passwords do not match."));
649 gcry_free(key);
650 gcry_free(key2);
651 gcry_cipher_close(gh);
652 return FALSE;
655 gcry_free(key2);
657 if ((fd = open(filename, O_RDONLY)) == -1) {
658 gcry_free(key);
659 warn("%s", filename);
660 gcry_cipher_close(gh);
661 return FALSE;
664 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
665 gcry_free(key);
666 close(fd);
667 log_write("%s", strerror(ENOMEM));
668 gcry_cipher_close(gh);
669 return FALSE;
672 if (read(fd, xmlbuf, st.st_size) == -1) {
673 error = errno;
674 close(fd);
675 gcry_free(key);
676 gcry_cipher_close(gh);
677 errno = error;
678 err(EXIT_FAILURE, "read()");
681 close(fd);
682 xmlbuf[st.st_size] = 0;
685 * Make sure the document validates.
687 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
688 log_write("xmlReadDoc()");
689 close(fd);
690 gcry_free(key);
691 gcry_free(xmlbuf);
692 gcry_cipher_close(gh);
693 return FALSE;
696 gcry_free(xmlbuf);
697 xmlDocDumpMemory(doc, &xml, &len);
698 xmlFreeDoc(doc);
700 level = get_key_file_integer(filename, "compression_level");
702 if (level < 0)
703 level = 0;
705 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zerror) == FALSE) {
706 memset(shakey, 0, sizeof(shakey));
707 gcry_free(xml);
709 if (zerror == Z_MEM_ERROR)
710 warnx("%s", strerror(ENOMEM));
711 else
712 warnx("do_compress() failed");
714 gcry_cipher_close(gh);
715 return FALSE;
717 else {
718 gcry_free(xml);
719 xml = outbuf;
720 len = outsize;
723 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key));
724 gcry_free(key);
725 error = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
726 gcry_cipher_close(gh);
728 if (error) {
729 memset(shakey, 0, sizeof(shakey));
730 warnx("%s", gpg_strerror(error));
731 return FALSE;
734 memset(shakey, 0, sizeof(shakey));
735 return TRUE;
738 gchar *get_key_file_string(const gchar *section, const gchar *what)
740 gchar *val = NULL;
741 GError *gerror = NULL;
743 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
744 val = g_key_file_get_string(keyfileh, section, what, &gerror);
746 if (gerror) {
747 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
748 g_clear_error(&gerror);
751 else {
752 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
753 val = g_key_file_get_string(keyfileh, "default", what, &gerror);
755 if (gerror) {
756 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
757 g_clear_error(&gerror);
762 return val;
765 gint get_key_file_integer(const gchar *section, const gchar *what)
767 gint val = -1;
768 GError *gerror = NULL;
770 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
771 val = g_key_file_get_integer(keyfileh, section, what, &gerror);
773 if (gerror) {
774 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
775 g_clear_error(&gerror);
778 else {
779 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
780 val = g_key_file_get_integer(keyfileh, "default", what, &gerror);
782 if (gerror) {
783 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
784 g_clear_error(&gerror);
789 return val;
792 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
794 gboolean val = FALSE;
795 GError *gerror = NULL;
797 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
798 val = g_key_file_get_boolean(keyfileh, section, what, &gerror);
800 if (gerror) {
801 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
802 g_clear_error(&gerror);
805 else {
806 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
807 val = g_key_file_get_boolean(keyfileh, "default", what, &gerror);
809 if (gerror) {
810 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
811 g_clear_error(&gerror);
816 return val;
819 gchar *expand_homedir(gchar *str)
821 gchar *p = str;
823 if (*p++ == '~')
824 return g_strdup_printf("%s%s", g_get_home_dir(), p);
826 return g_strdup(str);
829 static gchar *_getline(const gchar *file)
831 FILE *fp;
832 gchar buf[LINE_MAX], *p;
833 gchar *str = NULL;
835 if ((fp = fopen(file, "r")) == NULL) {
836 warn("%s", file);
837 return NULL;
840 if ((p = fgets(buf, sizeof(buf), fp)) == NULL) {
841 warnx(N_("%s: empty file?"), file);
842 return NULL;
845 fclose(fp);
847 if (buf[strlen(buf) - 1] == '\n')
848 buf[strlen(buf) - 1] = 0;
850 str = gcry_malloc(strlen(p) + 1);
851 memcpy(str, p, strlen(p));
852 str[strlen(p)] = 0;
853 memset(&buf, 0, sizeof(buf));
854 return str;
857 static gboolean parse_keyfile_key()
859 gsize n;
860 gchar **groups;
861 gchar **p;
862 gchar *str;
864 groups = g_key_file_get_groups(keyfileh, &n);
866 for (p = groups; *p; p++) {
867 GError *error = NULL;
869 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE) {
870 str = g_key_file_get_string(keyfileh, *p, "key", &error);
872 if (!str) {
873 if (error) {
874 warnx("%s", error->message);
875 g_clear_error(&error);
878 continue;
881 do_cache_push(*p, str);
882 g_free(str);
883 continue;
886 if (error) {
887 warnx("%s", error->message);
888 g_clear_error(&error);
889 continue;
892 if (g_key_file_has_key(keyfileh, *p, "key_file", &error) == TRUE) {
893 gchar *t;
894 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &error);
896 if (!file) {
897 if (error) {
898 warnx("%s", error->message);
899 g_clear_error(&error);
902 continue;
905 t = expand_homedir(file);
906 g_free(file);
907 file = t;
909 if ((str = _getline(file)) == NULL) {
910 g_free(file);
911 continue;
914 g_free(file);
915 do_cache_push(*p, str);
916 gcry_free(str);
917 continue;
920 if (error) {
921 warnx("%s", error->message);
922 g_clear_error(&error);
926 g_strfreev(groups);
927 return TRUE;
930 static gboolean do_cache_push(const gchar *filename, const gchar *password)
932 guchar *md5file;
933 guchar *key;
934 gint timeout;
935 const gchar *p = filename;
937 while (isspace(*p))
938 p++;
940 if (!*p)
941 return FALSE;
943 if (valid_filename(p) == FALSE) {
944 warnx(N_("%s: invalid characters in filename"), p);
945 return FALSE;
948 md5file = gcry_malloc(16);
949 key = gcry_malloc(gcrykeysize);
950 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
952 if (cache_iscached(md5file) == TRUE) {
953 warnx(N_("%s: file already cached, skipping"), p);
954 gcry_free(md5file);
955 gcry_free(key);
956 return FALSE;
959 if (access(p, R_OK|W_OK) != 0) {
960 gcry_free(md5file);
961 gcry_free(key);
963 if (errno != ENOENT) {
964 warn("%s", p);
965 return FALSE;
968 warn("%s", p);
969 return TRUE;
972 if (!password) {
973 if (get_input(p, key) == FALSE) {
974 gcry_free(key);
975 gcry_free(md5file);
976 return FALSE;
979 else {
980 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password));
982 if (do_try_xml_decrypt(filename, key) == FALSE) {
983 warnx(N_("%s: invalid password, skipping"), filename);
984 gcry_free(key);
985 gcry_free(md5file);
986 return FALSE;
990 if (cache_add_file(md5file, key) == FALSE) {
991 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
992 gcry_free(key);
993 gcry_free(md5file);
994 return FALSE;
997 timeout = get_key_file_integer(p, "cache_timeout");
998 cache_set_timeout(md5file, timeout);
999 warnx(N_("%s: file added to the cache"), filename);
1000 gcry_free(key);
1001 gcry_free(md5file);
1002 return TRUE;
1005 static GSList *remove_connection(GSList *list, struct client_thread_s *cn)
1007 gpointer value;
1008 struct client_s *cl = cn->cl;
1010 if (cn->keepalive_tid) {
1011 pth_raise(cn->keepalive_tid, SIGALRM);
1012 pth_join(cn->keepalive_tid, &value);
1015 pth_join(cn->tid, &value);
1016 close(cn->fd);
1018 if (cl->freed == FALSE)
1019 cleanup_assuan(cl->ctx);
1021 if (cl->ctx)
1022 assuan_deinit_server(cl->ctx);
1024 if (cl)
1025 g_free(cl);
1027 pth_event_isolate(cn->ev);
1028 pth_event_free(cn->ev, PTH_FREE_THIS);
1029 log_write(N_("client exited: fd=%i"), cn->fd);
1030 list = g_slist_remove(list, cn);
1031 g_free(cn);
1032 return list;
1036 * Can't pth_event_concat() to an empty event.
1038 static int event_ring_hack(void *data)
1040 return FALSE;
1044 * See if any thread has entered the DEAD queue and remove it.
1046 static GSList *cleanup_dead_queue(GSList *threads, pth_event_t tid_events)
1048 guint n, i;
1050 for (n = g_slist_length(threads), i = 0; i < n; i++) {
1051 struct client_thread_s *cn = g_slist_nth_data(threads, i);
1053 if (pth_event_occurred(cn->ev)) {
1054 threads = remove_connection(threads, cn);
1055 return cleanup_dead_queue(threads, tid_events);
1058 pth_event_concat(tid_events, cn->ev, NULL);
1061 return threads;
1064 static void *socket_thread(void *arg)
1066 gint sockfd = (gint)arg;
1067 pth_attr_t attr;
1070 * Thread priority is inherited from the calling thread. This thread is
1071 * PTH_PRIO_MAX. Keep the "child" threads at standard priority.
1073 attr = pth_attr_new();
1074 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1076 for (;;) {
1077 socklen_t slen = sizeof(struct sockaddr_un);
1078 struct sockaddr_un raddr;
1079 gint fd = -1;
1081 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1082 if (errno != EAGAIN) {
1083 if (!quit) // probably EBADF
1084 log_write("accept(): %s", strerror(errno));
1086 break;
1090 if (fd >= 0) {
1091 pth_t tid;
1092 struct client_thread_s *new;
1094 new = g_malloc0(sizeof(struct client_thread_s));
1096 if (!new) {
1097 log_write("%s", strerror(ENOMEM));
1098 continue;
1101 log_write(N_("new connection: fd=%i"), fd);
1102 new->fd = fd;
1103 tid = pth_spawn(attr, client_thread, new);
1105 if (!tid) {
1106 g_free(new);
1107 log_write(N_("pth_spawn() failed"));
1108 continue;
1111 new->tid = tid;
1112 new->fd = fd;
1113 new->ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1114 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1115 pth_event_concat(cn_events, new->ev, NULL);
1116 cn_thread_list = g_slist_append(cn_thread_list, new);
1117 pth_mutex_release(&cn_mutex);
1121 pth_attr_destroy(attr);
1123 /* Just in case pth_accept() failed for some reason other than EBADF */
1124 quit = 1;
1125 pth_exit(PTH_CANCELED);
1126 return NULL;
1129 static void *cleanup_thread(void *arg)
1131 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1133 for (;;) {
1134 if (pth_wait(cn_events) && pth_event_occurred(cn_events)) {
1135 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1136 pth_event_isolate(cn_events);
1137 pth_event_free(cn_events, PTH_FREE_THIS);
1138 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1139 cn_thread_list = cleanup_dead_queue(cn_thread_list, cn_events);
1140 pth_mutex_release(&cn_mutex);
1144 pth_event_isolate(cn_events);
1145 pth_event_free(cn_events, PTH_FREE_THIS);
1146 return NULL;
1149 static void *adjust_cache_time_thread(void *arg)
1151 CACHE_LOCK(NULL, NULL);
1152 cache_adjust_timer();
1153 CACHE_UNLOCK;
1154 return NULL;
1157 static void server_loop(int sockfd)
1159 pth_t socket_tid, cleanup_tid;
1160 guint n, i;
1161 sigset_t set;
1162 gint n_clients = 0;
1163 pth_attr_t attr;
1164 pth_event_t timeout_event;
1165 gpointer value;
1167 pth_mutex_init(&cn_mutex);
1168 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1170 sigemptyset(&set);
1171 sigaddset(&set, SIGTERM);
1172 sigaddset(&set, SIGINT);
1173 sigaddset(&set, SIGUSR1);
1174 sigaddset(&set, SIGHUP);
1175 sigaddset(&set, SIGABRT);
1177 attr = pth_attr_new();
1178 pth_attr_init(attr);
1179 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1180 socket_tid = pth_spawn(attr, socket_thread, (void *)sockfd);
1181 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1182 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ASYNCHRONOUS);
1183 cleanup_tid = pth_spawn(attr, cleanup_thread, NULL);
1186 * For the cache_timeout configuration parameter. This replaces the old
1187 * SIGALRM stuff and is safer.
1189 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1190 pth_attr_init(attr);
1191 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1192 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1194 do {
1195 gint sig = 0;
1197 pth_sigwait_ev(&set, &sig, timeout_event);
1199 if (pth_event_occurred(timeout_event)) {
1201 * The timer event has expired. Update the file cache. When the
1202 * cache mutex is locked and the timer expires again, the threads
1203 * will stack.
1205 pth_spawn(attr, adjust_cache_time_thread, NULL);
1206 pth_event_free(timeout_event, PTH_FREE_THIS);
1207 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1210 if (sig > 0) {
1211 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1213 /* Caught a signal. */
1214 switch (sig) {
1215 case SIGUSR1:
1216 reload_rcfile();
1217 break;
1218 case SIGABRT:
1219 CACHE_LOCK(NULL, NULL);
1220 cache_clear(NULL, 2);
1221 CACHE_UNLOCK;
1222 #ifndef MEM_DEBUG
1223 xpanic();
1224 #endif
1225 exit(EXIT_FAILURE);
1226 case SIGHUP:
1227 CACHE_LOCK(NULL, NULL);
1228 log_write(N_("clearing file cache"));
1229 cache_clear(NULL, 2);
1230 CACHE_UNLOCK;
1231 break;
1232 default:
1233 quit = 1;
1234 shutdown(sockfd, SHUT_RDWR);
1235 close(sockfd);
1236 break;
1239 } while (!quit);
1242 * We're out of the main server loop. This happens when a signal was sent
1243 * to terminate the daemon. We'll wait for all clients to disconnect
1244 * before exiting and ignore any following signals.
1246 pth_join(socket_tid, &value);
1247 pth_attr_destroy(attr);
1248 pth_event_free(timeout_event, PTH_FREE_THIS);
1250 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1252 /* 2 because the cleanup thread still exists, plus self. */
1253 if (n > 2)
1254 log_write(N_("waiting for all threads to terminate"));
1256 while (n > 2) {
1257 gint t;
1258 pth_event_t events;
1260 if (n != n_clients) {
1261 log_write(N_("%i threads remain"), n-2);
1262 n_clients = n;
1265 events = pth_event(PTH_EVENT_FUNC, event_ring_hack, NULL, pth_timeout(1, 0));
1266 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1268 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1269 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1271 pth_event_concat(events, cn->ev, NULL);
1274 if (!t)
1275 goto done;
1277 pth_mutex_release(&cn_mutex);
1278 pth_wait(events);
1279 pth_yield(cleanup_tid);
1280 done:
1281 pth_event_isolate(events);
1282 pth_event_free(events, PTH_FREE_THIS);
1283 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1286 pth_cancel(cleanup_tid);
1289 int main(int argc, char *argv[])
1291 gint opt;
1292 struct sockaddr_un addr;
1293 struct passwd *pw = getpwuid(getuid());
1294 gchar buf[PATH_MAX];
1295 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1296 gchar *socketarg = NULL;
1297 gchar *datadir = NULL;
1298 gboolean n;
1299 gchar *p;
1300 gchar **cache_push = NULL;
1301 gint iter = 0;
1302 gchar *import = NULL;
1303 gint default_timeout;
1304 gint rcfile_spec = 0;
1305 gint estatus = EXIT_FAILURE;
1306 gint sockfd;
1307 #ifndef MEM_DEBUG
1308 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1309 #endif
1310 gint do_unlink = 1;
1311 gboolean secure = FALSE;
1312 guint ptotal = 0;
1313 gint background = 0;
1314 sigset_t set;
1315 #ifndef DEBUG
1316 #ifdef HAVE_SETRLIMIT
1317 struct rlimit rl;
1319 rl.rlim_cur = rl.rlim_max = 0;
1321 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1322 err(EXIT_FAILURE, "setrlimit()");
1323 #endif
1324 #endif
1326 #ifdef ENABLE_NLS
1327 setlocale(LC_ALL, "");
1328 bindtextdomain("pwmd", LOCALEDIR);
1329 textdomain("pwmd");
1330 #endif
1332 gpg_err_init();
1333 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1334 #ifndef MEM_DEBUG
1335 g_mem_set_vtable(&mtable);
1336 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1337 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1338 xmlInitMemory();
1339 #endif
1340 pth_init();
1341 snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1343 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1344 err(EXIT_FAILURE, "%s", buf);
1346 snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1348 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1349 err(EXIT_FAILURE, "%s", buf);
1351 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1353 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1354 err(EXIT_FAILURE, "sysconf()");
1356 cache_size = page_size;
1358 while ((opt = getopt(argc, argv, "bI:hvf:D")) != EOF) {
1359 switch (opt) {
1360 case 'b':
1361 background = 1;
1362 break;
1363 case 'D':
1364 secure = TRUE;
1365 break;
1366 case 'I':
1367 import = optarg;
1368 break;
1369 case 'f':
1370 g_free(rcfile);
1371 rcfile = g_strdup(optarg);
1372 rcfile_spec = 1;
1373 break;
1374 case 'v':
1375 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1376 exit(EXIT_SUCCESS);
1377 case 'h':
1378 default:
1379 usage(argv[0]);
1383 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1384 exit(EXIT_FAILURE);
1386 if (g_key_file_has_key(keyfileh, "default", "syslog", NULL) == TRUE)
1387 log_syslog = g_key_file_get_boolean(keyfileh, "default", "syslog", NULL);
1389 if (log_syslog == TRUE)
1390 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1392 if (g_key_file_has_key(keyfileh, "default", "iterations", NULL) == TRUE)
1393 iter = g_key_file_get_integer(keyfileh, "default", "iterations", NULL);
1395 #ifdef HAVE_MLOCKALL
1396 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1397 warn("mlockall()");
1398 goto do_exit;
1400 #endif
1402 setup_gcrypt();
1404 if (import) {
1405 opt = xml_import(import, iter);
1406 g_key_file_free(keyfileh);
1407 g_free(rcfile);
1408 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1411 g_key_file_set_list_separator(keyfileh, ',');
1413 if ((p = g_key_file_get_string(keyfileh, "default", "socket_path", NULL)) == NULL)
1414 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1416 if (*p == '~') {
1417 p++;
1418 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1419 g_free(p);
1420 socketarg = g_strdup(buf);
1422 else
1423 socketarg = p;
1425 if ((p = g_key_file_get_string(keyfileh, "default", "data_directory", NULL)) == NULL)
1426 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1428 datadir = expand_homedir(p);
1429 g_free(p);
1431 if (secure == FALSE && g_key_file_has_key(keyfileh, "default", "disable_list_and_dump", NULL) == TRUE) {
1432 n = g_key_file_get_boolean(keyfileh, "default", "disable_list_and_dump", NULL);
1433 disable_list_and_dump = n;
1435 else
1436 disable_list_and_dump = secure;
1438 if (g_key_file_has_key(keyfileh, "default", "cache_timeout", NULL) == TRUE)
1439 default_timeout = g_key_file_get_integer(keyfileh, "default", "cache_timeout", NULL);
1440 else
1441 default_timeout = -1;
1443 if (g_key_file_has_key(keyfileh, "default", "cache_size", NULL) == TRUE) {
1444 cache_size = g_key_file_get_integer(keyfileh, "default", "cache_size", NULL);
1446 if (cache_size < page_size || cache_size % page_size)
1447 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1450 if (g_key_file_has_key(keyfileh, "default", "log_path", NULL) == TRUE) {
1451 if (g_key_file_has_key(keyfileh, "default", "enable_logging", NULL) == TRUE) {
1452 n = g_key_file_get_boolean(keyfileh, "default", "enable_logging", NULL);
1454 if (n == TRUE) {
1455 p = g_key_file_get_string(keyfileh, "default", "log_path", NULL);
1457 if (*p == '~') {
1458 p++;
1459 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1460 g_free(p);
1461 logfile = g_strdup(buf);
1463 else
1464 logfile = p;
1469 if (g_key_file_has_key(keyfileh, "default", "cache_push", NULL) == TRUE)
1470 cache_push = g_key_file_get_string_list(keyfileh, "default", "cache_push", NULL, NULL);
1472 if (argc != optind) {
1473 if (cache_push)
1474 ptotal = g_strv_length(cache_push);
1476 for (; optind < argc; optind++) {
1477 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1478 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1482 if (strchr(socketarg, '/') == NULL) {
1483 socketdir = g_get_current_dir();
1484 socketname = g_strdup(socketarg);
1485 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1487 else {
1488 socketname = g_strdup(strrchr(socketarg, '/'));
1489 socketname++;
1490 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1491 socketdir = g_strdup(socketarg);
1492 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1495 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1496 #ifdef MMAP_ANONYMOUS
1497 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1498 #else
1499 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1500 #endif
1501 err(EXIT_FAILURE, "mmap()");
1504 if (mlock(key_cache, cache_size) == -1)
1505 warn("mlock()");
1507 memset(key_cache, 0, cache_size);
1509 if (chdir(datadir)) {
1510 warn("%s", datadir);
1511 unlink(socketpath);
1512 goto do_exit;
1515 if (parse_keyfile_key() == FALSE)
1516 goto do_exit;
1518 clear_rcfile_key();
1521 * Set the cache entry for a file. Prompts for the password.
1523 if (cache_push) {
1524 for (opt = 0; cache_push[opt]; opt++)
1525 do_cache_push(cache_push[opt], NULL);
1527 g_strfreev(cache_push);
1528 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1532 * bind() doesn't like the full pathname of the socket or any non alphanum
1533 * characters so change to the directory where the socket is wanted then
1534 * create it then change to datadir.
1536 if (chdir(socketdir)) {
1537 warn("%s", socketdir);
1538 goto do_exit;
1541 g_free(socketdir);
1543 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1544 warn("socket()");
1545 goto do_exit;
1548 addr.sun_family = AF_UNIX;
1549 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1551 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1552 warn("bind()");
1554 if (errno == EADDRINUSE)
1555 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1556 "stale socket. Please remove it manually."), socketpath);
1558 do_unlink = 0;
1559 goto do_exit;
1562 if (g_key_file_has_key(keyfileh, "default", "socket_perms", NULL) == TRUE) {
1563 gchar *t = g_key_file_get_string(keyfileh, "default", "socket_perms", NULL);
1564 mode_t mode = strtol(t, NULL, 8);
1565 mode_t mask = umask(0);
1567 g_free(t);
1569 if (chmod(socketname, mode) == -1) {
1570 warn("%s", socketname);
1571 close(sockfd);
1572 unlink(socketpath);
1573 umask(mask);
1574 goto do_exit;
1577 umask(mask);
1580 g_free(--socketname);
1582 if (chdir(datadir)) {
1583 warn("%s", datadir);
1584 close(sockfd);
1585 unlink(socketpath);
1586 goto do_exit;
1589 g_free(datadir);
1590 pth_mutex_init(&cache_mutex);
1592 if (listen(sockfd, 0) == -1) {
1593 warn("listen()");
1594 goto do_exit;
1597 if (background) {
1598 switch (fork()) {
1599 case -1:
1600 warn("fork()");
1601 goto do_exit;
1602 case 0:
1603 close(0);
1604 close(1);
1605 close(2);
1606 setsid();
1607 break;
1608 default:
1609 exit(EXIT_SUCCESS);
1614 * These are the signals that we use in threads. libpth can catch signals
1615 * itself so ignore them everywhere else. Note that using
1616 * signal(N, SIG_IGN) doesn't work like you might think.
1618 sigemptyset(&set);
1620 /* Termination */
1621 sigaddset(&set, SIGTERM);
1622 sigaddset(&set, SIGINT);
1624 /* Configuration file reloading. */
1625 sigaddset(&set, SIGUSR1);
1627 /* Clears the file cache. */
1628 sigaddset(&set, SIGHUP);
1630 /* Caught in client_thread(). Sends a cache status message. */
1631 sigaddset(&set, SIGUSR2);
1633 /* Caught in client_thread(). When keepalive_thread() fails, this signal
1634 * is raised to terminate the client. More of a failsafe than anything. */
1635 sigaddset(&set, SIGQUIT);
1637 /* Ignored everywhere. When a client disconnects abnormally this signal
1638 * gets raised. It isn't needed though because client_thread() will check
1639 * for errors even after the client disconnects. */
1640 sigaddset(&set, SIGPIPE);
1641 pth_sigmask(SIG_BLOCK, &set, NULL);
1642 server_loop(sockfd);
1643 estatus = EXIT_SUCCESS;
1645 do_exit:
1646 if (socketpath && do_unlink) {
1647 unlink(socketpath);
1648 g_free(socketpath);
1651 g_key_file_free(keyfileh);
1652 g_free(rcfile);
1654 if (key_cache)
1655 memset(key_cache, 0, cache_size);
1657 if (key_cache && munmap(key_cache, cache_size) == -1)
1658 log_write("munmap(): %s", strerror(errno));
1660 if (estatus == EXIT_SUCCESS)
1661 log_write(N_("pwmd exiting normally"));
1663 pth_kill();
1664 #if defined(DEBUG) && !defined(MEM_DEBUG)
1665 xdump();
1666 #endif
1667 exit(estatus);