Use $enableval in configure.ac. Fixes --disable-feature.
[pwmd.git] / src / pwmd.c
blobd6581a722368a61dba8b8955059476f6091b4414
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 #ifdef TM_IN_SYS_TIME
52 #include <sys/time.h>
53 #else
54 #include <time.h>
55 #endif
57 #ifndef MEM_DEBUG
58 #include "mem.h"
59 #endif
61 #include "xml.h"
62 #include "common.h"
64 #ifdef WITH_PINENTRY
65 #include "pinentry.h"
66 #endif
68 #include "commands.h"
69 #include "pwmd_error.h"
70 #include "cache.h"
71 #include "misc.h"
72 #include "pwmd.h"
74 static void clear_errorfile_key()
76 gsize n;
77 gchar **groups;
78 gchar **p;
80 groups = g_key_file_get_groups(keyfileh, &n);
82 for (p = groups; *p; p++) {
83 GError *rc = NULL;
85 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
86 g_key_file_set_string(keyfileh, *p, "key", "");
89 g_strfreev(groups);
92 static void reload_rcfile()
94 log_write(N_("reloading configuration file '%s'"), rcfile);
95 g_key_file_free(keyfileh);
96 keyfileh = parse_rcfile(0);
97 clear_errorfile_key();
98 send_status_all(STATUS_CONFIG);
101 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
103 gpg_error_t n = gpg_error_from_errno(e);
105 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
108 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
110 gpg_err_code_t n = gpg_err_code(e);
111 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
112 struct client_s *client = assuan_get_pointer(ctx);
114 if (!e)
115 return assuan_process_done(ctx, 0);
117 if (!ctx) {
118 log_write("%s\n", pwmd_strerror(e));
119 return e;
122 if (n == EPWMD_LIBXML_ERROR) {
123 xmlErrorPtr xe = client->xml_error;
125 if (!xe)
126 xe = xmlGetLastError();
128 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
129 log_write("%s", xe->message);
131 if (xe == client->xml_error)
132 xmlResetError(xe);
133 else
134 xmlResetLastError();
136 client->xml_error = NULL;
137 return e;
140 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
143 void log_write(const gchar *fmt, ...)
145 gchar *args, *line;
146 va_list ap;
147 struct tm *tm;
148 time_t now;
149 gchar tbuf[21];
150 gint fd = -1;
151 pth_attr_t attr;
152 gchar *name;
153 pth_t tid = pth_self();
154 gchar tid_str[12], *p;
156 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
157 return;
159 if (logfile) {
160 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
161 warn(N_("logfile"));
162 return;
166 va_start(ap, fmt);
168 if (g_vasprintf(&args, fmt, ap) == -1) {
169 if (logfile)
170 close(fd);
172 va_end(ap);
173 return;
176 attr = pth_attr_of(tid);
178 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
179 name = "unknown";
181 pth_attr_destroy(attr);
182 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
183 p = tid_str;
185 if (strncmp(p+1, name, 9) == 0)
186 p = NULL;
188 if (log_syslog == TRUE)
189 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
191 va_end(ap);
192 time(&now);
193 tm = localtime(&now);
194 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
195 tbuf[sizeof(tbuf) - 1] = 0;
197 if (args[strlen(args)-1] == '\n')
198 args[strlen(args)-1] = 0;
200 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
201 p ? p : "", args);
202 g_free(args);
204 if (!line) {
205 if (logfile)
206 close(fd);
208 return;
211 if (logfile) {
212 write(fd, line, strlen(line));
213 fsync(fd);
214 close(fd);
217 if (isatty(STDERR_FILENO)) {
218 fprintf(stderr, "%s", line);
219 fflush(stderr);
222 g_free(line);
225 static void usage(gchar *pn)
227 g_printf(N_(
228 "Usage: %s [-hvDn] [-f <rcfile>] [-I <filename> [-i <iter>]] [file1] [...]\n"
229 " -n run as a foreground process\n"
230 " -f load the specified rcfile (~/.pwmd/config)\n"
231 " -I import an XML file and write the encrypted data to stdout\n"
232 " -i encrypt with the specified number of iterations when importing\n"
233 " (config default in the \"global\" section)\n"
234 " -D disable use of the LIST and DUMP commands\n"
235 " -v version\n"
236 " -h this help text\n"
237 ), pn);
238 exit(EXIT_SUCCESS);
241 #ifndef MEM_DEBUG
242 static int gcry_SecureCheck(const void *ptr)
244 return 1;
246 #endif
248 static void setup_gcrypt()
250 gcry_check_version(NULL);
252 #ifndef MEM_DEBUG
253 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
254 xfree);
255 #endif
257 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
258 NULL) != 0)
259 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
261 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
262 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
265 static assuan_context_t new_connection(gint fd)
267 gpg_error_t rc;
268 gchar ver[ASSUAN_LINELENGTH];
269 assuan_context_t ctx;
271 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
273 if (rc)
274 goto fail;
276 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
277 assuan_set_hello_line(ctx, ver);
278 rc = register_commands(ctx);
280 if (rc)
281 goto fail;
283 rc = assuan_accept(ctx);
285 if (rc)
286 goto fail;
288 return ctx;
290 fail:
291 assuan_deinit_server(ctx);
292 log_write("%s", gpg_strerror(rc));
293 return NULL;
296 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
298 gchar *line = NULL;
299 struct client_s *client = assuan_get_pointer(ctx);
300 gchar buf[ASSUAN_LINELENGTH];
301 gchar *status = NULL;
303 switch (which) {
304 case STATUS_CACHE:
305 CACHE_LOCK(client->ctx);
306 line = print_fmt(buf, sizeof(buf), "%i %i",
307 cache_file_count(),
308 (cache_size % sizeof(file_cache_t)) ?
309 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
310 (cache_size / sizeof(file_cache_t)) - cache_file_count());
311 CACHE_UNLOCK;
312 status = "CACHE";
313 break;
314 case STATUS_CLIENTS:
315 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
316 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
317 pth_mutex_release(&cn_mutex);
318 status = "CLIENTS";
319 break;
320 case STATUS_CONFIG:
321 status = "CONFIG";
322 break;
323 case STATUS_KEEPALIVE:
324 status = "KEEPALIVE";
325 break;
326 case STATUS_LOCKED:
327 status = "LOCKED";
328 line = N_("Waiting for lock");
329 break;
332 return assuan_write_status(ctx, status, line);
335 void send_status_all(status_msg_t which)
337 guint i, t;
339 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
341 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
342 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
343 pth_msgport_t m = pth_msgport_find(cn->msg_name);
345 if (m) {
346 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
348 msg->m_data = (status_msg_t *)which;
349 pth_msgport_put(m, msg);
353 pth_mutex_release(&cn_mutex);
356 static void xml_error_cb(void *data, xmlErrorPtr e)
358 struct client_s *client = data;
361 * Keep the first reported error as the one to show in the error
362 * description. Reset in send_error().
364 if (client->xml_error)
365 return;
367 xmlCopyError(e, client->xml_error);
371 * This is called after a child_thread terminates. Set with
372 * pth_cleanup_push().
374 static void cleanup_cb(void *arg)
376 struct client_thread_s *cn = arg;
377 gpointer value;
378 struct client_s *cl = cn->cl;
380 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
381 log_write(N_("exiting, fd=%i"), cn->fd);
383 if (cn->msg_tid) {
384 pth_cancel(cn->msg_tid);
385 pth_join(cn->msg_tid, &value);
386 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
389 if (cn->msg_name)
390 g_free(cn->msg_name);
392 if (cn->msg) {
393 while (pth_msgport_pending(cn->msg) > 0) {
394 pth_message_t *m = pth_msgport_get(cn->msg);
396 g_free(m);
399 pth_msgport_destroy(cn->msg);
402 pth_join(cn->tid, &value);
404 if (cl && cl->freed == FALSE)
405 cleanup_assuan(cl->ctx);
407 if (cl && cl->ctx)
408 assuan_deinit_server(cl->ctx);
410 #ifdef WITH_PINENTRY
411 if (cl && cl->pinentry)
412 cleanup_pinentry(cl->pinentry);
413 #endif
415 g_free(cl);
416 cn_thread_list = g_slist_remove(cn_thread_list, cn);
417 g_free(cn);
418 pth_mutex_release(&cn_mutex);
419 send_status_all(STATUS_CLIENTS);
422 static void *client_msg_thread(void *data)
424 struct client_s *cl = data;
425 pth_status_t ev_status;
427 for (;;) {
428 pth_wait(cl->thd->msg_ev);
429 ev_status = pth_event_status(cl->thd->msg_ev);
431 if (ev_status == PTH_STATUS_FAILED) {
432 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
433 __FUNCTION__);
434 continue;
437 if (ev_status == PTH_STATUS_OCCURRED) {
438 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
440 while (pth_msgport_pending(cl->thd->msg) > 0) {
441 pth_message_t *m = pth_msgport_get(cl->thd->msg);
442 status_msg_t n = (status_msg_t)m->m_data;
443 gpg_error_t rc = send_status(cl->ctx, n);
445 g_free(m);
447 if (rc) {
448 pth_mutex_release(&cn_mutex);
449 log_write("%s", gpg_strerror(rc));
450 break;
454 pth_mutex_release(&cn_mutex);
460 * Called every time a connection is made via pth_spawn(). This is the thread
461 * entry point.
463 static void *client_thread(void *data)
465 struct client_thread_s *thd = data;
466 gint fd = thd->fd;
467 pth_event_t ev;
468 struct client_s *cl = g_malloc0(sizeof(struct client_s));
469 gpg_error_t rc;
470 pth_attr_t attr;
472 if (!cl) {
473 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
474 goto fail;
477 #ifdef WITH_PINENTRY
478 cl->pinentry = pinentry_init();
480 if (!cl->pinentry) {
481 g_free(cl);
482 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
483 goto fail;
485 #endif
487 thd->cl = cl;
488 cl->thd = thd;
489 pth_cleanup_push(cleanup_cb, thd);
490 thd->msg_name = g_strdup_printf("%p", thd->tid);
492 if (!thd->msg_name) {
493 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
494 goto fail;
497 thd->msg = pth_msgport_create(thd->msg_name);
499 if (!thd->msg) {
500 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
501 goto fail;
504 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
505 attr = pth_attr_new();
506 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
507 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
508 pth_attr_destroy(attr);
510 if (!thd->msg_tid) {
511 log_write(N_("pth_spawn() failed"));
512 goto fail;
516 * This is a "child" thread. Don't catch any signals. Let the master
517 * thread take care of signals in accept_thread().
519 cl->ctx = new_connection(fd);
520 cl->fd = fd;
522 if (!cl->ctx)
523 goto fail;
525 assuan_set_pointer(cl->ctx, cl);
527 #ifdef HAVE_MLOCKALL
528 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
529 log_write("mlockall(): %s", strerror(errno));
530 goto fail;
532 #endif
534 rc = send_status(cl->ctx, STATUS_CACHE);
536 if (rc) {
537 log_write("%s", gpg_strerror(rc));
538 goto fail;
541 send_status_all(STATUS_CLIENTS);
542 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
543 xmlInitParser();
544 xmlXPathInit();
545 xmlSetStructuredErrorFunc(cl, xml_error_cb);
547 for (;;) {
548 pth_status_t ev_status;
550 pth_wait(ev);
551 ev_status = pth_event_status(ev);
553 if (ev_status == PTH_STATUS_FAILED) {
554 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
555 __FUNCTION__);
556 goto done;
558 else if (ev_status == PTH_STATUS_OCCURRED) {
559 rc = assuan_process_next(cl->ctx);
561 if (rc) {
562 cl->inquire_status = INQUIRE_INIT;
564 if (gpg_err_code(rc) == GPG_ERR_EOF)
565 goto done;
567 log_write("assuan_process_next(): %s", gpg_strerror(rc));
568 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
570 if (rc) {
571 log_write("assuan_process_done(): %s", gpg_strerror(rc));
572 goto done;
575 else {
576 #ifdef WITH_PINENTRY
577 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
578 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
579 pth_event_concat(ev, cl->pinentry->ev, NULL);
580 cl->pinentry->status = PINENTRY_RUNNING;
582 #endif
584 switch (cl->inquire_status) {
585 case INQUIRE_BUSY:
586 case INQUIRE_INIT:
587 break;
588 case INQUIRE_DONE:
589 cl->inquire_status = INQUIRE_INIT;
590 rc = assuan_process_done(cl->ctx, 0);
591 break;
596 #ifdef WITH_PINENTRY
597 ev = pinentry_iterate(cl, ev);
598 #endif
602 * Client cleanup (including XML data) is done in cleanup_cb() from
603 * the cleanup thread.
605 done:
606 pth_event_free(ev, PTH_FREE_ALL);
608 fail:
609 pth_exit(NULL);
610 return NULL;
613 static void setup_logging(GKeyFile *kf)
615 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
617 if (n == TRUE) {
618 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
620 if (*p == '~') {
621 gchar buf[PATH_MAX];
623 p++;
624 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
625 g_free(p);
627 if (logfile)
628 g_free(logfile);
630 logfile = g_strdup(buf);
632 else {
633 if (logfile)
634 g_free(logfile);
636 logfile = p;
640 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
644 * Make sure all settings are set to either the specified setting or a
645 * default.
647 static void set_rcfile_defaults(GKeyFile *kf)
649 gchar buf[PATH_MAX];
651 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
652 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
653 g_key_file_set_string(kf, "global", "socket_path", buf);
656 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
657 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
658 g_key_file_set_string(kf, "global", "data_directory", buf);
661 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
662 g_key_file_set_boolean(kf, "global", "backup", TRUE);
664 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
665 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
666 g_key_file_set_string(kf, "global", "log_path", buf);
669 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
670 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
672 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
673 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
675 #ifdef HAVE_MLOCKALL
676 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
677 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
678 #endif
680 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
681 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
683 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
684 g_key_file_set_integer(kf, "global", "iterations", 0);
686 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
687 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
689 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
690 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
692 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
693 g_key_file_set_integer(kf, "global", "compression_level", 6);
695 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
696 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
698 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
699 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
701 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
703 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
704 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
706 #ifdef HAVE_MLOCKALL
707 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
708 #endif
710 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
711 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
713 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
714 g_key_file_set_integer(kf, "global", "keepalive", 30);
716 #ifdef WITH_PINENTRY
717 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
718 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
720 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
721 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
722 #endif
724 setup_logging(kf);
727 static GKeyFile *parse_rcfile(int cmdline)
729 GKeyFile *kf = g_key_file_new();
730 GError *rc = NULL;
732 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
733 log_write("%s: %s", rcfile, rc->message);
735 if (cmdline)
736 exit(EXIT_FAILURE);
738 if (rc->code == G_FILE_ERROR_NOENT) {
739 g_clear_error(&rc);
740 set_rcfile_defaults(kf);
741 return kf;
744 g_clear_error(&rc);
745 return NULL;
747 else
748 set_rcfile_defaults(kf);
750 return kf;
753 static gchar *get_password(const gchar *prompt)
755 gchar buf[LINE_MAX] = {0}, *p;
756 struct termios told, tnew;
757 gchar *key;
759 if (tcgetattr(STDIN_FILENO, &told) == -1)
760 err(EXIT_FAILURE, "tcgetattr()");
762 memcpy(&tnew, &told, sizeof(struct termios));
763 tnew.c_lflag &= ~(ECHO);
764 tnew.c_lflag |= ICANON|ECHONL;
766 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
767 tcsetattr(STDIN_FILENO, TCSANOW, &told);
768 err(EXIT_FAILURE, "tcsetattr()");
771 fprintf(stderr, "%s", prompt);
773 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
774 tcsetattr(STDIN_FILENO, TCSANOW, &told);
775 return NULL;
778 tcsetattr(STDIN_FILENO, TCSANOW, &told);
779 p[strlen(p) - 1] = 0;
781 if (!buf[0]) {
782 key = gcry_malloc(1);
783 key[0] = 0;
785 else {
786 key = gcry_malloc(strlen(p) + 1);
787 sprintf(key, "%s", p);
790 memset(&buf, 0, sizeof(buf));
791 return key;
794 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
796 int fd;
797 struct stat st;
798 gpg_error_t rc;
799 gint iter;
801 if ((fd = open_file(filename, &st)) == -1) {
802 warn("%s", filename);
803 return FALSE;
806 if (st.st_size == 0) {
807 warnx(N_("%s: skipping empty file"), filename);
808 close(fd);
809 return FALSE;
812 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
813 close(fd);
814 return rc ? FALSE : TRUE;
817 static gboolean get_input(const gchar *filename, guchar *key)
819 gint try = 0;
820 gchar *password;
821 gchar *prompt;
823 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
825 again:
826 if ((password = get_password(prompt)) == NULL) {
827 warnx(N_("%s: skipping file"), filename);
828 g_free(prompt);
829 return FALSE;
832 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
833 gcry_free(password);
835 if (do_try_xml_decrypt(filename, key) == FALSE) {
836 if (try++ == 2) {
837 warnx(N_("%s: invalid password, skipping"), filename);
838 g_free(prompt);
839 return FALSE;
841 else {
842 warnx(N_("%s: invalid password"), filename);
843 goto again;
847 g_free(prompt);
848 return TRUE;
851 static gboolean xml_import(const gchar *filename, gint iter)
853 xmlDocPtr doc;
854 gint fd;
855 struct stat st;
856 gint len;
857 xmlChar *xmlbuf;
858 xmlChar *xml;
859 gchar *key = NULL;
860 gchar *key2 = NULL;
861 guchar shakey[gcrykeysize];
862 gcry_cipher_hd_t gh;
863 gpg_error_t rc;
864 gint level;
865 glong outsize;
866 gpointer outbuf;
867 gint zrc;
869 if (stat(filename, &st) == -1) {
870 warn("%s", filename);
871 return FALSE;
874 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
875 send_error(NULL, rc);
876 gcry_cipher_close(gh);
877 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
878 return FALSE;
881 if (iter == -1)
882 goto done;
884 if ((key = get_password(N_("New password: "))) == NULL) {
885 fprintf(stderr, "%s\n", N_("Invalid password."));
886 gcry_cipher_close(gh);
887 return FALSE;
890 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
891 fprintf(stderr, "%s\n", N_("Passwords do not match."));
892 gcry_free(key);
893 gcry_cipher_close(gh);
894 return FALSE;
897 if (g_utf8_collate(key, key2) != 0) {
898 fprintf(stderr, "%s\n", N_("Passwords do not match."));
899 gcry_free(key);
900 gcry_free(key2);
901 gcry_cipher_close(gh);
902 return FALSE;
905 gcry_free(key2);
907 done:
908 if ((fd = open(filename, O_RDONLY)) == -1) {
909 gcry_free(key);
910 warn("%s", filename);
911 gcry_cipher_close(gh);
912 return FALSE;
915 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
916 gcry_free(key);
917 close(fd);
918 log_write("%s", strerror(ENOMEM));
919 gcry_cipher_close(gh);
920 return FALSE;
923 if (read(fd, xmlbuf, st.st_size) == -1) {
924 rc = errno;
925 close(fd);
926 gcry_free(key);
927 gcry_cipher_close(gh);
928 errno = rc;
929 err(EXIT_FAILURE, "read()");
932 close(fd);
933 xmlbuf[st.st_size] = 0;
936 * Make sure the document validates.
938 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
939 log_write("xmlReadDoc()");
940 close(fd);
941 gcry_free(key);
942 gcry_free(xmlbuf);
943 gcry_cipher_close(gh);
944 return FALSE;
947 gcry_free(xmlbuf);
948 xmlDocDumpMemory(doc, &xml, &len);
949 xmlFreeDoc(doc);
951 level = get_key_file_integer(filename, "compression_level");
953 if (level < 0)
954 level = 0;
956 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
957 memset(shakey, 0, sizeof(shakey));
958 gcry_free(xml);
960 if (zrc == Z_MEM_ERROR)
961 warnx("%s", strerror(ENOMEM));
962 else
963 warnx("do_compress() failed");
965 gcry_cipher_close(gh);
966 return FALSE;
968 else {
969 gcry_free(xml);
970 xml = outbuf;
971 len = outsize;
974 if (iter == -1)
975 memset(shakey, '!', sizeof(shakey));
976 else{
977 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
978 gcry_free(key);
981 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
982 gcry_cipher_close(gh);
984 if (rc) {
985 memset(shakey, 0, sizeof(shakey));
986 warnx("%s", gpg_strerror(rc));
987 return FALSE;
990 memset(shakey, 0, sizeof(shakey));
991 return TRUE;
994 gchar *get_key_file_string(const gchar *section, const gchar *what)
996 gchar *val = NULL;
997 GError *grc = NULL;
999 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1000 val = g_key_file_get_string(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_string(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 gint get_key_file_integer(const gchar *section, const gchar *what)
1023 gint val = -1;
1024 GError *grc = NULL;
1026 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1027 val = g_key_file_get_integer(keyfileh, section, what, &grc);
1029 if (grc) {
1030 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1031 g_clear_error(&grc);
1034 else {
1035 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1036 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1038 if (grc) {
1039 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1040 g_clear_error(&grc);
1045 return val;
1048 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1050 gboolean val = FALSE;
1051 GError *grc = NULL;
1053 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1054 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1056 if (grc) {
1057 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1058 g_clear_error(&grc);
1061 else {
1062 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1063 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1065 if (grc) {
1066 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1067 g_clear_error(&grc);
1072 return val;
1075 static gboolean _getline(const gchar *file, gchar **result)
1077 FILE *fp;
1078 gchar buf[LINE_MAX] = {0}, *p;
1079 gchar *str = NULL;
1080 gint len;
1082 if ((fp = fopen(file, "r")) == NULL) {
1083 warn("%s", file);
1084 return FALSE;
1087 p = fgets(buf, sizeof(buf), fp);
1088 fclose(fp);
1089 len = strlen(buf);
1091 if (len && buf[len - 1] == '\n')
1092 buf[--len] = 0;
1094 str = gcry_malloc(len + 1);
1095 memcpy(str, buf, len ? len : 1);
1096 str[len] = 0;
1097 memset(&buf, 0, sizeof(buf));
1098 *result = str;
1099 return TRUE;
1102 static gboolean parse_keyfile_key()
1104 gsize n;
1105 gchar **groups;
1106 gchar **p;
1107 gchar *str;
1109 groups = g_key_file_get_groups(keyfileh, &n);
1111 for (p = groups; *p; p++) {
1112 GError *rc = NULL;
1114 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1115 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1117 if (!str) {
1118 if (rc) {
1119 warnx("%s", rc->message);
1120 g_clear_error(&rc);
1123 continue;
1126 do_cache_push(*p, str);
1127 g_free(str);
1128 continue;
1131 if (rc) {
1132 warnx("%s", rc->message);
1133 g_clear_error(&rc);
1134 continue;
1137 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1138 gchar *t;
1139 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1141 if (!file) {
1142 if (rc) {
1143 warnx("%s", rc->message);
1144 g_clear_error(&rc);
1147 continue;
1150 t = expand_homedir(file);
1151 g_free(file);
1152 file = t;
1154 if (_getline(file, &str) == FALSE) {
1155 g_free(file);
1156 continue;
1159 g_free(file);
1160 do_cache_push(*p, str);
1161 gcry_free(str);
1162 continue;
1165 if (rc) {
1166 warnx("%s", rc->message);
1167 g_clear_error(&rc);
1171 g_strfreev(groups);
1172 return TRUE;
1175 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1177 guchar *md5file;
1178 guchar *key;
1179 gint timeout;
1180 const gchar *p = filename;
1181 file_header_t file_header;
1182 gpg_error_t rc;
1184 while (isspace(*p))
1185 p++;
1187 if (!*p)
1188 return FALSE;
1190 if (valid_filename(p) == FALSE) {
1191 warnx(N_("%s: invalid characters in filename"), p);
1192 return FALSE;
1195 md5file = gcry_malloc(16);
1196 key = gcry_malloc(gcrykeysize);
1197 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1199 if (cache_iscached(md5file) == TRUE) {
1200 warnx(N_("%s: file already cached, skipping"), p);
1201 gcry_free(md5file);
1202 gcry_free(key);
1203 return FALSE;
1206 if (access(p, R_OK|W_OK) != 0) {
1207 gcry_free(md5file);
1208 gcry_free(key);
1210 if (errno != ENOENT) {
1211 warn("%s", p);
1212 return FALSE;
1215 warn("%s", p);
1216 return TRUE;
1219 rc = read_file_header(filename, &file_header);
1221 if (rc) {
1222 gcry_free(md5file);
1223 gcry_free(key);
1224 warnx("%s", pwmd_strerror(rc));
1225 return FALSE;
1228 if (file_header.iter == -1) {
1229 memset(key, '!', gcrykeysize);
1230 goto try_decrypt;
1233 if (!password) {
1234 #ifdef WITH_PINENTRY
1235 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1236 #endif
1237 if (get_input(p, key) == FALSE) {
1238 gcry_free(key);
1239 gcry_free(md5file);
1240 return FALSE;
1242 #ifdef WITH_PINENTRY
1244 else {
1245 gchar *result = NULL;
1246 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1247 gint try = 0;
1249 set_pinentry_defaults(pin);
1250 pin->which = PINENTRY_OPEN;
1251 pin->filename = g_strdup(filename);
1252 again:
1253 rc = pinentry_getpin(pin, &result);
1255 if (rc) {
1256 warnx("%s: %s", filename, gpg_strerror(rc));
1257 cleanup_pinentry(pin);
1258 gcry_free(key);
1259 gcry_free(md5file);
1260 xfree(result);
1261 return FALSE;
1264 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1265 xfree(result);
1267 if (do_try_xml_decrypt(filename, key) == FALSE) {
1268 if (try++ == 2) {
1269 cleanup_pinentry(pin);
1270 gcry_free(key);
1271 gcry_free(md5file);
1272 warnx(N_("%s: invalid password, skipping"), filename);
1273 return FALSE;
1275 else {
1276 g_free(pin->title);
1277 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1278 goto again;
1282 cleanup_pinentry(pin);
1284 #endif
1286 else {
1287 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1289 try_decrypt:
1290 if (do_try_xml_decrypt(filename, key) == FALSE) {
1291 warnx(N_("%s: invalid password, skipping"), filename);
1292 gcry_free(key);
1293 gcry_free(md5file);
1294 return FALSE;
1298 if (cache_add_file(md5file, key) == FALSE) {
1299 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1300 gcry_free(key);
1301 gcry_free(md5file);
1302 return FALSE;
1305 timeout = get_key_file_integer(p, "cache_timeout");
1306 cache_set_timeout(md5file, timeout);
1307 warnx(N_("%s: file added to the cache"), filename);
1308 gcry_free(key);
1309 gcry_free(md5file);
1310 return TRUE;
1313 static void *accept_thread(void *arg)
1315 gint sockfd = (gint)arg;
1317 for (;;) {
1318 socklen_t slen = sizeof(struct sockaddr_un);
1319 struct sockaddr_un raddr;
1320 gint fd = -1;
1321 pth_attr_t attr;
1323 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1324 if (errno != EAGAIN) {
1325 if (!quit) // probably EBADF
1326 log_write("accept(): %s", strerror(errno));
1328 break;
1332 if (fd >= 0) {
1333 pth_t tid;
1334 struct client_thread_s *new;
1335 gchar buf[41];
1337 new = g_malloc0(sizeof(struct client_thread_s));
1339 if (!new) {
1340 log_write("%s", strerror(ENOMEM));
1341 continue;
1345 * Thread priority is inherited from the calling thread. This
1346 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1347 * priority.
1349 new->fd = fd;
1350 attr = pth_attr_new();
1351 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1352 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1353 tid = pth_spawn(attr, client_thread, new);
1354 pth_attr_destroy(attr);
1356 if (!tid) {
1357 g_free(new);
1358 log_write(N_("pth_spawn() failed"));
1359 continue;
1362 g_snprintf(buf, sizeof(buf), "%p", tid);
1363 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1364 attr = pth_attr_of(tid);
1365 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1366 pth_attr_destroy(attr);
1367 new->tid = tid;
1368 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1369 cn_thread_list = g_slist_append(cn_thread_list, new);
1370 pth_mutex_release(&cn_mutex);
1374 /* Just in case pth_accept() failed for some reason other than EBADF */
1375 quit = 1;
1376 pth_exit(PTH_CANCELED);
1377 return NULL;
1381 * This thread isn't joinable. For operations that block, these threads will
1382 * stack.
1384 static void *adjust_timer_thread(void *arg)
1386 CACHE_LOCK(NULL);
1387 cache_adjust_timer();
1388 CACHE_UNLOCK;
1389 return NULL;
1392 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1393 pth_attr_t attr)
1395 pth_status_t ev_status;
1397 if (timeout_ev) {
1398 pth_event_isolate(timeout_ev);
1399 ev_status = pth_event_status(timeout_ev);
1400 pth_event_free(timeout_ev, PTH_FREE_THIS);
1402 if (ev_status == PTH_STATUS_OCCURRED) {
1404 * The timer event has expired. Update the file cache. When the
1405 * cache mutex is locked and the timer expires again, the threads
1406 * will stack.
1408 pth_spawn(attr, adjust_timer_thread, NULL);
1412 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1415 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1416 gint keepalive)
1418 pth_event_t ev = NULL;
1419 pth_status_t ev_status;
1421 if (keepalive_ev) {
1422 pth_event_isolate(keepalive_ev);
1423 ev_status = pth_event_status(keepalive_ev);
1425 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1426 if (ev_status == PTH_STATUS_OCCURRED)
1427 send_status_all(STATUS_KEEPALIVE);
1429 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1431 else
1432 ev = keepalive_ev;
1435 if (keepalive > 0 && !ev)
1436 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1438 return ev;
1441 static void server_loop(gint sockfd, gchar **socketpath)
1443 pth_t accept_tid;
1444 guint n;
1445 sigset_t set;
1446 gint n_clients = 0;
1447 pth_attr_t attr;
1448 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1449 gint keepalive = get_key_file_integer("global", "keepalive");
1450 gpointer value;
1452 pth_mutex_init(&cn_mutex);
1453 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1455 sigemptyset(&set);
1456 sigaddset(&set, SIGTERM);
1457 sigaddset(&set, SIGINT);
1458 sigaddset(&set, SIGUSR1);
1459 sigaddset(&set, SIGHUP);
1460 sigaddset(&set, SIGABRT);
1462 attr = pth_attr_new();
1463 pth_attr_init(attr);
1464 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1465 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1466 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1467 pth_attr_init(attr);
1468 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1469 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1472 * For the cache_timeout configuration parameter.
1474 timeout_ev = timeout_event_iterate(NULL, attr);
1475 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1476 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1478 do {
1479 gint sig = 0;
1481 pth_sigwait_ev(&set, &sig, timeout_ev);
1482 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1483 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1484 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1486 if (sig > 0) {
1487 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1489 /* Caught a signal. */
1490 switch (sig) {
1491 case SIGHUP:
1492 reload_rcfile();
1493 keepalive = get_key_file_integer("global", "keepalive");
1494 break;
1495 case SIGABRT:
1496 CACHE_LOCK(NULL);
1497 cache_clear(NULL, 2);
1498 CACHE_UNLOCK;
1499 #ifndef MEM_DEBUG
1500 xpanic();
1501 #endif
1502 exit(EXIT_FAILURE);
1503 case SIGUSR1:
1504 CACHE_LOCK(NULL);
1505 log_write(N_("clearing file cache"));
1506 cache_clear(NULL, 2);
1507 CACHE_UNLOCK;
1508 break;
1509 default:
1510 quit = 1;
1511 shutdown(sockfd, SHUT_RDWR);
1512 close(sockfd);
1513 break;
1516 } while (!quit);
1519 * We're out of the main server loop. This happens when a signal was sent
1520 * to terminate the daemon. We'll wait for all clients to disconnect
1521 * before exiting and ignore any following signals.
1523 pth_join(accept_tid, &value);
1524 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1525 unlink(*socketpath);
1526 g_free(*socketpath);
1527 *socketpath = NULL;
1529 if (n > 1)
1530 log_write(N_("waiting for all threads to terminate"));
1532 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1534 while (n > 1) {
1535 if (n != n_clients) {
1536 log_write(N_("%i threads remain"), n-1);
1537 n_clients = n;
1540 pth_wait(ev_quit);
1541 pth_event_isolate(ev_quit);
1542 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1543 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1544 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1545 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1548 pth_event_free(timeout_ev, PTH_FREE_THIS);
1549 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1550 pth_event_free(ev_quit, PTH_FREE_THIS);
1551 pth_attr_destroy(attr);
1555 * Called from pinentry_fork() in the child process.
1557 void free_client_list()
1559 gint i, t = g_slist_length(cn_thread_list);
1561 for (i = 0; i < t; i++) {
1562 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1564 free_client(cn->cl);
1567 memset(key_cache, 0, cache_size);
1570 int main(int argc, char *argv[])
1572 gint opt;
1573 struct sockaddr_un addr;
1574 struct passwd *pw = getpwuid(getuid());
1575 gchar buf[PATH_MAX];
1576 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1577 gchar *socketarg = NULL;
1578 gchar *datadir = NULL;
1579 gboolean n;
1580 gchar *p;
1581 gchar **cache_push = NULL;
1582 gint iter = 0;
1583 gchar *import = NULL;
1584 gint cmd_iterations = -1;
1585 gint default_timeout;
1586 gint rcfile_spec = 0;
1587 gint estatus = EXIT_FAILURE;
1588 gint sockfd;
1589 #ifndef MEM_DEBUG
1590 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1591 #endif
1592 gint do_unlink = 1;
1593 gboolean secure = FALSE;
1594 guint ptotal = 0;
1595 gint background = 1;
1596 sigset_t set;
1597 #ifndef DEBUG
1598 #ifdef HAVE_SETRLIMIT
1599 struct rlimit rl;
1601 rl.rlim_cur = rl.rlim_max = 0;
1603 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1604 err(EXIT_FAILURE, "setrlimit()");
1605 #endif
1606 #endif
1608 #ifdef ENABLE_NLS
1609 setlocale(LC_ALL, "");
1610 bindtextdomain("pwmd", LOCALEDIR);
1611 textdomain("pwmd");
1612 #endif
1614 gpg_err_init();
1615 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1616 #ifndef MEM_DEBUG
1617 g_mem_set_vtable(&mtable);
1618 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1619 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1620 xmlInitMemory();
1621 #endif
1622 pth_init();
1623 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1625 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1626 err(EXIT_FAILURE, "%s", buf);
1628 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1630 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1631 err(EXIT_FAILURE, "%s", buf);
1633 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1635 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1636 err(EXIT_FAILURE, "sysconf()");
1638 cache_size = page_size;
1640 while ((opt = getopt(argc, argv, "bnI:i:hvf:D")) != EOF) {
1641 switch (opt) {
1642 case 'b':
1643 /* Compatibility for version < 1.11 */
1644 break;
1645 case 'n':
1646 background = 0;
1647 break;
1648 case 'D':
1649 secure = TRUE;
1650 break;
1651 case 'I':
1652 import = optarg;
1653 break;
1654 case 'i':
1655 cmd_iterations = atoi(optarg);
1656 break;
1657 case 'f':
1658 g_free(rcfile);
1659 rcfile = g_strdup(optarg);
1660 rcfile_spec = 1;
1661 break;
1662 case 'v':
1663 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1664 exit(EXIT_SUCCESS);
1665 case 'h':
1666 default:
1667 usage(argv[0]);
1671 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1672 exit(EXIT_FAILURE);
1674 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1675 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1677 if (log_syslog == TRUE)
1678 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1680 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1681 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1682 errno = 0;
1684 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1685 warn("setpriority()");
1686 goto do_exit;
1690 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1691 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1693 #ifdef HAVE_MLOCKALL
1694 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1695 warn("mlockall()");
1696 goto do_exit;
1698 #endif
1700 setup_gcrypt();
1702 if (import) {
1703 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1704 g_key_file_free(keyfileh);
1705 g_free(rcfile);
1706 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1709 g_key_file_set_list_separator(keyfileh, ',');
1711 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1712 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1714 if (*p == '~') {
1715 p++;
1716 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1717 g_free(p);
1718 socketarg = g_strdup(buf);
1720 else
1721 socketarg = p;
1723 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1724 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1726 datadir = expand_homedir(p);
1727 g_free(p);
1729 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1730 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1731 disable_list_and_dump = n;
1733 else
1734 disable_list_and_dump = secure;
1736 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1737 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1738 else
1739 default_timeout = -1;
1741 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1742 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1744 if (cache_size < page_size || cache_size % page_size)
1745 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1748 setup_logging(keyfileh);
1750 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1751 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1753 if (argc != optind) {
1754 if (cache_push)
1755 ptotal = g_strv_length(cache_push);
1757 for (; optind < argc; optind++) {
1758 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1759 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1763 if (strchr(socketarg, '/') == NULL) {
1764 socketdir = g_get_current_dir();
1765 socketname = g_strdup(socketarg);
1766 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1768 else {
1769 socketname = g_strdup(strrchr(socketarg, '/'));
1770 socketname++;
1771 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1772 socketdir = g_strdup(socketarg);
1773 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1776 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1777 #ifdef MMAP_ANONYMOUS
1778 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1779 #else
1780 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1781 #endif
1782 err(EXIT_FAILURE, "mmap()");
1785 if (mlock(key_cache, cache_size) == -1)
1786 log_write("mlock(): %s", strerror(errno));
1788 memset(key_cache, 0, cache_size);
1790 if (chdir(datadir)) {
1791 warn("%s", datadir);
1792 unlink(socketpath);
1793 goto do_exit;
1796 if (parse_keyfile_key() == FALSE)
1797 goto do_exit;
1799 clear_errorfile_key();
1802 * Set the cache entry for a file. Prompts for the password.
1804 if (cache_push) {
1805 for (opt = 0; cache_push[opt]; opt++)
1806 do_cache_push(cache_push[opt], NULL);
1808 g_strfreev(cache_push);
1809 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1813 * bind() doesn't like the full pathname of the socket or any non alphanum
1814 * characters so change to the directory where the socket is wanted then
1815 * create it then change to datadir.
1817 if (chdir(socketdir)) {
1818 warn("%s", socketdir);
1819 goto do_exit;
1822 g_free(socketdir);
1824 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1825 warn("socket()");
1826 goto do_exit;
1829 addr.sun_family = AF_UNIX;
1830 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1832 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1833 warn("bind()");
1835 if (errno == EADDRINUSE)
1836 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1837 "stale socket. Please remove it manually."), socketpath);
1839 do_unlink = 0;
1840 goto do_exit;
1843 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1844 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1845 mode_t mode = strtol(t, NULL, 8);
1846 mode_t mask = umask(0);
1848 g_free(t);
1850 if (chmod(socketname, mode) == -1) {
1851 warn("%s", socketname);
1852 close(sockfd);
1853 unlink(socketpath);
1854 umask(mask);
1855 goto do_exit;
1858 umask(mask);
1861 g_free(--socketname);
1863 if (chdir(datadir)) {
1864 warn("%s", datadir);
1865 close(sockfd);
1866 unlink(socketpath);
1867 goto do_exit;
1870 g_free(datadir);
1871 pth_mutex_init(&cache_mutex);
1872 #ifdef WITH_PINENTRY
1873 pth_mutex_init(&pin_mutex);
1874 #endif
1876 if (listen(sockfd, 0) == -1) {
1877 warn("listen()");
1878 goto do_exit;
1881 if (background) {
1882 switch (fork()) {
1883 case -1:
1884 warn("fork()");
1885 goto do_exit;
1886 case 0:
1887 close(0);
1888 close(1);
1889 close(2);
1890 setsid();
1891 break;
1892 default:
1893 exit(EXIT_SUCCESS);
1898 * These are the signals that we use in threads. libpth can catch signals
1899 * itself so ignore them everywhere else. Note that using
1900 * signal(N, SIG_IGN) doesn't work like you might think.
1902 sigemptyset(&set);
1904 /* Termination */
1905 sigaddset(&set, SIGTERM);
1906 sigaddset(&set, SIGINT);
1908 /* Configuration file reloading. */
1909 sigaddset(&set, SIGUSR1);
1911 /* Clears the file cache. */
1912 sigaddset(&set, SIGHUP);
1914 /* Caught in client_thread(). Sends a cache status message. */
1915 sigaddset(&set, SIGUSR2);
1917 /* Ignored everywhere. When a client disconnects abnormally this signal
1918 * gets raised. It isn't needed though because client_thread() will check
1919 * for rcs even after the client disconnects. */
1920 signal(SIGPIPE, SIG_IGN);
1921 pth_sigmask(SIG_BLOCK, &set, NULL);
1922 server_loop(sockfd, &socketpath);
1923 estatus = EXIT_SUCCESS;
1925 do_exit:
1926 if (socketpath && do_unlink) {
1927 unlink(socketpath);
1928 g_free(socketpath);
1931 g_key_file_free(keyfileh);
1932 g_free(rcfile);
1933 xmlCleanupParser();
1935 if (key_cache) {
1936 cache_clear(NULL, 2);
1937 memset(key_cache, 0, cache_size);
1940 if (key_cache && munmap(key_cache, cache_size) == -1)
1941 log_write("munmap(): %s", strerror(errno));
1943 if (estatus == EXIT_SUCCESS)
1944 log_write(N_("pwmd exiting normally"));
1946 pth_kill();
1947 #if defined(DEBUG) && !defined(MEM_DEBUG)
1948 xdump();
1949 #endif
1950 exit(estatus);