Renamed adjust_cache_time_thread() to adjust_timer_thread() and
[pwmd.git] / src / pwmd.c
blob03e834bb6c5de263170a9f223b673c9f7a5708d4
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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/un.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <glib.h>
38 #include <glib/gprintf.h>
39 #include <sys/mman.h>
40 #include <termios.h>
41 #include <assert.h>
42 #include <syslog.h>
43 #include <zlib.h>
44 #include <gcrypt.h>
46 #ifdef HAVE_SETRLIMIT
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #endif
51 #ifndef MEM_DEBUG
52 #include "mem.h"
53 #endif
55 #include "xml.h"
56 #include "common.h"
58 #ifdef WITH_PINENTRY
59 #include "pinentry.h"
60 #endif
62 #include "commands.h"
63 #include "pwmd_error.h"
64 #include "cache.h"
65 #include "pwmd.h"
67 static void clear_rcfile_key()
69 gsize n;
70 gchar **groups;
71 gchar **p;
73 groups = g_key_file_get_groups(keyfileh, &n);
75 for (p = groups; *p; p++) {
76 GError *error = NULL;
78 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE)
79 g_key_file_set_string(keyfileh, *p, "key", "");
82 g_strfreev(groups);
85 static void reload_rcfile()
87 log_write(N_("reloading configuration file '%s'"), rcfile);
88 g_key_file_free(keyfileh);
89 keyfileh = parse_rcfile(0);
90 clear_rcfile_key();
93 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
95 gpg_error_t n = gpg_error_from_errno(e);
97 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
100 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
102 gpg_err_code_t n = gpg_err_code(e);
103 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
105 if (!e)
106 return assuan_process_done(ctx, 0);
108 if (!ctx) {
109 log_write("%s\n", pwmd_strerror(e));
110 return e;
113 if (n == EPWMD_LIBXML_ERROR) {
114 xmlErrorPtr xml_error = xmlGetLastError();
115 return assuan_process_done(ctx, assuan_set_error(ctx, code, xml_error->message));
118 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
121 void log_write(const gchar *fmt, ...)
123 gchar *args, *line;
124 va_list ap;
125 struct tm *tm;
126 time_t now;
127 gchar tbuf[21];
128 gint fd = -1;
129 pth_attr_t attr;
130 gchar *name;
132 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
133 return;
135 if (logfile) {
136 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
137 warn(N_("logfile"));
138 return;
142 va_start(ap, fmt);
144 if (g_vasprintf(&args, fmt, ap) == -1) {
145 va_end(ap);
146 return;
149 attr = pth_attr_of(pth_self());
150 pth_attr_get(attr, PTH_ATTR_NAME, &name);
152 if (log_syslog == TRUE)
153 syslog(LOG_INFO, "%s: %s", name, args);
155 va_end(ap);
156 time(&now);
157 tm = localtime(&now);
158 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
159 tbuf[sizeof(tbuf) - 1] = 0;
160 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
162 if (!line) {
163 if (logfile)
164 close(fd);
166 g_free(args);
167 return;
170 if (logfile) {
171 write(fd, line, strlen(line));
172 fsync(fd);
173 close(fd);
176 if (isatty(STDERR_FILENO)) {
177 fprintf(stderr, "%s", line);
178 fflush(stderr);
181 g_free(line);
182 g_free(args);
185 static void usage(gchar *pn)
187 g_printf(N_(
188 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
189 " -b run as a background process\n"
190 " -f load the specified rcfile (~/.pwmd/config)\n"
191 " -I import an XML file and write the encrypted data to stdout\n"
192 " -D disable use of the LIST and DUMP commands\n"
193 " -v version\n"
194 " -h this help text\n"
195 ), pn);
196 exit(EXIT_SUCCESS);
199 #ifndef MEM_DEBUG
200 static int gcry_SecureCheck(const void *ptr)
202 return 1;
204 #endif
206 static void setup_gcrypt()
208 gcry_check_version(NULL);
210 #ifndef MEM_DEBUG
211 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
212 xfree);
213 #endif
215 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
216 NULL) != 0)
217 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
219 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
220 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
223 static assuan_context_t new_connection(gint fd)
225 gpg_error_t rc;
226 gchar ver[ASSUAN_LINELENGTH];
227 assuan_context_t ctx;
229 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
231 if (rc)
232 goto fail;
234 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
235 assuan_set_hello_line(ctx, ver);
236 assuan_register_post_cmd_notify(ctx, command_finalize);
237 rc = register_commands(ctx);
239 if (rc)
240 goto fail;
242 rc = assuan_accept(ctx);
244 if (rc)
245 goto fail;
247 return ctx;
249 fail:
250 assuan_deinit_server(ctx);
251 log_write("%s", gpg_strerror(rc));
252 return NULL;
255 void send_cache_status_all()
257 guint i, t;
259 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
260 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
262 if (cn->tid == pth_self()) {
263 send_cache_status(cn->cl->ctx);
264 continue;
267 pth_raise(cn->tid, SIGUSR2);
271 static void *keepalive_thread(void *arg)
273 struct client_thread_s *thd = arg;
274 pth_event_t ev;
275 sigset_t set;
277 sigemptyset(&set);
278 sigaddset(&set, SIGALRM);
280 for (;;) {
281 gint sig = 0;
282 gpg_error_t error;
283 gint k = get_key_file_integer("default", "keepalive");
285 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k <= 0 ? 1 : k, 0));
286 pth_sigwait_ev(&set, &sig, ev);
287 pth_event_free(ev, PTH_FREE_THIS);
289 if (sig)
290 break;
292 if (k <= 0)
293 continue;
295 error = assuan_write_status(thd->cl->ctx, "KEEPALIVE", NULL);
297 if (error) {
298 pth_raise(thd->tid, SIGQUIT);
299 break;
303 return NULL;
307 * Called every time a connection is made via pth_spawn(). This is the thread
308 * entry point.
310 static void *client_thread(void *data)
312 struct client_thread_s *thd = data;
313 gint fd = thd->fd;
314 pth_event_t ev;
315 #ifdef WITH_PINENTRY
316 pth_event_t pinentry_ev = NULL;
317 #endif
318 struct client_s *cl = g_malloc0(sizeof(struct client_s));
319 sigset_t set;
321 if (!cl) {
322 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
323 goto fail;
326 #ifdef WITH_PINENTRY
327 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
329 if (!cl->pinentry) {
330 g_free(cl);
331 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
332 goto fail;
335 set_pinentry_defaults(cl->pinentry);
336 #endif
337 thd->cl = cl;
338 cl->thd = thd;
341 * This is a "child" thread. Don't catch any signals. Let the master
342 * thread take care of signals in server_loop().
344 sigfillset(&set);
345 pth_sigmask(SIG_BLOCK, &set, NULL);
346 sigemptyset(&set);
347 /* Sends a cache status message to the client. */
348 sigaddset(&set, SIGUSR2);
349 /* Terminates this thread. Raised from keepalive_thread(). */
350 sigaddset(&set, SIGQUIT);
352 cl->ctx = new_connection(fd);
353 cl->fd = fd;
355 if (!cl->ctx)
356 goto fail;
358 assuan_set_pointer(cl->ctx, cl);
360 #ifdef HAVE_MLOCKALL
361 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
362 log_write("mlockall(): %s", strerror(errno));
363 goto fail;
365 #endif
367 send_cache_status(cl->ctx);
368 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
369 thd->keepalive_tid = pth_spawn(NULL, keepalive_thread, thd);
371 for (;;) {
372 gpg_error_t rc;
373 gint sig = 0;
375 pth_sigwait_ev(&set, &sig, ev);
377 if (sig > 0) {
378 switch (sig) {
379 case SIGUSR2:
380 send_cache_status(cl->ctx);
381 continue;
382 case SIGQUIT:
383 goto done;
384 default:
385 break;
389 pth_event_isolate(ev);
391 if (pth_event_occurred(ev)) {
392 rc = assuan_process_next(cl->ctx);
394 if (rc) {
395 cl->inquire_status = INQUIRE_INIT;
397 if (gpg_err_code(rc) == GPG_ERR_EOF)
398 goto done;
400 log_write("assuan_process_next(): %s", gpg_strerror(rc));
401 rc = assuan_process_done(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
403 if (rc) {
404 log_write("assuan_process_done(): %s", gpg_strerror(rc));
405 goto done;
408 else {
409 #ifdef WITH_PINENTRY
410 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
411 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
412 pth_event_concat(ev, pinentry_ev, NULL);
413 cl->pinentry->status = PINENTRY_RUNNING;
415 #endif
417 switch (cl->inquire_status) {
418 case INQUIRE_BUSY:
419 case INQUIRE_INIT:
420 break;
421 case INQUIRE_DONE:
422 cl->inquire_status = INQUIRE_INIT;
423 rc = assuan_process_done(cl->ctx, 0);
424 break;
429 #ifdef WITH_PINENTRY
430 if (cl->pinentry->status == PINENTRY_RUNNING) {
431 pth_event_isolate(pinentry_ev);
433 if (pth_event_occurred(pinentry_ev)) {
434 guchar shakey[gcrykeysize];
435 pinentry_key_s pk;
436 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
437 gint status;
439 pth_event_free(pinentry_ev, PTH_FREE_THIS);
440 pinentry_ev = NULL;
441 cl->pinentry->status = PINENTRY_NONE;
443 if (len == sizeof(pk)) {
444 if (pk.error)
445 rc = assuan_process_done(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE,
446 pk.error));
447 else {
448 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
449 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
450 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
451 memset(shakey, 0, sizeof(shakey));
454 else if (len == -1)
455 log_write("%s", strerror(errno));
456 else if (len == 0)
457 log_write("pth_read(): EOF");
458 else
459 log_write(N_("pth_read(): short byte count"));
461 memset(&pk, 0, sizeof(pk));
462 pth_waitpid(cl->pinentry->pid, &status, 0);
463 close(cl->pinentry->fd);
464 cl->pinentry->fd = -1;
465 cl->pinentry->pid = 0;
466 unlock_file_mutex(cl);
469 pth_event_concat(ev, pinentry_ev, NULL);
471 #endif
475 * Client cleanup (including XML data) is done in remove_connection() from
476 * the cleanup thread.
478 done:
479 pth_event_free(ev, PTH_FREE_ALL);
481 fail:
482 log_write(N_("exiting, fd=%i"), thd->fd);
483 pth_exit(NULL);
484 return NULL;
488 * Make sure all settings are set to either the specified setting or a
489 * default.
491 static void set_rcfile_defaults(GKeyFile *kf)
493 gchar buf[PATH_MAX];
495 if (g_key_file_has_key(kf, "default", "socket_path", NULL) == FALSE) {
496 snprintf(buf, sizeof(buf), "~/.pwmd/socket");
497 g_key_file_set_string(kf, "default", "socket_path", buf);
500 if (g_key_file_has_key(kf, "default", "data_directory", NULL) == FALSE) {
501 snprintf(buf, sizeof(buf), "~/.pwmd/data");
502 g_key_file_set_string(kf, "default", "data_directory", buf);
505 if (g_key_file_has_key(kf, "default", "log_path", NULL) == FALSE) {
506 snprintf(buf, sizeof(buf), "~/.pwmd/log");
507 g_key_file_set_string(kf, "default", "log_path", buf);
510 if (g_key_file_has_key(kf, "default", "enable_logging", NULL) == FALSE)
511 g_key_file_set_boolean(kf, "default", "enable_logging", FALSE);
513 if (g_key_file_has_key(kf, "default", "cache_size", NULL) == FALSE)
514 g_key_file_set_integer(kf, "default", "cache_size", cache_size);
516 #ifdef HAVE_MLOCKALL
517 if (g_key_file_has_key(kf, "default", "disable_mlockall", NULL) == FALSE)
518 g_key_file_set_boolean(kf, "default", "disable_mlockall", TRUE);
519 #endif
521 if (g_key_file_has_key(kf, "default", "cache_timeout", NULL) == FALSE)
522 g_key_file_set_integer(kf, "default", "cache_timeout", -1);
524 if (g_key_file_has_key(kf, "default", "iterations", NULL) == FALSE)
525 g_key_file_set_integer(kf, "default", "iterations", 0);
527 if (g_key_file_has_key(kf, "default", "disable_list_and_dump", NULL) == FALSE)
528 g_key_file_set_boolean(kf, "default", "disable_list_and_dump", FALSE);
530 if (g_key_file_has_key(kf, "default", "iteration_progress", NULL) == FALSE)
531 g_key_file_set_integer(kf, "default", "iteration_progress", 0);
533 if (g_key_file_has_key(kf, "default", "compression_level", NULL) == FALSE)
534 g_key_file_set_integer(kf, "default", "compression_level", 6);
536 if (g_key_file_has_key(kf, "default", "recursion_depth", NULL) == FALSE)
537 g_key_file_set_integer(kf, "default", "recursion_depth", DEFAULT_RECURSION_DEPTH);
539 if (g_key_file_has_key(kf, "default", "zlib_bufsize", NULL) == FALSE)
540 g_key_file_set_integer(kf, "default", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
542 zlib_bufsize = g_key_file_get_integer(kf, "default", "zlib_bufsize", NULL);
544 max_recursion_depth = g_key_file_get_integer(kf, "default", "recursion_depth", NULL);
545 disable_list_and_dump = g_key_file_get_boolean(kf, "default", "disable_list_and_dump", NULL);
547 #ifdef HAVE_MLOCKALL
548 disable_mlock = g_key_file_get_boolean(kf, "default", "disable_mlockall", NULL);
549 #endif
551 if (g_key_file_has_key(kf, "default", "syslog", NULL) == FALSE)
552 g_key_file_set_boolean(kf, "default", "syslog", FALSE);
554 if (g_key_file_has_key(kf, "default", "keepalive", NULL) == FALSE)
555 g_key_file_set_integer(kf, "default", "keepalive", 5);
557 #ifdef WITH_PINENTRY
558 if (g_key_file_has_key(kf, "default", "enable_pinentry", NULL) == FALSE)
559 g_key_file_set_boolean(kf, "default", "enable_pinentry", TRUE);
560 #endif
563 static GKeyFile *parse_rcfile(int cmdline)
565 GKeyFile *kf = g_key_file_new();
566 GError *error = NULL;
568 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &error) == FALSE) {
569 log_write("%s: %s", rcfile, error->message);
571 if (cmdline)
572 exit(EXIT_FAILURE);
574 if (error->code == G_FILE_ERROR_NOENT) {
575 g_clear_error(&error);
576 set_rcfile_defaults(kf);
577 return kf;
580 g_clear_error(&error);
581 return NULL;
583 else
584 set_rcfile_defaults(kf);
586 return kf;
589 static gchar *get_password(const gchar *prompt)
591 gchar buf[LINE_MAX] = {0}, *p;
592 struct termios told, tnew;
593 gchar *key;
595 if (tcgetattr(STDIN_FILENO, &told) == -1)
596 err(EXIT_FAILURE, "tcgetattr()");
598 memcpy(&tnew, &told, sizeof(struct termios));
599 tnew.c_lflag &= ~(ECHO);
600 tnew.c_lflag |= ICANON|ECHONL;
602 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
603 tcsetattr(STDIN_FILENO, TCSANOW, &told);
604 err(EXIT_FAILURE, "tcsetattr()");
607 fprintf(stderr, "%s", prompt);
609 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
610 tcsetattr(STDIN_FILENO, TCSANOW, &told);
611 return NULL;
614 tcsetattr(STDIN_FILENO, TCSANOW, &told);
615 p[strlen(p) - 1] = 0;
617 if (!buf[0]) {
618 key = gcry_malloc(1);
619 key[0] = 0;
621 else {
622 key = gcry_malloc(strlen(p) + 1);
623 sprintf(key, "%s", p);
626 memset(&buf, 0, sizeof(buf));
627 return key;
630 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
632 int fd;
633 struct stat st;
634 gpg_error_t error;
636 if ((fd = open_file(filename, &st)) == -1) {
637 warn("%s", filename);
638 return FALSE;
641 if (st.st_size == 0) {
642 warnx(N_("%s: skipping empty file"), filename);
643 close(fd);
644 return FALSE;
647 error = try_xml_decrypt(NULL, fd, st, key);
648 close(fd);
649 return error ? FALSE : TRUE;
652 static gboolean get_input(const gchar *filename, guchar *key)
654 gint try = 0;
655 gchar *password;
656 gchar *prompt;
658 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
660 again:
661 if ((password = get_password(prompt)) == NULL) {
662 warnx(N_("%s: skipping file"), filename);
663 g_free(prompt);
664 return FALSE;
667 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
668 gcry_free(password);
670 if (do_try_xml_decrypt(filename, key) == FALSE) {
671 if (try++ == 2) {
672 warnx(N_("%s: invalid password, skipping"), filename);
673 g_free(prompt);
674 return FALSE;
676 else {
677 warnx(N_("%s: invalid password"), filename);
678 goto again;
682 g_free(prompt);
683 return TRUE;
686 static gboolean xml_import(const gchar *filename, gint iter)
688 xmlDocPtr doc;
689 gint fd;
690 struct stat st;
691 gint len;
692 xmlChar *xmlbuf;
693 xmlChar *xml;
694 gchar *key = NULL;
695 gchar *key2 = NULL;
696 guchar shakey[gcrykeysize];
697 gcry_cipher_hd_t gh;
698 gpg_error_t error;
699 gint level;
700 glong outsize;
701 gpointer outbuf;
702 gint zerror;
704 if (stat(filename, &st) == -1) {
705 warn("%s", filename);
706 return FALSE;
709 if ((error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
710 send_error(NULL, error);
711 gcry_cipher_close(gh);
712 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
713 return FALSE;
716 if (iter == -1)
717 goto done;
719 if ((key = get_password(N_("New password: "))) == NULL) {
720 fprintf(stderr, "%s\n", N_("Invalid password."));
721 gcry_cipher_close(gh);
722 return FALSE;
725 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
726 fprintf(stderr, "%s\n", N_("Passwords do not match."));
727 gcry_free(key);
728 gcry_cipher_close(gh);
729 return FALSE;
732 if (g_utf8_collate(key, key2) != 0) {
733 fprintf(stderr, "%s\n", N_("Passwords do not match."));
734 gcry_free(key);
735 gcry_free(key2);
736 gcry_cipher_close(gh);
737 return FALSE;
740 gcry_free(key2);
742 done:
743 if ((fd = open(filename, O_RDONLY)) == -1) {
744 gcry_free(key);
745 warn("%s", filename);
746 gcry_cipher_close(gh);
747 return FALSE;
750 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
751 gcry_free(key);
752 close(fd);
753 log_write("%s", strerror(ENOMEM));
754 gcry_cipher_close(gh);
755 return FALSE;
758 if (read(fd, xmlbuf, st.st_size) == -1) {
759 error = errno;
760 close(fd);
761 gcry_free(key);
762 gcry_cipher_close(gh);
763 errno = error;
764 err(EXIT_FAILURE, "read()");
767 close(fd);
768 xmlbuf[st.st_size] = 0;
771 * Make sure the document validates.
773 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
774 log_write("xmlReadDoc()");
775 close(fd);
776 gcry_free(key);
777 gcry_free(xmlbuf);
778 gcry_cipher_close(gh);
779 return FALSE;
782 gcry_free(xmlbuf);
783 xmlDocDumpMemory(doc, &xml, &len);
784 xmlFreeDoc(doc);
786 level = get_key_file_integer(filename, "compression_level");
788 if (level < 0)
789 level = 0;
791 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zerror) == FALSE) {
792 memset(shakey, 0, sizeof(shakey));
793 gcry_free(xml);
795 if (zerror == Z_MEM_ERROR)
796 warnx("%s", strerror(ENOMEM));
797 else
798 warnx("do_compress() failed");
800 gcry_cipher_close(gh);
801 return FALSE;
803 else {
804 gcry_free(xml);
805 xml = outbuf;
806 len = outsize;
809 if (iter == -1)
810 memset(shakey, '!', sizeof(shakey));
811 else{
812 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
813 gcry_free(key);
816 error = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
817 gcry_cipher_close(gh);
819 if (error) {
820 memset(shakey, 0, sizeof(shakey));
821 warnx("%s", gpg_strerror(error));
822 return FALSE;
825 memset(shakey, 0, sizeof(shakey));
826 return TRUE;
829 gchar *get_key_file_string(const gchar *section, const gchar *what)
831 gchar *val = NULL;
832 GError *gerror = NULL;
834 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
835 val = g_key_file_get_string(keyfileh, section, what, &gerror);
837 if (gerror) {
838 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
839 g_clear_error(&gerror);
842 else {
843 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
844 val = g_key_file_get_string(keyfileh, "default", what, &gerror);
846 if (gerror) {
847 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
848 g_clear_error(&gerror);
853 return val;
856 gint get_key_file_integer(const gchar *section, const gchar *what)
858 gint val = -1;
859 GError *gerror = NULL;
861 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
862 val = g_key_file_get_integer(keyfileh, section, what, &gerror);
864 if (gerror) {
865 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
866 g_clear_error(&gerror);
869 else {
870 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
871 val = g_key_file_get_integer(keyfileh, "default", what, &gerror);
873 if (gerror) {
874 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
875 g_clear_error(&gerror);
880 return val;
883 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
885 gboolean val = FALSE;
886 GError *gerror = NULL;
888 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
889 val = g_key_file_get_boolean(keyfileh, section, what, &gerror);
891 if (gerror) {
892 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
893 g_clear_error(&gerror);
896 else {
897 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
898 val = g_key_file_get_boolean(keyfileh, "default", what, &gerror);
900 if (gerror) {
901 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
902 g_clear_error(&gerror);
907 return val;
910 gchar *expand_homedir(gchar *str)
912 gchar *p = str;
914 if (*p++ == '~')
915 return g_strdup_printf("%s%s", g_get_home_dir(), p);
917 return g_strdup(str);
920 static gboolean _getline(const gchar *file, gchar **result)
922 FILE *fp;
923 gchar buf[LINE_MAX] = {0}, *p;
924 gchar *str = NULL;
925 gint len;
927 if ((fp = fopen(file, "r")) == NULL) {
928 warn("%s", file);
929 return FALSE;
932 p = fgets(buf, sizeof(buf), fp);
933 fclose(fp);
934 len = strlen(buf);
936 if (len && buf[len - 1] == '\n')
937 buf[--len] = 0;
939 str = gcry_malloc(len + 1);
940 memcpy(str, buf, len ? len : 1);
941 str[len] = 0;
942 memset(&buf, 0, sizeof(buf));
943 *result = str;
944 return TRUE;
947 static gboolean parse_keyfile_key()
949 gsize n;
950 gchar **groups;
951 gchar **p;
952 gchar *str;
954 groups = g_key_file_get_groups(keyfileh, &n);
956 for (p = groups; *p; p++) {
957 GError *error = NULL;
959 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE) {
960 str = g_key_file_get_string(keyfileh, *p, "key", &error);
962 if (!str) {
963 if (error) {
964 warnx("%s", error->message);
965 g_clear_error(&error);
968 continue;
971 do_cache_push(*p, str);
972 g_free(str);
973 continue;
976 if (error) {
977 warnx("%s", error->message);
978 g_clear_error(&error);
979 continue;
982 if (g_key_file_has_key(keyfileh, *p, "key_file", &error) == TRUE) {
983 gchar *t;
984 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &error);
986 if (!file) {
987 if (error) {
988 warnx("%s", error->message);
989 g_clear_error(&error);
992 continue;
995 t = expand_homedir(file);
996 g_free(file);
997 file = t;
999 if (_getline(file, &str) == FALSE) {
1000 g_free(file);
1001 continue;
1004 g_free(file);
1005 do_cache_push(*p, str);
1006 gcry_free(str);
1007 continue;
1010 if (error) {
1011 warnx("%s", error->message);
1012 g_clear_error(&error);
1016 g_strfreev(groups);
1017 return TRUE;
1020 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1022 guchar *md5file;
1023 guchar *key;
1024 gint timeout;
1025 const gchar *p = filename;
1026 file_header_t file_header;
1027 gpg_error_t error;
1029 while (isspace(*p))
1030 p++;
1032 if (!*p)
1033 return FALSE;
1035 if (valid_filename(p) == FALSE) {
1036 warnx(N_("%s: invalid characters in filename"), p);
1037 return FALSE;
1040 md5file = gcry_malloc(16);
1041 key = gcry_malloc(gcrykeysize);
1042 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1044 if (cache_iscached(md5file) == TRUE) {
1045 warnx(N_("%s: file already cached, skipping"), p);
1046 gcry_free(md5file);
1047 gcry_free(key);
1048 return FALSE;
1051 if (access(p, R_OK|W_OK) != 0) {
1052 gcry_free(md5file);
1053 gcry_free(key);
1055 if (errno != ENOENT) {
1056 warn("%s", p);
1057 return FALSE;
1060 warn("%s", p);
1061 return TRUE;
1064 error = read_file_header(filename, &file_header);
1066 if (error) {
1067 gcry_free(md5file);
1068 gcry_free(key);
1069 warnx("%s", pwmd_strerror(error));
1070 return FALSE;
1073 if (file_header.iter == -1) {
1074 memset(key, '!', gcrykeysize);
1075 goto try_decrypt;
1078 if (!password) {
1079 if (get_input(p, key) == FALSE) {
1080 gcry_free(key);
1081 gcry_free(md5file);
1082 return FALSE;
1085 else {
1086 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1088 try_decrypt:
1089 if (do_try_xml_decrypt(filename, key) == FALSE) {
1090 warnx(N_("%s: invalid password, skipping"), filename);
1091 gcry_free(key);
1092 gcry_free(md5file);
1093 return FALSE;
1097 if (cache_add_file(md5file, key) == FALSE) {
1098 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1099 gcry_free(key);
1100 gcry_free(md5file);
1101 return FALSE;
1104 timeout = get_key_file_integer(p, "cache_timeout");
1105 cache_set_timeout(md5file, timeout);
1106 warnx(N_("%s: file added to the cache"), filename);
1107 gcry_free(key);
1108 gcry_free(md5file);
1109 return TRUE;
1112 static GSList *remove_connection(GSList *list, struct client_thread_s *cn)
1114 gpointer value;
1115 struct client_s *cl = cn->cl;
1117 if (cn->keepalive_tid) {
1118 pth_raise(cn->keepalive_tid, SIGALRM);
1119 pth_join(cn->keepalive_tid, &value);
1122 log_write("%p", cn->tid);
1123 pth_join(cn->tid, &value);
1124 close(cn->fd);
1126 if (cl->freed == FALSE)
1127 cleanup_assuan(cl->ctx);
1129 if (cl->ctx)
1130 assuan_deinit_server(cl->ctx);
1132 #ifdef WITH_PINENTRY
1133 if (cl->pinentry)
1134 cleanup_pinentry(cl->pinentry);
1135 #endif
1137 if (cl)
1138 g_free(cl);
1140 pth_event_isolate(cn->ev);
1141 pth_event_free(cn->ev, PTH_FREE_THIS);
1142 list = g_slist_remove(list, cn);
1143 g_free(cn);
1144 return list;
1148 * Can't pth_event_concat() to an empty event.
1150 static int event_ring_hack(void *data)
1152 return FALSE;
1156 * See if any thread has entered the DEAD queue and remove it.
1158 static GSList *cleanup_dead_queue(GSList *threads, pth_event_t tid_events)
1160 guint n, i;
1162 for (n = g_slist_length(threads), i = 0; i < n; i++) {
1163 struct client_thread_s *cn = g_slist_nth_data(threads, i);
1165 if (pth_event_occurred(cn->ev)) {
1166 threads = remove_connection(threads, cn);
1167 return cleanup_dead_queue(threads, tid_events);
1170 pth_event_concat(tid_events, cn->ev, NULL);
1173 return threads;
1176 static void *socket_thread(void *arg)
1178 gint sockfd = (gint)arg;
1180 for (;;) {
1181 socklen_t slen = sizeof(struct sockaddr_un);
1182 struct sockaddr_un raddr;
1183 gint fd = -1;
1184 pth_attr_t attr;
1186 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1187 if (errno != EAGAIN) {
1188 if (!quit) // probably EBADF
1189 log_write("accept(): %s", strerror(errno));
1191 break;
1195 if (fd >= 0) {
1196 pth_t tid;
1197 struct client_thread_s *new;
1198 gchar buf[41];
1200 new = g_malloc0(sizeof(struct client_thread_s));
1202 if (!new) {
1203 log_write("%s", strerror(ENOMEM));
1204 continue;
1208 * Thread priority is inherited from the calling thread. This
1209 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1210 * priority.
1212 attr = pth_attr_new();
1213 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1214 tid = pth_spawn(attr, client_thread, new);
1215 pth_attr_destroy(attr);
1217 if (!tid) {
1218 g_free(new);
1219 log_write(N_("pth_spawn() failed"));
1220 continue;
1223 snprintf(buf, sizeof(buf), "%p", tid);
1224 attr = pth_attr_of(tid);
1225 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1226 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1227 new->fd = fd;
1228 new->tid = tid;
1229 new->fd = fd;
1230 new->ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1231 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1232 pth_event_concat(cn_events, new->ev, NULL);
1233 cn_thread_list = g_slist_append(cn_thread_list, new);
1234 pth_mutex_release(&cn_mutex);
1238 /* Just in case pth_accept() failed for some reason other than EBADF */
1239 quit = 1;
1240 pth_exit(PTH_CANCELED);
1241 return NULL;
1244 static void *cleanup_thread(void *arg)
1246 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1248 for (;;) {
1249 if (pth_wait(cn_events) && pth_event_occurred(cn_events)) {
1250 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1251 pth_event_isolate(cn_events);
1252 pth_event_free(cn_events, PTH_FREE_THIS);
1253 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1254 cn_thread_list = cleanup_dead_queue(cn_thread_list, cn_events);
1255 pth_mutex_release(&cn_mutex);
1259 pth_event_isolate(cn_events);
1260 pth_event_free(cn_events, PTH_FREE_THIS);
1261 return NULL;
1264 static void *adjust_timer_thread(void *arg)
1266 CACHE_LOCK(NULL);
1267 cache_adjust_timer();
1268 CACHE_UNLOCK;
1269 return NULL;
1272 static void server_loop(int sockfd)
1274 pth_t socket_tid, cleanup_tid;
1275 guint n, i;
1276 sigset_t set;
1277 gint n_clients = 0;
1278 pth_attr_t attr;
1279 pth_event_t timeout_event;
1280 gpointer value;
1282 pth_mutex_init(&cn_mutex);
1283 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1285 sigemptyset(&set);
1286 sigaddset(&set, SIGTERM);
1287 sigaddset(&set, SIGINT);
1288 sigaddset(&set, SIGUSR1);
1289 sigaddset(&set, SIGHUP);
1290 sigaddset(&set, SIGABRT);
1292 attr = pth_attr_new();
1293 pth_attr_init(attr);
1294 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1295 pth_attr_set(attr, PTH_ATTR_NAME, "socket");
1296 socket_tid = pth_spawn(attr, socket_thread, (void *)sockfd);
1297 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1298 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ASYNCHRONOUS);
1299 pth_attr_set(attr, PTH_ATTR_NAME, "cleanup");
1300 cleanup_tid = pth_spawn(attr, cleanup_thread, NULL);
1303 * For the cache_timeout configuration parameter. This replaces the old
1304 * SIGALRM stuff and is safer.
1306 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1307 pth_attr_init(attr);
1308 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1309 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1311 do {
1312 gint sig = 0;
1314 pth_sigwait_ev(&set, &sig, timeout_event);
1316 if (pth_event_occurred(timeout_event)) {
1318 * The timer event has expired. Update the file cache. When the
1319 * cache mutex is locked and the timer expires again, the threads
1320 * will stack.
1322 pth_spawn(attr, adjust_timer_thread, NULL);
1323 pth_event_free(timeout_event, PTH_FREE_THIS);
1324 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1327 if (sig > 0) {
1328 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1330 /* Caught a signal. */
1331 switch (sig) {
1332 case SIGUSR1:
1333 reload_rcfile();
1334 break;
1335 case SIGABRT:
1336 CACHE_LOCK(NULL);
1337 cache_clear(NULL, 2);
1338 CACHE_UNLOCK;
1339 #ifndef MEM_DEBUG
1340 xpanic();
1341 #endif
1342 exit(EXIT_FAILURE);
1343 case SIGHUP:
1344 CACHE_LOCK(NULL);
1345 log_write(N_("clearing file cache"));
1346 cache_clear(NULL, 2);
1347 CACHE_UNLOCK;
1348 break;
1349 default:
1350 quit = 1;
1351 shutdown(sockfd, SHUT_RDWR);
1352 close(sockfd);
1353 break;
1356 } while (!quit);
1359 * We're out of the main server loop. This happens when a signal was sent
1360 * to terminate the daemon. We'll wait for all clients to disconnect
1361 * before exiting and ignore any following signals.
1363 pth_join(socket_tid, &value);
1364 pth_attr_destroy(attr);
1365 pth_event_free(timeout_event, PTH_FREE_THIS);
1367 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1369 /* 2 because the cleanup thread still exists, plus self. */
1370 if (n > 2)
1371 log_write(N_("waiting for all threads to terminate"));
1373 while (n > 2) {
1374 gint t;
1375 pth_event_t events;
1377 if (n != n_clients) {
1378 log_write(N_("%i threads remain"), n-2);
1379 n_clients = n;
1382 events = pth_event(PTH_EVENT_FUNC, event_ring_hack, NULL, pth_timeout(1, 0));
1383 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1385 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1386 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1388 pth_event_concat(events, cn->ev, NULL);
1391 if (!t)
1392 goto done;
1394 pth_mutex_release(&cn_mutex);
1395 pth_wait(events);
1396 pth_yield(cleanup_tid);
1397 done:
1398 pth_event_isolate(events);
1399 pth_event_free(events, PTH_FREE_THIS);
1400 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1403 pth_cancel(cleanup_tid);
1406 int main(int argc, char *argv[])
1408 gint opt;
1409 struct sockaddr_un addr;
1410 struct passwd *pw = getpwuid(getuid());
1411 gchar buf[PATH_MAX];
1412 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1413 gchar *socketarg = NULL;
1414 gchar *datadir = NULL;
1415 gboolean n;
1416 gchar *p;
1417 gchar **cache_push = NULL;
1418 gint iter = 0;
1419 gchar *import = NULL;
1420 gint default_timeout;
1421 gint rcfile_spec = 0;
1422 gint estatus = EXIT_FAILURE;
1423 gint sockfd;
1424 #ifndef MEM_DEBUG
1425 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1426 #endif
1427 gint do_unlink = 1;
1428 gboolean secure = FALSE;
1429 guint ptotal = 0;
1430 gint background = 0;
1431 sigset_t set;
1432 #ifndef DEBUG
1433 #ifdef HAVE_SETRLIMIT
1434 struct rlimit rl;
1436 rl.rlim_cur = rl.rlim_max = 0;
1438 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1439 err(EXIT_FAILURE, "setrlimit()");
1440 #endif
1441 #endif
1443 #ifdef ENABLE_NLS
1444 setlocale(LC_ALL, "");
1445 bindtextdomain("pwmd", LOCALEDIR);
1446 textdomain("pwmd");
1447 #endif
1449 gpg_err_init();
1450 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1451 #ifndef MEM_DEBUG
1452 g_mem_set_vtable(&mtable);
1453 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1454 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1455 xmlInitMemory();
1456 #endif
1457 pth_init();
1458 snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1460 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1461 err(EXIT_FAILURE, "%s", buf);
1463 snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1465 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1466 err(EXIT_FAILURE, "%s", buf);
1468 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1470 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1471 err(EXIT_FAILURE, "sysconf()");
1473 cache_size = page_size;
1475 while ((opt = getopt(argc, argv, "bI:hvf:D")) != EOF) {
1476 switch (opt) {
1477 case 'b':
1478 background = 1;
1479 break;
1480 case 'D':
1481 secure = TRUE;
1482 break;
1483 case 'I':
1484 import = optarg;
1485 break;
1486 case 'f':
1487 g_free(rcfile);
1488 rcfile = g_strdup(optarg);
1489 rcfile_spec = 1;
1490 break;
1491 case 'v':
1492 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1493 exit(EXIT_SUCCESS);
1494 case 'h':
1495 default:
1496 usage(argv[0]);
1500 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1501 exit(EXIT_FAILURE);
1503 if (g_key_file_has_key(keyfileh, "default", "syslog", NULL) == TRUE)
1504 log_syslog = g_key_file_get_boolean(keyfileh, "default", "syslog", NULL);
1506 if (log_syslog == TRUE)
1507 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1509 if (g_key_file_has_key(keyfileh, "default", "iterations", NULL) == TRUE)
1510 iter = g_key_file_get_integer(keyfileh, "default", "iterations", NULL);
1512 #ifdef HAVE_MLOCKALL
1513 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1514 warn("mlockall()");
1515 goto do_exit;
1517 #endif
1519 setup_gcrypt();
1521 if (import) {
1522 opt = xml_import(import, iter);
1523 g_key_file_free(keyfileh);
1524 g_free(rcfile);
1525 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1528 g_key_file_set_list_separator(keyfileh, ',');
1530 if ((p = g_key_file_get_string(keyfileh, "default", "socket_path", NULL)) == NULL)
1531 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1533 if (*p == '~') {
1534 p++;
1535 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1536 g_free(p);
1537 socketarg = g_strdup(buf);
1539 else
1540 socketarg = p;
1542 if ((p = g_key_file_get_string(keyfileh, "default", "data_directory", NULL)) == NULL)
1543 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1545 datadir = expand_homedir(p);
1546 g_free(p);
1548 if (secure == FALSE && g_key_file_has_key(keyfileh, "default", "disable_list_and_dump", NULL) == TRUE) {
1549 n = g_key_file_get_boolean(keyfileh, "default", "disable_list_and_dump", NULL);
1550 disable_list_and_dump = n;
1552 else
1553 disable_list_and_dump = secure;
1555 if (g_key_file_has_key(keyfileh, "default", "cache_timeout", NULL) == TRUE)
1556 default_timeout = g_key_file_get_integer(keyfileh, "default", "cache_timeout", NULL);
1557 else
1558 default_timeout = -1;
1560 if (g_key_file_has_key(keyfileh, "default", "cache_size", NULL) == TRUE) {
1561 cache_size = g_key_file_get_integer(keyfileh, "default", "cache_size", NULL);
1563 if (cache_size < page_size || cache_size % page_size)
1564 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1567 if (g_key_file_has_key(keyfileh, "default", "log_path", NULL) == TRUE) {
1568 if (g_key_file_has_key(keyfileh, "default", "enable_logging", NULL) == TRUE) {
1569 n = g_key_file_get_boolean(keyfileh, "default", "enable_logging", NULL);
1571 if (n == TRUE) {
1572 p = g_key_file_get_string(keyfileh, "default", "log_path", NULL);
1574 if (*p == '~') {
1575 p++;
1576 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1577 g_free(p);
1578 logfile = g_strdup(buf);
1580 else
1581 logfile = p;
1586 if (g_key_file_has_key(keyfileh, "default", "cache_push", NULL) == TRUE)
1587 cache_push = g_key_file_get_string_list(keyfileh, "default", "cache_push", NULL, NULL);
1589 if (argc != optind) {
1590 if (cache_push)
1591 ptotal = g_strv_length(cache_push);
1593 for (; optind < argc; optind++) {
1594 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1595 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1599 if (strchr(socketarg, '/') == NULL) {
1600 socketdir = g_get_current_dir();
1601 socketname = g_strdup(socketarg);
1602 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1604 else {
1605 socketname = g_strdup(strrchr(socketarg, '/'));
1606 socketname++;
1607 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1608 socketdir = g_strdup(socketarg);
1609 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1612 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1613 #ifdef MMAP_ANONYMOUS
1614 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1615 #else
1616 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1617 #endif
1618 err(EXIT_FAILURE, "mmap()");
1621 if (mlock(key_cache, cache_size) == -1)
1622 log_write("mlock(): %s", strerror(errno));
1624 memset(key_cache, 0, cache_size);
1626 if (chdir(datadir)) {
1627 warn("%s", datadir);
1628 unlink(socketpath);
1629 goto do_exit;
1632 if (parse_keyfile_key() == FALSE)
1633 goto do_exit;
1635 clear_rcfile_key();
1638 * Set the cache entry for a file. Prompts for the password.
1640 if (cache_push) {
1641 for (opt = 0; cache_push[opt]; opt++)
1642 do_cache_push(cache_push[opt], NULL);
1644 g_strfreev(cache_push);
1645 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1649 * bind() doesn't like the full pathname of the socket or any non alphanum
1650 * characters so change to the directory where the socket is wanted then
1651 * create it then change to datadir.
1653 if (chdir(socketdir)) {
1654 warn("%s", socketdir);
1655 goto do_exit;
1658 g_free(socketdir);
1660 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1661 warn("socket()");
1662 goto do_exit;
1665 addr.sun_family = AF_UNIX;
1666 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1668 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1669 warn("bind()");
1671 if (errno == EADDRINUSE)
1672 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1673 "stale socket. Please remove it manually."), socketpath);
1675 do_unlink = 0;
1676 goto do_exit;
1679 if (g_key_file_has_key(keyfileh, "default", "socket_perms", NULL) == TRUE) {
1680 gchar *t = g_key_file_get_string(keyfileh, "default", "socket_perms", NULL);
1681 mode_t mode = strtol(t, NULL, 8);
1682 mode_t mask = umask(0);
1684 g_free(t);
1686 if (chmod(socketname, mode) == -1) {
1687 warn("%s", socketname);
1688 close(sockfd);
1689 unlink(socketpath);
1690 umask(mask);
1691 goto do_exit;
1694 umask(mask);
1697 g_free(--socketname);
1699 if (chdir(datadir)) {
1700 warn("%s", datadir);
1701 close(sockfd);
1702 unlink(socketpath);
1703 goto do_exit;
1706 g_free(datadir);
1707 pth_mutex_init(&cache_mutex);
1709 if (listen(sockfd, 0) == -1) {
1710 warn("listen()");
1711 goto do_exit;
1714 if (background) {
1715 switch (fork()) {
1716 case -1:
1717 warn("fork()");
1718 goto do_exit;
1719 case 0:
1720 close(0);
1721 close(1);
1722 close(2);
1723 setsid();
1724 break;
1725 default:
1726 exit(EXIT_SUCCESS);
1731 * These are the signals that we use in threads. libpth can catch signals
1732 * itself so ignore them everywhere else. Note that using
1733 * signal(N, SIG_IGN) doesn't work like you might think.
1735 sigemptyset(&set);
1737 /* Termination */
1738 sigaddset(&set, SIGTERM);
1739 sigaddset(&set, SIGINT);
1741 /* Configuration file reloading. */
1742 sigaddset(&set, SIGUSR1);
1744 /* Clears the file cache. */
1745 sigaddset(&set, SIGHUP);
1747 /* Caught in client_thread(). Sends a cache status message. */
1748 sigaddset(&set, SIGUSR2);
1750 /* Caught in client_thread(). When keepalive_thread() fails, this signal
1751 * is raised to terminate the client. More of a failsafe than anything. */
1752 sigaddset(&set, SIGQUIT);
1754 /* Ignored everywhere. When a client disconnects abnormally this signal
1755 * gets raised. It isn't needed though because client_thread() will check
1756 * for errors even after the client disconnects. */
1757 signal(SIGPIPE, SIG_IGN);
1758 pth_sigmask(SIG_BLOCK, &set, NULL);
1759 server_loop(sockfd);
1760 estatus = EXIT_SUCCESS;
1762 do_exit:
1763 if (socketpath && do_unlink) {
1764 unlink(socketpath);
1765 g_free(socketpath);
1768 g_key_file_free(keyfileh);
1769 g_free(rcfile);
1771 if (key_cache) {
1772 cache_clear(NULL, 2);
1773 memset(key_cache, 0, cache_size);
1776 if (key_cache && munmap(key_cache, cache_size) == -1)
1777 log_write("munmap(): %s", strerror(errno));
1779 if (estatus == EXIT_SUCCESS)
1780 log_write(N_("pwmd exiting normally"));
1782 pth_kill();
1783 #if defined(DEBUG) && !defined(MEM_DEBUG)
1784 xdump();
1785 #endif
1786 exit(estatus);