Send the total number of iterations with the ENCRYPT and DECRYPT
[pwmd.git] / src / pwmd.c
blob6b1a65f39629c5146c8f87b74187c9eebd76cbea
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());
170 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
171 name = "unknown";
173 pth_attr_destroy(attr);
175 if (log_syslog == TRUE)
176 syslog(LOG_INFO, "%s: %s", name, args);
178 va_end(ap);
179 time(&now);
180 tm = localtime(&now);
181 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
182 tbuf[sizeof(tbuf) - 1] = 0;
184 if (args[strlen(args)-1] == '\n')
185 args[strlen(args)-1] = 0;
187 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
188 g_free(args);
190 if (!line) {
191 if (logfile)
192 close(fd);
194 return;
197 if (logfile) {
198 write(fd, line, strlen(line));
199 fsync(fd);
200 close(fd);
203 if (isatty(STDERR_FILENO)) {
204 fprintf(stderr, "%s", line);
205 fflush(stderr);
208 g_free(line);
211 static void usage(gchar *pn)
213 g_printf(N_(
214 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename> [-i <iter>] [file1] [...]\n"
215 " -b run as a background process\n"
216 " -f load the specified rcfile (~/.pwmd/config)\n"
217 " -I import an XML file and write the encrypted data to stdout\n"
218 " -i encrypt with the specified number of iterations when importing\n"
219 " (config default in the \"global\" section)\n"
220 " -D disable use of the LIST and DUMP commands\n"
221 " -v version\n"
222 " -h this help text\n"
223 ), pn);
224 exit(EXIT_SUCCESS);
227 #ifndef MEM_DEBUG
228 static int gcry_SecureCheck(const void *ptr)
230 return 1;
232 #endif
234 static void setup_gcrypt()
236 gcry_check_version(NULL);
238 #ifndef MEM_DEBUG
239 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
240 xfree);
241 #endif
243 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
244 NULL) != 0)
245 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
247 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
248 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
251 static assuan_context_t new_connection(gint fd)
253 gpg_error_t rc;
254 gchar ver[ASSUAN_LINELENGTH];
255 assuan_context_t ctx;
257 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
259 if (rc)
260 goto fail;
262 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
263 assuan_set_hello_line(ctx, ver);
264 assuan_register_post_cmd_notify(ctx, command_finalize);
265 rc = register_commands(ctx);
267 if (rc)
268 goto fail;
270 rc = assuan_accept(ctx);
272 if (rc)
273 goto fail;
275 return ctx;
277 fail:
278 assuan_deinit_server(ctx);
279 log_write("%s", gpg_strerror(rc));
280 return NULL;
283 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
285 gchar *line = NULL;
286 struct client_s *client = assuan_get_pointer(ctx);
287 gchar buf[ASSUAN_LINELENGTH];
288 gchar *status = NULL;
290 switch (which) {
291 case STATUS_CACHE:
292 CACHE_LOCK(client->ctx);
293 line = print_fmt(buf, sizeof(buf), "%i %i",
294 cache_file_count(),
295 (cache_size / sizeof(file_cache_t)) - cache_file_count());
296 CACHE_UNLOCK;
297 status = "CACHE";
298 break;
299 case STATUS_CLIENTS:
300 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
301 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
302 pth_mutex_release(&cn_mutex);
303 status = "CLIENTS";
304 break;
305 case STATUS_CONFIG:
306 status = "CONFIG";
307 break;
308 case STATUS_KEEPALIVE:
309 status = "KEEPALIVE";
310 break;
311 case STATUS_LOCKED:
312 status = "LOCKED";
313 line = N_("Waiting for lock");
314 break;
317 return assuan_write_status(ctx, status, line);
320 void send_status_all(status_msg_t which)
322 guint i, t;
324 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
326 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
327 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
328 pth_msgport_t m = pth_msgport_find(cn->msg_name);
330 if (m) {
331 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
333 msg->m_data = (status_msg_t *)which;
334 pth_msgport_put(m, msg);
338 pth_mutex_release(&cn_mutex);
341 static void xml_error_cb(void *data, xmlErrorPtr e)
343 struct client_s *client = data;
346 * Keep the first reported error as the one to show. Reset in
347 * send_error().
349 if (client->xml_error)
350 return;
352 xmlCopyError(e, client->xml_error);
356 * This is called after a child_thread terminates. Set with
357 * pth_cleanup_push().
359 static void cleanup_cb(void *arg)
361 struct client_thread_s *cn = arg;
362 gpointer value;
363 struct client_s *cl = cn->cl;
365 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
366 log_write(N_("exiting, fd=%i"), cn->fd);
367 pth_join(cn->tid, &value);
369 if (cl && cl->freed == FALSE)
370 cleanup_assuan(cl->ctx);
372 if (cl && cl->ctx)
373 assuan_deinit_server(cl->ctx);
375 #ifdef WITH_PINENTRY
376 if (cl && cl->pinentry)
377 cleanup_pinentry(cl->pinentry);
378 #endif
380 g_free(cl);
382 if (cn->msg_name)
383 g_free(cn->msg_name);
385 if (cn->msg) {
386 while (pth_msgport_pending(cn->msg) > 0) {
387 pth_message_t *m = pth_msgport_get(cn->msg);
389 g_free(m);
392 pth_msgport_destroy(cn->msg);
395 cn_thread_list = g_slist_remove(cn_thread_list, cn);
396 g_free(cn);
397 pth_mutex_release(&cn_mutex);
398 send_status_all(STATUS_CLIENTS);
402 * Called every time a connection is made via pth_spawn(). This is the thread
403 * entry point.
405 static void *client_thread(void *data)
407 struct client_thread_s *thd = data;
408 gint fd = thd->fd;
409 pth_event_t ev, msg_ev;
410 #ifdef WITH_PINENTRY
411 pth_event_t pinentry_ev = NULL;
412 #endif
413 struct client_s *cl = g_malloc0(sizeof(struct client_s));
414 gpg_error_t rc;
416 if (!cl) {
417 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
418 goto fail;
421 #ifdef WITH_PINENTRY
422 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
424 if (!cl->pinentry) {
425 g_free(cl);
426 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
427 goto fail;
430 set_pinentry_defaults(cl->pinentry);
431 #endif
432 thd->cl = cl;
433 cl->thd = thd;
434 pth_cleanup_push(cleanup_cb, thd);
435 thd->msg_name = g_strdup_printf("%p", thd->tid);
437 if (!thd->msg_name) {
438 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
439 goto fail;
442 thd->msg = pth_msgport_create(thd->msg_name);
444 if (!thd->msg) {
445 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
446 goto fail;
450 * This is a "child" thread. Don't catch any signals. Let the master
451 * thread take care of signals in server_loop().
453 cl->ctx = new_connection(fd);
454 cl->fd = fd;
456 if (!cl->ctx)
457 goto fail;
459 assuan_set_pointer(cl->ctx, cl);
461 #ifdef HAVE_MLOCKALL
462 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
463 log_write("mlockall(): %s", strerror(errno));
464 goto fail;
466 #endif
468 rc = send_status(cl->ctx, STATUS_CACHE);
470 if (rc) {
471 log_write("%s", gpg_strerror(rc));
472 goto fail;
475 send_status_all(STATUS_CLIENTS);
476 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
477 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
478 pth_event_concat(ev, msg_ev, NULL);
479 xmlInitParser();
480 xmlXPathInit();
481 xmlSetStructuredErrorFunc(cl, xml_error_cb);
483 for (;;) {
484 pth_wait(ev);
485 pth_event_isolate(ev);
486 pth_event_isolate(msg_ev);
488 if (pth_event_occurred(msg_ev)) {
489 pth_event_free(msg_ev, PTH_FREE_THIS);
491 while (pth_msgport_pending(thd->msg) > 0) {
492 pth_message_t *m = pth_msgport_get(thd->msg);
493 status_msg_t n = (status_msg_t)m->m_data;
495 rc = send_status(cl->ctx, n);
496 g_free(m);
498 if (rc) {
499 log_write("%s", gpg_strerror(rc));
500 goto done;
504 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
507 pth_event_concat(ev, msg_ev, NULL);
509 if (pth_event_occurred(ev)) {
510 rc = assuan_process_next(cl->ctx);
512 if (rc) {
513 cl->inquire_status = INQUIRE_INIT;
515 if (gpg_err_code(rc) == GPG_ERR_EOF)
516 goto done;
518 log_write("assuan_process_next(): %s", gpg_strerror(rc));
519 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
521 if (rc) {
522 log_write("assuan_process_done(): %s", gpg_strerror(rc));
523 goto done;
526 else {
527 #ifdef WITH_PINENTRY
528 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
529 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
530 pth_event_concat(ev, pinentry_ev, NULL);
531 cl->pinentry->status = PINENTRY_RUNNING;
533 #endif
535 switch (cl->inquire_status) {
536 case INQUIRE_BUSY:
537 case INQUIRE_INIT:
538 break;
539 case INQUIRE_DONE:
540 cl->inquire_status = INQUIRE_INIT;
541 rc = assuan_process_done(cl->ctx, 0);
542 break;
547 #ifdef WITH_PINENTRY
548 if (cl->pinentry->status == PINENTRY_RUNNING) {
549 pth_event_isolate(pinentry_ev);
551 if (pth_event_occurred(pinentry_ev)) {
552 guchar shakey[gcrykeysize];
553 pinentry_key_s pk;
554 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
555 gint status;
557 pth_event_free(pinentry_ev, PTH_FREE_THIS);
558 pinentry_ev = NULL;
559 cl->pinentry->status = PINENTRY_NONE;
561 if (len == sizeof(pk)) {
562 if (pk.error)
563 rc = send_error(cl->ctx, pk.error);
564 else {
565 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
566 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
567 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
568 memset(shakey, 0, sizeof(shakey));
571 else if (len == -1)
572 log_write("%s", strerror(errno));
573 else if (len == 0)
574 log_write("pth_read(): EOF");
575 else
576 log_write(N_("pth_read(): short byte count"));
578 pth_waitpid(cl->pinentry->pid, &status, 0);
579 close(cl->pinentry->fd);
580 cl->pinentry->fd = -1;
581 cl->pinentry->pid = 0;
583 if (pk.error && cl->pinentry->which == PINENTRY_OPEN)
584 cleanup_client(cl);
585 else
586 unlock_file_mutex(cl);
588 memset(&pk, 0, sizeof(pk));
589 unlock_pin_mutex(cl->pinentry);
592 pth_event_concat(ev, pinentry_ev, NULL);
594 #endif
598 * Client cleanup (including XML data) is done in remove_connection() from
599 * the cleanup thread.
601 done:
602 pth_event_free(ev, PTH_FREE_ALL);
604 fail:
605 pth_exit(NULL);
606 return NULL;
609 static void setup_logging(GKeyFile *kf)
611 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
613 if (n == TRUE) {
614 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
616 if (*p == '~') {
617 gchar buf[PATH_MAX];
619 p++;
620 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
621 g_free(p);
623 if (logfile)
624 g_free(logfile);
626 logfile = g_strdup(buf);
628 else {
629 if (logfile)
630 g_free(logfile);
632 logfile = p;
636 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
640 * Make sure all settings are set to either the specified setting or a
641 * default.
643 static void set_rcfile_defaults(GKeyFile *kf)
645 gchar buf[PATH_MAX];
647 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
648 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
649 g_key_file_set_string(kf, "global", "socket_path", buf);
652 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
653 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
654 g_key_file_set_string(kf, "global", "data_directory", buf);
657 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
658 g_key_file_set_boolean(kf, "global", "backup", TRUE);
660 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
661 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
662 g_key_file_set_string(kf, "global", "log_path", buf);
665 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
666 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
668 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
669 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
671 #ifdef HAVE_MLOCKALL
672 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
673 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
674 #endif
676 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
677 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
679 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
680 g_key_file_set_integer(kf, "global", "iterations", 0);
682 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
683 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
685 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
686 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
688 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
689 g_key_file_set_integer(kf, "global", "compression_level", 6);
691 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
692 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
694 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
695 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
697 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
699 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
700 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
702 #ifdef HAVE_MLOCKALL
703 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
704 #endif
706 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
707 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
709 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
710 g_key_file_set_integer(kf, "global", "keepalive", 30);
712 #ifdef WITH_PINENTRY
713 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
714 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
715 #endif
717 setup_logging(kf);
720 static GKeyFile *parse_rcfile(int cmdline)
722 GKeyFile *kf = g_key_file_new();
723 GError *rc = NULL;
725 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
726 log_write("%s: %s", rcfile, rc->message);
728 if (cmdline)
729 exit(EXIT_FAILURE);
731 if (rc->code == G_FILE_ERROR_NOENT) {
732 g_clear_error(&rc);
733 set_rcfile_defaults(kf);
734 return kf;
737 g_clear_error(&rc);
738 return NULL;
740 else
741 set_rcfile_defaults(kf);
743 return kf;
746 static gchar *get_password(const gchar *prompt)
748 gchar buf[LINE_MAX] = {0}, *p;
749 struct termios told, tnew;
750 gchar *key;
752 if (tcgetattr(STDIN_FILENO, &told) == -1)
753 err(EXIT_FAILURE, "tcgetattr()");
755 memcpy(&tnew, &told, sizeof(struct termios));
756 tnew.c_lflag &= ~(ECHO);
757 tnew.c_lflag |= ICANON|ECHONL;
759 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
760 tcsetattr(STDIN_FILENO, TCSANOW, &told);
761 err(EXIT_FAILURE, "tcsetattr()");
764 fprintf(stderr, "%s", prompt);
766 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
767 tcsetattr(STDIN_FILENO, TCSANOW, &told);
768 return NULL;
771 tcsetattr(STDIN_FILENO, TCSANOW, &told);
772 p[strlen(p) - 1] = 0;
774 if (!buf[0]) {
775 key = gcry_malloc(1);
776 key[0] = 0;
778 else {
779 key = gcry_malloc(strlen(p) + 1);
780 sprintf(key, "%s", p);
783 memset(&buf, 0, sizeof(buf));
784 return key;
787 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
789 int fd;
790 struct stat st;
791 gpg_error_t rc;
792 gint iter;
794 if ((fd = open_file(filename, &st)) == -1) {
795 warn("%s", filename);
796 return FALSE;
799 if (st.st_size == 0) {
800 warnx(N_("%s: skipping empty file"), filename);
801 close(fd);
802 return FALSE;
805 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
806 close(fd);
807 return rc ? FALSE : TRUE;
810 static gboolean get_input(const gchar *filename, guchar *key)
812 gint try = 0;
813 gchar *password;
814 gchar *prompt;
816 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
818 again:
819 if ((password = get_password(prompt)) == NULL) {
820 warnx(N_("%s: skipping file"), filename);
821 g_free(prompt);
822 return FALSE;
825 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
826 gcry_free(password);
828 if (do_try_xml_decrypt(filename, key) == FALSE) {
829 if (try++ == 2) {
830 warnx(N_("%s: invalid password, skipping"), filename);
831 g_free(prompt);
832 return FALSE;
834 else {
835 warnx(N_("%s: invalid password"), filename);
836 goto again;
840 g_free(prompt);
841 return TRUE;
844 static gboolean xml_import(const gchar *filename, gint iter)
846 xmlDocPtr doc;
847 gint fd;
848 struct stat st;
849 gint len;
850 xmlChar *xmlbuf;
851 xmlChar *xml;
852 gchar *key = NULL;
853 gchar *key2 = NULL;
854 guchar shakey[gcrykeysize];
855 gcry_cipher_hd_t gh;
856 gpg_error_t rc;
857 gint level;
858 glong outsize;
859 gpointer outbuf;
860 gint zrc;
862 if (stat(filename, &st) == -1) {
863 warn("%s", filename);
864 return FALSE;
867 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
868 send_error(NULL, rc);
869 gcry_cipher_close(gh);
870 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
871 return FALSE;
874 if (iter == -1)
875 goto done;
877 if ((key = get_password(N_("New password: "))) == NULL) {
878 fprintf(stderr, "%s\n", N_("Invalid password."));
879 gcry_cipher_close(gh);
880 return FALSE;
883 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
884 fprintf(stderr, "%s\n", N_("Passwords do not match."));
885 gcry_free(key);
886 gcry_cipher_close(gh);
887 return FALSE;
890 if (g_utf8_collate(key, key2) != 0) {
891 fprintf(stderr, "%s\n", N_("Passwords do not match."));
892 gcry_free(key);
893 gcry_free(key2);
894 gcry_cipher_close(gh);
895 return FALSE;
898 gcry_free(key2);
900 done:
901 if ((fd = open(filename, O_RDONLY)) == -1) {
902 gcry_free(key);
903 warn("%s", filename);
904 gcry_cipher_close(gh);
905 return FALSE;
908 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
909 gcry_free(key);
910 close(fd);
911 log_write("%s", strerror(ENOMEM));
912 gcry_cipher_close(gh);
913 return FALSE;
916 if (read(fd, xmlbuf, st.st_size) == -1) {
917 rc = errno;
918 close(fd);
919 gcry_free(key);
920 gcry_cipher_close(gh);
921 errno = rc;
922 err(EXIT_FAILURE, "read()");
925 close(fd);
926 xmlbuf[st.st_size] = 0;
929 * Make sure the document validates.
931 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
932 log_write("xmlReadDoc()");
933 close(fd);
934 gcry_free(key);
935 gcry_free(xmlbuf);
936 gcry_cipher_close(gh);
937 return FALSE;
940 gcry_free(xmlbuf);
941 xmlDocDumpMemory(doc, &xml, &len);
942 xmlFreeDoc(doc);
944 level = get_key_file_integer(filename, "compression_level");
946 if (level < 0)
947 level = 0;
949 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
950 memset(shakey, 0, sizeof(shakey));
951 gcry_free(xml);
953 if (zrc == Z_MEM_ERROR)
954 warnx("%s", strerror(ENOMEM));
955 else
956 warnx("do_compress() failed");
958 gcry_cipher_close(gh);
959 return FALSE;
961 else {
962 gcry_free(xml);
963 xml = outbuf;
964 len = outsize;
967 if (iter == -1)
968 memset(shakey, '!', sizeof(shakey));
969 else{
970 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
971 gcry_free(key);
974 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
975 gcry_cipher_close(gh);
977 if (rc) {
978 memset(shakey, 0, sizeof(shakey));
979 warnx("%s", gpg_strerror(rc));
980 return FALSE;
983 memset(shakey, 0, sizeof(shakey));
984 return TRUE;
987 gchar *get_key_file_string(const gchar *section, const gchar *what)
989 gchar *val = NULL;
990 GError *grc = NULL;
992 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
993 val = g_key_file_get_string(keyfileh, section, what, &grc);
995 if (grc) {
996 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
997 g_clear_error(&grc);
1000 else {
1001 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1002 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1004 if (grc) {
1005 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1006 g_clear_error(&grc);
1011 return val;
1014 gint get_key_file_integer(const gchar *section, const gchar *what)
1016 gint val = -1;
1017 GError *grc = NULL;
1019 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1020 val = g_key_file_get_integer(keyfileh, section, what, &grc);
1022 if (grc) {
1023 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1024 g_clear_error(&grc);
1027 else {
1028 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1029 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1031 if (grc) {
1032 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1033 g_clear_error(&grc);
1038 return val;
1041 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1043 gboolean val = FALSE;
1044 GError *grc = NULL;
1046 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1047 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1049 if (grc) {
1050 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1051 g_clear_error(&grc);
1054 else {
1055 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1056 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1058 if (grc) {
1059 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1060 g_clear_error(&grc);
1065 return val;
1068 static gboolean _getline(const gchar *file, gchar **result)
1070 FILE *fp;
1071 gchar buf[LINE_MAX] = {0}, *p;
1072 gchar *str = NULL;
1073 gint len;
1075 if ((fp = fopen(file, "r")) == NULL) {
1076 warn("%s", file);
1077 return FALSE;
1080 p = fgets(buf, sizeof(buf), fp);
1081 fclose(fp);
1082 len = strlen(buf);
1084 if (len && buf[len - 1] == '\n')
1085 buf[--len] = 0;
1087 str = gcry_malloc(len + 1);
1088 memcpy(str, buf, len ? len : 1);
1089 str[len] = 0;
1090 memset(&buf, 0, sizeof(buf));
1091 *result = str;
1092 return TRUE;
1095 static gboolean parse_keyfile_key()
1097 gsize n;
1098 gchar **groups;
1099 gchar **p;
1100 gchar *str;
1102 groups = g_key_file_get_groups(keyfileh, &n);
1104 for (p = groups; *p; p++) {
1105 GError *rc = NULL;
1107 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1108 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1110 if (!str) {
1111 if (rc) {
1112 warnx("%s", rc->message);
1113 g_clear_error(&rc);
1116 continue;
1119 do_cache_push(*p, str);
1120 g_free(str);
1121 continue;
1124 if (rc) {
1125 warnx("%s", rc->message);
1126 g_clear_error(&rc);
1127 continue;
1130 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1131 gchar *t;
1132 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1134 if (!file) {
1135 if (rc) {
1136 warnx("%s", rc->message);
1137 g_clear_error(&rc);
1140 continue;
1143 t = expand_homedir(file);
1144 g_free(file);
1145 file = t;
1147 if (_getline(file, &str) == FALSE) {
1148 g_free(file);
1149 continue;
1152 g_free(file);
1153 do_cache_push(*p, str);
1154 gcry_free(str);
1155 continue;
1158 if (rc) {
1159 warnx("%s", rc->message);
1160 g_clear_error(&rc);
1164 g_strfreev(groups);
1165 return TRUE;
1168 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1170 guchar *md5file;
1171 guchar *key;
1172 gint timeout;
1173 const gchar *p = filename;
1174 file_header_t file_header;
1175 gpg_error_t rc;
1177 while (isspace(*p))
1178 p++;
1180 if (!*p)
1181 return FALSE;
1183 if (valid_filename(p) == FALSE) {
1184 warnx(N_("%s: invalid characters in filename"), p);
1185 return FALSE;
1188 md5file = gcry_malloc(16);
1189 key = gcry_malloc(gcrykeysize);
1190 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1192 if (cache_iscached(md5file) == TRUE) {
1193 warnx(N_("%s: file already cached, skipping"), p);
1194 gcry_free(md5file);
1195 gcry_free(key);
1196 return FALSE;
1199 if (access(p, R_OK|W_OK) != 0) {
1200 gcry_free(md5file);
1201 gcry_free(key);
1203 if (errno != ENOENT) {
1204 warn("%s", p);
1205 return FALSE;
1208 warn("%s", p);
1209 return TRUE;
1212 rc = read_file_header(filename, &file_header);
1214 if (rc) {
1215 gcry_free(md5file);
1216 gcry_free(key);
1217 warnx("%s", pwmd_strerror(rc));
1218 return FALSE;
1221 if (file_header.iter == -1) {
1222 memset(key, '!', gcrykeysize);
1223 goto try_decrypt;
1226 if (!password) {
1227 #ifdef WITH_PINENTRY
1228 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1229 #endif
1230 if (get_input(p, key) == FALSE) {
1231 gcry_free(key);
1232 gcry_free(md5file);
1233 return FALSE;
1235 #ifdef WITH_PINENTRY
1237 else {
1238 gchar *result = NULL;
1239 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1240 gint try = 0;
1242 pin->which = PINENTRY_OPEN;
1243 pin->filename = g_strdup(filename);
1244 again:
1245 rc = pinentry_getpin(pin, &result);
1247 if (rc) {
1248 warnx("%s: %s", filename, gpg_strerror(rc));
1249 cleanup_pinentry(pin);
1250 gcry_free(key);
1251 gcry_free(md5file);
1252 xfree(result);
1253 return FALSE;
1256 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1257 xfree(result);
1259 if (do_try_xml_decrypt(filename, key) == FALSE) {
1260 if (try++ == 2) {
1261 cleanup_pinentry(pin);
1262 gcry_free(key);
1263 gcry_free(md5file);
1264 warnx(N_("%s: invalid password, skipping"), filename);
1265 return FALSE;
1267 else {
1268 g_free(pin->title);
1269 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1270 goto again;
1274 cleanup_pinentry(pin);
1276 #endif
1278 else {
1279 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1281 try_decrypt:
1282 if (do_try_xml_decrypt(filename, key) == FALSE) {
1283 warnx(N_("%s: invalid password, skipping"), filename);
1284 gcry_free(key);
1285 gcry_free(md5file);
1286 return FALSE;
1290 if (cache_add_file(md5file, key) == FALSE) {
1291 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1292 gcry_free(key);
1293 gcry_free(md5file);
1294 return FALSE;
1297 timeout = get_key_file_integer(p, "cache_timeout");
1298 cache_set_timeout(md5file, timeout);
1299 warnx(N_("%s: file added to the cache"), filename);
1300 gcry_free(key);
1301 gcry_free(md5file);
1302 return TRUE;
1305 static void *accept_thread(void *arg)
1307 gint sockfd = (gint)arg;
1309 for (;;) {
1310 socklen_t slen = sizeof(struct sockaddr_un);
1311 struct sockaddr_un raddr;
1312 gint fd = -1;
1313 pth_attr_t attr;
1315 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1316 if (errno != EAGAIN) {
1317 if (!quit) // probably EBADF
1318 log_write("accept(): %s", strerror(errno));
1320 break;
1324 if (fd >= 0) {
1325 pth_t tid;
1326 struct client_thread_s *new;
1327 gchar buf[41];
1329 new = g_malloc0(sizeof(struct client_thread_s));
1331 if (!new) {
1332 log_write("%s", strerror(ENOMEM));
1333 continue;
1337 * Thread priority is inherited from the calling thread. This
1338 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1339 * priority.
1341 new->fd = fd;
1342 attr = pth_attr_new();
1343 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1344 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1345 tid = pth_spawn(attr, client_thread, new);
1346 pth_attr_destroy(attr);
1348 if (!tid) {
1349 g_free(new);
1350 log_write(N_("pth_spawn() failed"));
1351 continue;
1354 g_snprintf(buf, sizeof(buf), "%p", tid);
1355 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1356 attr = pth_attr_of(tid);
1357 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1358 pth_attr_destroy(attr);
1359 new->tid = tid;
1360 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1361 cn_thread_list = g_slist_append(cn_thread_list, new);
1362 pth_mutex_release(&cn_mutex);
1366 /* Just in case pth_accept() failed for some reason other than EBADF */
1367 quit = 1;
1368 pth_exit(PTH_CANCELED);
1369 return NULL;
1373 * This thread isn't joinable. For operations that block, these threads will
1374 * stack.
1376 static void *adjust_timer_thread(void *arg)
1378 CACHE_LOCK(NULL);
1379 cache_adjust_timer();
1380 CACHE_UNLOCK;
1381 return NULL;
1384 static void server_loop(gint sockfd, gchar **socketpath)
1386 pth_t accept_tid;
1387 guint n;
1388 sigset_t set;
1389 gint n_clients = 0;
1390 pth_attr_t attr;
1391 pth_event_t timeout_ev, keepalive_ev = NULL;
1392 gint keepalive = get_key_file_integer("global", "keepalive");
1393 gpointer value;
1395 pth_mutex_init(&cn_mutex);
1396 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1398 sigemptyset(&set);
1399 sigaddset(&set, SIGTERM);
1400 sigaddset(&set, SIGINT);
1401 sigaddset(&set, SIGUSR1);
1402 sigaddset(&set, SIGHUP);
1403 sigaddset(&set, SIGABRT);
1405 attr = pth_attr_new();
1406 pth_attr_init(attr);
1407 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1408 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1409 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1412 * For the cache_timeout configuration parameter. This replaces the old
1413 * SIGALRM stuff and is safer.
1415 timeout_ev = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1417 if (keepalive > 0) {
1418 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1419 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1422 pth_attr_init(attr);
1423 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1424 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1426 do {
1427 gint sig = 0;
1429 pth_sigwait_ev(&set, &sig, timeout_ev);
1430 pth_event_isolate(timeout_ev);
1431 pth_event_isolate(keepalive_ev);
1433 if (pth_event_occurred(timeout_ev)) {
1435 * The timer event has expired. Update the file cache. When the
1436 * cache mutex is locked and the timer expires again, the threads
1437 * will stack.
1439 pth_spawn(attr, adjust_timer_thread, NULL);
1440 pth_event_free(timeout_ev, PTH_FREE_THIS);
1441 timeout_ev= pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1444 * Just in case the configuration file has been reloaded.
1446 keepalive = get_key_file_integer("global", "keepalive");
1449 if (keepalive_ev && pth_event_occurred(keepalive_ev)) {
1450 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1451 keepalive_ev = NULL;
1452 send_status_all(STATUS_KEEPALIVE);
1454 if (keepalive > 0)
1455 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1458 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1460 if (sig > 0) {
1461 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1463 /* Caught a signal. */
1464 switch (sig) {
1465 case SIGUSR1:
1466 reload_rcfile();
1467 break;
1468 case SIGABRT:
1469 CACHE_LOCK(NULL);
1470 cache_clear(NULL, 2);
1471 CACHE_UNLOCK;
1472 #ifndef MEM_DEBUG
1473 xpanic();
1474 #endif
1475 exit(EXIT_FAILURE);
1476 case SIGHUP:
1477 CACHE_LOCK(NULL);
1478 log_write(N_("clearing file cache"));
1479 cache_clear(NULL, 2);
1480 CACHE_UNLOCK;
1481 break;
1482 default:
1483 quit = 1;
1484 shutdown(sockfd, SHUT_RDWR);
1485 close(sockfd);
1486 break;
1489 } while (!quit);
1492 * We're out of the main server loop. This happens when a signal was sent
1493 * to terminate the daemon. We'll wait for all clients to disconnect
1494 * before exiting and ignore any following signals.
1496 pth_join(accept_tid, &value);
1497 pth_attr_destroy(attr);
1498 pth_event_free(timeout_ev, PTH_FREE_THIS);
1499 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1500 unlink(*socketpath);
1501 g_free(*socketpath);
1502 *socketpath = NULL;
1504 if (n > 1)
1505 log_write(N_("waiting for all threads to terminate"));
1507 while (n > 1) {
1508 pth_event_t events;
1510 if (n != n_clients) {
1511 log_write(N_("%i threads remain"), n-1);
1512 n_clients = n;
1515 events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1516 pth_wait(events);
1517 pth_event_isolate(events);
1518 pth_event_free(events, PTH_FREE_THIS);
1519 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1524 * Called from pinentry_fork() in the child process.
1526 void free_client_list()
1528 gint i, t = g_slist_length(cn_thread_list);
1530 for (i = 0; i < t; i++) {
1531 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1533 free_client(cn->cl);
1536 memset(key_cache, 0, cache_size);
1539 int main(int argc, char *argv[])
1541 gint opt;
1542 struct sockaddr_un addr;
1543 struct passwd *pw = getpwuid(getuid());
1544 gchar buf[PATH_MAX];
1545 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1546 gchar *socketarg = NULL;
1547 gchar *datadir = NULL;
1548 gboolean n;
1549 gchar *p;
1550 gchar **cache_push = NULL;
1551 gint iter = 0;
1552 gchar *import = NULL;
1553 gint cmd_iterations = -1;
1554 gint default_timeout;
1555 gint rcfile_spec = 0;
1556 gint estatus = EXIT_FAILURE;
1557 gint sockfd;
1558 #ifndef MEM_DEBUG
1559 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1560 #endif
1561 gint do_unlink = 1;
1562 gboolean secure = FALSE;
1563 guint ptotal = 0;
1564 gint background = 0;
1565 sigset_t set;
1566 #ifndef DEBUG
1567 #ifdef HAVE_SETRLIMIT
1568 struct rlimit rl;
1570 rl.rlim_cur = rl.rlim_max = 0;
1572 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1573 err(EXIT_FAILURE, "setrlimit()");
1574 #endif
1575 #endif
1577 #ifdef ENABLE_NLS
1578 setlocale(LC_ALL, "");
1579 bindtextdomain("pwmd", LOCALEDIR);
1580 textdomain("pwmd");
1581 #endif
1583 gpg_err_init();
1584 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1585 #ifndef MEM_DEBUG
1586 g_mem_set_vtable(&mtable);
1587 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1588 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1589 xmlInitMemory();
1590 #endif
1591 pth_init();
1592 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1594 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1595 err(EXIT_FAILURE, "%s", buf);
1597 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1599 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1600 err(EXIT_FAILURE, "%s", buf);
1602 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1604 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1605 err(EXIT_FAILURE, "sysconf()");
1607 cache_size = page_size;
1609 while ((opt = getopt(argc, argv, "bI:i:hvf:D")) != EOF) {
1610 switch (opt) {
1611 case 'b':
1612 background = 1;
1613 break;
1614 case 'D':
1615 secure = TRUE;
1616 break;
1617 case 'I':
1618 import = optarg;
1619 break;
1620 case 'i':
1621 cmd_iterations = atoi(optarg);
1622 break;
1623 case 'f':
1624 g_free(rcfile);
1625 rcfile = g_strdup(optarg);
1626 rcfile_spec = 1;
1627 break;
1628 case 'v':
1629 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1630 exit(EXIT_SUCCESS);
1631 case 'h':
1632 default:
1633 usage(argv[0]);
1637 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1638 exit(EXIT_FAILURE);
1640 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1641 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1643 if (log_syslog == TRUE)
1644 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1646 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1647 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1649 #ifdef HAVE_MLOCKALL
1650 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1651 warn("mlockall()");
1652 goto do_exit;
1654 #endif
1656 setup_gcrypt();
1658 if (import) {
1659 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1660 g_key_file_free(keyfileh);
1661 g_free(rcfile);
1662 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1665 g_key_file_set_list_separator(keyfileh, ',');
1667 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1668 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1670 if (*p == '~') {
1671 p++;
1672 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1673 g_free(p);
1674 socketarg = g_strdup(buf);
1676 else
1677 socketarg = p;
1679 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1680 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1682 datadir = expand_homedir(p);
1683 g_free(p);
1685 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1686 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1687 disable_list_and_dump = n;
1689 else
1690 disable_list_and_dump = secure;
1692 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1693 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1694 else
1695 default_timeout = -1;
1697 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1698 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1700 if (cache_size < page_size || cache_size % page_size)
1701 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1704 setup_logging(keyfileh);
1706 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1707 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1709 if (argc != optind) {
1710 if (cache_push)
1711 ptotal = g_strv_length(cache_push);
1713 for (; optind < argc; optind++) {
1714 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1715 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1719 if (strchr(socketarg, '/') == NULL) {
1720 socketdir = g_get_current_dir();
1721 socketname = g_strdup(socketarg);
1722 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1724 else {
1725 socketname = g_strdup(strrchr(socketarg, '/'));
1726 socketname++;
1727 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1728 socketdir = g_strdup(socketarg);
1729 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1732 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1733 #ifdef MMAP_ANONYMOUS
1734 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1735 #else
1736 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1737 #endif
1738 err(EXIT_FAILURE, "mmap()");
1741 if (mlock(key_cache, cache_size) == -1)
1742 log_write("mlock(): %s", strerror(errno));
1744 memset(key_cache, 0, cache_size);
1746 if (chdir(datadir)) {
1747 warn("%s", datadir);
1748 unlink(socketpath);
1749 goto do_exit;
1752 if (parse_keyfile_key() == FALSE)
1753 goto do_exit;
1755 clear_errorfile_key();
1758 * Set the cache entry for a file. Prompts for the password.
1760 if (cache_push) {
1761 for (opt = 0; cache_push[opt]; opt++)
1762 do_cache_push(cache_push[opt], NULL);
1764 g_strfreev(cache_push);
1765 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1769 * bind() doesn't like the full pathname of the socket or any non alphanum
1770 * characters so change to the directory where the socket is wanted then
1771 * create it then change to datadir.
1773 if (chdir(socketdir)) {
1774 warn("%s", socketdir);
1775 goto do_exit;
1778 g_free(socketdir);
1780 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1781 warn("socket()");
1782 goto do_exit;
1785 addr.sun_family = AF_UNIX;
1786 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1788 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1789 warn("bind()");
1791 if (errno == EADDRINUSE)
1792 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1793 "stale socket. Please remove it manually."), socketpath);
1795 do_unlink = 0;
1796 goto do_exit;
1799 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1800 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1801 mode_t mode = strtol(t, NULL, 8);
1802 mode_t mask = umask(0);
1804 g_free(t);
1806 if (chmod(socketname, mode) == -1) {
1807 warn("%s", socketname);
1808 close(sockfd);
1809 unlink(socketpath);
1810 umask(mask);
1811 goto do_exit;
1814 umask(mask);
1817 g_free(--socketname);
1819 if (chdir(datadir)) {
1820 warn("%s", datadir);
1821 close(sockfd);
1822 unlink(socketpath);
1823 goto do_exit;
1826 g_free(datadir);
1827 pth_mutex_init(&cache_mutex);
1828 #ifdef WITH_PINENTRY
1829 pth_mutex_init(&pin_mutex);
1830 #endif
1832 if (listen(sockfd, 0) == -1) {
1833 warn("listen()");
1834 goto do_exit;
1837 if (background) {
1838 switch (fork()) {
1839 case -1:
1840 warn("fork()");
1841 goto do_exit;
1842 case 0:
1843 close(0);
1844 close(1);
1845 close(2);
1846 setsid();
1847 break;
1848 default:
1849 exit(EXIT_SUCCESS);
1854 * These are the signals that we use in threads. libpth can catch signals
1855 * itself so ignore them everywhere else. Note that using
1856 * signal(N, SIG_IGN) doesn't work like you might think.
1858 sigemptyset(&set);
1860 /* Termination */
1861 sigaddset(&set, SIGTERM);
1862 sigaddset(&set, SIGINT);
1864 /* Configuration file reloading. */
1865 sigaddset(&set, SIGUSR1);
1867 /* Clears the file cache. */
1868 sigaddset(&set, SIGHUP);
1870 /* Caught in client_thread(). Sends a cache status message. */
1871 sigaddset(&set, SIGUSR2);
1873 /* Ignored everywhere. When a client disconnects abnormally this signal
1874 * gets raised. It isn't needed though because client_thread() will check
1875 * for rcs even after the client disconnects. */
1876 signal(SIGPIPE, SIG_IGN);
1877 pth_sigmask(SIG_BLOCK, &set, NULL);
1878 server_loop(sockfd, &socketpath);
1879 estatus = EXIT_SUCCESS;
1881 do_exit:
1882 if (socketpath && do_unlink) {
1883 unlink(socketpath);
1884 g_free(socketpath);
1887 g_key_file_free(keyfileh);
1888 g_free(rcfile);
1889 xmlCleanupParser();
1891 if (key_cache) {
1892 cache_clear(NULL, 2);
1893 memset(key_cache, 0, cache_size);
1896 if (key_cache && munmap(key_cache, cache_size) == -1)
1897 log_write("munmap(): %s", strerror(errno));
1899 if (estatus == EXIT_SUCCESS)
1900 log_write(N_("pwmd exiting normally"));
1902 pth_kill();
1903 #if defined(DEBUG) && !defined(MEM_DEBUG)
1904 xdump();
1905 #endif
1906 exit(estatus);