Updated the FSF address in the copyright header.
[pwmd.git] / src / pwmd.c
bloba76deccd1718d3dd1f2eeea08efaf0a2012c6aa8
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 02110-1301 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 [-hvDn] [-f <rcfile>] [-I <filename> [-i <iter>]] [file1] [...]\n"
215 " -n run as a foreground 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 rc = register_commands(ctx);
266 if (rc)
267 goto fail;
269 rc = assuan_accept(ctx);
271 if (rc)
272 goto fail;
274 return ctx;
276 fail:
277 assuan_deinit_server(ctx);
278 log_write("%s", gpg_strerror(rc));
279 return NULL;
282 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
284 gchar *line = NULL;
285 struct client_s *client = assuan_get_pointer(ctx);
286 gchar buf[ASSUAN_LINELENGTH];
287 gchar *status = NULL;
289 switch (which) {
290 case STATUS_CACHE:
291 CACHE_LOCK(client->ctx);
292 line = print_fmt(buf, sizeof(buf), "%i %i",
293 cache_file_count(),
294 (cache_size / sizeof(file_cache_t)) - cache_file_count());
295 CACHE_UNLOCK;
296 status = "CACHE";
297 break;
298 case STATUS_CLIENTS:
299 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
300 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
301 pth_mutex_release(&cn_mutex);
302 status = "CLIENTS";
303 break;
304 case STATUS_CONFIG:
305 status = "CONFIG";
306 break;
307 case STATUS_KEEPALIVE:
308 status = "KEEPALIVE";
309 break;
310 case STATUS_LOCKED:
311 status = "LOCKED";
312 line = N_("Waiting for lock");
313 break;
316 return assuan_write_status(ctx, status, line);
319 void send_status_all(status_msg_t which)
321 guint i, t;
323 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
325 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
326 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
327 pth_msgport_t m = pth_msgport_find(cn->msg_name);
329 if (m) {
330 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
332 msg->m_data = (status_msg_t *)which;
333 pth_msgport_put(m, msg);
337 pth_mutex_release(&cn_mutex);
340 static void xml_error_cb(void *data, xmlErrorPtr e)
342 struct client_s *client = data;
345 * Keep the first reported error as the one to show in the error
346 * description. Reset in send_error().
348 if (client->xml_error)
349 return;
351 xmlCopyError(e, client->xml_error);
355 * This is called after a child_thread terminates. Set with
356 * pth_cleanup_push().
358 static void cleanup_cb(void *arg)
360 struct client_thread_s *cn = arg;
361 gpointer value;
362 struct client_s *cl = cn->cl;
364 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
365 log_write(N_("exiting, fd=%i"), cn->fd);
366 pth_join(cn->tid, &value);
368 if (cl && cl->freed == FALSE)
369 cleanup_assuan(cl->ctx);
371 if (cl && cl->ctx)
372 assuan_deinit_server(cl->ctx);
374 #ifdef WITH_PINENTRY
375 if (cl && cl->pinentry)
376 cleanup_pinentry(cl->pinentry);
377 #endif
379 g_free(cl);
381 if (cn->msg_name)
382 g_free(cn->msg_name);
384 if (cn->msg) {
385 while (pth_msgport_pending(cn->msg) > 0) {
386 pth_message_t *m = pth_msgport_get(cn->msg);
388 g_free(m);
391 pth_msgport_destroy(cn->msg);
394 cn_thread_list = g_slist_remove(cn_thread_list, cn);
395 g_free(cn);
396 pth_mutex_release(&cn_mutex);
397 send_status_all(STATUS_CLIENTS);
401 * Called every time a connection is made via pth_spawn(). This is the thread
402 * entry point.
404 static void *client_thread(void *data)
406 struct client_thread_s *thd = data;
407 gint fd = thd->fd;
408 pth_event_t ev, msg_ev;
409 struct client_s *cl = g_malloc0(sizeof(struct client_s));
410 gpg_error_t rc;
412 if (!cl) {
413 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
414 goto fail;
417 #ifdef WITH_PINENTRY
418 cl->pinentry = pinentry_init();
420 if (!cl->pinentry) {
421 g_free(cl);
422 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
423 goto fail;
425 #endif
427 thd->cl = cl;
428 cl->thd = thd;
429 pth_cleanup_push(cleanup_cb, thd);
430 thd->msg_name = g_strdup_printf("%p", thd->tid);
432 if (!thd->msg_name) {
433 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
434 goto fail;
437 thd->msg = pth_msgport_create(thd->msg_name);
439 if (!thd->msg) {
440 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
441 goto fail;
445 * This is a "child" thread. Don't catch any signals. Let the master
446 * thread take care of signals in accept_thread().
448 cl->ctx = new_connection(fd);
449 cl->fd = fd;
451 if (!cl->ctx)
452 goto fail;
454 assuan_set_pointer(cl->ctx, cl);
456 #ifdef HAVE_MLOCKALL
457 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
458 log_write("mlockall(): %s", strerror(errno));
459 goto fail;
461 #endif
463 rc = send_status(cl->ctx, STATUS_CACHE);
465 if (rc) {
466 log_write("%s", gpg_strerror(rc));
467 goto fail;
470 send_status_all(STATUS_CLIENTS);
471 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
472 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
473 pth_event_concat(ev, msg_ev, NULL);
474 xmlInitParser();
475 xmlXPathInit();
476 xmlSetStructuredErrorFunc(cl, xml_error_cb);
478 for (;;) {
479 pth_wait(ev);
480 pth_event_isolate(ev);
481 pth_event_isolate(msg_ev);
483 if (pth_event_occurred(msg_ev)) {
484 pth_event_free(msg_ev, PTH_FREE_THIS);
486 while (pth_msgport_pending(thd->msg) > 0) {
487 pth_message_t *m = pth_msgport_get(thd->msg);
488 status_msg_t n = (status_msg_t)m->m_data;
490 rc = send_status(cl->ctx, n);
491 g_free(m);
493 if (rc) {
494 log_write("%s", gpg_strerror(rc));
495 goto done;
499 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
502 pth_event_concat(ev, msg_ev, NULL);
504 if (pth_event_occurred(ev)) {
505 rc = assuan_process_next(cl->ctx);
507 if (rc) {
508 cl->inquire_status = INQUIRE_INIT;
510 if (gpg_err_code(rc) == GPG_ERR_EOF)
511 goto done;
513 log_write("assuan_process_next(): %s", gpg_strerror(rc));
514 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
516 if (rc) {
517 log_write("assuan_process_done(): %s", gpg_strerror(rc));
518 goto done;
521 else {
522 #ifdef WITH_PINENTRY
523 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
524 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
525 pth_event_concat(ev, cl->pinentry->ev, NULL);
526 cl->pinentry->status = PINENTRY_RUNNING;
528 #endif
530 switch (cl->inquire_status) {
531 case INQUIRE_BUSY:
532 case INQUIRE_INIT:
533 break;
534 case INQUIRE_DONE:
535 cl->inquire_status = INQUIRE_INIT;
536 rc = assuan_process_done(cl->ctx, 0);
537 break;
542 #ifdef WITH_PINENTRY
543 ev = pinentry_iterate(cl, ev);
544 #endif
548 * Client cleanup (including XML data) is done in cleanup_cb() from
549 * the cleanup thread.
551 done:
552 pth_event_free(ev, PTH_FREE_ALL);
554 fail:
555 pth_exit(NULL);
556 return NULL;
559 static void setup_logging(GKeyFile *kf)
561 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
563 if (n == TRUE) {
564 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
566 if (*p == '~') {
567 gchar buf[PATH_MAX];
569 p++;
570 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
571 g_free(p);
573 if (logfile)
574 g_free(logfile);
576 logfile = g_strdup(buf);
578 else {
579 if (logfile)
580 g_free(logfile);
582 logfile = p;
586 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
590 * Make sure all settings are set to either the specified setting or a
591 * default.
593 static void set_rcfile_defaults(GKeyFile *kf)
595 gchar buf[PATH_MAX];
597 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
598 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
599 g_key_file_set_string(kf, "global", "socket_path", buf);
602 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
603 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
604 g_key_file_set_string(kf, "global", "data_directory", buf);
607 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
608 g_key_file_set_boolean(kf, "global", "backup", TRUE);
610 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
611 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
612 g_key_file_set_string(kf, "global", "log_path", buf);
615 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
616 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
618 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
619 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
621 #ifdef HAVE_MLOCKALL
622 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
623 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
624 #endif
626 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
627 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
629 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
630 g_key_file_set_integer(kf, "global", "iterations", 0);
632 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
633 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
635 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
636 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
638 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
639 g_key_file_set_integer(kf, "global", "compression_level", 6);
641 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
642 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
644 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
645 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
647 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
649 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
650 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
652 #ifdef HAVE_MLOCKALL
653 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
654 #endif
656 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
657 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
659 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
660 g_key_file_set_integer(kf, "global", "keepalive", 30);
662 #ifdef WITH_PINENTRY
663 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
664 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
666 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
667 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
668 #endif
670 setup_logging(kf);
673 static GKeyFile *parse_rcfile(int cmdline)
675 GKeyFile *kf = g_key_file_new();
676 GError *rc = NULL;
678 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
679 log_write("%s: %s", rcfile, rc->message);
681 if (cmdline)
682 exit(EXIT_FAILURE);
684 if (rc->code == G_FILE_ERROR_NOENT) {
685 g_clear_error(&rc);
686 set_rcfile_defaults(kf);
687 return kf;
690 g_clear_error(&rc);
691 return NULL;
693 else
694 set_rcfile_defaults(kf);
696 return kf;
699 static gchar *get_password(const gchar *prompt)
701 gchar buf[LINE_MAX] = {0}, *p;
702 struct termios told, tnew;
703 gchar *key;
705 if (tcgetattr(STDIN_FILENO, &told) == -1)
706 err(EXIT_FAILURE, "tcgetattr()");
708 memcpy(&tnew, &told, sizeof(struct termios));
709 tnew.c_lflag &= ~(ECHO);
710 tnew.c_lflag |= ICANON|ECHONL;
712 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
713 tcsetattr(STDIN_FILENO, TCSANOW, &told);
714 err(EXIT_FAILURE, "tcsetattr()");
717 fprintf(stderr, "%s", prompt);
719 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
720 tcsetattr(STDIN_FILENO, TCSANOW, &told);
721 return NULL;
724 tcsetattr(STDIN_FILENO, TCSANOW, &told);
725 p[strlen(p) - 1] = 0;
727 if (!buf[0]) {
728 key = gcry_malloc(1);
729 key[0] = 0;
731 else {
732 key = gcry_malloc(strlen(p) + 1);
733 sprintf(key, "%s", p);
736 memset(&buf, 0, sizeof(buf));
737 return key;
740 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
742 int fd;
743 struct stat st;
744 gpg_error_t rc;
745 gint iter;
747 if ((fd = open_file(filename, &st)) == -1) {
748 warn("%s", filename);
749 return FALSE;
752 if (st.st_size == 0) {
753 warnx(N_("%s: skipping empty file"), filename);
754 close(fd);
755 return FALSE;
758 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
759 close(fd);
760 return rc ? FALSE : TRUE;
763 static gboolean get_input(const gchar *filename, guchar *key)
765 gint try = 0;
766 gchar *password;
767 gchar *prompt;
769 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
771 again:
772 if ((password = get_password(prompt)) == NULL) {
773 warnx(N_("%s: skipping file"), filename);
774 g_free(prompt);
775 return FALSE;
778 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
779 gcry_free(password);
781 if (do_try_xml_decrypt(filename, key) == FALSE) {
782 if (try++ == 2) {
783 warnx(N_("%s: invalid password, skipping"), filename);
784 g_free(prompt);
785 return FALSE;
787 else {
788 warnx(N_("%s: invalid password"), filename);
789 goto again;
793 g_free(prompt);
794 return TRUE;
797 static gboolean xml_import(const gchar *filename, gint iter)
799 xmlDocPtr doc;
800 gint fd;
801 struct stat st;
802 gint len;
803 xmlChar *xmlbuf;
804 xmlChar *xml;
805 gchar *key = NULL;
806 gchar *key2 = NULL;
807 guchar shakey[gcrykeysize];
808 gcry_cipher_hd_t gh;
809 gpg_error_t rc;
810 gint level;
811 glong outsize;
812 gpointer outbuf;
813 gint zrc;
815 if (stat(filename, &st) == -1) {
816 warn("%s", filename);
817 return FALSE;
820 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
821 send_error(NULL, rc);
822 gcry_cipher_close(gh);
823 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
824 return FALSE;
827 if (iter == -1)
828 goto done;
830 if ((key = get_password(N_("New password: "))) == NULL) {
831 fprintf(stderr, "%s\n", N_("Invalid password."));
832 gcry_cipher_close(gh);
833 return FALSE;
836 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
837 fprintf(stderr, "%s\n", N_("Passwords do not match."));
838 gcry_free(key);
839 gcry_cipher_close(gh);
840 return FALSE;
843 if (g_utf8_collate(key, key2) != 0) {
844 fprintf(stderr, "%s\n", N_("Passwords do not match."));
845 gcry_free(key);
846 gcry_free(key2);
847 gcry_cipher_close(gh);
848 return FALSE;
851 gcry_free(key2);
853 done:
854 if ((fd = open(filename, O_RDONLY)) == -1) {
855 gcry_free(key);
856 warn("%s", filename);
857 gcry_cipher_close(gh);
858 return FALSE;
861 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
862 gcry_free(key);
863 close(fd);
864 log_write("%s", strerror(ENOMEM));
865 gcry_cipher_close(gh);
866 return FALSE;
869 if (read(fd, xmlbuf, st.st_size) == -1) {
870 rc = errno;
871 close(fd);
872 gcry_free(key);
873 gcry_cipher_close(gh);
874 errno = rc;
875 err(EXIT_FAILURE, "read()");
878 close(fd);
879 xmlbuf[st.st_size] = 0;
882 * Make sure the document validates.
884 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
885 log_write("xmlReadDoc()");
886 close(fd);
887 gcry_free(key);
888 gcry_free(xmlbuf);
889 gcry_cipher_close(gh);
890 return FALSE;
893 gcry_free(xmlbuf);
894 xmlDocDumpMemory(doc, &xml, &len);
895 xmlFreeDoc(doc);
897 level = get_key_file_integer(filename, "compression_level");
899 if (level < 0)
900 level = 0;
902 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
903 memset(shakey, 0, sizeof(shakey));
904 gcry_free(xml);
906 if (zrc == Z_MEM_ERROR)
907 warnx("%s", strerror(ENOMEM));
908 else
909 warnx("do_compress() failed");
911 gcry_cipher_close(gh);
912 return FALSE;
914 else {
915 gcry_free(xml);
916 xml = outbuf;
917 len = outsize;
920 if (iter == -1)
921 memset(shakey, '!', sizeof(shakey));
922 else{
923 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
924 gcry_free(key);
927 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
928 gcry_cipher_close(gh);
930 if (rc) {
931 memset(shakey, 0, sizeof(shakey));
932 warnx("%s", gpg_strerror(rc));
933 return FALSE;
936 memset(shakey, 0, sizeof(shakey));
937 return TRUE;
940 gchar *get_key_file_string(const gchar *section, const gchar *what)
942 gchar *val = NULL;
943 GError *grc = NULL;
945 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
946 val = g_key_file_get_string(keyfileh, section, what, &grc);
948 if (grc) {
949 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
950 g_clear_error(&grc);
953 else {
954 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
955 val = g_key_file_get_string(keyfileh, "global", what, &grc);
957 if (grc) {
958 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
959 g_clear_error(&grc);
964 return val;
967 gint get_key_file_integer(const gchar *section, const gchar *what)
969 gint val = -1;
970 GError *grc = NULL;
972 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
973 val = g_key_file_get_integer(keyfileh, section, what, &grc);
975 if (grc) {
976 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
977 g_clear_error(&grc);
980 else {
981 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
982 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
984 if (grc) {
985 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
986 g_clear_error(&grc);
991 return val;
994 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
996 gboolean val = FALSE;
997 GError *grc = NULL;
999 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1000 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1002 if (grc) {
1003 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1004 g_clear_error(&grc);
1007 else {
1008 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1009 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1011 if (grc) {
1012 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1013 g_clear_error(&grc);
1018 return val;
1021 static gboolean _getline(const gchar *file, gchar **result)
1023 FILE *fp;
1024 gchar buf[LINE_MAX] = {0}, *p;
1025 gchar *str = NULL;
1026 gint len;
1028 if ((fp = fopen(file, "r")) == NULL) {
1029 warn("%s", file);
1030 return FALSE;
1033 p = fgets(buf, sizeof(buf), fp);
1034 fclose(fp);
1035 len = strlen(buf);
1037 if (len && buf[len - 1] == '\n')
1038 buf[--len] = 0;
1040 str = gcry_malloc(len + 1);
1041 memcpy(str, buf, len ? len : 1);
1042 str[len] = 0;
1043 memset(&buf, 0, sizeof(buf));
1044 *result = str;
1045 return TRUE;
1048 static gboolean parse_keyfile_key()
1050 gsize n;
1051 gchar **groups;
1052 gchar **p;
1053 gchar *str;
1055 groups = g_key_file_get_groups(keyfileh, &n);
1057 for (p = groups; *p; p++) {
1058 GError *rc = NULL;
1060 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1061 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1063 if (!str) {
1064 if (rc) {
1065 warnx("%s", rc->message);
1066 g_clear_error(&rc);
1069 continue;
1072 do_cache_push(*p, str);
1073 g_free(str);
1074 continue;
1077 if (rc) {
1078 warnx("%s", rc->message);
1079 g_clear_error(&rc);
1080 continue;
1083 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1084 gchar *t;
1085 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1087 if (!file) {
1088 if (rc) {
1089 warnx("%s", rc->message);
1090 g_clear_error(&rc);
1093 continue;
1096 t = expand_homedir(file);
1097 g_free(file);
1098 file = t;
1100 if (_getline(file, &str) == FALSE) {
1101 g_free(file);
1102 continue;
1105 g_free(file);
1106 do_cache_push(*p, str);
1107 gcry_free(str);
1108 continue;
1111 if (rc) {
1112 warnx("%s", rc->message);
1113 g_clear_error(&rc);
1117 g_strfreev(groups);
1118 return TRUE;
1121 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1123 guchar *md5file;
1124 guchar *key;
1125 gint timeout;
1126 const gchar *p = filename;
1127 file_header_t file_header;
1128 gpg_error_t rc;
1130 while (isspace(*p))
1131 p++;
1133 if (!*p)
1134 return FALSE;
1136 if (valid_filename(p) == FALSE) {
1137 warnx(N_("%s: invalid characters in filename"), p);
1138 return FALSE;
1141 md5file = gcry_malloc(16);
1142 key = gcry_malloc(gcrykeysize);
1143 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1145 if (cache_iscached(md5file) == TRUE) {
1146 warnx(N_("%s: file already cached, skipping"), p);
1147 gcry_free(md5file);
1148 gcry_free(key);
1149 return FALSE;
1152 if (access(p, R_OK|W_OK) != 0) {
1153 gcry_free(md5file);
1154 gcry_free(key);
1156 if (errno != ENOENT) {
1157 warn("%s", p);
1158 return FALSE;
1161 warn("%s", p);
1162 return TRUE;
1165 rc = read_file_header(filename, &file_header);
1167 if (rc) {
1168 gcry_free(md5file);
1169 gcry_free(key);
1170 warnx("%s", pwmd_strerror(rc));
1171 return FALSE;
1174 if (file_header.iter == -1) {
1175 memset(key, '!', gcrykeysize);
1176 goto try_decrypt;
1179 if (!password) {
1180 #ifdef WITH_PINENTRY
1181 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1182 #endif
1183 if (get_input(p, key) == FALSE) {
1184 gcry_free(key);
1185 gcry_free(md5file);
1186 return FALSE;
1188 #ifdef WITH_PINENTRY
1190 else {
1191 gchar *result = NULL;
1192 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1193 gint try = 0;
1195 pin->which = PINENTRY_OPEN;
1196 pin->filename = g_strdup(filename);
1197 again:
1198 rc = pinentry_getpin(pin, &result);
1200 if (rc) {
1201 warnx("%s: %s", filename, gpg_strerror(rc));
1202 cleanup_pinentry(pin);
1203 gcry_free(key);
1204 gcry_free(md5file);
1205 xfree(result);
1206 return FALSE;
1209 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1210 xfree(result);
1212 if (do_try_xml_decrypt(filename, key) == FALSE) {
1213 if (try++ == 2) {
1214 cleanup_pinentry(pin);
1215 gcry_free(key);
1216 gcry_free(md5file);
1217 warnx(N_("%s: invalid password, skipping"), filename);
1218 return FALSE;
1220 else {
1221 g_free(pin->title);
1222 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1223 goto again;
1227 cleanup_pinentry(pin);
1229 #endif
1231 else {
1232 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1234 try_decrypt:
1235 if (do_try_xml_decrypt(filename, key) == FALSE) {
1236 warnx(N_("%s: invalid password, skipping"), filename);
1237 gcry_free(key);
1238 gcry_free(md5file);
1239 return FALSE;
1243 if (cache_add_file(md5file, key) == FALSE) {
1244 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1245 gcry_free(key);
1246 gcry_free(md5file);
1247 return FALSE;
1250 timeout = get_key_file_integer(p, "cache_timeout");
1251 cache_set_timeout(md5file, timeout);
1252 warnx(N_("%s: file added to the cache"), filename);
1253 gcry_free(key);
1254 gcry_free(md5file);
1255 return TRUE;
1258 static void *accept_thread(void *arg)
1260 gint sockfd = (gint)arg;
1262 for (;;) {
1263 socklen_t slen = sizeof(struct sockaddr_un);
1264 struct sockaddr_un raddr;
1265 gint fd = -1;
1266 pth_attr_t attr;
1268 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1269 if (errno != EAGAIN) {
1270 if (!quit) // probably EBADF
1271 log_write("accept(): %s", strerror(errno));
1273 break;
1277 if (fd >= 0) {
1278 pth_t tid;
1279 struct client_thread_s *new;
1280 gchar buf[41];
1282 new = g_malloc0(sizeof(struct client_thread_s));
1284 if (!new) {
1285 log_write("%s", strerror(ENOMEM));
1286 continue;
1290 * Thread priority is inherited from the calling thread. This
1291 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1292 * priority.
1294 new->fd = fd;
1295 attr = pth_attr_new();
1296 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1297 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1298 tid = pth_spawn(attr, client_thread, new);
1299 pth_attr_destroy(attr);
1301 if (!tid) {
1302 g_free(new);
1303 log_write(N_("pth_spawn() failed"));
1304 continue;
1307 g_snprintf(buf, sizeof(buf), "%p", tid);
1308 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1309 attr = pth_attr_of(tid);
1310 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1311 pth_attr_destroy(attr);
1312 new->tid = tid;
1313 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1314 cn_thread_list = g_slist_append(cn_thread_list, new);
1315 pth_mutex_release(&cn_mutex);
1319 /* Just in case pth_accept() failed for some reason other than EBADF */
1320 quit = 1;
1321 pth_exit(PTH_CANCELED);
1322 return NULL;
1326 * This thread isn't joinable. For operations that block, these threads will
1327 * stack.
1329 static void *adjust_timer_thread(void *arg)
1331 CACHE_LOCK(NULL);
1332 cache_adjust_timer();
1333 CACHE_UNLOCK;
1334 return NULL;
1337 static void server_loop(gint sockfd, gchar **socketpath)
1339 pth_t accept_tid;
1340 guint n;
1341 sigset_t set;
1342 gint n_clients = 0;
1343 pth_attr_t attr;
1344 pth_event_t timeout_ev, keepalive_ev = NULL;
1345 gint keepalive = get_key_file_integer("global", "keepalive");
1346 gpointer value;
1348 pth_mutex_init(&cn_mutex);
1349 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1351 sigemptyset(&set);
1352 sigaddset(&set, SIGTERM);
1353 sigaddset(&set, SIGINT);
1354 sigaddset(&set, SIGUSR1);
1355 sigaddset(&set, SIGHUP);
1356 sigaddset(&set, SIGABRT);
1358 attr = pth_attr_new();
1359 pth_attr_init(attr);
1360 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1361 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1362 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1365 * For the cache_timeout configuration parameter. This replaces the old
1366 * SIGALRM stuff and is safer.
1368 timeout_ev = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1370 if (keepalive > 0) {
1371 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1372 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1375 pth_attr_init(attr);
1376 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1377 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1379 do {
1380 gint sig = 0;
1382 pth_sigwait_ev(&set, &sig, timeout_ev);
1383 pth_event_isolate(timeout_ev);
1384 pth_event_isolate(keepalive_ev);
1386 if (pth_event_occurred(timeout_ev)) {
1388 * The timer event has expired. Update the file cache. When the
1389 * cache mutex is locked and the timer expires again, the threads
1390 * will stack.
1392 pth_spawn(attr, adjust_timer_thread, NULL);
1393 pth_event_free(timeout_ev, PTH_FREE_THIS);
1394 timeout_ev= pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1397 * Just in case the configuration file has been reloaded.
1399 keepalive = get_key_file_integer("global", "keepalive");
1402 if (keepalive_ev && pth_event_occurred(keepalive_ev)) {
1403 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1404 keepalive_ev = NULL;
1405 send_status_all(STATUS_KEEPALIVE);
1407 if (keepalive > 0)
1408 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1411 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1413 if (sig > 0) {
1414 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1416 /* Caught a signal. */
1417 switch (sig) {
1418 case SIGHUP:
1419 reload_rcfile();
1420 break;
1421 case SIGABRT:
1422 CACHE_LOCK(NULL);
1423 cache_clear(NULL, 2);
1424 CACHE_UNLOCK;
1425 #ifndef MEM_DEBUG
1426 xpanic();
1427 #endif
1428 exit(EXIT_FAILURE);
1429 case SIGUSR1:
1430 CACHE_LOCK(NULL);
1431 log_write(N_("clearing file cache"));
1432 cache_clear(NULL, 2);
1433 CACHE_UNLOCK;
1434 break;
1435 default:
1436 quit = 1;
1437 shutdown(sockfd, SHUT_RDWR);
1438 close(sockfd);
1439 break;
1442 } while (!quit);
1445 * We're out of the main server loop. This happens when a signal was sent
1446 * to terminate the daemon. We'll wait for all clients to disconnect
1447 * before exiting and ignore any following signals.
1449 pth_join(accept_tid, &value);
1450 pth_attr_destroy(attr);
1451 pth_event_free(timeout_ev, PTH_FREE_THIS);
1452 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1453 unlink(*socketpath);
1454 g_free(*socketpath);
1455 *socketpath = NULL;
1457 if (n > 1)
1458 log_write(N_("waiting for all threads to terminate"));
1460 while (n > 1) {
1461 pth_event_t events;
1463 if (n != n_clients) {
1464 log_write(N_("%i threads remain"), n-1);
1465 n_clients = n;
1468 events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1469 pth_wait(events);
1470 pth_event_isolate(events);
1471 pth_event_free(events, PTH_FREE_THIS);
1472 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1477 * Called from pinentry_fork() in the child process.
1479 void free_client_list()
1481 gint i, t = g_slist_length(cn_thread_list);
1483 for (i = 0; i < t; i++) {
1484 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1486 free_client(cn->cl);
1489 memset(key_cache, 0, cache_size);
1492 int main(int argc, char *argv[])
1494 gint opt;
1495 struct sockaddr_un addr;
1496 struct passwd *pw = getpwuid(getuid());
1497 gchar buf[PATH_MAX];
1498 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1499 gchar *socketarg = NULL;
1500 gchar *datadir = NULL;
1501 gboolean n;
1502 gchar *p;
1503 gchar **cache_push = NULL;
1504 gint iter = 0;
1505 gchar *import = NULL;
1506 gint cmd_iterations = -1;
1507 gint default_timeout;
1508 gint rcfile_spec = 0;
1509 gint estatus = EXIT_FAILURE;
1510 gint sockfd;
1511 #ifndef MEM_DEBUG
1512 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1513 #endif
1514 gint do_unlink = 1;
1515 gboolean secure = FALSE;
1516 guint ptotal = 0;
1517 gint background = 1;
1518 sigset_t set;
1519 #ifndef DEBUG
1520 #ifdef HAVE_SETRLIMIT
1521 struct rlimit rl;
1523 rl.rlim_cur = rl.rlim_max = 0;
1525 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1526 err(EXIT_FAILURE, "setrlimit()");
1527 #endif
1528 #endif
1530 #ifdef ENABLE_NLS
1531 setlocale(LC_ALL, "");
1532 bindtextdomain("pwmd", LOCALEDIR);
1533 textdomain("pwmd");
1534 #endif
1536 gpg_err_init();
1537 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1538 #ifndef MEM_DEBUG
1539 g_mem_set_vtable(&mtable);
1540 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1541 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1542 xmlInitMemory();
1543 #endif
1544 pth_init();
1545 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1547 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1548 err(EXIT_FAILURE, "%s", buf);
1550 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1552 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1553 err(EXIT_FAILURE, "%s", buf);
1555 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1557 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1558 err(EXIT_FAILURE, "sysconf()");
1560 cache_size = page_size;
1562 while ((opt = getopt(argc, argv, "bnI:i:hvf:D")) != EOF) {
1563 switch (opt) {
1564 case 'b':
1565 /* Compatibility for version < 1.11 */
1566 break;
1567 case 'n':
1568 background = 0;
1569 break;
1570 case 'D':
1571 secure = TRUE;
1572 break;
1573 case 'I':
1574 import = optarg;
1575 break;
1576 case 'i':
1577 cmd_iterations = atoi(optarg);
1578 break;
1579 case 'f':
1580 g_free(rcfile);
1581 rcfile = g_strdup(optarg);
1582 rcfile_spec = 1;
1583 break;
1584 case 'v':
1585 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1586 exit(EXIT_SUCCESS);
1587 case 'h':
1588 default:
1589 usage(argv[0]);
1593 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1594 exit(EXIT_FAILURE);
1596 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1597 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1599 if (log_syslog == TRUE)
1600 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1602 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1603 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1604 errno = 0;
1606 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1607 warn("setpriority()");
1608 goto do_exit;
1612 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1613 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1615 #ifdef HAVE_MLOCKALL
1616 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1617 warn("mlockall()");
1618 goto do_exit;
1620 #endif
1622 setup_gcrypt();
1624 if (import) {
1625 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1626 g_key_file_free(keyfileh);
1627 g_free(rcfile);
1628 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1631 g_key_file_set_list_separator(keyfileh, ',');
1633 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1634 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1636 if (*p == '~') {
1637 p++;
1638 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1639 g_free(p);
1640 socketarg = g_strdup(buf);
1642 else
1643 socketarg = p;
1645 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1646 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1648 datadir = expand_homedir(p);
1649 g_free(p);
1651 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1652 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1653 disable_list_and_dump = n;
1655 else
1656 disable_list_and_dump = secure;
1658 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1659 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1660 else
1661 default_timeout = -1;
1663 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1664 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1666 if (cache_size < page_size || cache_size % page_size)
1667 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1670 setup_logging(keyfileh);
1672 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1673 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1675 if (argc != optind) {
1676 if (cache_push)
1677 ptotal = g_strv_length(cache_push);
1679 for (; optind < argc; optind++) {
1680 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1681 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1685 if (strchr(socketarg, '/') == NULL) {
1686 socketdir = g_get_current_dir();
1687 socketname = g_strdup(socketarg);
1688 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1690 else {
1691 socketname = g_strdup(strrchr(socketarg, '/'));
1692 socketname++;
1693 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1694 socketdir = g_strdup(socketarg);
1695 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1698 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1699 #ifdef MMAP_ANONYMOUS
1700 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1701 #else
1702 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1703 #endif
1704 err(EXIT_FAILURE, "mmap()");
1707 if (mlock(key_cache, cache_size) == -1)
1708 log_write("mlock(): %s", strerror(errno));
1710 memset(key_cache, 0, cache_size);
1712 if (chdir(datadir)) {
1713 warn("%s", datadir);
1714 unlink(socketpath);
1715 goto do_exit;
1718 if (parse_keyfile_key() == FALSE)
1719 goto do_exit;
1721 clear_errorfile_key();
1724 * Set the cache entry for a file. Prompts for the password.
1726 if (cache_push) {
1727 for (opt = 0; cache_push[opt]; opt++)
1728 do_cache_push(cache_push[opt], NULL);
1730 g_strfreev(cache_push);
1731 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1735 * bind() doesn't like the full pathname of the socket or any non alphanum
1736 * characters so change to the directory where the socket is wanted then
1737 * create it then change to datadir.
1739 if (chdir(socketdir)) {
1740 warn("%s", socketdir);
1741 goto do_exit;
1744 g_free(socketdir);
1746 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1747 warn("socket()");
1748 goto do_exit;
1751 addr.sun_family = AF_UNIX;
1752 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1754 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1755 warn("bind()");
1757 if (errno == EADDRINUSE)
1758 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1759 "stale socket. Please remove it manually."), socketpath);
1761 do_unlink = 0;
1762 goto do_exit;
1765 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1766 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1767 mode_t mode = strtol(t, NULL, 8);
1768 mode_t mask = umask(0);
1770 g_free(t);
1772 if (chmod(socketname, mode) == -1) {
1773 warn("%s", socketname);
1774 close(sockfd);
1775 unlink(socketpath);
1776 umask(mask);
1777 goto do_exit;
1780 umask(mask);
1783 g_free(--socketname);
1785 if (chdir(datadir)) {
1786 warn("%s", datadir);
1787 close(sockfd);
1788 unlink(socketpath);
1789 goto do_exit;
1792 g_free(datadir);
1793 pth_mutex_init(&cache_mutex);
1794 #ifdef WITH_PINENTRY
1795 pth_mutex_init(&pin_mutex);
1796 #endif
1798 if (listen(sockfd, 0) == -1) {
1799 warn("listen()");
1800 goto do_exit;
1803 if (background) {
1804 switch (fork()) {
1805 case -1:
1806 warn("fork()");
1807 goto do_exit;
1808 case 0:
1809 close(0);
1810 close(1);
1811 close(2);
1812 setsid();
1813 break;
1814 default:
1815 exit(EXIT_SUCCESS);
1820 * These are the signals that we use in threads. libpth can catch signals
1821 * itself so ignore them everywhere else. Note that using
1822 * signal(N, SIG_IGN) doesn't work like you might think.
1824 sigemptyset(&set);
1826 /* Termination */
1827 sigaddset(&set, SIGTERM);
1828 sigaddset(&set, SIGINT);
1830 /* Configuration file reloading. */
1831 sigaddset(&set, SIGUSR1);
1833 /* Clears the file cache. */
1834 sigaddset(&set, SIGHUP);
1836 /* Caught in client_thread(). Sends a cache status message. */
1837 sigaddset(&set, SIGUSR2);
1839 /* Ignored everywhere. When a client disconnects abnormally this signal
1840 * gets raised. It isn't needed though because client_thread() will check
1841 * for rcs even after the client disconnects. */
1842 signal(SIGPIPE, SIG_IGN);
1843 pth_sigmask(SIG_BLOCK, &set, NULL);
1844 server_loop(sockfd, &socketpath);
1845 estatus = EXIT_SUCCESS;
1847 do_exit:
1848 if (socketpath && do_unlink) {
1849 unlink(socketpath);
1850 g_free(socketpath);
1853 g_key_file_free(keyfileh);
1854 g_free(rcfile);
1855 xmlCleanupParser();
1857 if (key_cache) {
1858 cache_clear(NULL, 2);
1859 memset(key_cache, 0, cache_size);
1862 if (key_cache && munmap(key_cache, cache_size) == -1)
1863 log_write("munmap(): %s", strerror(errno));
1865 if (estatus == EXIT_SUCCESS)
1866 log_write(N_("pwmd exiting normally"));
1868 pth_kill();
1869 #if defined(DEBUG) && !defined(MEM_DEBUG)
1870 xdump();
1871 #endif
1872 exit(estatus);