Call assuan_register_post_cmd_notify() from register_commands().
[pwmd.git] / src / pwmd.c
blob9c1d883c462c001193e7f7f889d8ea8faf7fa4da
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 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 #ifdef WITH_PINENTRY
410 pth_event_t pinentry_ev = NULL;
411 #endif
412 struct client_s *cl = g_malloc0(sizeof(struct client_s));
413 gpg_error_t rc;
415 if (!cl) {
416 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
417 goto fail;
420 #ifdef WITH_PINENTRY
421 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
423 if (!cl->pinentry) {
424 g_free(cl);
425 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
426 goto fail;
429 set_pinentry_defaults(cl->pinentry);
430 #endif
431 thd->cl = cl;
432 cl->thd = thd;
433 pth_cleanup_push(cleanup_cb, thd);
434 thd->msg_name = g_strdup_printf("%p", thd->tid);
436 if (!thd->msg_name) {
437 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
438 goto fail;
441 thd->msg = pth_msgport_create(thd->msg_name);
443 if (!thd->msg) {
444 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
445 goto fail;
449 * This is a "child" thread. Don't catch any signals. Let the master
450 * thread take care of signals in accept_thread().
452 cl->ctx = new_connection(fd);
453 cl->fd = fd;
455 if (!cl->ctx)
456 goto fail;
458 assuan_set_pointer(cl->ctx, cl);
460 #ifdef HAVE_MLOCKALL
461 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
462 log_write("mlockall(): %s", strerror(errno));
463 goto fail;
465 #endif
467 rc = send_status(cl->ctx, STATUS_CACHE);
469 if (rc) {
470 log_write("%s", gpg_strerror(rc));
471 goto fail;
474 send_status_all(STATUS_CLIENTS);
475 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
476 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
477 pth_event_concat(ev, msg_ev, NULL);
478 xmlInitParser();
479 xmlXPathInit();
480 xmlSetStructuredErrorFunc(cl, xml_error_cb);
482 for (;;) {
483 pth_wait(ev);
484 pth_event_isolate(ev);
485 pth_event_isolate(msg_ev);
487 if (pth_event_occurred(msg_ev)) {
488 pth_event_free(msg_ev, PTH_FREE_THIS);
490 while (pth_msgport_pending(thd->msg) > 0) {
491 pth_message_t *m = pth_msgport_get(thd->msg);
492 status_msg_t n = (status_msg_t)m->m_data;
494 rc = send_status(cl->ctx, n);
495 g_free(m);
497 if (rc) {
498 log_write("%s", gpg_strerror(rc));
499 goto done;
503 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
506 pth_event_concat(ev, msg_ev, NULL);
508 if (pth_event_occurred(ev)) {
509 rc = assuan_process_next(cl->ctx);
511 if (rc) {
512 cl->inquire_status = INQUIRE_INIT;
514 if (gpg_err_code(rc) == GPG_ERR_EOF)
515 goto done;
517 log_write("assuan_process_next(): %s", gpg_strerror(rc));
518 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
520 if (rc) {
521 log_write("assuan_process_done(): %s", gpg_strerror(rc));
522 goto done;
525 else {
526 #ifdef WITH_PINENTRY
527 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
528 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
529 pth_event_concat(ev, pinentry_ev, NULL);
530 cl->pinentry->status = PINENTRY_RUNNING;
532 #endif
534 switch (cl->inquire_status) {
535 case INQUIRE_BUSY:
536 case INQUIRE_INIT:
537 break;
538 case INQUIRE_DONE:
539 cl->inquire_status = INQUIRE_INIT;
540 rc = assuan_process_done(cl->ctx, 0);
541 break;
546 #ifdef WITH_PINENTRY
547 if (cl->pinentry->status == PINENTRY_RUNNING) {
548 pth_event_isolate(pinentry_ev);
550 if (pth_event_occurred(pinentry_ev)) {
551 guchar shakey[gcrykeysize];
552 pinentry_key_s pk;
553 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
554 gint status;
556 pth_event_free(pinentry_ev, PTH_FREE_THIS);
557 pinentry_ev = NULL;
558 cl->pinentry->status = PINENTRY_NONE;
560 if (len == sizeof(pk)) {
561 if (pk.error)
562 rc = send_error(cl->ctx, pk.error);
563 else {
564 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
565 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
566 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
567 memset(shakey, 0, sizeof(shakey));
570 else if (len == -1)
571 log_write("%s", strerror(errno));
572 else if (len == 0)
573 log_write("pth_read(): EOF");
574 else
575 log_write(N_("pth_read(): short byte count"));
577 pth_waitpid(cl->pinentry->pid, &status, 0);
578 close(cl->pinentry->fd);
579 cl->pinentry->fd = -1;
580 cl->pinentry->pid = 0;
582 if (pk.error && cl->pinentry->which == PINENTRY_OPEN)
583 cleanup_client(cl);
584 else
585 unlock_file_mutex(cl);
587 memset(&pk, 0, sizeof(pk));
588 unlock_pin_mutex(cl->pinentry);
591 pth_event_concat(ev, pinentry_ev, NULL);
593 #endif
597 * Client cleanup (including XML data) is done in cleanup_cb() from
598 * the cleanup thread.
600 done:
601 pth_event_free(ev, PTH_FREE_ALL);
603 fail:
604 pth_exit(NULL);
605 return NULL;
608 static void setup_logging(GKeyFile *kf)
610 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
612 if (n == TRUE) {
613 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
615 if (*p == '~') {
616 gchar buf[PATH_MAX];
618 p++;
619 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
620 g_free(p);
622 if (logfile)
623 g_free(logfile);
625 logfile = g_strdup(buf);
627 else {
628 if (logfile)
629 g_free(logfile);
631 logfile = p;
635 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
639 * Make sure all settings are set to either the specified setting or a
640 * default.
642 static void set_rcfile_defaults(GKeyFile *kf)
644 gchar buf[PATH_MAX];
646 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
647 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
648 g_key_file_set_string(kf, "global", "socket_path", buf);
651 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
652 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
653 g_key_file_set_string(kf, "global", "data_directory", buf);
656 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
657 g_key_file_set_boolean(kf, "global", "backup", TRUE);
659 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
660 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
661 g_key_file_set_string(kf, "global", "log_path", buf);
664 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
665 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
667 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
668 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
670 #ifdef HAVE_MLOCKALL
671 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
672 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
673 #endif
675 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
676 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
678 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
679 g_key_file_set_integer(kf, "global", "iterations", 0);
681 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
682 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
684 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
685 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
687 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
688 g_key_file_set_integer(kf, "global", "compression_level", 6);
690 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
691 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
693 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
694 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
696 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
698 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
699 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
701 #ifdef HAVE_MLOCKALL
702 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
703 #endif
705 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
706 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
708 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
709 g_key_file_set_integer(kf, "global", "keepalive", 30);
711 #ifdef WITH_PINENTRY
712 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
713 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
714 #endif
716 setup_logging(kf);
719 static GKeyFile *parse_rcfile(int cmdline)
721 GKeyFile *kf = g_key_file_new();
722 GError *rc = NULL;
724 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
725 log_write("%s: %s", rcfile, rc->message);
727 if (cmdline)
728 exit(EXIT_FAILURE);
730 if (rc->code == G_FILE_ERROR_NOENT) {
731 g_clear_error(&rc);
732 set_rcfile_defaults(kf);
733 return kf;
736 g_clear_error(&rc);
737 return NULL;
739 else
740 set_rcfile_defaults(kf);
742 return kf;
745 static gchar *get_password(const gchar *prompt)
747 gchar buf[LINE_MAX] = {0}, *p;
748 struct termios told, tnew;
749 gchar *key;
751 if (tcgetattr(STDIN_FILENO, &told) == -1)
752 err(EXIT_FAILURE, "tcgetattr()");
754 memcpy(&tnew, &told, sizeof(struct termios));
755 tnew.c_lflag &= ~(ECHO);
756 tnew.c_lflag |= ICANON|ECHONL;
758 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
759 tcsetattr(STDIN_FILENO, TCSANOW, &told);
760 err(EXIT_FAILURE, "tcsetattr()");
763 fprintf(stderr, "%s", prompt);
765 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
766 tcsetattr(STDIN_FILENO, TCSANOW, &told);
767 return NULL;
770 tcsetattr(STDIN_FILENO, TCSANOW, &told);
771 p[strlen(p) - 1] = 0;
773 if (!buf[0]) {
774 key = gcry_malloc(1);
775 key[0] = 0;
777 else {
778 key = gcry_malloc(strlen(p) + 1);
779 sprintf(key, "%s", p);
782 memset(&buf, 0, sizeof(buf));
783 return key;
786 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
788 int fd;
789 struct stat st;
790 gpg_error_t rc;
791 gint iter;
793 if ((fd = open_file(filename, &st)) == -1) {
794 warn("%s", filename);
795 return FALSE;
798 if (st.st_size == 0) {
799 warnx(N_("%s: skipping empty file"), filename);
800 close(fd);
801 return FALSE;
804 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
805 close(fd);
806 return rc ? FALSE : TRUE;
809 static gboolean get_input(const gchar *filename, guchar *key)
811 gint try = 0;
812 gchar *password;
813 gchar *prompt;
815 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
817 again:
818 if ((password = get_password(prompt)) == NULL) {
819 warnx(N_("%s: skipping file"), filename);
820 g_free(prompt);
821 return FALSE;
824 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
825 gcry_free(password);
827 if (do_try_xml_decrypt(filename, key) == FALSE) {
828 if (try++ == 2) {
829 warnx(N_("%s: invalid password, skipping"), filename);
830 g_free(prompt);
831 return FALSE;
833 else {
834 warnx(N_("%s: invalid password"), filename);
835 goto again;
839 g_free(prompt);
840 return TRUE;
843 static gboolean xml_import(const gchar *filename, gint iter)
845 xmlDocPtr doc;
846 gint fd;
847 struct stat st;
848 gint len;
849 xmlChar *xmlbuf;
850 xmlChar *xml;
851 gchar *key = NULL;
852 gchar *key2 = NULL;
853 guchar shakey[gcrykeysize];
854 gcry_cipher_hd_t gh;
855 gpg_error_t rc;
856 gint level;
857 glong outsize;
858 gpointer outbuf;
859 gint zrc;
861 if (stat(filename, &st) == -1) {
862 warn("%s", filename);
863 return FALSE;
866 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
867 send_error(NULL, rc);
868 gcry_cipher_close(gh);
869 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
870 return FALSE;
873 if (iter == -1)
874 goto done;
876 if ((key = get_password(N_("New password: "))) == NULL) {
877 fprintf(stderr, "%s\n", N_("Invalid password."));
878 gcry_cipher_close(gh);
879 return FALSE;
882 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
883 fprintf(stderr, "%s\n", N_("Passwords do not match."));
884 gcry_free(key);
885 gcry_cipher_close(gh);
886 return FALSE;
889 if (g_utf8_collate(key, key2) != 0) {
890 fprintf(stderr, "%s\n", N_("Passwords do not match."));
891 gcry_free(key);
892 gcry_free(key2);
893 gcry_cipher_close(gh);
894 return FALSE;
897 gcry_free(key2);
899 done:
900 if ((fd = open(filename, O_RDONLY)) == -1) {
901 gcry_free(key);
902 warn("%s", filename);
903 gcry_cipher_close(gh);
904 return FALSE;
907 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
908 gcry_free(key);
909 close(fd);
910 log_write("%s", strerror(ENOMEM));
911 gcry_cipher_close(gh);
912 return FALSE;
915 if (read(fd, xmlbuf, st.st_size) == -1) {
916 rc = errno;
917 close(fd);
918 gcry_free(key);
919 gcry_cipher_close(gh);
920 errno = rc;
921 err(EXIT_FAILURE, "read()");
924 close(fd);
925 xmlbuf[st.st_size] = 0;
928 * Make sure the document validates.
930 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
931 log_write("xmlReadDoc()");
932 close(fd);
933 gcry_free(key);
934 gcry_free(xmlbuf);
935 gcry_cipher_close(gh);
936 return FALSE;
939 gcry_free(xmlbuf);
940 xmlDocDumpMemory(doc, &xml, &len);
941 xmlFreeDoc(doc);
943 level = get_key_file_integer(filename, "compression_level");
945 if (level < 0)
946 level = 0;
948 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
949 memset(shakey, 0, sizeof(shakey));
950 gcry_free(xml);
952 if (zrc == Z_MEM_ERROR)
953 warnx("%s", strerror(ENOMEM));
954 else
955 warnx("do_compress() failed");
957 gcry_cipher_close(gh);
958 return FALSE;
960 else {
961 gcry_free(xml);
962 xml = outbuf;
963 len = outsize;
966 if (iter == -1)
967 memset(shakey, '!', sizeof(shakey));
968 else{
969 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
970 gcry_free(key);
973 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
974 gcry_cipher_close(gh);
976 if (rc) {
977 memset(shakey, 0, sizeof(shakey));
978 warnx("%s", gpg_strerror(rc));
979 return FALSE;
982 memset(shakey, 0, sizeof(shakey));
983 return TRUE;
986 gchar *get_key_file_string(const gchar *section, const gchar *what)
988 gchar *val = NULL;
989 GError *grc = NULL;
991 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
992 val = g_key_file_get_string(keyfileh, section, what, &grc);
994 if (grc) {
995 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
996 g_clear_error(&grc);
999 else {
1000 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1001 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1003 if (grc) {
1004 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1005 g_clear_error(&grc);
1010 return val;
1013 gint get_key_file_integer(const gchar *section, const gchar *what)
1015 gint val = -1;
1016 GError *grc = NULL;
1018 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1019 val = g_key_file_get_integer(keyfileh, section, what, &grc);
1021 if (grc) {
1022 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1023 g_clear_error(&grc);
1026 else {
1027 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1028 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1030 if (grc) {
1031 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1032 g_clear_error(&grc);
1037 return val;
1040 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1042 gboolean val = FALSE;
1043 GError *grc = NULL;
1045 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1046 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1048 if (grc) {
1049 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1050 g_clear_error(&grc);
1053 else {
1054 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1055 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1057 if (grc) {
1058 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1059 g_clear_error(&grc);
1064 return val;
1067 static gboolean _getline(const gchar *file, gchar **result)
1069 FILE *fp;
1070 gchar buf[LINE_MAX] = {0}, *p;
1071 gchar *str = NULL;
1072 gint len;
1074 if ((fp = fopen(file, "r")) == NULL) {
1075 warn("%s", file);
1076 return FALSE;
1079 p = fgets(buf, sizeof(buf), fp);
1080 fclose(fp);
1081 len = strlen(buf);
1083 if (len && buf[len - 1] == '\n')
1084 buf[--len] = 0;
1086 str = gcry_malloc(len + 1);
1087 memcpy(str, buf, len ? len : 1);
1088 str[len] = 0;
1089 memset(&buf, 0, sizeof(buf));
1090 *result = str;
1091 return TRUE;
1094 static gboolean parse_keyfile_key()
1096 gsize n;
1097 gchar **groups;
1098 gchar **p;
1099 gchar *str;
1101 groups = g_key_file_get_groups(keyfileh, &n);
1103 for (p = groups; *p; p++) {
1104 GError *rc = NULL;
1106 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1107 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1109 if (!str) {
1110 if (rc) {
1111 warnx("%s", rc->message);
1112 g_clear_error(&rc);
1115 continue;
1118 do_cache_push(*p, str);
1119 g_free(str);
1120 continue;
1123 if (rc) {
1124 warnx("%s", rc->message);
1125 g_clear_error(&rc);
1126 continue;
1129 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1130 gchar *t;
1131 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1133 if (!file) {
1134 if (rc) {
1135 warnx("%s", rc->message);
1136 g_clear_error(&rc);
1139 continue;
1142 t = expand_homedir(file);
1143 g_free(file);
1144 file = t;
1146 if (_getline(file, &str) == FALSE) {
1147 g_free(file);
1148 continue;
1151 g_free(file);
1152 do_cache_push(*p, str);
1153 gcry_free(str);
1154 continue;
1157 if (rc) {
1158 warnx("%s", rc->message);
1159 g_clear_error(&rc);
1163 g_strfreev(groups);
1164 return TRUE;
1167 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1169 guchar *md5file;
1170 guchar *key;
1171 gint timeout;
1172 const gchar *p = filename;
1173 file_header_t file_header;
1174 gpg_error_t rc;
1176 while (isspace(*p))
1177 p++;
1179 if (!*p)
1180 return FALSE;
1182 if (valid_filename(p) == FALSE) {
1183 warnx(N_("%s: invalid characters in filename"), p);
1184 return FALSE;
1187 md5file = gcry_malloc(16);
1188 key = gcry_malloc(gcrykeysize);
1189 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1191 if (cache_iscached(md5file) == TRUE) {
1192 warnx(N_("%s: file already cached, skipping"), p);
1193 gcry_free(md5file);
1194 gcry_free(key);
1195 return FALSE;
1198 if (access(p, R_OK|W_OK) != 0) {
1199 gcry_free(md5file);
1200 gcry_free(key);
1202 if (errno != ENOENT) {
1203 warn("%s", p);
1204 return FALSE;
1207 warn("%s", p);
1208 return TRUE;
1211 rc = read_file_header(filename, &file_header);
1213 if (rc) {
1214 gcry_free(md5file);
1215 gcry_free(key);
1216 warnx("%s", pwmd_strerror(rc));
1217 return FALSE;
1220 if (file_header.iter == -1) {
1221 memset(key, '!', gcrykeysize);
1222 goto try_decrypt;
1225 if (!password) {
1226 #ifdef WITH_PINENTRY
1227 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1228 #endif
1229 if (get_input(p, key) == FALSE) {
1230 gcry_free(key);
1231 gcry_free(md5file);
1232 return FALSE;
1234 #ifdef WITH_PINENTRY
1236 else {
1237 gchar *result = NULL;
1238 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1239 gint try = 0;
1241 pin->which = PINENTRY_OPEN;
1242 pin->filename = g_strdup(filename);
1243 again:
1244 rc = pinentry_getpin(pin, &result);
1246 if (rc) {
1247 warnx("%s: %s", filename, gpg_strerror(rc));
1248 cleanup_pinentry(pin);
1249 gcry_free(key);
1250 gcry_free(md5file);
1251 xfree(result);
1252 return FALSE;
1255 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1256 xfree(result);
1258 if (do_try_xml_decrypt(filename, key) == FALSE) {
1259 if (try++ == 2) {
1260 cleanup_pinentry(pin);
1261 gcry_free(key);
1262 gcry_free(md5file);
1263 warnx(N_("%s: invalid password, skipping"), filename);
1264 return FALSE;
1266 else {
1267 g_free(pin->title);
1268 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1269 goto again;
1273 cleanup_pinentry(pin);
1275 #endif
1277 else {
1278 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1280 try_decrypt:
1281 if (do_try_xml_decrypt(filename, key) == FALSE) {
1282 warnx(N_("%s: invalid password, skipping"), filename);
1283 gcry_free(key);
1284 gcry_free(md5file);
1285 return FALSE;
1289 if (cache_add_file(md5file, key) == FALSE) {
1290 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1291 gcry_free(key);
1292 gcry_free(md5file);
1293 return FALSE;
1296 timeout = get_key_file_integer(p, "cache_timeout");
1297 cache_set_timeout(md5file, timeout);
1298 warnx(N_("%s: file added to the cache"), filename);
1299 gcry_free(key);
1300 gcry_free(md5file);
1301 return TRUE;
1304 static void *accept_thread(void *arg)
1306 gint sockfd = (gint)arg;
1308 for (;;) {
1309 socklen_t slen = sizeof(struct sockaddr_un);
1310 struct sockaddr_un raddr;
1311 gint fd = -1;
1312 pth_attr_t attr;
1314 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1315 if (errno != EAGAIN) {
1316 if (!quit) // probably EBADF
1317 log_write("accept(): %s", strerror(errno));
1319 break;
1323 if (fd >= 0) {
1324 pth_t tid;
1325 struct client_thread_s *new;
1326 gchar buf[41];
1328 new = g_malloc0(sizeof(struct client_thread_s));
1330 if (!new) {
1331 log_write("%s", strerror(ENOMEM));
1332 continue;
1336 * Thread priority is inherited from the calling thread. This
1337 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1338 * priority.
1340 new->fd = fd;
1341 attr = pth_attr_new();
1342 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1343 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1344 tid = pth_spawn(attr, client_thread, new);
1345 pth_attr_destroy(attr);
1347 if (!tid) {
1348 g_free(new);
1349 log_write(N_("pth_spawn() failed"));
1350 continue;
1353 g_snprintf(buf, sizeof(buf), "%p", tid);
1354 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1355 attr = pth_attr_of(tid);
1356 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1357 pth_attr_destroy(attr);
1358 new->tid = tid;
1359 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1360 cn_thread_list = g_slist_append(cn_thread_list, new);
1361 pth_mutex_release(&cn_mutex);
1365 /* Just in case pth_accept() failed for some reason other than EBADF */
1366 quit = 1;
1367 pth_exit(PTH_CANCELED);
1368 return NULL;
1372 * This thread isn't joinable. For operations that block, these threads will
1373 * stack.
1375 static void *adjust_timer_thread(void *arg)
1377 CACHE_LOCK(NULL);
1378 cache_adjust_timer();
1379 CACHE_UNLOCK;
1380 return NULL;
1383 static void server_loop(gint sockfd, gchar **socketpath)
1385 pth_t accept_tid;
1386 guint n;
1387 sigset_t set;
1388 gint n_clients = 0;
1389 pth_attr_t attr;
1390 pth_event_t timeout_ev, keepalive_ev = NULL;
1391 gint keepalive = get_key_file_integer("global", "keepalive");
1392 gpointer value;
1394 pth_mutex_init(&cn_mutex);
1395 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1397 sigemptyset(&set);
1398 sigaddset(&set, SIGTERM);
1399 sigaddset(&set, SIGINT);
1400 sigaddset(&set, SIGUSR1);
1401 sigaddset(&set, SIGHUP);
1402 sigaddset(&set, SIGABRT);
1404 attr = pth_attr_new();
1405 pth_attr_init(attr);
1406 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1407 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1408 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1411 * For the cache_timeout configuration parameter. This replaces the old
1412 * SIGALRM stuff and is safer.
1414 timeout_ev = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1416 if (keepalive > 0) {
1417 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1418 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1421 pth_attr_init(attr);
1422 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1423 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1425 do {
1426 gint sig = 0;
1428 pth_sigwait_ev(&set, &sig, timeout_ev);
1429 pth_event_isolate(timeout_ev);
1430 pth_event_isolate(keepalive_ev);
1432 if (pth_event_occurred(timeout_ev)) {
1434 * The timer event has expired. Update the file cache. When the
1435 * cache mutex is locked and the timer expires again, the threads
1436 * will stack.
1438 pth_spawn(attr, adjust_timer_thread, NULL);
1439 pth_event_free(timeout_ev, PTH_FREE_THIS);
1440 timeout_ev= pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1443 * Just in case the configuration file has been reloaded.
1445 keepalive = get_key_file_integer("global", "keepalive");
1448 if (keepalive_ev && pth_event_occurred(keepalive_ev)) {
1449 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1450 keepalive_ev = NULL;
1451 send_status_all(STATUS_KEEPALIVE);
1453 if (keepalive > 0)
1454 keepalive_ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1457 pth_event_concat(timeout_ev, keepalive_ev, NULL);
1459 if (sig > 0) {
1460 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1462 /* Caught a signal. */
1463 switch (sig) {
1464 case SIGUSR1:
1465 reload_rcfile();
1466 break;
1467 case SIGABRT:
1468 CACHE_LOCK(NULL);
1469 cache_clear(NULL, 2);
1470 CACHE_UNLOCK;
1471 #ifndef MEM_DEBUG
1472 xpanic();
1473 #endif
1474 exit(EXIT_FAILURE);
1475 case SIGHUP:
1476 CACHE_LOCK(NULL);
1477 log_write(N_("clearing file cache"));
1478 cache_clear(NULL, 2);
1479 CACHE_UNLOCK;
1480 break;
1481 default:
1482 quit = 1;
1483 shutdown(sockfd, SHUT_RDWR);
1484 close(sockfd);
1485 break;
1488 } while (!quit);
1491 * We're out of the main server loop. This happens when a signal was sent
1492 * to terminate the daemon. We'll wait for all clients to disconnect
1493 * before exiting and ignore any following signals.
1495 pth_join(accept_tid, &value);
1496 pth_attr_destroy(attr);
1497 pth_event_free(timeout_ev, PTH_FREE_THIS);
1498 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1499 unlink(*socketpath);
1500 g_free(*socketpath);
1501 *socketpath = NULL;
1503 if (n > 1)
1504 log_write(N_("waiting for all threads to terminate"));
1506 while (n > 1) {
1507 pth_event_t events;
1509 if (n != n_clients) {
1510 log_write(N_("%i threads remain"), n-1);
1511 n_clients = n;
1514 events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1515 pth_wait(events);
1516 pth_event_isolate(events);
1517 pth_event_free(events, PTH_FREE_THIS);
1518 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1523 * Called from pinentry_fork() in the child process.
1525 void free_client_list()
1527 gint i, t = g_slist_length(cn_thread_list);
1529 for (i = 0; i < t; i++) {
1530 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1532 free_client(cn->cl);
1535 memset(key_cache, 0, cache_size);
1538 int main(int argc, char *argv[])
1540 gint opt;
1541 struct sockaddr_un addr;
1542 struct passwd *pw = getpwuid(getuid());
1543 gchar buf[PATH_MAX];
1544 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1545 gchar *socketarg = NULL;
1546 gchar *datadir = NULL;
1547 gboolean n;
1548 gchar *p;
1549 gchar **cache_push = NULL;
1550 gint iter = 0;
1551 gchar *import = NULL;
1552 gint cmd_iterations = -1;
1553 gint default_timeout;
1554 gint rcfile_spec = 0;
1555 gint estatus = EXIT_FAILURE;
1556 gint sockfd;
1557 #ifndef MEM_DEBUG
1558 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1559 #endif
1560 gint do_unlink = 1;
1561 gboolean secure = FALSE;
1562 guint ptotal = 0;
1563 gint background = 0;
1564 sigset_t set;
1565 #ifndef DEBUG
1566 #ifdef HAVE_SETRLIMIT
1567 struct rlimit rl;
1569 rl.rlim_cur = rl.rlim_max = 0;
1571 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1572 err(EXIT_FAILURE, "setrlimit()");
1573 #endif
1574 #endif
1576 #ifdef ENABLE_NLS
1577 setlocale(LC_ALL, "");
1578 bindtextdomain("pwmd", LOCALEDIR);
1579 textdomain("pwmd");
1580 #endif
1582 gpg_err_init();
1583 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1584 #ifndef MEM_DEBUG
1585 g_mem_set_vtable(&mtable);
1586 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1587 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1588 xmlInitMemory();
1589 #endif
1590 pth_init();
1591 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1593 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1594 err(EXIT_FAILURE, "%s", buf);
1596 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1598 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1599 err(EXIT_FAILURE, "%s", buf);
1601 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1603 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1604 err(EXIT_FAILURE, "sysconf()");
1606 cache_size = page_size;
1608 while ((opt = getopt(argc, argv, "bI:i:hvf:D")) != EOF) {
1609 switch (opt) {
1610 case 'b':
1611 background = 1;
1612 break;
1613 case 'D':
1614 secure = TRUE;
1615 break;
1616 case 'I':
1617 import = optarg;
1618 break;
1619 case 'i':
1620 cmd_iterations = atoi(optarg);
1621 break;
1622 case 'f':
1623 g_free(rcfile);
1624 rcfile = g_strdup(optarg);
1625 rcfile_spec = 1;
1626 break;
1627 case 'v':
1628 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1629 exit(EXIT_SUCCESS);
1630 case 'h':
1631 default:
1632 usage(argv[0]);
1636 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1637 exit(EXIT_FAILURE);
1639 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1640 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1642 if (log_syslog == TRUE)
1643 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1645 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1646 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1648 #ifdef HAVE_MLOCKALL
1649 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1650 warn("mlockall()");
1651 goto do_exit;
1653 #endif
1655 setup_gcrypt();
1657 if (import) {
1658 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1659 g_key_file_free(keyfileh);
1660 g_free(rcfile);
1661 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1664 g_key_file_set_list_separator(keyfileh, ',');
1666 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1667 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1669 if (*p == '~') {
1670 p++;
1671 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1672 g_free(p);
1673 socketarg = g_strdup(buf);
1675 else
1676 socketarg = p;
1678 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1679 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1681 datadir = expand_homedir(p);
1682 g_free(p);
1684 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1685 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1686 disable_list_and_dump = n;
1688 else
1689 disable_list_and_dump = secure;
1691 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1692 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1693 else
1694 default_timeout = -1;
1696 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1697 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1699 if (cache_size < page_size || cache_size % page_size)
1700 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1703 setup_logging(keyfileh);
1705 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1706 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1708 if (argc != optind) {
1709 if (cache_push)
1710 ptotal = g_strv_length(cache_push);
1712 for (; optind < argc; optind++) {
1713 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1714 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1718 if (strchr(socketarg, '/') == NULL) {
1719 socketdir = g_get_current_dir();
1720 socketname = g_strdup(socketarg);
1721 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1723 else {
1724 socketname = g_strdup(strrchr(socketarg, '/'));
1725 socketname++;
1726 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1727 socketdir = g_strdup(socketarg);
1728 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1731 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1732 #ifdef MMAP_ANONYMOUS
1733 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1734 #else
1735 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1736 #endif
1737 err(EXIT_FAILURE, "mmap()");
1740 if (mlock(key_cache, cache_size) == -1)
1741 log_write("mlock(): %s", strerror(errno));
1743 memset(key_cache, 0, cache_size);
1745 if (chdir(datadir)) {
1746 warn("%s", datadir);
1747 unlink(socketpath);
1748 goto do_exit;
1751 if (parse_keyfile_key() == FALSE)
1752 goto do_exit;
1754 clear_errorfile_key();
1757 * Set the cache entry for a file. Prompts for the password.
1759 if (cache_push) {
1760 for (opt = 0; cache_push[opt]; opt++)
1761 do_cache_push(cache_push[opt], NULL);
1763 g_strfreev(cache_push);
1764 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1768 * bind() doesn't like the full pathname of the socket or any non alphanum
1769 * characters so change to the directory where the socket is wanted then
1770 * create it then change to datadir.
1772 if (chdir(socketdir)) {
1773 warn("%s", socketdir);
1774 goto do_exit;
1777 g_free(socketdir);
1779 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1780 warn("socket()");
1781 goto do_exit;
1784 addr.sun_family = AF_UNIX;
1785 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1787 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1788 warn("bind()");
1790 if (errno == EADDRINUSE)
1791 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1792 "stale socket. Please remove it manually."), socketpath);
1794 do_unlink = 0;
1795 goto do_exit;
1798 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1799 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1800 mode_t mode = strtol(t, NULL, 8);
1801 mode_t mask = umask(0);
1803 g_free(t);
1805 if (chmod(socketname, mode) == -1) {
1806 warn("%s", socketname);
1807 close(sockfd);
1808 unlink(socketpath);
1809 umask(mask);
1810 goto do_exit;
1813 umask(mask);
1816 g_free(--socketname);
1818 if (chdir(datadir)) {
1819 warn("%s", datadir);
1820 close(sockfd);
1821 unlink(socketpath);
1822 goto do_exit;
1825 g_free(datadir);
1826 pth_mutex_init(&cache_mutex);
1827 #ifdef WITH_PINENTRY
1828 pth_mutex_init(&pin_mutex);
1829 #endif
1831 if (listen(sockfd, 0) == -1) {
1832 warn("listen()");
1833 goto do_exit;
1836 if (background) {
1837 switch (fork()) {
1838 case -1:
1839 warn("fork()");
1840 goto do_exit;
1841 case 0:
1842 close(0);
1843 close(1);
1844 close(2);
1845 setsid();
1846 break;
1847 default:
1848 exit(EXIT_SUCCESS);
1853 * These are the signals that we use in threads. libpth can catch signals
1854 * itself so ignore them everywhere else. Note that using
1855 * signal(N, SIG_IGN) doesn't work like you might think.
1857 sigemptyset(&set);
1859 /* Termination */
1860 sigaddset(&set, SIGTERM);
1861 sigaddset(&set, SIGINT);
1863 /* Configuration file reloading. */
1864 sigaddset(&set, SIGUSR1);
1866 /* Clears the file cache. */
1867 sigaddset(&set, SIGHUP);
1869 /* Caught in client_thread(). Sends a cache status message. */
1870 sigaddset(&set, SIGUSR2);
1872 /* Ignored everywhere. When a client disconnects abnormally this signal
1873 * gets raised. It isn't needed though because client_thread() will check
1874 * for rcs even after the client disconnects. */
1875 signal(SIGPIPE, SIG_IGN);
1876 pth_sigmask(SIG_BLOCK, &set, NULL);
1877 server_loop(sockfd, &socketpath);
1878 estatus = EXIT_SUCCESS;
1880 do_exit:
1881 if (socketpath && do_unlink) {
1882 unlink(socketpath);
1883 g_free(socketpath);
1886 g_key_file_free(keyfileh);
1887 g_free(rcfile);
1888 xmlCleanupParser();
1890 if (key_cache) {
1891 cache_clear(NULL, 2);
1892 memset(key_cache, 0, cache_size);
1895 if (key_cache && munmap(key_cache, cache_size) == -1)
1896 log_write("munmap(): %s", strerror(errno));
1898 if (estatus == EXIT_SUCCESS)
1899 log_write(N_("pwmd exiting normally"));
1901 pth_kill();
1902 #if defined(DEBUG) && !defined(MEM_DEBUG)
1903 xdump();
1904 #endif
1905 exit(estatus);