Replaced occurrences of 'error' with 'rc' since an error() function
[pwmd.git] / src / pwmd.c
blob6dc1653a71bf9b5a99ba6d67cb870f7af3dfb243
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 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 "misc.h"
66 #include "pwmd.h"
68 static void clear_errorfile_key()
70 gsize n;
71 gchar **groups;
72 gchar **p;
74 groups = g_key_file_get_groups(keyfileh, &n);
76 for (p = groups; *p; p++) {
77 GError *rc = NULL;
79 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
80 g_key_file_set_string(keyfileh, *p, "key", "");
83 g_strfreev(groups);
86 static void reload_rcfile()
88 log_write(N_("reloading configuration file '%s'"), rcfile);
89 g_key_file_free(keyfileh);
90 keyfileh = parse_rcfile(0);
91 clear_errorfile_key();
94 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
96 gpg_error_t n = gpg_error_from_errno(e);
98 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
101 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
103 gpg_err_code_t n = gpg_err_code(e);
104 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
106 if (!e)
107 return assuan_process_done(ctx, 0);
109 if (!ctx) {
110 log_write("%s\n", pwmd_strerror(e));
111 return e;
114 if (n == EPWMD_LIBXML_ERROR) {
115 xmlErrorPtr xml_rc = xmlGetLastError();
116 return assuan_process_done(ctx, assuan_set_error(ctx, code, xml_rc->message));
119 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
122 void log_write(const gchar *fmt, ...)
124 gchar *args, *line;
125 va_list ap;
126 struct tm *tm;
127 time_t now;
128 gchar tbuf[21];
129 gint fd = -1;
130 pth_attr_t attr;
131 gchar *name;
133 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
134 return;
136 if (logfile) {
137 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
138 warn(N_("logfile"));
139 return;
143 va_start(ap, fmt);
145 if (g_vasprintf(&args, fmt, ap) == -1) {
146 if (logfile)
147 close(fd);
149 va_end(ap);
150 return;
153 attr = pth_attr_of(pth_self());
154 pth_attr_get(attr, PTH_ATTR_NAME, &name);
155 pth_attr_destroy(attr);
157 if (log_syslog == TRUE)
158 syslog(LOG_INFO, "%s: %s", name, args);
160 va_end(ap);
161 time(&now);
162 tm = localtime(&now);
163 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
164 tbuf[sizeof(tbuf) - 1] = 0;
165 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
166 g_free(args);
168 if (!line) {
169 if (logfile)
170 close(fd);
172 return;
175 if (logfile) {
176 write(fd, line, strlen(line));
177 fsync(fd);
178 close(fd);
181 if (isatty(STDERR_FILENO)) {
182 fprintf(stderr, "%s", line);
183 fflush(stderr);
186 g_free(line);
189 static void usage(gchar *pn)
191 g_printf(N_(
192 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
193 " -b run as a background process\n"
194 " -f load the specified rcfile (~/.pwmd/config)\n"
195 " -I import an XML file and write the encrypted data to stdout\n"
196 " -D disable use of the LIST and DUMP commands\n"
197 " -v version\n"
198 " -h this help text\n"
199 ), pn);
200 exit(EXIT_SUCCESS);
203 #ifndef MEM_DEBUG
204 static int gcry_SecureCheck(const void *ptr)
206 return 1;
208 #endif
210 static void setup_gcrypt()
212 gcry_check_version(NULL);
214 #ifndef MEM_DEBUG
215 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
216 xfree);
217 #endif
219 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
220 NULL) != 0)
221 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
223 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
224 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
227 static assuan_context_t new_connection(gint fd)
229 gpg_error_t rc;
230 gchar ver[ASSUAN_LINELENGTH];
231 assuan_context_t ctx;
233 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
235 if (rc)
236 goto fail;
238 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
239 assuan_set_hello_line(ctx, ver);
240 assuan_register_post_cmd_notify(ctx, command_finalize);
241 rc = register_commands(ctx);
243 if (rc)
244 goto fail;
246 rc = assuan_accept(ctx);
248 if (rc)
249 goto fail;
251 return ctx;
253 fail:
254 assuan_deinit_server(ctx);
255 log_write("%s", gpg_strerror(rc));
256 return NULL;
259 void send_cache_status_all()
261 guint i, t;
263 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
265 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
266 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
268 if (cn->tid == pth_self()) {
269 send_cache_status(cn->cl->ctx);
270 continue;
273 pth_raise(cn->tid, SIGUSR2);
276 pth_mutex_release(&cn_mutex);
279 static void *keepalive_thread(void *arg)
281 struct client_thread_s *thd = arg;
283 for (;;) {
284 gpg_error_t rc;
285 pth_event_t ev;
286 gint k = get_key_file_integer("global", "keepalive");
288 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k <= 0 ? 1 : k, 0));
289 pth_wait(ev);
290 pth_event_free(ev, PTH_FREE_THIS);
291 pth_cancel_point();
293 if (k <= 0)
294 continue;
296 rc = assuan_write_status(thd->cl->ctx, "KEEPALIVE", NULL);
298 if (rc) {
299 log_write("%s", gpg_strerror(rc));
300 pth_raise(thd->tid, SIGQUIT);
301 break;
305 return NULL;
309 * Called every time a connection is made via pth_spawn(). This is the thread
310 * entry point.
312 static void *client_thread(void *data)
314 struct client_thread_s *thd = data;
315 gint fd = thd->fd;
316 pth_event_t ev;
317 #ifdef WITH_PINENTRY
318 pth_event_t pinentry_ev = NULL;
319 #endif
320 struct client_s *cl = g_malloc0(sizeof(struct client_s));
321 sigset_t set;
322 gpg_error_t rc;
323 pth_attr_t attr;
325 if (!cl) {
326 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
327 goto fail;
330 #ifdef WITH_PINENTRY
331 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
333 if (!cl->pinentry) {
334 g_free(cl);
335 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
336 goto fail;
339 set_pinentry_defaults(cl->pinentry);
340 #endif
341 thd->cl = cl;
342 cl->thd = thd;
345 * This is a "child" thread. Don't catch any signals. Let the master
346 * thread take care of signals in server_loop().
348 sigfillset(&set);
349 pth_sigmask(SIG_BLOCK, &set, NULL);
350 sigemptyset(&set);
351 /* Sends a cache status message to the client. */
352 sigaddset(&set, SIGUSR2);
353 /* Terminates this thread. Raised from keepalive_thread(). */
354 sigaddset(&set, SIGQUIT);
356 cl->ctx = new_connection(fd);
357 cl->fd = fd;
359 if (!cl->ctx)
360 goto fail;
362 assuan_set_pointer(cl->ctx, cl);
364 #ifdef HAVE_MLOCKALL
365 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
366 log_write("mlockall(): %s", strerror(errno));
367 goto fail;
369 #endif
371 rc = send_cache_status(cl->ctx);
373 if (rc) {
374 log_write("%s", gpg_strerror(rc));
375 goto fail;
378 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
379 attr = pth_attr_new();
380 pth_attr_init(attr);
381 pth_attr_set(attr, PTH_ATTR_NAME, "keepalive");
382 thd->keepalive_tid = pth_spawn(attr, keepalive_thread, thd);
383 pth_attr_destroy(attr);
384 xmlInitParser();
385 xmlXPathInit();
387 for (;;) {
388 gint sig = 0;
390 pth_sigwait_ev(&set, &sig, ev);
392 if (sig > 0) {
393 switch (sig) {
394 case SIGUSR2:
395 rc = send_cache_status(cl->ctx);
397 if (rc) {
398 log_write("%s", gpg_strerror(rc));
399 goto done;
402 break;
403 case SIGQUIT:
404 /* pth_raise() from keepalive_thread(). */
405 goto done;
406 default:
407 break;
411 pth_event_isolate(ev);
413 if (pth_event_occurred(ev)) {
414 rc = assuan_process_next(cl->ctx);
416 if (rc) {
417 cl->inquire_status = INQUIRE_INIT;
419 if (gpg_err_code(rc) == GPG_ERR_EOF)
420 goto done;
422 log_write("assuan_process_next(): %s", gpg_strerror(rc));
423 rc = assuan_process_done(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
425 if (rc) {
426 log_write("assuan_process_done(): %s", gpg_strerror(rc));
427 goto done;
430 else {
431 #ifdef WITH_PINENTRY
432 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
433 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
434 pth_event_concat(ev, pinentry_ev, NULL);
435 cl->pinentry->status = PINENTRY_RUNNING;
437 #endif
439 switch (cl->inquire_status) {
440 case INQUIRE_BUSY:
441 case INQUIRE_INIT:
442 break;
443 case INQUIRE_DONE:
444 cl->inquire_status = INQUIRE_INIT;
445 rc = assuan_process_done(cl->ctx, 0);
446 break;
451 #ifdef WITH_PINENTRY
452 if (cl->pinentry->status == PINENTRY_RUNNING) {
453 pth_event_isolate(pinentry_ev);
455 if (pth_event_occurred(pinentry_ev)) {
456 guchar shakey[gcrykeysize];
457 pinentry_key_s pk;
458 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
459 gint status;
461 pth_event_free(pinentry_ev, PTH_FREE_THIS);
462 pinentry_ev = NULL;
463 cl->pinentry->status = PINENTRY_NONE;
465 if (len == sizeof(pk)) {
466 if (pk.error)
467 rc = send_error(cl->ctx, pk.error);
468 else {
469 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
470 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
471 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
472 memset(shakey, 0, sizeof(shakey));
475 else if (len == -1)
476 log_write("%s", strerror(errno));
477 else if (len == 0)
478 log_write("pth_read(): EOF");
479 else
480 log_write(N_("pth_read(): short byte count"));
482 pth_waitpid(cl->pinentry->pid, &status, 0);
483 close(cl->pinentry->fd);
484 cl->pinentry->fd = -1;
485 cl->pinentry->pid = 0;
487 if (pk.error && cl->pinentry->which == PINENTRY_OPEN)
488 cleanup_client(cl);
489 else
490 unlock_file_mutex(cl);
492 memset(&pk, 0, sizeof(pk));
493 unlock_pin_mutex(cl->pinentry);
496 pth_event_concat(ev, pinentry_ev, NULL);
498 #endif
502 * Client cleanup (including XML data) is done in remove_connection() from
503 * the cleanup thread.
505 done:
506 pth_event_free(ev, PTH_FREE_ALL);
508 fail:
509 log_write(N_("exiting, fd=%i"), thd->fd);
510 pth_exit(NULL);
511 return NULL;
514 static void setup_logging(GKeyFile *kf)
516 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
518 if (n == TRUE) {
519 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
521 if (*p == '~') {
522 gchar buf[PATH_MAX];
524 p++;
525 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
526 g_free(p);
528 if (logfile)
529 g_free(logfile);
531 logfile = g_strdup(buf);
533 else {
534 if (logfile)
535 g_free(logfile);
537 logfile = p;
541 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
545 * Make sure all settings are set to either the specified setting or a
546 * default.
548 static void set_rcfile_defaults(GKeyFile *kf)
550 gchar buf[PATH_MAX];
552 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
553 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
554 g_key_file_set_string(kf, "global", "socket_path", buf);
557 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
558 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
559 g_key_file_set_string(kf, "global", "data_directory", buf);
562 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
563 g_key_file_set_boolean(kf, "global", "backup", TRUE);
565 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
566 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
567 g_key_file_set_string(kf, "global", "log_path", buf);
570 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
571 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
573 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
574 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
576 #ifdef HAVE_MLOCKALL
577 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
578 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
579 #endif
581 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
582 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
584 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
585 g_key_file_set_integer(kf, "global", "iterations", 0);
587 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
588 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
590 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
591 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
593 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
594 g_key_file_set_integer(kf, "global", "compression_level", 6);
596 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
597 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
599 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
600 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
602 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
604 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
605 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
607 #ifdef HAVE_MLOCKALL
608 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
609 #endif
611 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
612 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
614 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
615 g_key_file_set_integer(kf, "global", "keepalive", 5);
617 #ifdef WITH_PINENTRY
618 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
619 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
620 #endif
622 setup_logging(kf);
625 static GKeyFile *parse_rcfile(int cmdline)
627 GKeyFile *kf = g_key_file_new();
628 GError *rc = NULL;
630 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
631 log_write("%s: %s", rcfile, rc->message);
633 if (cmdline)
634 exit(EXIT_FAILURE);
636 if (rc->code == G_FILE_ERROR_NOENT) {
637 g_clear_error(&rc);
638 set_rcfile_defaults(kf);
639 return kf;
642 g_clear_error(&rc);
643 return NULL;
645 else
646 set_rcfile_defaults(kf);
648 return kf;
651 static gchar *get_password(const gchar *prompt)
653 gchar buf[LINE_MAX] = {0}, *p;
654 struct termios told, tnew;
655 gchar *key;
657 if (tcgetattr(STDIN_FILENO, &told) == -1)
658 err(EXIT_FAILURE, "tcgetattr()");
660 memcpy(&tnew, &told, sizeof(struct termios));
661 tnew.c_lflag &= ~(ECHO);
662 tnew.c_lflag |= ICANON|ECHONL;
664 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
665 tcsetattr(STDIN_FILENO, TCSANOW, &told);
666 err(EXIT_FAILURE, "tcsetattr()");
669 fprintf(stderr, "%s", prompt);
671 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
672 tcsetattr(STDIN_FILENO, TCSANOW, &told);
673 return NULL;
676 tcsetattr(STDIN_FILENO, TCSANOW, &told);
677 p[strlen(p) - 1] = 0;
679 if (!buf[0]) {
680 key = gcry_malloc(1);
681 key[0] = 0;
683 else {
684 key = gcry_malloc(strlen(p) + 1);
685 sprintf(key, "%s", p);
688 memset(&buf, 0, sizeof(buf));
689 return key;
692 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
694 int fd;
695 struct stat st;
696 gpg_error_t rc;
698 if ((fd = open_file(filename, &st)) == -1) {
699 warn("%s", filename);
700 return FALSE;
703 if (st.st_size == 0) {
704 warnx(N_("%s: skipping empty file"), filename);
705 close(fd);
706 return FALSE;
709 rc = try_xml_decrypt(NULL, fd, st, key);
710 close(fd);
711 return rc ? FALSE : TRUE;
714 static gboolean get_input(const gchar *filename, guchar *key)
716 gint try = 0;
717 gchar *password;
718 gchar *prompt;
720 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
722 again:
723 if ((password = get_password(prompt)) == NULL) {
724 warnx(N_("%s: skipping file"), filename);
725 g_free(prompt);
726 return FALSE;
729 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
730 gcry_free(password);
732 if (do_try_xml_decrypt(filename, key) == FALSE) {
733 if (try++ == 2) {
734 warnx(N_("%s: invalid password, skipping"), filename);
735 g_free(prompt);
736 return FALSE;
738 else {
739 warnx(N_("%s: invalid password"), filename);
740 goto again;
744 g_free(prompt);
745 return TRUE;
748 static gboolean xml_import(const gchar *filename, gint iter)
750 xmlDocPtr doc;
751 gint fd;
752 struct stat st;
753 gint len;
754 xmlChar *xmlbuf;
755 xmlChar *xml;
756 gchar *key = NULL;
757 gchar *key2 = NULL;
758 guchar shakey[gcrykeysize];
759 gcry_cipher_hd_t gh;
760 gpg_error_t rc;
761 gint level;
762 glong outsize;
763 gpointer outbuf;
764 gint zrc;
766 if (stat(filename, &st) == -1) {
767 warn("%s", filename);
768 return FALSE;
771 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
772 send_error(NULL, rc);
773 gcry_cipher_close(gh);
774 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
775 return FALSE;
778 if (iter == -1)
779 goto done;
781 if ((key = get_password(N_("New password: "))) == NULL) {
782 fprintf(stderr, "%s\n", N_("Invalid password."));
783 gcry_cipher_close(gh);
784 return FALSE;
787 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
788 fprintf(stderr, "%s\n", N_("Passwords do not match."));
789 gcry_free(key);
790 gcry_cipher_close(gh);
791 return FALSE;
794 if (g_utf8_collate(key, key2) != 0) {
795 fprintf(stderr, "%s\n", N_("Passwords do not match."));
796 gcry_free(key);
797 gcry_free(key2);
798 gcry_cipher_close(gh);
799 return FALSE;
802 gcry_free(key2);
804 done:
805 if ((fd = open(filename, O_RDONLY)) == -1) {
806 gcry_free(key);
807 warn("%s", filename);
808 gcry_cipher_close(gh);
809 return FALSE;
812 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
813 gcry_free(key);
814 close(fd);
815 log_write("%s", strerror(ENOMEM));
816 gcry_cipher_close(gh);
817 return FALSE;
820 if (read(fd, xmlbuf, st.st_size) == -1) {
821 rc = errno;
822 close(fd);
823 gcry_free(key);
824 gcry_cipher_close(gh);
825 errno = rc;
826 err(EXIT_FAILURE, "read()");
829 close(fd);
830 xmlbuf[st.st_size] = 0;
833 * Make sure the document validates.
835 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
836 log_write("xmlReadDoc()");
837 close(fd);
838 gcry_free(key);
839 gcry_free(xmlbuf);
840 gcry_cipher_close(gh);
841 return FALSE;
844 gcry_free(xmlbuf);
845 xmlDocDumpMemory(doc, &xml, &len);
846 xmlFreeDoc(doc);
848 level = get_key_file_integer(filename, "compression_level");
850 if (level < 0)
851 level = 0;
853 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
854 memset(shakey, 0, sizeof(shakey));
855 gcry_free(xml);
857 if (zrc == Z_MEM_ERROR)
858 warnx("%s", strerror(ENOMEM));
859 else
860 warnx("do_compress() failed");
862 gcry_cipher_close(gh);
863 return FALSE;
865 else {
866 gcry_free(xml);
867 xml = outbuf;
868 len = outsize;
871 if (iter == -1)
872 memset(shakey, '!', sizeof(shakey));
873 else{
874 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
875 gcry_free(key);
878 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
879 gcry_cipher_close(gh);
881 if (rc) {
882 memset(shakey, 0, sizeof(shakey));
883 warnx("%s", gpg_strerror(rc));
884 return FALSE;
887 memset(shakey, 0, sizeof(shakey));
888 return TRUE;
891 gchar *get_key_file_string(const gchar *section, const gchar *what)
893 gchar *val = NULL;
894 GError *grc = NULL;
896 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
897 val = g_key_file_get_string(keyfileh, section, what, &grc);
899 if (grc) {
900 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
901 g_clear_error(&grc);
904 else {
905 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
906 val = g_key_file_get_string(keyfileh, "global", what, &grc);
908 if (grc) {
909 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
910 g_clear_error(&grc);
915 return val;
918 gint get_key_file_integer(const gchar *section, const gchar *what)
920 gint val = -1;
921 GError *grc = NULL;
923 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
924 val = g_key_file_get_integer(keyfileh, section, what, &grc);
926 if (grc) {
927 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
928 g_clear_error(&grc);
931 else {
932 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
933 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
935 if (grc) {
936 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
937 g_clear_error(&grc);
942 return val;
945 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
947 gboolean val = FALSE;
948 GError *grc = NULL;
950 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
951 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
953 if (grc) {
954 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
955 g_clear_error(&grc);
958 else {
959 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
960 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
962 if (grc) {
963 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
964 g_clear_error(&grc);
969 return val;
972 static gboolean _getline(const gchar *file, gchar **result)
974 FILE *fp;
975 gchar buf[LINE_MAX] = {0}, *p;
976 gchar *str = NULL;
977 gint len;
979 if ((fp = fopen(file, "r")) == NULL) {
980 warn("%s", file);
981 return FALSE;
984 p = fgets(buf, sizeof(buf), fp);
985 fclose(fp);
986 len = strlen(buf);
988 if (len && buf[len - 1] == '\n')
989 buf[--len] = 0;
991 str = gcry_malloc(len + 1);
992 memcpy(str, buf, len ? len : 1);
993 str[len] = 0;
994 memset(&buf, 0, sizeof(buf));
995 *result = str;
996 return TRUE;
999 static gboolean parse_keyfile_key()
1001 gsize n;
1002 gchar **groups;
1003 gchar **p;
1004 gchar *str;
1006 groups = g_key_file_get_groups(keyfileh, &n);
1008 for (p = groups; *p; p++) {
1009 GError *rc = NULL;
1011 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1012 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1014 if (!str) {
1015 if (rc) {
1016 warnx("%s", rc->message);
1017 g_clear_error(&rc);
1020 continue;
1023 do_cache_push(*p, str);
1024 g_free(str);
1025 continue;
1028 if (rc) {
1029 warnx("%s", rc->message);
1030 g_clear_error(&rc);
1031 continue;
1034 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1035 gchar *t;
1036 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1038 if (!file) {
1039 if (rc) {
1040 warnx("%s", rc->message);
1041 g_clear_error(&rc);
1044 continue;
1047 t = expand_homedir(file);
1048 g_free(file);
1049 file = t;
1051 if (_getline(file, &str) == FALSE) {
1052 g_free(file);
1053 continue;
1056 g_free(file);
1057 do_cache_push(*p, str);
1058 gcry_free(str);
1059 continue;
1062 if (rc) {
1063 warnx("%s", rc->message);
1064 g_clear_error(&rc);
1068 g_strfreev(groups);
1069 return TRUE;
1072 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1074 guchar *md5file;
1075 guchar *key;
1076 gint timeout;
1077 const gchar *p = filename;
1078 file_header_t file_header;
1079 gpg_error_t rc;
1081 while (isspace(*p))
1082 p++;
1084 if (!*p)
1085 return FALSE;
1087 if (valid_filename(p) == FALSE) {
1088 warnx(N_("%s: invalid characters in filename"), p);
1089 return FALSE;
1092 md5file = gcry_malloc(16);
1093 key = gcry_malloc(gcrykeysize);
1094 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1096 if (cache_iscached(md5file) == TRUE) {
1097 warnx(N_("%s: file already cached, skipping"), p);
1098 gcry_free(md5file);
1099 gcry_free(key);
1100 return FALSE;
1103 if (access(p, R_OK|W_OK) != 0) {
1104 gcry_free(md5file);
1105 gcry_free(key);
1107 if (errno != ENOENT) {
1108 warn("%s", p);
1109 return FALSE;
1112 warn("%s", p);
1113 return TRUE;
1116 rc = read_file_header(filename, &file_header);
1118 if (rc) {
1119 gcry_free(md5file);
1120 gcry_free(key);
1121 warnx("%s", pwmd_strerror(rc));
1122 return FALSE;
1125 if (file_header.iter == -1) {
1126 memset(key, '!', gcrykeysize);
1127 goto try_decrypt;
1130 if (!password) {
1131 #ifdef WITH_PINENTRY
1132 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1133 #endif
1134 if (get_input(p, key) == FALSE) {
1135 gcry_free(key);
1136 gcry_free(md5file);
1137 return FALSE;
1139 #ifdef WITH_PINENTRY
1141 else {
1142 gchar *result = NULL;
1143 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1144 gint try = 0;
1146 pin->which = PINENTRY_OPEN;
1147 pin->filename = g_strdup(filename);
1148 again:
1149 rc = pinentry_getpin(pin, &result);
1151 if (rc) {
1152 warnx("%s: %s", filename, gpg_strerror(rc));
1153 cleanup_pinentry(pin);
1154 gcry_free(key);
1155 gcry_free(md5file);
1156 xfree(result);
1157 return FALSE;
1160 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1161 xfree(result);
1163 if (do_try_xml_decrypt(filename, key) == FALSE) {
1164 if (try++ == 2) {
1165 cleanup_pinentry(pin);
1166 gcry_free(key);
1167 gcry_free(md5file);
1168 warnx(N_("%s: invalid password, skipping"), filename);
1169 return FALSE;
1171 else {
1172 g_free(pin->title);
1173 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1174 goto again;
1178 cleanup_pinentry(pin);
1180 #endif
1182 else {
1183 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1185 try_decrypt:
1186 if (do_try_xml_decrypt(filename, key) == FALSE) {
1187 warnx(N_("%s: invalid password, skipping"), filename);
1188 gcry_free(key);
1189 gcry_free(md5file);
1190 return FALSE;
1194 if (cache_add_file(md5file, key) == FALSE) {
1195 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1196 gcry_free(key);
1197 gcry_free(md5file);
1198 return FALSE;
1201 timeout = get_key_file_integer(p, "cache_timeout");
1202 cache_set_timeout(md5file, timeout);
1203 warnx(N_("%s: file added to the cache"), filename);
1204 gcry_free(key);
1205 gcry_free(md5file);
1206 return TRUE;
1209 static GSList *remove_connection(GSList *list, struct client_thread_s *cn)
1211 gpointer value;
1212 struct client_s *cl = cn->cl;
1214 if (cn->keepalive_tid) {
1215 pth_cancel(cn->keepalive_tid);
1216 pth_join(cn->keepalive_tid, &value);
1219 log_write("%p", cn->tid);
1220 pth_join(cn->tid, &value);
1222 if (cl->freed == FALSE)
1223 cleanup_assuan(cl->ctx);
1225 if (cl->ctx)
1226 assuan_deinit_server(cl->ctx);
1228 #ifdef WITH_PINENTRY
1229 if (cl->pinentry)
1230 cleanup_pinentry(cl->pinentry);
1231 #endif
1233 g_free(cl);
1234 pth_event_isolate(cn->ev);
1235 pth_event_free(cn->ev, PTH_FREE_THIS);
1236 list = g_slist_remove(list, cn);
1237 g_free(cn);
1238 return list;
1242 * Can't pth_event_concat() to an empty event.
1244 static int event_ring_hack(void *data)
1246 return FALSE;
1250 * See if any thread has entered the DEAD queue and remove it.
1252 static GSList *cleanup_dead_queue(GSList *threads, pth_event_t tid_events)
1254 guint n, i;
1256 for (n = g_slist_length(threads), i = 0; i < n; i++) {
1257 struct client_thread_s *cn = g_slist_nth_data(threads, i);
1259 if (pth_event_occurred(cn->ev)) {
1260 threads = remove_connection(threads, cn);
1261 return cleanup_dead_queue(threads, tid_events);
1264 pth_event_concat(tid_events, cn->ev, NULL);
1267 return threads;
1270 static void *accept_thread(void *arg)
1272 gint sockfd = (gint)arg;
1274 for (;;) {
1275 socklen_t slen = sizeof(struct sockaddr_un);
1276 struct sockaddr_un raddr;
1277 gint fd = -1;
1278 pth_attr_t attr;
1280 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1281 if (errno != EAGAIN) {
1282 if (!quit) // probably EBADF
1283 log_write("accept(): %s", strerror(errno));
1285 break;
1289 if (fd >= 0) {
1290 pth_t tid;
1291 struct client_thread_s *new;
1292 gchar buf[41];
1294 new = g_malloc0(sizeof(struct client_thread_s));
1296 if (!new) {
1297 log_write("%s", strerror(ENOMEM));
1298 continue;
1302 * Thread priority is inherited from the calling thread. This
1303 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1304 * priority.
1306 new->fd = fd;
1307 attr = pth_attr_new();
1308 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1309 tid = pth_spawn(attr, client_thread, new);
1310 pth_attr_destroy(attr);
1312 if (!tid) {
1313 g_free(new);
1314 log_write(N_("pth_spawn() failed"));
1315 continue;
1318 g_snprintf(buf, sizeof(buf), "%p", tid);
1319 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1320 attr = pth_attr_of(tid);
1321 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1322 pth_attr_destroy(attr);
1323 new->tid = tid;
1324 new->ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1325 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1326 pth_event_concat(cn_events, new->ev, NULL);
1327 cn_thread_list = g_slist_append(cn_thread_list, new);
1328 pth_mutex_release(&cn_mutex);
1332 /* Just in case pth_accept() failed for some reason other than EBADF */
1333 quit = 1;
1334 pth_exit(PTH_CANCELED);
1335 return NULL;
1339 * There needs to be a pth_timeout() here so pth_wait() can wait for new
1340 * cn_events which is updated from cleanup_dead_queue().
1342 static void *cleanup_thread(void *arg)
1344 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1346 for (;;) {
1347 if (pth_wait(cn_events) && pth_event_occurred(cn_events)) {
1348 pth_event_isolate(cn_events);
1349 pth_event_free(cn_events, PTH_FREE_THIS);
1350 pth_cancel_point();
1351 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1352 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1353 cn_thread_list = cleanup_dead_queue(cn_thread_list, cn_events);
1354 pth_mutex_release(&cn_mutex);
1358 return NULL;
1362 * This thread isn't joinable. For operations that block, these threads will
1363 * stack.
1365 static void *adjust_timer_thread(void *arg)
1367 CACHE_LOCK(NULL);
1368 cache_adjust_timer();
1369 CACHE_UNLOCK;
1370 return NULL;
1373 static void server_loop(gint sockfd, gchar **socketpath)
1375 pth_t accept_tid, cleanup_tid;
1376 guint n, i;
1377 sigset_t set;
1378 gint n_clients = 0;
1379 pth_attr_t attr;
1380 pth_event_t timeout_event;
1381 gpointer value;
1383 pth_mutex_init(&cn_mutex);
1384 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1386 sigemptyset(&set);
1387 sigaddset(&set, SIGTERM);
1388 sigaddset(&set, SIGINT);
1389 sigaddset(&set, SIGUSR1);
1390 sigaddset(&set, SIGHUP);
1391 sigaddset(&set, SIGABRT);
1393 attr = pth_attr_new();
1394 pth_attr_init(attr);
1395 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1396 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1397 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1398 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1399 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ASYNCHRONOUS);
1400 pth_attr_set(attr, PTH_ATTR_NAME, "cleanup");
1401 cleanup_tid = pth_spawn(attr, cleanup_thread, NULL);
1404 * For the cache_timeout configuration parameter. This replaces the old
1405 * SIGALRM stuff and is safer.
1407 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1408 pth_attr_init(attr);
1409 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1410 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1412 do {
1413 gint sig = 0;
1415 pth_sigwait_ev(&set, &sig, timeout_event);
1417 if (pth_event_occurred(timeout_event)) {
1419 * The timer event has expired. Update the file cache. When the
1420 * cache mutex is locked and the timer expires again, the threads
1421 * will stack.
1423 pth_spawn(attr, adjust_timer_thread, NULL);
1424 pth_event_free(timeout_event, PTH_FREE_THIS);
1425 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1428 if (sig > 0) {
1429 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1431 /* Caught a signal. */
1432 switch (sig) {
1433 case SIGUSR1:
1434 reload_rcfile();
1435 break;
1436 case SIGABRT:
1437 CACHE_LOCK(NULL);
1438 cache_clear(NULL, 2);
1439 CACHE_UNLOCK;
1440 #ifndef MEM_DEBUG
1441 xpanic();
1442 #endif
1443 exit(EXIT_FAILURE);
1444 case SIGHUP:
1445 CACHE_LOCK(NULL);
1446 log_write(N_("clearing file cache"));
1447 cache_clear(NULL, 2);
1448 CACHE_UNLOCK;
1449 break;
1450 default:
1451 quit = 1;
1452 shutdown(sockfd, SHUT_RDWR);
1453 close(sockfd);
1454 break;
1457 } while (!quit);
1460 * We're out of the main server loop. This happens when a signal was sent
1461 * to terminate the daemon. We'll wait for all clients to disconnect
1462 * before exiting and ignore any following signals.
1464 pth_join(accept_tid, &value);
1465 pth_attr_destroy(attr);
1466 pth_event_free(timeout_event, PTH_FREE_THIS);
1467 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1468 unlink(*socketpath);
1469 g_free(*socketpath);
1470 *socketpath = NULL;
1472 /* 2 because the cleanup thread still exists, plus self. */
1473 if (n > 2)
1474 log_write(N_("waiting for all threads to terminate"));
1476 while (n > 2) {
1477 gint t;
1478 pth_event_t events;
1480 if (n != n_clients) {
1481 log_write(N_("%i threads remain"), n-2);
1482 n_clients = n;
1485 events = pth_event(PTH_EVENT_FUNC, event_ring_hack, NULL, pth_timeout(1, 0));
1486 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1488 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1489 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1491 pth_event_concat(events, cn->ev, NULL);
1494 pth_mutex_release(&cn_mutex);
1496 if (!t)
1497 goto done;
1499 pth_wait(events);
1500 pth_yield(cleanup_tid);
1501 done:
1502 pth_event_isolate(events);
1503 pth_event_free(events, PTH_FREE_THIS);
1504 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1507 pth_cancel(cleanup_tid);
1511 * Called from pinentry_fork() in the child process.
1513 void free_client_list()
1515 gint i, t = g_slist_length(cn_thread_list);
1517 for (i = 0; i < t; i++) {
1518 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1520 free_client(cn->cl);
1523 memset(key_cache, 0, cache_size);
1526 int main(int argc, char *argv[])
1528 gint opt;
1529 struct sockaddr_un addr;
1530 struct passwd *pw = getpwuid(getuid());
1531 gchar buf[PATH_MAX];
1532 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1533 gchar *socketarg = NULL;
1534 gchar *datadir = NULL;
1535 gboolean n;
1536 gchar *p;
1537 gchar **cache_push = NULL;
1538 gint iter = 0;
1539 gchar *import = NULL;
1540 gint default_timeout;
1541 gint rcfile_spec = 0;
1542 gint estatus = EXIT_FAILURE;
1543 gint sockfd;
1544 #ifndef MEM_DEBUG
1545 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1546 #endif
1547 gint do_unlink = 1;
1548 gboolean secure = FALSE;
1549 guint ptotal = 0;
1550 gint background = 0;
1551 sigset_t set;
1552 #ifndef DEBUG
1553 #ifdef HAVE_SETRLIMIT
1554 struct rlimit rl;
1556 rl.rlim_cur = rl.rlim_max = 0;
1558 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1559 err(EXIT_FAILURE, "setrlimit()");
1560 #endif
1561 #endif
1563 #ifdef ENABLE_NLS
1564 setlocale(LC_ALL, "");
1565 bindtextdomain("pwmd", LOCALEDIR);
1566 textdomain("pwmd");
1567 #endif
1569 gpg_err_init();
1570 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1571 #ifndef MEM_DEBUG
1572 g_mem_set_vtable(&mtable);
1573 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1574 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1575 xmlInitMemory();
1576 #endif
1577 pth_init();
1578 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1580 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1581 err(EXIT_FAILURE, "%s", buf);
1583 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1585 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1586 err(EXIT_FAILURE, "%s", buf);
1588 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1590 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1591 err(EXIT_FAILURE, "sysconf()");
1593 cache_size = page_size;
1595 while ((opt = getopt(argc, argv, "bI:hvf:D")) != EOF) {
1596 switch (opt) {
1597 case 'b':
1598 background = 1;
1599 break;
1600 case 'D':
1601 secure = TRUE;
1602 break;
1603 case 'I':
1604 import = optarg;
1605 break;
1606 case 'f':
1607 g_free(rcfile);
1608 rcfile = g_strdup(optarg);
1609 rcfile_spec = 1;
1610 break;
1611 case 'v':
1612 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1613 exit(EXIT_SUCCESS);
1614 case 'h':
1615 default:
1616 usage(argv[0]);
1620 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1621 exit(EXIT_FAILURE);
1623 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1624 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1626 if (log_syslog == TRUE)
1627 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1629 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1630 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1632 #ifdef HAVE_MLOCKALL
1633 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1634 warn("mlockall()");
1635 goto do_exit;
1637 #endif
1639 setup_gcrypt();
1641 if (import) {
1642 opt = xml_import(import, iter);
1643 g_key_file_free(keyfileh);
1644 g_free(rcfile);
1645 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1648 g_key_file_set_list_separator(keyfileh, ',');
1650 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1651 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1653 if (*p == '~') {
1654 p++;
1655 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1656 g_free(p);
1657 socketarg = g_strdup(buf);
1659 else
1660 socketarg = p;
1662 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1663 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1665 datadir = expand_homedir(p);
1666 g_free(p);
1668 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1669 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1670 disable_list_and_dump = n;
1672 else
1673 disable_list_and_dump = secure;
1675 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1676 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1677 else
1678 default_timeout = -1;
1680 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1681 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1683 if (cache_size < page_size || cache_size % page_size)
1684 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1687 setup_logging(keyfileh);
1689 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1690 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1692 if (argc != optind) {
1693 if (cache_push)
1694 ptotal = g_strv_length(cache_push);
1696 for (; optind < argc; optind++) {
1697 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1698 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1702 if (strchr(socketarg, '/') == NULL) {
1703 socketdir = g_get_current_dir();
1704 socketname = g_strdup(socketarg);
1705 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1707 else {
1708 socketname = g_strdup(strrchr(socketarg, '/'));
1709 socketname++;
1710 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1711 socketdir = g_strdup(socketarg);
1712 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1715 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1716 #ifdef MMAP_ANONYMOUS
1717 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1718 #else
1719 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1720 #endif
1721 err(EXIT_FAILURE, "mmap()");
1724 if (mlock(key_cache, cache_size) == -1)
1725 log_write("mlock(): %s", strerror(errno));
1727 memset(key_cache, 0, cache_size);
1729 if (chdir(datadir)) {
1730 warn("%s", datadir);
1731 unlink(socketpath);
1732 goto do_exit;
1735 if (parse_keyfile_key() == FALSE)
1736 goto do_exit;
1738 clear_errorfile_key();
1741 * Set the cache entry for a file. Prompts for the password.
1743 if (cache_push) {
1744 for (opt = 0; cache_push[opt]; opt++)
1745 do_cache_push(cache_push[opt], NULL);
1747 g_strfreev(cache_push);
1748 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1752 * bind() doesn't like the full pathname of the socket or any non alphanum
1753 * characters so change to the directory where the socket is wanted then
1754 * create it then change to datadir.
1756 if (chdir(socketdir)) {
1757 warn("%s", socketdir);
1758 goto do_exit;
1761 g_free(socketdir);
1763 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1764 warn("socket()");
1765 goto do_exit;
1768 addr.sun_family = AF_UNIX;
1769 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1771 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1772 warn("bind()");
1774 if (errno == EADDRINUSE)
1775 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1776 "stale socket. Please remove it manually."), socketpath);
1778 do_unlink = 0;
1779 goto do_exit;
1782 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1783 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1784 mode_t mode = strtol(t, NULL, 8);
1785 mode_t mask = umask(0);
1787 g_free(t);
1789 if (chmod(socketname, mode) == -1) {
1790 warn("%s", socketname);
1791 close(sockfd);
1792 unlink(socketpath);
1793 umask(mask);
1794 goto do_exit;
1797 umask(mask);
1800 g_free(--socketname);
1802 if (chdir(datadir)) {
1803 warn("%s", datadir);
1804 close(sockfd);
1805 unlink(socketpath);
1806 goto do_exit;
1809 g_free(datadir);
1810 pth_mutex_init(&cache_mutex);
1811 #ifdef WITH_PINENTRY
1812 pth_mutex_init(&pin_mutex);
1813 #endif
1815 if (listen(sockfd, 0) == -1) {
1816 warn("listen()");
1817 goto do_exit;
1820 if (background) {
1821 switch (fork()) {
1822 case -1:
1823 warn("fork()");
1824 goto do_exit;
1825 case 0:
1826 close(0);
1827 close(1);
1828 close(2);
1829 setsid();
1830 break;
1831 default:
1832 exit(EXIT_SUCCESS);
1837 * These are the signals that we use in threads. libpth can catch signals
1838 * itself so ignore them everywhere else. Note that using
1839 * signal(N, SIG_IGN) doesn't work like you might think.
1841 sigemptyset(&set);
1843 /* Termination */
1844 sigaddset(&set, SIGTERM);
1845 sigaddset(&set, SIGINT);
1847 /* Configuration file reloading. */
1848 sigaddset(&set, SIGUSR1);
1850 /* Clears the file cache. */
1851 sigaddset(&set, SIGHUP);
1853 /* Caught in client_thread(). Sends a cache status message. */
1854 sigaddset(&set, SIGUSR2);
1856 /* Caught in client_thread(). When keepalive_thread() fails, this signal
1857 * is raised to terminate the client. More of a failsafe than anything. */
1858 sigaddset(&set, SIGQUIT);
1860 /* Ignored everywhere. When a client disconnects abnormally this signal
1861 * gets raised. It isn't needed though because client_thread() will check
1862 * for rcs even after the client disconnects. */
1863 signal(SIGPIPE, SIG_IGN);
1864 pth_sigmask(SIG_BLOCK, &set, NULL);
1865 server_loop(sockfd, &socketpath);
1866 estatus = EXIT_SUCCESS;
1868 do_exit:
1869 if (socketpath && do_unlink) {
1870 unlink(socketpath);
1871 g_free(socketpath);
1874 g_key_file_free(keyfileh);
1875 g_free(rcfile);
1876 xmlCleanupParser();
1878 if (key_cache) {
1879 cache_clear(NULL, 2);
1880 memset(key_cache, 0, cache_size);
1883 if (key_cache && munmap(key_cache, cache_size) == -1)
1884 log_write("munmap(): %s", strerror(errno));
1886 if (estatus == EXIT_SUCCESS)
1887 log_write(N_("pwmd exiting normally"));
1889 pth_kill();
1890 #if defined(DEBUG) && !defined(MEM_DEBUG)
1891 xdump();
1892 #endif
1893 exit(estatus);