No need to create an extra thread in client_msg_thread(). Call
[pwmd.git] / src / pwmd.c
blob74f96048f8df310b9688e3036bc83c1904389697
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 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>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <sys/time.h>
49 #include <sys/resource.h>
51 #ifdef TM_IN_SYS_TIME
52 #include <sys/time.h>
53 #else
54 #include <time.h>
55 #endif
57 #include "mem.h"
58 #include "xml.h"
59 #include "common.h"
61 #ifdef WITH_PINENTRY
62 #include "pinentry.h"
63 #endif
65 #include "commands.h"
66 #include "pwmd_error.h"
67 #include "cache.h"
68 #include "misc.h"
69 #include "pwmd.h"
70 #include "lock.h"
72 GCRY_THREAD_OPTION_PTH_IMPL;
74 static void clear_rcfile_keys()
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_thread(void *arg)
94 gboolean b = disable_list_and_dump;
95 GKeyFile *k;
96 pth_attr_t attr = pth_attr_of(pth_self());
98 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
99 pth_attr_destroy(attr);
100 MUTEX_LOCK(&rcfile_mutex);
101 log_write(N_("reloading configuration file '%s'"), rcfile);
102 k = parse_rcfile(FALSE);
104 if (!k)
105 goto done;
107 g_key_file_free(keyfileh);
108 keyfileh = k;
109 parse_rcfile_keys();
110 clear_rcfile_keys();
111 disable_list_and_dump = b;
112 startStopKeepAlive(FALSE);
113 send_status_all(STATUS_CONFIG);
114 done:
115 MUTEX_UNLOCK(&rcfile_mutex);
116 return NULL;
119 static void reload_rcfile()
121 pth_t tid;
122 pth_attr_t attr = pth_attr_new();
123 gint n;
125 pth_attr_init(attr);
126 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
127 tid = pth_spawn(attr, reload_rcfile_thread, NULL);
128 n = errno;
129 pth_attr_destroy(attr);
131 if (!tid)
132 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
133 _gpg_strerror(gpg_error_from_errno(n)));
136 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
138 gpg_error_t n = gpg_error_from_errno(e);
140 pth_cancel_point();
141 return assuan_process_done(ctx, assuan_set_error(ctx, n, _gpg_strerror(n)));
144 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
146 gpg_err_code_t n = gpg_err_code(e);
147 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
148 struct client_s *client = assuan_get_pointer(ctx);
150 pth_cancel_point();
152 if (!e)
153 return assuan_process_done(ctx, 0);
155 if (!ctx) {
156 log_write("%s", pwmd_strerror(e));
157 return e;
160 if (n == EPWMD_LIBXML_ERROR) {
161 xmlErrorPtr xe = client->xml_error;
163 if (!xe)
164 xe = xmlGetLastError();
166 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
167 log_write("%s", xe->message);
169 if (xe == client->xml_error)
170 xmlResetError(xe);
171 else
172 xmlResetLastError();
174 client->xml_error = NULL;
175 return e;
178 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
181 void log_write(const gchar *fmt, ...)
183 gchar *args, *line;
184 va_list ap;
185 struct tm *tm;
186 time_t now;
187 gchar tbuf[21];
188 gint fd = -1;
189 gchar *name;
190 gchar buf[255];
191 pth_t tid = pth_self();
192 pth_attr_t attr;
194 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
195 return;
197 if (!cmdline && logfile) {
198 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
199 warn("%s", logfile);
200 return;
204 va_start(ap, fmt);
206 if (g_vasprintf(&args, fmt, ap) == -1) {
207 if (logfile)
208 close(fd);
210 va_end(ap);
211 return;
214 va_end(ap);
216 if (cmdline) {
217 fprintf(stderr, "%s\n", args);
218 fflush(stderr);
219 g_free(args);
220 return;
223 attr = pth_attr_of(tid);
225 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
226 name = "unknown";
228 pth_attr_destroy(attr);
229 name = print_fmt(buf, sizeof(buf), "%s(%p): ", name, tid);
231 if (!cmdline && log_syslog == TRUE)
232 syslog(LOG_INFO, "%s%s", name, args);
234 time(&now);
235 tm = localtime(&now);
236 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
237 tbuf[sizeof(tbuf) - 1] = 0;
239 if (args[strlen(args)-1] == '\n')
240 args[strlen(args)-1] = 0;
242 line = g_strdup_printf("%s %i %s%s\n", tbuf, getpid(), name, args);
243 g_free(args);
245 if (!line) {
246 if (logfile)
247 close(fd);
249 return;
252 if (logfile) {
253 write(fd, line, strlen(line));
254 fsync(fd);
255 close(fd);
258 if (isatty(STDERR_FILENO)) {
259 fprintf(stderr, "%s", line);
260 fflush(stderr);
263 g_free(line);
266 static void usage(gchar *pn)
268 g_fprintf(stderr, N_(
269 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
270 "[-I <filename> [-i <iter>]]\n "
271 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
272 " -n run as a foreground process\n"
273 " -f load the specified rcfile (~/.pwmd/config)\n"
274 " -C convert a version 1 data file to version 2\n"
275 " -I import an XML file\n"
276 " -i encrypt with the specified number of iterations when importing\n"
277 " (config default in the \"global\" section)\n"
278 " -k obtain the key from the specified file\n"
279 " -o output file for use with the -C and -I options\n"
280 " -D disable use of the LIST and DUMP commands\n"
281 " -P disable pinentry\n"
282 " -v version\n"
283 " -h this help text\n"
284 ), pn);
285 exit(EXIT_FAILURE);
288 static int gcry_SecureCheck(const void *ptr)
290 return 1;
293 static void setup_gcrypt()
295 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
296 gcry_check_version(GCRYPT_VERSION);
298 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
299 xfree);
301 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
302 NULL) != 0)
303 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
305 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
306 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
309 static gint new_connection(struct client_s *cl)
311 gpg_error_t rc;
312 gchar *ver;
314 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
316 if (rc)
317 goto fail;
319 assuan_set_pointer(cl->ctx, cl);
320 ver = g_strdup_printf("%s", PACKAGE_STRING);
321 assuan_set_hello_line(cl->ctx, ver);
322 g_free(ver);
323 rc = register_commands(cl->ctx);
325 if (rc)
326 goto fail;
328 rc = assuan_accept(cl->ctx);
330 if (rc)
331 goto fail;
333 return 0;
335 fail:
336 log_write("%s", _gpg_strerror(rc));
337 close(cl->thd->fd);
338 cl->thd->fd = -1;
339 return 1;
342 static void xml_error_cb(void *data, xmlErrorPtr e)
344 struct client_s *client = data;
347 * Keep the first reported error as the one to show in the error
348 * description. Reset in send_error().
350 if (client->xml_error)
351 return;
353 xmlCopyError(e, client->xml_error);
356 static void cleanup_crypto_handler(void *arg)
358 struct client_crypto_s **a = (struct client_crypto_s **)arg;
359 struct client_crypto_s *cr = *a;
361 if (cr->fh) {
362 if (cr->fh->fd != -1 ||
363 (cmdline == TRUE && cr->fh->fd != STDOUT_FILENO))
364 close(cr->fh->fd);
366 if (cr->fh->doc)
367 gcry_free(cr->fh->doc);
369 g_free(cr->fh);
372 if (cr->gh)
373 gcry_cipher_close(cr->gh);
375 g_free(cr);
376 *a = NULL;
379 void cleanup_crypto(struct client_crypto_s **c)
381 struct client_crypto_s *cr = *c;
383 if (!cr)
384 return;
386 if (cr->iv)
387 gcry_free(cr->iv);
389 if (cr->key)
390 gcry_free(cr->key);
392 if (cr->tkey)
393 gcry_free(cr->tkey);
395 if (cr->tkey2)
396 gcry_free(cr->tkey2);
398 if (cr->inbuf)
399 gcry_free(cr->inbuf);
401 if (cr->outbuf)
402 gcry_free(cr->outbuf);
404 cleanup_crypto_handler(c);
408 * This is called after a child_thread terminates. Set with
409 * pth_cleanup_push().
411 static void cleanup_cb(void *arg)
413 struct client_thread_s *cn = arg;
414 struct client_s *cl = cn->cl;
416 MUTEX_LOCK(&cn_mutex);
417 cn_thread_list = g_slist_remove(cn_thread_list, cn);
418 MUTEX_UNLOCK(&cn_mutex);
420 if (cn->msg_tid) {
421 pth_cancel(cn->msg_tid);
422 pth_join(cn->msg_tid, NULL);
425 for (;;) {
426 struct status_msg_s *m = g_slist_nth_data(cn->msg_list, 0);
428 if (!m)
429 break;
431 cn->msg_list = g_slist_remove(cn->msg_list, m);
432 g_free(m);
435 if (cl && cl->freed == FALSE)
436 cleanup_client(cl);
438 if (cl && cl->ctx)
439 assuan_deinit_server(cl->ctx);
440 else if (cl && cl->thd && cl->thd->fd != -1)
441 close(cl->thd->fd);
443 #ifdef WITH_PINENTRY
444 if (cl && cl->pinentry)
445 cleanup_pinentry(cl->pinentry);
446 #endif
448 if (cl->crypto)
449 cleanup_crypto(&cl->crypto);
451 g_free(cl);
452 log_write(N_("exiting, fd=%i"), cn->fd);
453 g_free(cn);
454 send_status_all(STATUS_CLIENTS);
458 * Called every time a connection is made from init_new_connection(). This is
459 * the thread entry point.
461 static void *client_thread(void *data)
463 struct client_thread_s *thd = data;
464 struct client_s *cl = g_malloc0(sizeof(struct client_s));
465 gpg_error_t rc;
466 pth_attr_t attr;
467 gint n;
470 * Prevent a race condition with init_new_connection() if this thread
471 * fails (returns) for some reason before init_new_connection() releases
472 * the cn_mutex.
474 MUTEX_LOCK(&cn_mutex);
475 MUTEX_UNLOCK(&cn_mutex);
476 pth_cleanup_push(cleanup_cb, thd);
478 if (!cl) {
479 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
480 goto fail;
483 attr = pth_attr_of(pth_self());
484 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
485 pth_attr_destroy(attr);
486 thd->cl = cl;
487 cl->thd = thd;
489 if (new_connection(cl))
490 goto fail;
492 #ifdef WITH_PINENTRY
493 cl->pinentry = pinentry_init();
495 if (!cl->pinentry) {
496 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
497 goto fail;
499 #endif
501 #ifdef HAVE_MLOCKALL
502 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
503 log_write("mlockall(): %s", strerror(errno));
504 goto fail;
506 #endif
508 pth_mutex_init(&thd->msg_list_mutex);
509 attr = pth_attr_new();
510 pth_attr_init(attr);
511 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
512 thd->msg_tid = pth_spawn(attr, client_msg_thread, thd);
513 n = errno;
514 pth_attr_destroy(attr);
516 if (!thd->msg_tid) {
517 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
518 _gpg_strerror(gpg_error_from_errno(n)));
519 goto fail;
522 pth_yield(thd->msg_tid);
523 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
525 if (rc) {
526 log_write("%s", _gpg_strerror(rc));
527 goto fail;
530 send_status_all(STATUS_CLIENTS);
531 xmlSetStructuredErrorFunc(cl, xml_error_cb);
533 for (;;) {
534 #ifdef WITH_PINENTRY
535 pth_event_t pev = NULL;
536 #endif
537 pth_status_t st;
538 pth_event_t ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE,
539 cl->thd->fd);
541 #ifdef WITH_PINENTRY
542 if (cl->pinentry->status == PINENTRY_RUNNING) {
543 pev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
544 ev = pth_event_concat(ev, pev, NULL);
546 #endif
548 pth_wait(ev);
549 pth_event_isolate(ev);
550 st = pth_event_status(ev);
552 if (st == PTH_STATUS_OCCURRED) {
553 rc = assuan_process_next(cl->ctx);
554 pth_cancel_point();
556 if (rc) {
557 cl->inquire_status = INQUIRE_INIT;
559 if (gpg_err_code(rc) == GPG_ERR_EOF)
560 goto done;
562 log_write("assuan_process_next(): %s", _gpg_strerror(rc));
563 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
565 if (rc) {
566 log_write("assuan_process_done(): %s", _gpg_strerror(rc));
567 goto done;
570 else {
571 #ifdef WITH_PINENTRY
572 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT)
573 cl->pinentry->status = PINENTRY_RUNNING;
574 #endif
576 switch (cl->inquire_status) {
577 case INQUIRE_BUSY:
578 case INQUIRE_INIT:
579 break;
580 case INQUIRE_DONE:
581 cl->inquire_status = INQUIRE_INIT;
582 rc = assuan_process_done(cl->ctx, 0);
583 pth_cancel_point();
584 break;
589 pth_event_free(ev, PTH_FREE_THIS);
591 #ifdef WITH_PINENTRY
592 if (pev) {
593 pth_event_isolate(pev);
594 st = pth_event_status(pev);
595 pth_event_free(pev, PTH_FREE_THIS);
598 rc = pinentry_iterate(cl,
599 pev && cl->pinentry->fd != -1 && st == PTH_STATUS_OCCURRED);
600 #endif
604 * Client cleanup (including XML data) is done in cleanup_cb() from
605 * the cleanup thread.
607 done:
608 fail:
609 pth_cleanup_pop(1);
610 pth_exit(PTH_CANCELED);
611 return NULL;
614 static void setup_logging(GKeyFile *kf)
616 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
618 if (n == TRUE) {
619 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
621 if (*p == '~') {
622 gchar buf[PATH_MAX];
624 p++;
625 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
626 g_free(p);
628 if (logfile)
629 g_free(logfile);
631 logfile = g_strdup(buf);
633 else {
634 if (logfile)
635 g_free(logfile);
637 logfile = p;
641 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
645 * Make sure all settings are set to either the specified setting or a
646 * default.
648 static void set_rcfile_defaults(GKeyFile *kf)
650 gchar buf[PATH_MAX];
652 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
653 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
654 g_key_file_set_string(kf, "global", "socket_path", buf);
657 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
658 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
659 g_key_file_set_string(kf, "global", "data_directory", buf);
662 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
663 g_key_file_set_boolean(kf, "global", "backup", TRUE);
665 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
666 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
667 g_key_file_set_string(kf, "global", "log_path", buf);
670 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
671 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
673 #ifdef HAVE_MLOCKALL
674 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
675 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
676 #endif
678 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
679 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
681 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
682 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
683 g_key_file_set_integer(kf, "global", "iterations", 1);
685 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
686 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
688 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
689 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
691 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
692 g_key_file_set_integer(kf, "global", "compression_level", 6);
694 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
695 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
697 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
698 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
700 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
702 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
703 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
705 #ifdef HAVE_MLOCKALL
706 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
707 #endif
709 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
710 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
712 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
713 g_key_file_set_integer(kf, "global", "keepalive", DEFAULT_KEEPALIVE_TO);
715 #ifdef WITH_PINENTRY
716 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
717 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
719 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
720 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
721 #endif
723 setup_logging(kf);
726 static GKeyFile *parse_rcfile(gboolean specified)
728 GKeyFile *kf = g_key_file_new();
729 GError *rc = NULL;
731 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
732 log_write("%s: %s", rcfile, rc->message);
734 if (cmdline && specified) {
735 g_clear_error(&rc);
736 return NULL;
739 if (rc->code == G_FILE_ERROR_NOENT) {
740 g_clear_error(&rc);
741 set_rcfile_defaults(kf);
742 return kf;
745 g_clear_error(&rc);
746 return NULL;
749 set_rcfile_defaults(kf);
750 return kf;
753 static gchar *do_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 log_write("tcgetattr(): %s", strerror(errno));
761 return NULL;
764 memcpy(&tnew, &told, sizeof(struct termios));
765 tnew.c_lflag &= ~(ECHO);
766 tnew.c_lflag |= ICANON|ECHONL;
768 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
769 log_write("tcsetattr(): %s", strerror(errno));
770 tcsetattr(STDIN_FILENO, TCSANOW, &told);
771 return NULL;
774 fprintf(stderr, "%s", prompt);
776 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
777 tcsetattr(STDIN_FILENO, TCSANOW, &told);
778 return NULL;
781 tcsetattr(STDIN_FILENO, TCSANOW, &told);
782 p[strlen(p) - 1] = 0;
784 if (!buf[0]) {
785 key = gcry_malloc(1);
786 key[0] = 0;
788 else {
789 key = gcry_malloc(strlen(p) + 1);
790 sprintf(key, "%s", p);
793 memset(&buf, 0, sizeof(buf));
794 return key;
797 /* Only used when "enable_pinentry" is "false" or -P. */
798 static gpg_error_t get_input(const gchar *filename,
799 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
801 gchar *prompt;
803 if (which == PINENTRY_SAVE) {
804 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
805 crypto->tkey = do_get_password(prompt);
806 g_free(prompt);
808 if (!crypto->tkey) {
809 log_write(N_("%s: Skipping file"), filename);
810 return GPG_ERR_BAD_PASSPHRASE;
813 prompt = g_strdup_printf(N_("Repeat passphrase: "));
814 crypto->tkey2 = do_get_password(prompt);
815 g_free(prompt);
817 if (!crypto->tkey2) {
818 log_write(N_("%s: Skipping file"), filename);
819 return GPG_ERR_BAD_PASSPHRASE;
822 if (strcmp(crypto->tkey, crypto->tkey2)) {
823 log_write(N_("%s: Passphrase mismatch"), filename);
824 return EPWMD_BADKEY;
827 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
828 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
829 return 0;
832 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
834 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
835 log_write(N_("%s: Skipping file"), filename);
836 g_free(prompt);
837 return GPG_ERR_BAD_PASSPHRASE;
840 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
841 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
842 g_free(prompt);
843 return 0;
847 * inbuf must have been allocated with gcry_malloc().
849 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
850 gpointer inbuf, gulong insize)
852 gpg_error_t rc;
853 gint level, zrc;
854 gulong outsize;
855 gpointer outbuf;
857 level = get_key_file_integer(filename, "compression_level");
859 if (level < 0)
860 level = 0;
862 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
863 == FALSE) {
864 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
867 crypto->inbuf = outbuf;
868 crypto->insize = outsize;
869 rc = do_xml_encrypt(NULL, crypto, filename);
870 return rc;
873 static gpg_error_t get_password(const gchar *filename,
874 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
875 pinentry_cmd_t which)
877 #ifdef WITH_PINENTRY
878 gpg_error_t rc = 0;
880 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
881 == FALSE) {
882 #endif
883 return get_input(filename, crypto, key, which);
884 #ifdef WITH_PINENTRY
886 else {
887 gchar *result = NULL;
888 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
890 set_pinentry_defaults(pin);
891 pin->which = which;
892 pin->filename = g_strdup(filename);
893 rc = pinentry_getpin(pin, &result);
895 if (rc) {
896 xfree(result);
897 goto done;
900 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
901 xfree(result);
902 cleanup_pinentry(pin);
905 done:
906 return rc;
907 #endif
910 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
912 FILE *fp;
913 gchar buf[LINE_MAX] = {0}, *p;
914 gchar *str = NULL;
915 gint len;
917 *rc = 0;
919 if ((fp = fopen(file, "r")) == NULL) {
920 *rc = gpg_error_from_syserror();
921 return FALSE;
924 p = fgets(buf, sizeof(buf), fp);
925 fclose(fp);
926 len = strlen(buf);
928 if (len && buf[len - 1] == '\n')
929 buf[--len] = 0;
931 str = gcry_malloc(len + 1);
933 if (!str) {
934 *rc = gpg_error_from_errno(ENOMEM);
935 return FALSE;
938 memcpy(str, buf, len ? len : 1);
939 str[len] = 0;
940 memset(&buf, 0, sizeof(buf));
941 *result = str;
942 return TRUE;
945 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
946 gpg_error_t *rc)
948 GError *rv = NULL;
949 gchar *t, *file = NULL, *str;
951 *rc = GPG_ERR_UNKNOWN_ERRNO;
953 if (import == FALSE) {
954 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
955 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
957 if (!file) {
958 if (rv) {
959 log_write("%s: key_file: %s", rcfile, rv->message);
960 g_clear_error(&rv);
963 return NULL;
966 t = expand_homedir(file);
968 if (!t) {
969 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
970 *rc = gpg_error_from_errno(ENOMEM);
971 return NULL;
974 g_free(file);
975 file = t;
978 else {
979 /* -I or -C. The filename is a key file. */
980 file = g_strdup(filename);
982 if (!file) {
983 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
984 *rc = gpg_error_from_errno(ENOMEM);
985 return NULL;
989 if (rv) {
990 log_write("%s: key_file: %s", rcfile, rv->message);
991 g_clear_error(&rv);
992 return NULL;
995 if (!file)
996 return NULL;
998 if (_getline(file, &str, rc) == FALSE) {
999 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1000 g_free(file);
1001 return NULL;
1004 g_free(file);
1005 *rc = 0;
1006 return str;
1009 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1010 const gchar *keyfile, guint64 iter)
1012 xmlDocPtr doc;
1013 gint fd;
1014 struct stat st;
1015 gint len;
1016 xmlChar *xmlbuf;
1017 xmlChar *xml;
1018 gpg_error_t rc;
1019 struct client_crypto_s *crypto;
1021 if (stat(filename, &st) == -1) {
1022 log_write("%s: %s", filename, strerror(errno));
1023 return FALSE;
1026 crypto = init_client_crypto();
1028 if (!crypto)
1029 return FALSE;
1031 crypto->key = gcry_malloc(gcrykeysize);
1032 memset(crypto->key, 0, gcrykeysize);
1034 if (!crypto->key) {
1035 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1036 goto fail;
1039 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1040 filename, outfile);
1042 if (iter && keyfile) {
1043 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1045 if (!crypto->tkey)
1046 goto fail;
1048 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1049 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1051 else if (iter) {
1052 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1054 if (rc)
1055 goto fail;
1058 if ((fd = open(filename, O_RDONLY)) == -1) {
1059 log_write("%s: %s", filename, strerror(errno));
1060 goto fail;
1063 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1064 close(fd);
1065 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1066 goto fail;
1069 if (pth_read(fd, xmlbuf, st.st_size) == -1) {
1070 rc = errno;
1071 close(fd);
1072 errno = rc;
1073 log_write("%s: %s", filename, strerror(errno));
1074 goto fail;
1077 close(fd);
1078 xmlbuf[st.st_size] = 0;
1081 * Make sure the document validates.
1083 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1084 log_write("xmlReadDoc() failed");
1085 gcry_free(xmlbuf);
1086 goto fail;
1089 gcry_free(xmlbuf);
1090 xmlDocDumpMemory(doc, &xml, &len);
1091 xmlFreeDoc(doc);
1093 if (!iter)
1094 memset(crypto->key, '!', gcrykeysize);
1096 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1098 if (!crypto->fh) {
1099 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1100 goto fail;
1103 crypto->fh->fh2.iter = iter;
1104 rc = export_common(outfile, crypto, xml, len);
1105 xmlFree(xml);
1107 if (rc) {
1108 send_error(NULL, rc);
1109 goto fail;
1112 cleanup_crypto(&crypto);
1113 return TRUE;
1115 fail:
1116 cleanup_crypto(&crypto);
1117 return FALSE;
1120 gchar *get_key_file_string(const gchar *section, const gchar *what)
1122 gchar *val = NULL;
1123 GError *grc = NULL;
1125 MUTEX_LOCK(&rcfile_mutex);
1127 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1128 val = g_key_file_get_string(keyfileh, section, what, &grc);
1130 if (grc) {
1131 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1132 g_clear_error(&grc);
1135 else {
1136 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1137 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1139 if (grc) {
1140 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1141 g_clear_error(&grc);
1146 MUTEX_UNLOCK(&rcfile_mutex);
1147 return val;
1150 gint get_key_file_integer(const gchar *section, const gchar *what)
1152 gint val = -1;
1153 GError *grc = NULL;
1155 MUTEX_LOCK(&rcfile_mutex);
1157 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1158 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1160 if (grc) {
1161 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1162 g_clear_error(&grc);
1165 else {
1166 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1167 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1169 if (grc) {
1170 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1171 g_clear_error(&grc);
1176 MUTEX_UNLOCK(&rcfile_mutex);
1177 return val;
1180 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1182 gboolean val = FALSE;
1183 GError *grc = NULL;
1185 MUTEX_LOCK(&rcfile_mutex);
1187 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1188 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1190 if (grc) {
1191 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1192 g_clear_error(&grc);
1195 else {
1196 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1197 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1199 if (grc) {
1200 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1201 g_clear_error(&grc);
1206 MUTEX_UNLOCK(&rcfile_mutex);
1207 return val;
1210 static gboolean parse_rcfile_keys()
1212 gsize n;
1213 gchar **groups;
1214 gchar **p;
1215 gchar *str;
1217 groups = g_key_file_get_groups(keyfileh, &n);
1219 for (p = groups; *p; p++) {
1220 GError *rc = NULL;
1222 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1223 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1225 if (!str) {
1226 if (rc) {
1227 log_write("%s: key: %s", rcfile, rc->message);
1228 g_clear_error(&rc);
1230 continue;
1233 do_cache_push(*p, str);
1234 g_free(str);
1235 continue;
1238 if (rc) {
1239 log_write("%s: key: %s", rcfile, rc->message);
1240 g_clear_error(&rc);
1241 continue;
1244 gpg_error_t ret;
1245 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1247 if (!str)
1248 continue;
1250 do_cache_push(*p, str);
1251 gcry_free(str);
1254 g_strfreev(groups);
1255 return TRUE;
1258 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1260 guchar md5file[16];
1261 gint timeout;
1262 const gchar *p = filename;
1263 struct client_crypto_s *crypto;
1264 gpg_error_t rc;
1266 while (isspace(*p))
1267 p++;
1269 if (!*p)
1270 return FALSE;
1272 if (valid_filename(p) == FALSE) {
1273 log_write(N_("%s: Invalid characters in filename"), p);
1274 return FALSE;
1277 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1279 if (access(p, R_OK|W_OK) != 0) {
1280 log_write("%s: %s", p, strerror(errno));
1281 return FALSE;
1284 crypto = init_client_crypto();
1286 if (!crypto)
1287 return FALSE;
1289 crypto->fh = read_file_header(filename, FALSE, &rc);
1291 if (!crypto->fh) {
1292 log_write("%s: %s", p, pwmd_strerror(rc));
1293 cleanup_crypto(&crypto);
1294 return FALSE;
1297 crypto->key = gcry_malloc(gcrykeysize);
1299 if (!crypto->key) {
1300 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1301 cleanup_crypto(&crypto);
1302 return FALSE;
1305 log_write(N_("Adding '%s' to the file cache ..."), filename);
1307 if (crypto->fh->fh2.iter <= 0) {
1308 memset(crypto->key, '!', gcrykeysize);
1309 goto try_decrypt;
1312 if (!password) {
1313 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1315 if (rc) {
1316 send_error(NULL, rc);
1317 cleanup_crypto(&crypto);
1318 return FALSE;
1321 gcry_free(crypto->fh->doc);
1322 crypto->fh->doc = NULL;
1324 else
1325 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1326 strlen(password) ? strlen(password) : 1);
1328 try_decrypt:
1329 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1331 if (rc) {
1332 log_write("%s: %s", filename, pwmd_strerror(rc));
1333 cleanup_crypto(&crypto);
1334 return FALSE;
1337 if (cache_update_key(md5file, crypto->key) == FALSE) {
1338 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1339 cleanup_crypto(&crypto);
1340 return FALSE;
1343 timeout = get_key_file_integer(p, "cache_timeout");
1344 cache_set_timeout(md5file, timeout);
1345 log_write(N_("File '%s' now cached"), filename);
1346 cleanup_crypto(&crypto);
1347 return TRUE;
1350 static void init_new_connection(gint fd)
1352 pth_attr_t attr;
1353 struct client_thread_s *new;
1354 gint n;
1356 new = g_malloc0(sizeof(struct client_thread_s));
1358 if (!new) {
1359 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1360 close(fd);
1361 return;
1364 MUTEX_LOCK(&cn_mutex);
1365 new->fd = fd;
1366 attr = pth_attr_new();
1367 pth_attr_init(attr);
1368 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1369 new->tid = pth_spawn(attr, client_thread, new);
1370 n = errno;
1371 pth_attr_destroy(attr);
1373 if (!new->tid) {
1374 g_free(new);
1375 close(fd);
1376 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1377 _gpg_strerror(gpg_error_from_errno(n)));
1378 MUTEX_UNLOCK(&cn_mutex);
1379 return;
1382 cn_thread_list = g_slist_append(cn_thread_list, new);
1383 MUTEX_UNLOCK(&cn_mutex);
1384 log_write(N_("new connection: tid=%p, fd=%i"), new->tid, fd);
1387 static void *accept_thread(void *arg)
1389 gint sockfd = (gint)arg;
1390 pth_attr_t attr = pth_attr_of(pth_self());
1392 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1393 pth_attr_destroy(attr);
1395 for (;;) {
1396 socklen_t slen = sizeof(struct sockaddr_un);
1397 struct sockaddr_un raddr;
1398 gint fd = -1;
1400 fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen);
1401 pth_cancel_point();
1403 if (fd == -1) {
1404 if (errno != EAGAIN) {
1405 if (!quit) // probably EBADF
1406 log_write("accept(): %s", strerror(errno));
1408 break;
1411 continue;
1414 init_new_connection(fd);
1417 /* Just in case accept() failed for some reason other than EBADF */
1418 quit = 1;
1419 pth_exit(PTH_CANCELED);
1420 return NULL;
1423 static void *adjust_cache_timer_thread(void *arg)
1425 pth_attr_t attr = pth_attr_of(pth_self());
1427 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1428 pth_attr_destroy(attr);
1430 for (;;) {
1431 pth_sleep(1);
1432 pth_cancel_point();
1433 CACHE_LOCK(NULL);
1434 cache_adjust_timer();
1435 CACHE_UNLOCK;
1438 return NULL;
1441 static void keepalive_cleanup(void *arg)
1443 pth_event_t ev = arg;
1445 pth_event_free(ev, PTH_FREE_ALL);
1448 static void *keepalive_thread(void *arg)
1450 gint to = (gint)arg;
1451 pth_mutex_t m;
1452 pth_cond_t cond;
1453 pth_attr_t attr = pth_attr_of(pth_self());
1455 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1456 pth_attr_destroy(attr);
1457 pth_cond_init(&cond);
1458 pth_mutex_init(&m);
1459 pth_mutex_acquire(&m, FALSE, NULL);
1461 for (;;) {
1462 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1463 pth_cleanup_push(keepalive_cleanup, ev);
1464 pth_cond_await(&cond, &m, ev);
1465 pth_cancel_point();
1466 send_status_all(STATUS_KEEPALIVE);
1467 pth_cleanup_pop(1);
1470 return NULL;
1473 static void startStopKeepAlive(gboolean term)
1475 gint n = get_key_file_integer("global", "keepalive");
1477 if (keepalive_tid)
1478 pth_cancel(keepalive_tid);
1480 keepalive_tid = NULL;
1482 if (term)
1483 return;
1485 if (n > 0) {
1486 gint e;
1487 pth_attr_t attr = pth_attr_new();
1488 pth_attr_init(attr);
1489 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1490 keepalive_tid = pth_spawn(attr, keepalive_thread, (void *)n);
1491 e = errno;
1492 pth_attr_destroy(attr);
1494 if (!keepalive_tid) {
1495 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1496 _gpg_strerror(gpg_error_from_errno(e)));
1497 return;
1500 pth_yield(keepalive_tid);
1504 static gboolean waiting_for_exit()
1506 guint i, t;
1507 pth_event_t evs = NULL;
1509 MUTEX_LOCK(&cn_mutex);
1511 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1512 struct client_thread_s *thd = g_slist_nth_data(cn_thread_list, i);
1513 pth_event_t ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, thd->tid);
1515 if (evs)
1516 evs = pth_event_concat(evs, ev, NULL);
1517 else
1518 evs = ev;
1521 MUTEX_UNLOCK(&cn_mutex);
1523 if (!evs)
1524 return FALSE;
1526 pth_wait(evs);
1527 MUTEX_LOCK(&cn_mutex);
1528 i = g_slist_length(cn_thread_list);
1529 MUTEX_UNLOCK(&cn_mutex);
1530 return i ? TRUE : FALSE;
1533 static void server_loop(gint sockfd, gchar **socketpath)
1535 pth_t accept_tid;
1536 guint n;
1537 sigset_t sigset;
1538 pth_attr_t attr;
1539 pth_t cache_timeout_tid;
1541 sigemptyset(&sigset);
1543 /* Termination */
1544 sigaddset(&sigset, SIGTERM);
1545 sigaddset(&sigset, SIGINT);
1547 /* Clears the file cache. */
1548 sigaddset(&sigset, SIGUSR1);
1550 /* Configuration file reloading. */
1551 sigaddset(&sigset, SIGHUP);
1553 /* Clears the cache and exits when something bad happens. */
1554 sigaddset(&sigset, SIGABRT);
1556 /* Ignored everywhere. When a client disconnects abnormally this signal
1557 * gets raised. It isn't needed though because client_thread() will check
1558 * for rcs even after the client disconnects. */
1559 signal(SIGPIPE, SIG_IGN);
1560 sigprocmask(SIG_BLOCK, &sigset, NULL);
1562 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1563 attr = pth_attr_new();
1564 pth_attr_init(attr);
1565 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1567 if (!accept_tid) {
1568 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1569 _gpg_strerror(gpg_error_from_errno(errno)));
1570 goto done;
1573 pth_yield(accept_tid);
1574 startStopKeepAlive(FALSE);
1575 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1576 cache_timeout_tid = pth_spawn(attr, adjust_cache_timer_thread, NULL);
1578 if (!cache_timeout_tid) {
1579 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1580 _gpg_strerror(gpg_error_from_errno(errno)));
1581 goto done;
1584 pth_yield(cache_timeout_tid);
1585 pth_attr_destroy(attr);
1587 do {
1588 gint sig;
1590 pth_sigwait(&sigset, &sig);
1591 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1593 /* Caught a signal. */
1594 switch (sig) {
1595 case SIGHUP:
1596 reload_rcfile();
1597 break;
1598 case SIGABRT:
1599 cache_clear(NULL, 2);
1600 #ifndef MEM_DEBUG
1601 xpanic();
1602 #endif
1603 exit(EXIT_FAILURE);
1604 case SIGUSR1:
1605 CACHE_LOCK(NULL);
1606 log_write(N_("clearing file cache"));
1607 cache_clear(NULL, 2);
1608 CACHE_UNLOCK;
1609 break;
1610 default:
1611 quit = 1;
1612 break;
1614 } while (!quit);
1616 done:
1618 * We're out of the main server loop. This happens when a signal was sent
1619 * to terminate the daemon. We'll wait for all clients to disconnect
1620 * before exiting and ignore any following signals.
1622 shutdown(sockfd, SHUT_RDWR);
1623 close(sockfd);
1624 pth_cancel(accept_tid);
1625 pth_join(accept_tid, NULL);
1626 unlink(*socketpath);
1627 g_free(*socketpath);
1628 *socketpath = NULL;
1629 MUTEX_LOCK(&cn_mutex);
1630 n = g_slist_length(cn_thread_list);
1631 MUTEX_UNLOCK(&cn_mutex);
1633 if (n) {
1634 log_write(N_("waiting for all clients to disconnect"));
1636 do {
1637 MUTEX_LOCK(&cn_mutex);
1638 n = g_slist_length(cn_thread_list);
1639 MUTEX_UNLOCK(&cn_mutex);
1640 log_write(N_("%i clients remain"), n);
1641 } while (waiting_for_exit());
1644 startStopKeepAlive(TRUE);
1645 pth_cancel(cache_timeout_tid);
1646 cache_free();
1650 * Called from pinentry_fork() in the child process.
1652 void free_client_list()
1654 gint i, t = g_slist_length(cn_thread_list);
1656 for (i = 0; i < t; i++) {
1657 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1659 free_client(cn->cl);
1662 cache_free();
1665 struct client_crypto_s *init_client_crypto()
1667 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1668 gpg_error_t rc;
1670 if (!new) {
1671 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1672 return NULL;
1675 rc = gcry_cipher_open(&new->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
1677 if (rc) {
1678 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1679 g_free(new);
1680 return NULL;
1683 return new;
1686 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1687 const gchar *outfile)
1689 gpg_error_t rc;
1690 guchar md5file[16];
1691 guint64 iter;
1692 struct client_crypto_s *crypto = init_client_crypto();
1694 if (!crypto)
1695 return GPG_ERR_ENOMEM;
1697 crypto->key = gcry_malloc(gcrykeysize);
1699 if (!crypto->key) {
1700 cleanup_crypto(&crypto);
1701 return GPG_ERR_ENOMEM;
1704 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1705 filename);
1706 crypto->fh = read_file_header(filename, TRUE, &rc);
1708 if (!crypto->fh)
1709 goto done;
1711 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1713 /* The header in version 1 had a bug where the iterations were off-by-one.
1714 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1715 * header.
1717 if (crypto->fh->fh1.iter >= 0) {
1718 if (keyfile) {
1719 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1721 if (!crypto->tkey)
1722 goto done;
1724 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1725 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1727 else {
1728 rc = get_password(filename, crypto, md5file, crypto->key,
1729 PINENTRY_OPEN);
1731 if (rc)
1732 goto done;
1736 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
1737 &crypto->fh->len);
1739 if (rc)
1740 goto done;
1742 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
1744 if (rc) {
1745 log_write("%s: %s", filename, pwmd_strerror(rc));
1746 goto done;
1749 crypto->fh->v1 = FALSE;
1750 iter = crypto->fh->fh1.iter;
1751 memset(&crypto->fh->fh2, 0, sizeof(crypto->fh->fh2));
1752 /* Keep the iterations and key from the original file. */
1753 crypto->fh->fh2.iter = iter+1; // Bugfix for v1 data files.
1754 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
1756 done:
1757 if (rc)
1758 send_error(NULL, rc);
1760 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1761 cleanup_crypto(&crypto);
1762 return rc;
1765 int main(int argc, char *argv[])
1767 gint opt;
1768 struct sockaddr_un addr;
1769 gchar buf[PATH_MAX];
1770 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1771 gchar *socketarg = NULL;
1772 gchar *datadir = NULL;
1773 gboolean n;
1774 gint x;
1775 gchar *p;
1776 gchar **cache_push = NULL;
1777 gchar *import = NULL, *keyfile = NULL;
1778 guint64 cmd_iterations = -1;
1779 gint default_timeout;
1780 gboolean rcfile_spec = FALSE;
1781 gint estatus = EXIT_FAILURE;
1782 gint sockfd;
1783 gchar *outfile = NULL;
1784 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1785 gint do_unlink = 1;
1786 gboolean secure = FALSE;
1787 gint background = 1;
1788 gchar *convert = NULL;
1789 #ifdef WITH_PINENTRY
1790 gboolean disable_pinentry = FALSE;
1791 #endif
1792 #if 0
1793 #ifndef DEBUG
1794 #ifdef HAVE_SETRLIMIT
1795 struct rlimit rl;
1797 rl.rlim_cur = rl.rlim_max = 0;
1799 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1800 err(EXIT_FAILURE, "setrlimit()");
1801 #endif
1802 #endif
1803 #endif
1805 #ifdef ENABLE_NLS
1806 setlocale(LC_ALL, "");
1807 bindtextdomain("pwmd", LOCALEDIR);
1808 textdomain("pwmd");
1809 #endif
1811 #ifndef MEM_DEBUG
1812 xmem_init();
1813 #endif
1814 setup_gcrypt();
1815 gpg_err_init();
1816 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1817 g_mem_set_vtable(&mtable);
1818 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1819 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1820 xmlInitMemory();
1821 xmlInitGlobals();
1822 xmlInitParser();
1823 xmlXPathInit();
1824 g_snprintf(buf, sizeof(buf), "%s/.pwmd", g_get_home_dir());
1826 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1827 err(EXIT_FAILURE, "%s", buf);
1829 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", g_get_home_dir());
1831 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1832 err(EXIT_FAILURE, "%s", buf);
1834 cmdline = TRUE;
1836 while ((opt = getopt(argc, argv, "Po:C:nI:i:k:hvf:D")) != EOF) {
1837 switch (opt) {
1838 #ifdef WITH_PINENTRY
1839 case 'P':
1840 disable_pinentry = TRUE;
1841 break;
1842 #endif
1843 case 'o':
1844 outfile = optarg;
1845 break;
1846 case 'C':
1847 convert = optarg;
1848 break;
1849 case 'n':
1850 background = 0;
1851 break;
1852 case 'D':
1853 secure = TRUE;
1854 break;
1855 case 'I':
1856 import = optarg;
1857 break;
1858 case 'i':
1859 cmd_iterations = strtol(optarg, NULL, 10);
1860 break;
1861 case 'k':
1862 keyfile = optarg;
1863 break;
1864 case 'f':
1865 rcfile = g_strdup(optarg);
1866 rcfile_spec = TRUE;
1867 break;
1868 case 'v':
1869 printf(N_("%s\nCopyright (c) %s\nReleased under the terms of the GPL v2. Use at your own risk.\n\nCompile time features:\n%s"), PACKAGE_STRING,
1870 PACKAGE_BUGREPORT,
1871 #ifdef WITH_PINENTRY
1872 "+WITH_PINENTRY\n"
1873 #else
1874 "-WITH_PINENTRY\n"
1875 #endif
1876 #ifdef WITH_QUALITY
1877 "+WITH_QUALITY\n"
1878 #else
1879 "-WITH_QUALITY\n"
1880 #endif
1881 #ifdef DEBUG
1882 "+DEBUG\n"
1883 #else
1884 "-DEBUG\n"
1885 #endif
1886 #ifdef MEM_DEBUG
1887 "+MEM_DEBUG\n"
1888 #else
1889 "-MEM_DEBUG\n"
1890 #endif
1892 exit(EXIT_SUCCESS);
1893 case 'h':
1894 default:
1895 usage(argv[0]);
1899 pth_mutex_init(&cn_mutex);
1900 pth_mutex_init(&cache_mutex);
1901 pth_mutex_init(&rcfile_mutex);
1902 #ifdef WITH_PINENTRY
1903 pth_mutex_init(&pin_mutex);
1904 #endif
1906 if (!rcfile)
1907 rcfile = g_strdup_printf("%s/.pwmd/config", g_get_home_dir());
1909 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1910 exit(EXIT_FAILURE);
1912 #ifdef WITH_PINENTRY
1913 if (disable_pinentry == TRUE)
1914 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
1915 #endif
1917 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1918 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1920 if (log_syslog == TRUE)
1921 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1923 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1924 x = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1925 errno = 0;
1927 if (setpriority(PRIO_PROCESS, 0, x) == -1) {
1928 log_write("setpriority(): %s", strerror(errno));
1929 goto do_exit;
1933 #ifdef HAVE_MLOCKALL
1934 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1935 log_write("mlockall(): %s", strerror(errno));
1936 goto do_exit;
1938 #endif
1940 if (convert) {
1941 if (!outfile)
1942 usage(argv[0]);
1944 opt = convert_file(convert, keyfile, outfile);
1945 g_key_file_free(keyfileh);
1946 g_free(rcfile);
1947 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
1950 if (import) {
1951 if (!outfile)
1952 usage(argv[0]);
1954 if (cmd_iterations == -1)
1955 cmd_iterations = (guint64)get_key_file_integer("global", "iterations");
1957 opt = xml_import(import, outfile, keyfile, cmd_iterations);
1958 g_key_file_free(keyfileh);
1959 g_free(rcfile);
1960 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1963 g_key_file_set_list_separator(keyfileh, ',');
1965 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1966 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1968 socketarg = expand_homedir(p);
1969 g_free(p);
1971 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1972 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1974 datadir = expand_homedir(p);
1975 g_free(p);
1977 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1978 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1979 disable_list_and_dump = n;
1981 else
1982 disable_list_and_dump = secure;
1984 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1985 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1986 else
1987 default_timeout = -1;
1989 setup_logging(keyfileh);
1991 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1992 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1994 if (argc != optind) {
1995 for (; optind < argc; optind++) {
1996 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1997 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2001 if (strchr(socketarg, '/') == NULL) {
2002 socketdir = g_get_current_dir();
2003 socketname = g_strdup(socketarg);
2004 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2006 else {
2007 socketname = g_strdup(strrchr(socketarg, '/'));
2008 socketname++;
2009 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2010 socketdir = g_strdup(socketarg);
2011 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2014 if (chdir(datadir)) {
2015 log_write("%s: %s", datadir, strerror(errno));
2016 unlink(socketpath);
2017 goto do_exit;
2020 if (parse_rcfile_keys() == FALSE)
2021 goto do_exit;
2023 clear_rcfile_keys();
2026 * Set the cache entry for a file. Prompts for the password.
2028 if (cache_push) {
2029 for (opt = 0; cache_push[opt]; opt++)
2030 do_cache_push(cache_push[opt], NULL);
2032 g_strfreev(cache_push);
2033 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2037 * bind() doesn't like the full pathname of the socket or any non alphanum
2038 * characters so change to the directory where the socket is wanted then
2039 * create it then change to datadir.
2041 if (chdir(socketdir)) {
2042 log_write("%s: %s", socketdir, strerror(errno));
2043 goto do_exit;
2046 g_free(socketdir);
2048 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2049 log_write("socket(): %s", strerror(errno));
2050 goto do_exit;
2053 addr.sun_family = AF_UNIX;
2054 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2056 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2057 log_write("bind(): %s", strerror(errno));
2059 if (errno == EADDRINUSE)
2060 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2061 "stale socket. Please remove it manually."), socketpath);
2063 do_unlink = 0;
2064 goto do_exit;
2067 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2068 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2069 mode_t mode = strtol(t, NULL, 8);
2070 mode_t mask = umask(0);
2072 g_free(t);
2074 if (chmod(socketname, mode) == -1) {
2075 log_write("%s: %s", socketname, strerror(errno));
2076 close(sockfd);
2077 unlink(socketpath);
2078 umask(mask);
2079 goto do_exit;
2082 umask(mask);
2085 g_free(--socketname);
2087 if (chdir(datadir)) {
2088 log_write("%s: %s", datadir, strerror(errno));
2089 close(sockfd);
2090 unlink(socketpath);
2091 goto do_exit;
2094 g_free(datadir);
2096 if (listen(sockfd, 0) == -1) {
2097 log_write("listen(): %s", strerror(errno));
2098 goto do_exit;
2101 cmdline = FALSE;
2103 if (background) {
2104 switch (fork()) {
2105 case -1:
2106 log_write("fork(): %s", strerror(errno));
2107 goto do_exit;
2108 case 0:
2109 close(0);
2110 close(1);
2111 close(2);
2112 setsid();
2113 break;
2114 default:
2115 exit(EXIT_SUCCESS);
2119 server_loop(sockfd, &socketpath);
2120 estatus = EXIT_SUCCESS;
2122 do_exit:
2123 if (socketpath && do_unlink) {
2124 unlink(socketpath);
2125 g_free(socketpath);
2128 g_key_file_free(keyfileh);
2129 g_free(rcfile);
2130 xmlCleanupParser();
2131 xmlCleanupGlobals();
2133 if (estatus == EXIT_SUCCESS)
2134 log_write(N_("pwmd exiting normally"));
2136 #if defined(DEBUG) && !defined(MEM_DEBUG)
2137 xdump();
2138 #endif
2139 exit(estatus);