Use pth_msgport_put() for the current thread too.
[pwmd.git] / src / pwmd.c
blobee2be9cb121a61ac1d4db7ddd93b1b5d347b35dd
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();
92 send_status_all(STATUS_CONFIG);
95 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
97 gpg_error_t n = gpg_error_from_errno(e);
99 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
102 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
104 gpg_err_code_t n = gpg_err_code(e);
105 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
106 struct client_s *client = assuan_get_pointer(ctx);
108 if (!e)
109 return assuan_process_done(ctx, 0);
111 if (!ctx) {
112 log_write("%s\n", pwmd_strerror(e));
113 return e;
116 if (n == EPWMD_LIBXML_ERROR) {
117 xmlErrorPtr xe = client->xml_error;
119 if (!xe)
120 xe = xmlGetLastError();
122 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
123 log_write("%s", xe->message);
125 if (xe == client->xml_error)
126 xmlResetError(xe);
127 else
128 xmlResetLastError();
130 client->xml_error = NULL;
131 return e;
134 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
137 void log_write(const gchar *fmt, ...)
139 gchar *args, *line;
140 va_list ap;
141 struct tm *tm;
142 time_t now;
143 gchar tbuf[21];
144 gint fd = -1;
145 pth_attr_t attr;
146 gchar *name;
148 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
149 return;
151 if (logfile) {
152 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
153 warn(N_("logfile"));
154 return;
158 va_start(ap, fmt);
160 if (g_vasprintf(&args, fmt, ap) == -1) {
161 if (logfile)
162 close(fd);
164 va_end(ap);
165 return;
168 attr = pth_attr_of(pth_self());
169 pth_attr_get(attr, PTH_ATTR_NAME, &name);
170 pth_attr_destroy(attr);
172 if (log_syslog == TRUE)
173 syslog(LOG_INFO, "%s: %s", name, args);
175 va_end(ap);
176 time(&now);
177 tm = localtime(&now);
178 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
179 tbuf[sizeof(tbuf) - 1] = 0;
181 if (args[strlen(args)-1] == '\n')
182 args[strlen(args)-1] = 0;
184 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
185 g_free(args);
187 if (!line) {
188 if (logfile)
189 close(fd);
191 return;
194 if (logfile) {
195 write(fd, line, strlen(line));
196 fsync(fd);
197 close(fd);
200 if (isatty(STDERR_FILENO)) {
201 fprintf(stderr, "%s", line);
202 fflush(stderr);
205 g_free(line);
208 static void usage(gchar *pn)
210 g_printf(N_(
211 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename> [-i <iter>] [file1] [...]\n"
212 " -b run as a background process\n"
213 " -f load the specified rcfile (~/.pwmd/config)\n"
214 " -I import an XML file and write the encrypted data to stdout\n"
215 " -i encrypt with the specified number of iterations when importing\n"
216 " (config default in the \"global\" section)\n"
217 " -D disable use of the LIST and DUMP commands\n"
218 " -v version\n"
219 " -h this help text\n"
220 ), pn);
221 exit(EXIT_SUCCESS);
224 #ifndef MEM_DEBUG
225 static int gcry_SecureCheck(const void *ptr)
227 return 1;
229 #endif
231 static void setup_gcrypt()
233 gcry_check_version(NULL);
235 #ifndef MEM_DEBUG
236 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
237 xfree);
238 #endif
240 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
241 NULL) != 0)
242 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
244 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
245 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
248 static assuan_context_t new_connection(gint fd)
250 gpg_error_t rc;
251 gchar ver[ASSUAN_LINELENGTH];
252 assuan_context_t ctx;
254 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
256 if (rc)
257 goto fail;
259 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
260 assuan_set_hello_line(ctx, ver);
261 assuan_register_post_cmd_notify(ctx, command_finalize);
262 rc = register_commands(ctx);
264 if (rc)
265 goto fail;
267 rc = assuan_accept(ctx);
269 if (rc)
270 goto fail;
272 return ctx;
274 fail:
275 assuan_deinit_server(ctx);
276 log_write("%s", gpg_strerror(rc));
277 return NULL;
280 void send_status_all(status_msg_t which)
282 guint i, t;
284 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
286 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
287 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
288 pth_msgport_t m = pth_msgport_find(cn->msg_name);
290 if (m) {
291 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
293 msg->m_data = (status_msg_t *)which;
294 pth_msgport_put(m, msg);
298 pth_mutex_release(&cn_mutex);
301 static void xml_error_cb(void *data, xmlErrorPtr e)
303 struct client_s *client = data;
306 * Keep the first reported error as the one to show. Reset in
307 * send_error().
309 if (client->xml_error)
310 return;
312 xmlCopyError(e, client->xml_error);
316 * This is called after a child_thread terminates. Set with
317 * pth_cleanup_push().
319 static void cleanup_cb(void *arg)
321 struct client_thread_s *cn = arg;
322 gpointer value;
323 struct client_s *cl = cn->cl;
325 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
326 log_write(N_("exiting, fd=%i"), cn->fd);
327 pth_join(cn->tid, &value);
329 if (cl && cl->freed == FALSE)
330 cleanup_assuan(cl->ctx);
332 if (cl && cl->ctx)
333 assuan_deinit_server(cl->ctx);
335 #ifdef WITH_PINENTRY
336 if (cl && cl->pinentry)
337 cleanup_pinentry(cl->pinentry);
338 #endif
340 g_free(cl);
342 if (cn->msg_name)
343 g_free(cn->msg_name);
345 if (cn->msg) {
346 while (pth_msgport_pending(cn->msg) > 0) {
347 pth_message_t *m = pth_msgport_get(cn->msg);
349 g_free(m);
352 pth_msgport_destroy(cn->msg);
355 cn_thread_list = g_slist_remove(cn_thread_list, cn);
356 g_free(cn);
357 pth_mutex_release(&cn_mutex);
361 * Called every time a connection is made via pth_spawn(). This is the thread
362 * entry point.
364 static void *client_thread(void *data)
366 struct client_thread_s *thd = data;
367 gint fd = thd->fd;
368 pth_event_t ev, msg_ev;
369 #ifdef WITH_PINENTRY
370 pth_event_t pinentry_ev = NULL;
371 #endif
372 struct client_s *cl = g_malloc0(sizeof(struct client_s));
373 gpg_error_t rc;
375 if (!cl) {
376 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
377 goto fail;
380 #ifdef WITH_PINENTRY
381 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
383 if (!cl->pinentry) {
384 g_free(cl);
385 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
386 goto fail;
389 set_pinentry_defaults(cl->pinentry);
390 #endif
391 thd->cl = cl;
392 cl->thd = thd;
393 pth_cleanup_push(cleanup_cb, thd);
394 thd->msg_name = g_strdup_printf("%p", thd->tid);
396 if (!thd->msg_name) {
397 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
398 goto fail;
401 thd->msg = pth_msgport_create(thd->msg_name);
403 if (!thd->msg) {
404 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
405 goto fail;
409 * This is a "child" thread. Don't catch any signals. Let the master
410 * thread take care of signals in server_loop().
412 cl->ctx = new_connection(fd);
413 cl->fd = fd;
415 if (!cl->ctx)
416 goto fail;
418 assuan_set_pointer(cl->ctx, cl);
420 #ifdef HAVE_MLOCKALL
421 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
422 log_write("mlockall(): %s", strerror(errno));
423 goto fail;
425 #endif
427 rc = send_status(cl->ctx, STATUS_CACHE);
429 if (rc) {
430 log_write("%s", gpg_strerror(rc));
431 goto fail;
434 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
435 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
436 pth_event_concat(ev, msg_ev, NULL);
437 xmlInitParser();
438 xmlXPathInit();
439 xmlSetStructuredErrorFunc(cl, xml_error_cb);
441 for (;;) {
442 pth_wait(ev);
443 pth_event_isolate(ev);
444 pth_event_isolate(msg_ev);
446 if (pth_event_occurred(msg_ev)) {
447 pth_event_free(msg_ev, PTH_FREE_THIS);
449 while (pth_msgport_pending(thd->msg) > 0) {
450 pth_message_t *m = pth_msgport_get(thd->msg);
451 status_msg_t n = (status_msg_t)m->m_data;
453 rc = send_status(cl->ctx, n);
454 g_free(m);
456 if (rc) {
457 log_write("%s", gpg_strerror(rc));
458 goto done;
462 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
465 pth_event_concat(ev, msg_ev, NULL);
467 if (pth_event_occurred(ev)) {
468 rc = assuan_process_next(cl->ctx);
470 if (rc) {
471 cl->inquire_status = INQUIRE_INIT;
473 if (gpg_err_code(rc) == GPG_ERR_EOF)
474 goto done;
476 log_write("assuan_process_next(): %s", gpg_strerror(rc));
477 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
479 if (rc) {
480 log_write("assuan_process_done(): %s", gpg_strerror(rc));
481 goto done;
484 else {
485 #ifdef WITH_PINENTRY
486 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
487 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
488 pth_event_concat(ev, pinentry_ev, NULL);
489 cl->pinentry->status = PINENTRY_RUNNING;
491 #endif
493 switch (cl->inquire_status) {
494 case INQUIRE_BUSY:
495 case INQUIRE_INIT:
496 break;
497 case INQUIRE_DONE:
498 cl->inquire_status = INQUIRE_INIT;
499 rc = assuan_process_done(cl->ctx, 0);
500 break;
505 #ifdef WITH_PINENTRY
506 if (cl->pinentry->status == PINENTRY_RUNNING) {
507 pth_event_isolate(pinentry_ev);
509 if (pth_event_occurred(pinentry_ev)) {
510 guchar shakey[gcrykeysize];
511 pinentry_key_s pk;
512 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
513 gint status;
515 pth_event_free(pinentry_ev, PTH_FREE_THIS);
516 pinentry_ev = NULL;
517 cl->pinentry->status = PINENTRY_NONE;
519 if (len == sizeof(pk)) {
520 if (pk.error)
521 rc = send_error(cl->ctx, pk.error);
522 else {
523 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
524 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
525 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
526 memset(shakey, 0, sizeof(shakey));
529 else if (len == -1)
530 log_write("%s", strerror(errno));
531 else if (len == 0)
532 log_write("pth_read(): EOF");
533 else
534 log_write(N_("pth_read(): short byte count"));
536 pth_waitpid(cl->pinentry->pid, &status, 0);
537 close(cl->pinentry->fd);
538 cl->pinentry->fd = -1;
539 cl->pinentry->pid = 0;
541 if (pk.error && cl->pinentry->which == PINENTRY_OPEN)
542 cleanup_client(cl);
543 else
544 unlock_file_mutex(cl);
546 memset(&pk, 0, sizeof(pk));
547 unlock_pin_mutex(cl->pinentry);
550 pth_event_concat(ev, pinentry_ev, NULL);
552 #endif
556 * Client cleanup (including XML data) is done in remove_connection() from
557 * the cleanup thread.
559 done:
560 pth_event_free(ev, PTH_FREE_ALL);
562 fail:
563 pth_exit(NULL);
564 return NULL;
567 static void setup_logging(GKeyFile *kf)
569 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
571 if (n == TRUE) {
572 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
574 if (*p == '~') {
575 gchar buf[PATH_MAX];
577 p++;
578 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
579 g_free(p);
581 if (logfile)
582 g_free(logfile);
584 logfile = g_strdup(buf);
586 else {
587 if (logfile)
588 g_free(logfile);
590 logfile = p;
594 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
598 * Make sure all settings are set to either the specified setting or a
599 * default.
601 static void set_rcfile_defaults(GKeyFile *kf)
603 gchar buf[PATH_MAX];
605 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
606 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
607 g_key_file_set_string(kf, "global", "socket_path", buf);
610 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
611 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
612 g_key_file_set_string(kf, "global", "data_directory", buf);
615 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
616 g_key_file_set_boolean(kf, "global", "backup", TRUE);
618 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
619 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
620 g_key_file_set_string(kf, "global", "log_path", buf);
623 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
624 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
626 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
627 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
629 #ifdef HAVE_MLOCKALL
630 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
631 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
632 #endif
634 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
635 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
637 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
638 g_key_file_set_integer(kf, "global", "iterations", 0);
640 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
641 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
643 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
644 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
646 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
647 g_key_file_set_integer(kf, "global", "compression_level", 6);
649 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
650 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
652 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
653 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
655 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
657 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
658 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
660 #ifdef HAVE_MLOCKALL
661 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
662 #endif
664 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
665 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
667 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
668 g_key_file_set_integer(kf, "global", "keepalive", 30);
670 #ifdef WITH_PINENTRY
671 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
672 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
673 #endif
675 setup_logging(kf);
678 static GKeyFile *parse_rcfile(int cmdline)
680 GKeyFile *kf = g_key_file_new();
681 GError *rc = NULL;
683 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
684 log_write("%s: %s", rcfile, rc->message);
686 if (cmdline)
687 exit(EXIT_FAILURE);
689 if (rc->code == G_FILE_ERROR_NOENT) {
690 g_clear_error(&rc);
691 set_rcfile_defaults(kf);
692 return kf;
695 g_clear_error(&rc);
696 return NULL;
698 else
699 set_rcfile_defaults(kf);
701 return kf;
704 static gchar *get_password(const gchar *prompt)
706 gchar buf[LINE_MAX] = {0}, *p;
707 struct termios told, tnew;
708 gchar *key;
710 if (tcgetattr(STDIN_FILENO, &told) == -1)
711 err(EXIT_FAILURE, "tcgetattr()");
713 memcpy(&tnew, &told, sizeof(struct termios));
714 tnew.c_lflag &= ~(ECHO);
715 tnew.c_lflag |= ICANON|ECHONL;
717 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
718 tcsetattr(STDIN_FILENO, TCSANOW, &told);
719 err(EXIT_FAILURE, "tcsetattr()");
722 fprintf(stderr, "%s", prompt);
724 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
725 tcsetattr(STDIN_FILENO, TCSANOW, &told);
726 return NULL;
729 tcsetattr(STDIN_FILENO, TCSANOW, &told);
730 p[strlen(p) - 1] = 0;
732 if (!buf[0]) {
733 key = gcry_malloc(1);
734 key[0] = 0;
736 else {
737 key = gcry_malloc(strlen(p) + 1);
738 sprintf(key, "%s", p);
741 memset(&buf, 0, sizeof(buf));
742 return key;
745 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
747 int fd;
748 struct stat st;
749 gpg_error_t rc;
751 if ((fd = open_file(filename, &st)) == -1) {
752 warn("%s", filename);
753 return FALSE;
756 if (st.st_size == 0) {
757 warnx(N_("%s: skipping empty file"), filename);
758 close(fd);
759 return FALSE;
762 rc = try_xml_decrypt(NULL, fd, st, key);
763 close(fd);
764 return rc ? FALSE : TRUE;
767 static gboolean get_input(const gchar *filename, guchar *key)
769 gint try = 0;
770 gchar *password;
771 gchar *prompt;
773 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
775 again:
776 if ((password = get_password(prompt)) == NULL) {
777 warnx(N_("%s: skipping file"), filename);
778 g_free(prompt);
779 return FALSE;
782 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
783 gcry_free(password);
785 if (do_try_xml_decrypt(filename, key) == FALSE) {
786 if (try++ == 2) {
787 warnx(N_("%s: invalid password, skipping"), filename);
788 g_free(prompt);
789 return FALSE;
791 else {
792 warnx(N_("%s: invalid password"), filename);
793 goto again;
797 g_free(prompt);
798 return TRUE;
801 static gboolean xml_import(const gchar *filename, gint iter)
803 xmlDocPtr doc;
804 gint fd;
805 struct stat st;
806 gint len;
807 xmlChar *xmlbuf;
808 xmlChar *xml;
809 gchar *key = NULL;
810 gchar *key2 = NULL;
811 guchar shakey[gcrykeysize];
812 gcry_cipher_hd_t gh;
813 gpg_error_t rc;
814 gint level;
815 glong outsize;
816 gpointer outbuf;
817 gint zrc;
819 if (stat(filename, &st) == -1) {
820 warn("%s", filename);
821 return FALSE;
824 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
825 send_error(NULL, rc);
826 gcry_cipher_close(gh);
827 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
828 return FALSE;
831 if (iter == -1)
832 goto done;
834 if ((key = get_password(N_("New password: "))) == NULL) {
835 fprintf(stderr, "%s\n", N_("Invalid password."));
836 gcry_cipher_close(gh);
837 return FALSE;
840 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
841 fprintf(stderr, "%s\n", N_("Passwords do not match."));
842 gcry_free(key);
843 gcry_cipher_close(gh);
844 return FALSE;
847 if (g_utf8_collate(key, key2) != 0) {
848 fprintf(stderr, "%s\n", N_("Passwords do not match."));
849 gcry_free(key);
850 gcry_free(key2);
851 gcry_cipher_close(gh);
852 return FALSE;
855 gcry_free(key2);
857 done:
858 if ((fd = open(filename, O_RDONLY)) == -1) {
859 gcry_free(key);
860 warn("%s", filename);
861 gcry_cipher_close(gh);
862 return FALSE;
865 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
866 gcry_free(key);
867 close(fd);
868 log_write("%s", strerror(ENOMEM));
869 gcry_cipher_close(gh);
870 return FALSE;
873 if (read(fd, xmlbuf, st.st_size) == -1) {
874 rc = errno;
875 close(fd);
876 gcry_free(key);
877 gcry_cipher_close(gh);
878 errno = rc;
879 err(EXIT_FAILURE, "read()");
882 close(fd);
883 xmlbuf[st.st_size] = 0;
886 * Make sure the document validates.
888 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
889 log_write("xmlReadDoc()");
890 close(fd);
891 gcry_free(key);
892 gcry_free(xmlbuf);
893 gcry_cipher_close(gh);
894 return FALSE;
897 gcry_free(xmlbuf);
898 xmlDocDumpMemory(doc, &xml, &len);
899 xmlFreeDoc(doc);
901 level = get_key_file_integer(filename, "compression_level");
903 if (level < 0)
904 level = 0;
906 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
907 memset(shakey, 0, sizeof(shakey));
908 gcry_free(xml);
910 if (zrc == Z_MEM_ERROR)
911 warnx("%s", strerror(ENOMEM));
912 else
913 warnx("do_compress() failed");
915 gcry_cipher_close(gh);
916 return FALSE;
918 else {
919 gcry_free(xml);
920 xml = outbuf;
921 len = outsize;
924 if (iter == -1)
925 memset(shakey, '!', sizeof(shakey));
926 else{
927 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
928 gcry_free(key);
931 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
932 gcry_cipher_close(gh);
934 if (rc) {
935 memset(shakey, 0, sizeof(shakey));
936 warnx("%s", gpg_strerror(rc));
937 return FALSE;
940 memset(shakey, 0, sizeof(shakey));
941 return TRUE;
944 gchar *get_key_file_string(const gchar *section, const gchar *what)
946 gchar *val = NULL;
947 GError *grc = NULL;
949 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
950 val = g_key_file_get_string(keyfileh, section, what, &grc);
952 if (grc) {
953 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
954 g_clear_error(&grc);
957 else {
958 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
959 val = g_key_file_get_string(keyfileh, "global", what, &grc);
961 if (grc) {
962 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
963 g_clear_error(&grc);
968 return val;
971 gint get_key_file_integer(const gchar *section, const gchar *what)
973 gint val = -1;
974 GError *grc = NULL;
976 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
977 val = g_key_file_get_integer(keyfileh, section, what, &grc);
979 if (grc) {
980 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
981 g_clear_error(&grc);
984 else {
985 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
986 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
988 if (grc) {
989 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
990 g_clear_error(&grc);
995 return val;
998 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1000 gboolean val = FALSE;
1001 GError *grc = NULL;
1003 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1004 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1006 if (grc) {
1007 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1008 g_clear_error(&grc);
1011 else {
1012 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1013 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1015 if (grc) {
1016 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1017 g_clear_error(&grc);
1022 return val;
1025 static gboolean _getline(const gchar *file, gchar **result)
1027 FILE *fp;
1028 gchar buf[LINE_MAX] = {0}, *p;
1029 gchar *str = NULL;
1030 gint len;
1032 if ((fp = fopen(file, "r")) == NULL) {
1033 warn("%s", file);
1034 return FALSE;
1037 p = fgets(buf, sizeof(buf), fp);
1038 fclose(fp);
1039 len = strlen(buf);
1041 if (len && buf[len - 1] == '\n')
1042 buf[--len] = 0;
1044 str = gcry_malloc(len + 1);
1045 memcpy(str, buf, len ? len : 1);
1046 str[len] = 0;
1047 memset(&buf, 0, sizeof(buf));
1048 *result = str;
1049 return TRUE;
1052 static gboolean parse_keyfile_key()
1054 gsize n;
1055 gchar **groups;
1056 gchar **p;
1057 gchar *str;
1059 groups = g_key_file_get_groups(keyfileh, &n);
1061 for (p = groups; *p; p++) {
1062 GError *rc = NULL;
1064 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1065 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1067 if (!str) {
1068 if (rc) {
1069 warnx("%s", rc->message);
1070 g_clear_error(&rc);
1073 continue;
1076 do_cache_push(*p, str);
1077 g_free(str);
1078 continue;
1081 if (rc) {
1082 warnx("%s", rc->message);
1083 g_clear_error(&rc);
1084 continue;
1087 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1088 gchar *t;
1089 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1091 if (!file) {
1092 if (rc) {
1093 warnx("%s", rc->message);
1094 g_clear_error(&rc);
1097 continue;
1100 t = expand_homedir(file);
1101 g_free(file);
1102 file = t;
1104 if (_getline(file, &str) == FALSE) {
1105 g_free(file);
1106 continue;
1109 g_free(file);
1110 do_cache_push(*p, str);
1111 gcry_free(str);
1112 continue;
1115 if (rc) {
1116 warnx("%s", rc->message);
1117 g_clear_error(&rc);
1121 g_strfreev(groups);
1122 return TRUE;
1125 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1127 guchar *md5file;
1128 guchar *key;
1129 gint timeout;
1130 const gchar *p = filename;
1131 file_header_t file_header;
1132 gpg_error_t rc;
1134 while (isspace(*p))
1135 p++;
1137 if (!*p)
1138 return FALSE;
1140 if (valid_filename(p) == FALSE) {
1141 warnx(N_("%s: invalid characters in filename"), p);
1142 return FALSE;
1145 md5file = gcry_malloc(16);
1146 key = gcry_malloc(gcrykeysize);
1147 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1149 if (cache_iscached(md5file) == TRUE) {
1150 warnx(N_("%s: file already cached, skipping"), p);
1151 gcry_free(md5file);
1152 gcry_free(key);
1153 return FALSE;
1156 if (access(p, R_OK|W_OK) != 0) {
1157 gcry_free(md5file);
1158 gcry_free(key);
1160 if (errno != ENOENT) {
1161 warn("%s", p);
1162 return FALSE;
1165 warn("%s", p);
1166 return TRUE;
1169 rc = read_file_header(filename, &file_header);
1171 if (rc) {
1172 gcry_free(md5file);
1173 gcry_free(key);
1174 warnx("%s", pwmd_strerror(rc));
1175 return FALSE;
1178 if (file_header.iter == -1) {
1179 memset(key, '!', gcrykeysize);
1180 goto try_decrypt;
1183 if (!password) {
1184 #ifdef WITH_PINENTRY
1185 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1186 #endif
1187 if (get_input(p, key) == FALSE) {
1188 gcry_free(key);
1189 gcry_free(md5file);
1190 return FALSE;
1192 #ifdef WITH_PINENTRY
1194 else {
1195 gchar *result = NULL;
1196 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1197 gint try = 0;
1199 pin->which = PINENTRY_OPEN;
1200 pin->filename = g_strdup(filename);
1201 again:
1202 rc = pinentry_getpin(pin, &result);
1204 if (rc) {
1205 warnx("%s: %s", filename, gpg_strerror(rc));
1206 cleanup_pinentry(pin);
1207 gcry_free(key);
1208 gcry_free(md5file);
1209 xfree(result);
1210 return FALSE;
1213 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1214 xfree(result);
1216 if (do_try_xml_decrypt(filename, key) == FALSE) {
1217 if (try++ == 2) {
1218 cleanup_pinentry(pin);
1219 gcry_free(key);
1220 gcry_free(md5file);
1221 warnx(N_("%s: invalid password, skipping"), filename);
1222 return FALSE;
1224 else {
1225 g_free(pin->title);
1226 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1227 goto again;
1231 cleanup_pinentry(pin);
1233 #endif
1235 else {
1236 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1238 try_decrypt:
1239 if (do_try_xml_decrypt(filename, key) == FALSE) {
1240 warnx(N_("%s: invalid password, skipping"), filename);
1241 gcry_free(key);
1242 gcry_free(md5file);
1243 return FALSE;
1247 if (cache_add_file(md5file, key) == FALSE) {
1248 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1249 gcry_free(key);
1250 gcry_free(md5file);
1251 return FALSE;
1254 timeout = get_key_file_integer(p, "cache_timeout");
1255 cache_set_timeout(md5file, timeout);
1256 warnx(N_("%s: file added to the cache"), filename);
1257 gcry_free(key);
1258 gcry_free(md5file);
1259 return TRUE;
1262 static void *accept_thread(void *arg)
1264 gint sockfd = (gint)arg;
1266 for (;;) {
1267 socklen_t slen = sizeof(struct sockaddr_un);
1268 struct sockaddr_un raddr;
1269 gint fd = -1;
1270 pth_attr_t attr;
1272 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1273 if (errno != EAGAIN) {
1274 if (!quit) // probably EBADF
1275 log_write("accept(): %s", strerror(errno));
1277 break;
1281 if (fd >= 0) {
1282 pth_t tid;
1283 struct client_thread_s *new;
1284 gchar buf[41];
1286 new = g_malloc0(sizeof(struct client_thread_s));
1288 if (!new) {
1289 log_write("%s", strerror(ENOMEM));
1290 continue;
1294 * Thread priority is inherited from the calling thread. This
1295 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1296 * priority.
1298 new->fd = fd;
1299 attr = pth_attr_new();
1300 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1301 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1302 tid = pth_spawn(attr, client_thread, new);
1303 pth_attr_destroy(attr);
1305 if (!tid) {
1306 g_free(new);
1307 log_write(N_("pth_spawn() failed"));
1308 continue;
1311 g_snprintf(buf, sizeof(buf), "%p", tid);
1312 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1313 attr = pth_attr_of(tid);
1314 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1315 pth_attr_destroy(attr);
1316 new->tid = tid;
1317 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1318 cn_thread_list = g_slist_append(cn_thread_list, new);
1319 pth_mutex_release(&cn_mutex);
1323 /* Just in case pth_accept() failed for some reason other than EBADF */
1324 quit = 1;
1325 pth_exit(PTH_CANCELED);
1326 return NULL;
1330 * This thread isn't joinable. For operations that block, these threads will
1331 * stack.
1333 static void *adjust_timer_thread(void *arg)
1335 CACHE_LOCK(NULL);
1336 cache_adjust_timer();
1337 CACHE_UNLOCK;
1338 return NULL;
1341 static void server_loop(gint sockfd, gchar **socketpath)
1343 pth_t accept_tid;
1344 guint n;
1345 sigset_t set;
1346 gint n_clients = 0;
1347 pth_attr_t attr;
1348 pth_event_t timeout_ev, keepalive_ev = NULL;
1349 gint keepalive = get_key_file_integer("global", "keepalive");
1350 gpointer value;
1352 pth_mutex_init(&cn_mutex);
1353 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1355 sigemptyset(&set);
1356 sigaddset(&set, SIGTERM);
1357 sigaddset(&set, SIGINT);
1358 sigaddset(&set, SIGUSR1);
1359 sigaddset(&set, SIGHUP);
1360 sigaddset(&set, SIGABRT);
1362 attr = pth_attr_new();
1363 pth_attr_init(attr);
1364 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1365 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1366 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1369 * For the cache_timeout configuration parameter. This replaces the old
1370 * SIGALRM stuff and is safer.
1372 timeout_ev = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1374 if (keepalive > 0) {
1375 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1376 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1379 pth_attr_init(attr);
1380 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1381 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1383 do {
1384 gint sig = 0;
1386 pth_sigwait_ev(&set, &sig, timeout_ev);
1387 pth_event_isolate(timeout_ev);
1388 pth_event_isolate(keepalive_ev);
1390 if (pth_event_occurred(timeout_ev)) {
1392 * The timer event has expired. Update the file cache. When the
1393 * cache mutex is locked and the timer expires again, the threads
1394 * will stack.
1396 pth_spawn(attr, adjust_timer_thread, NULL);
1397 pth_event_free(timeout_ev, PTH_FREE_THIS);
1398 timeout_ev= pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1401 * Just in case the configuration file has been reloaded.
1403 keepalive = get_key_file_integer("global", "keepalive");
1406 if (keepalive_ev && pth_event_occurred(keepalive_ev)) {
1407 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1408 keepalive_ev = NULL;
1409 send_status_all(STATUS_KEEPALIVE);
1411 if (keepalive > 0)
1412 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1415 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1417 if (sig > 0) {
1418 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1420 /* Caught a signal. */
1421 switch (sig) {
1422 case SIGUSR1:
1423 reload_rcfile();
1424 break;
1425 case SIGABRT:
1426 CACHE_LOCK(NULL);
1427 cache_clear(NULL, 2);
1428 CACHE_UNLOCK;
1429 #ifndef MEM_DEBUG
1430 xpanic();
1431 #endif
1432 exit(EXIT_FAILURE);
1433 case SIGHUP:
1434 CACHE_LOCK(NULL);
1435 log_write(N_("clearing file cache"));
1436 cache_clear(NULL, 2);
1437 CACHE_UNLOCK;
1438 break;
1439 default:
1440 quit = 1;
1441 shutdown(sockfd, SHUT_RDWR);
1442 close(sockfd);
1443 break;
1446 } while (!quit);
1449 * We're out of the main server loop. This happens when a signal was sent
1450 * to terminate the daemon. We'll wait for all clients to disconnect
1451 * before exiting and ignore any following signals.
1453 pth_join(accept_tid, &value);
1454 pth_attr_destroy(attr);
1455 pth_event_free(timeout_ev, PTH_FREE_THIS);
1456 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1457 unlink(*socketpath);
1458 g_free(*socketpath);
1459 *socketpath = NULL;
1461 if (n > 1)
1462 log_write(N_("waiting for all threads to terminate"));
1464 while (n > 1) {
1465 pth_event_t events;
1467 if (n != n_clients) {
1468 log_write(N_("%i threads remain"), n-1);
1469 n_clients = n;
1472 events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1473 pth_wait(events);
1474 pth_event_isolate(events);
1475 pth_event_free(events, PTH_FREE_THIS);
1476 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1481 * Called from pinentry_fork() in the child process.
1483 void free_client_list()
1485 gint i, t = g_slist_length(cn_thread_list);
1487 for (i = 0; i < t; i++) {
1488 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1490 free_client(cn->cl);
1493 memset(key_cache, 0, cache_size);
1496 int main(int argc, char *argv[])
1498 gint opt;
1499 struct sockaddr_un addr;
1500 struct passwd *pw = getpwuid(getuid());
1501 gchar buf[PATH_MAX];
1502 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1503 gchar *socketarg = NULL;
1504 gchar *datadir = NULL;
1505 gboolean n;
1506 gchar *p;
1507 gchar **cache_push = NULL;
1508 gint iter = 0;
1509 gchar *import = NULL;
1510 gint cmd_iterations = -1;
1511 gint default_timeout;
1512 gint rcfile_spec = 0;
1513 gint estatus = EXIT_FAILURE;
1514 gint sockfd;
1515 #ifndef MEM_DEBUG
1516 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1517 #endif
1518 gint do_unlink = 1;
1519 gboolean secure = FALSE;
1520 guint ptotal = 0;
1521 gint background = 0;
1522 sigset_t set;
1523 #ifndef DEBUG
1524 #ifdef HAVE_SETRLIMIT
1525 struct rlimit rl;
1527 rl.rlim_cur = rl.rlim_max = 0;
1529 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1530 err(EXIT_FAILURE, "setrlimit()");
1531 #endif
1532 #endif
1534 #ifdef ENABLE_NLS
1535 setlocale(LC_ALL, "");
1536 bindtextdomain("pwmd", LOCALEDIR);
1537 textdomain("pwmd");
1538 #endif
1540 gpg_err_init();
1541 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1542 #ifndef MEM_DEBUG
1543 g_mem_set_vtable(&mtable);
1544 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1545 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1546 xmlInitMemory();
1547 #endif
1548 pth_init();
1549 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1551 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1552 err(EXIT_FAILURE, "%s", buf);
1554 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1556 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1557 err(EXIT_FAILURE, "%s", buf);
1559 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1561 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1562 err(EXIT_FAILURE, "sysconf()");
1564 cache_size = page_size;
1566 while ((opt = getopt(argc, argv, "bI:i:hvf:D")) != EOF) {
1567 switch (opt) {
1568 case 'b':
1569 background = 1;
1570 break;
1571 case 'D':
1572 secure = TRUE;
1573 break;
1574 case 'I':
1575 import = optarg;
1576 break;
1577 case 'i':
1578 cmd_iterations = atoi(optarg);
1579 break;
1580 case 'f':
1581 g_free(rcfile);
1582 rcfile = g_strdup(optarg);
1583 rcfile_spec = 1;
1584 break;
1585 case 'v':
1586 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1587 exit(EXIT_SUCCESS);
1588 case 'h':
1589 default:
1590 usage(argv[0]);
1594 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1595 exit(EXIT_FAILURE);
1597 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1598 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1600 if (log_syslog == TRUE)
1601 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1603 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1604 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1606 #ifdef HAVE_MLOCKALL
1607 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1608 warn("mlockall()");
1609 goto do_exit;
1611 #endif
1613 setup_gcrypt();
1615 if (import) {
1616 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1617 g_key_file_free(keyfileh);
1618 g_free(rcfile);
1619 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1622 g_key_file_set_list_separator(keyfileh, ',');
1624 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1625 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1627 if (*p == '~') {
1628 p++;
1629 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1630 g_free(p);
1631 socketarg = g_strdup(buf);
1633 else
1634 socketarg = p;
1636 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1637 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1639 datadir = expand_homedir(p);
1640 g_free(p);
1642 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1643 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1644 disable_list_and_dump = n;
1646 else
1647 disable_list_and_dump = secure;
1649 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1650 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1651 else
1652 default_timeout = -1;
1654 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1655 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1657 if (cache_size < page_size || cache_size % page_size)
1658 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1661 setup_logging(keyfileh);
1663 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1664 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1666 if (argc != optind) {
1667 if (cache_push)
1668 ptotal = g_strv_length(cache_push);
1670 for (; optind < argc; optind++) {
1671 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1672 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1676 if (strchr(socketarg, '/') == NULL) {
1677 socketdir = g_get_current_dir();
1678 socketname = g_strdup(socketarg);
1679 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1681 else {
1682 socketname = g_strdup(strrchr(socketarg, '/'));
1683 socketname++;
1684 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1685 socketdir = g_strdup(socketarg);
1686 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1689 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1690 #ifdef MMAP_ANONYMOUS
1691 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1692 #else
1693 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1694 #endif
1695 err(EXIT_FAILURE, "mmap()");
1698 if (mlock(key_cache, cache_size) == -1)
1699 log_write("mlock(): %s", strerror(errno));
1701 memset(key_cache, 0, cache_size);
1703 if (chdir(datadir)) {
1704 warn("%s", datadir);
1705 unlink(socketpath);
1706 goto do_exit;
1709 if (parse_keyfile_key() == FALSE)
1710 goto do_exit;
1712 clear_errorfile_key();
1715 * Set the cache entry for a file. Prompts for the password.
1717 if (cache_push) {
1718 for (opt = 0; cache_push[opt]; opt++)
1719 do_cache_push(cache_push[opt], NULL);
1721 g_strfreev(cache_push);
1722 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1726 * bind() doesn't like the full pathname of the socket or any non alphanum
1727 * characters so change to the directory where the socket is wanted then
1728 * create it then change to datadir.
1730 if (chdir(socketdir)) {
1731 warn("%s", socketdir);
1732 goto do_exit;
1735 g_free(socketdir);
1737 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1738 warn("socket()");
1739 goto do_exit;
1742 addr.sun_family = AF_UNIX;
1743 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1745 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1746 warn("bind()");
1748 if (errno == EADDRINUSE)
1749 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1750 "stale socket. Please remove it manually."), socketpath);
1752 do_unlink = 0;
1753 goto do_exit;
1756 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1757 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1758 mode_t mode = strtol(t, NULL, 8);
1759 mode_t mask = umask(0);
1761 g_free(t);
1763 if (chmod(socketname, mode) == -1) {
1764 warn("%s", socketname);
1765 close(sockfd);
1766 unlink(socketpath);
1767 umask(mask);
1768 goto do_exit;
1771 umask(mask);
1774 g_free(--socketname);
1776 if (chdir(datadir)) {
1777 warn("%s", datadir);
1778 close(sockfd);
1779 unlink(socketpath);
1780 goto do_exit;
1783 g_free(datadir);
1784 pth_mutex_init(&cache_mutex);
1785 #ifdef WITH_PINENTRY
1786 pth_mutex_init(&pin_mutex);
1787 #endif
1789 if (listen(sockfd, 0) == -1) {
1790 warn("listen()");
1791 goto do_exit;
1794 if (background) {
1795 switch (fork()) {
1796 case -1:
1797 warn("fork()");
1798 goto do_exit;
1799 case 0:
1800 close(0);
1801 close(1);
1802 close(2);
1803 setsid();
1804 break;
1805 default:
1806 exit(EXIT_SUCCESS);
1811 * These are the signals that we use in threads. libpth can catch signals
1812 * itself so ignore them everywhere else. Note that using
1813 * signal(N, SIG_IGN) doesn't work like you might think.
1815 sigemptyset(&set);
1817 /* Termination */
1818 sigaddset(&set, SIGTERM);
1819 sigaddset(&set, SIGINT);
1821 /* Configuration file reloading. */
1822 sigaddset(&set, SIGUSR1);
1824 /* Clears the file cache. */
1825 sigaddset(&set, SIGHUP);
1827 /* Caught in client_thread(). Sends a cache status message. */
1828 sigaddset(&set, SIGUSR2);
1830 /* Ignored everywhere. When a client disconnects abnormally this signal
1831 * gets raised. It isn't needed though because client_thread() will check
1832 * for rcs even after the client disconnects. */
1833 signal(SIGPIPE, SIG_IGN);
1834 pth_sigmask(SIG_BLOCK, &set, NULL);
1835 server_loop(sockfd, &socketpath);
1836 estatus = EXIT_SUCCESS;
1838 do_exit:
1839 if (socketpath && do_unlink) {
1840 unlink(socketpath);
1841 g_free(socketpath);
1844 g_key_file_free(keyfileh);
1845 g_free(rcfile);
1846 xmlCleanupParser();
1848 if (key_cache) {
1849 cache_clear(NULL, 2);
1850 memset(key_cache, 0, cache_size);
1853 if (key_cache && munmap(key_cache, cache_size) == -1)
1854 log_write("munmap(): %s", strerror(errno));
1856 if (estatus == EXIT_SUCCESS)
1857 log_write(N_("pwmd exiting normally"));
1859 pth_kill();
1860 #if defined(DEBUG) && !defined(MEM_DEBUG)
1861 xdump();
1862 #endif
1863 exit(estatus);