Moved read_hook() and write_hook() to tls.c.
[pwmd.git] / src / pwmd.c
blob54203fcb1856a640a31b9855f4aa2852a4ed878c
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>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
49 #ifdef HAVE_SETRLIMIT
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #endif
54 #ifdef TM_IN_SYS_TIME
55 #include <sys/time.h>
56 #else
57 #include <time.h>
58 #endif
60 #ifndef MEM_DEBUG
61 #include "mem.h"
62 #endif
64 #include "xml.h"
65 #include "common.h"
67 #ifdef WITH_PINENTRY
68 #include "pinentry.h"
69 #endif
71 #ifdef WITH_GNUTLS
72 #include "tls.h"
73 #endif
74 #include "commands.h"
75 #include "pwmd_error.h"
76 #include "cache.h"
77 #include "misc.h"
78 #include "pwmd.h"
80 GCRY_THREAD_OPTION_PTH_IMPL;
82 static void clear_rcfile_keys()
84 gsize n;
85 gchar **groups;
86 gchar **p;
88 groups = g_key_file_get_groups(keyfileh, &n);
90 for (p = groups; *p; p++) {
91 GError *rc = NULL;
93 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
94 g_key_file_set_string(keyfileh, *p, "key", "");
97 g_strfreev(groups);
100 static void reload_rcfile()
102 gboolean b = disable_list_and_dump;
104 log_write(N_("reloading configuration file '%s'"), rcfile);
105 g_key_file_free(keyfileh);
106 keyfileh = parse_rcfile(0);
107 parse_rcfile_keys(FALSE);
108 clear_rcfile_keys();
109 disable_list_and_dump = b;
110 send_status_all(STATUS_CONFIG);
113 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
115 gpg_error_t n = gpg_error_from_errno(e);
117 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
120 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
122 gpg_err_code_t n = gpg_err_code(e);
123 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
124 struct client_s *client = assuan_get_pointer(ctx);
126 if (!e)
127 return assuan_process_done(ctx, 0);
129 if (!ctx) {
130 log_write("%s\n", pwmd_strerror(e));
131 return e;
134 if (n == EPWMD_LIBXML_ERROR) {
135 xmlErrorPtr xe = client->xml_error;
137 if (!xe)
138 xe = xmlGetLastError();
140 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
141 log_write("%s", xe->message);
143 if (xe == client->xml_error)
144 xmlResetError(xe);
145 else
146 xmlResetLastError();
148 client->xml_error = NULL;
149 return e;
152 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
155 void log_write(const gchar *fmt, ...)
157 gchar *args, *line;
158 va_list ap;
159 struct tm *tm;
160 time_t now;
161 gchar tbuf[21];
162 gint fd = -1;
163 pth_attr_t attr;
164 gchar *name;
165 pth_t tid = pth_self();
166 gchar tid_str[12], *p;
168 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
169 return;
171 if (!cmdline && logfile) {
172 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
173 warn("%s", logfile);
174 return;
178 va_start(ap, fmt);
180 if (g_vasprintf(&args, fmt, ap) == -1) {
181 if (logfile)
182 close(fd);
184 va_end(ap);
185 return;
188 if (cmdline) {
189 warnx("%s", args);
190 fflush(stderr);
191 g_free(args);
192 return;
195 attr = pth_attr_of(tid);
197 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
198 name = "unknown";
200 pth_attr_destroy(attr);
201 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
202 p = tid_str;
204 if (strncmp(p+1, name, 9) == 0)
205 p = NULL;
207 if (!cmdline && log_syslog == TRUE)
208 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
210 va_end(ap);
211 time(&now);
212 tm = localtime(&now);
213 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
214 tbuf[sizeof(tbuf) - 1] = 0;
216 if (args[strlen(args)-1] == '\n')
217 args[strlen(args)-1] = 0;
219 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
220 p ? p : "", args);
221 g_free(args);
223 if (!line) {
224 if (logfile)
225 close(fd);
227 return;
230 if (logfile) {
231 write(fd, line, strlen(line));
232 fsync(fd);
233 close(fd);
236 if (isatty(STDERR_FILENO)) {
237 fprintf(stderr, "%s", line);
238 fflush(stderr);
241 g_free(line);
244 static void usage(gchar *pn)
246 g_fprintf(stderr, N_(
247 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
248 "[-I <filename> [-i <iter>]]\n "
249 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
250 " -n run as a foreground process\n"
251 " -f load the specified rcfile (~/.pwmd/config)\n"
252 " -C convert a version 1 data file to version 2\n"
253 " -I import an XML file\n"
254 " -i encrypt with the specified number of iterations when importing\n"
255 " (config default in the \"global\" section)\n"
256 " -k obtain the key from the specified file\n"
257 " -o output file for use with the -C and -I options\n"
258 " -D disable use of the LIST and DUMP commands\n"
259 " -P disable pinentry\n"
260 " -v version\n"
261 " -h this help text\n"
262 ), pn);
263 exit(EXIT_FAILURE);
266 #ifndef MEM_DEBUG
267 static int gcry_SecureCheck(const void *ptr)
269 return 1;
271 #endif
273 static void setup_gcrypt()
275 gcry_check_version(NULL);
277 #ifndef MEM_DEBUG
278 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
279 xfree);
280 #endif
282 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
283 NULL) != 0)
284 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
286 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
287 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
290 static gint new_connection(struct client_s *cl)
292 gpg_error_t rc;
293 gchar ver[ASSUAN_LINELENGTH];
295 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
297 if (rc)
298 goto fail;
300 assuan_set_pointer(cl->ctx, cl);
301 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
302 assuan_set_hello_line(cl->ctx, ver);
303 rc = register_commands(cl->ctx);
305 if (rc)
306 goto fail;
308 rc = assuan_accept(cl->ctx);
310 if (rc)
311 goto fail;
313 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
314 return 0;
316 fail:
317 log_write("%s", gpg_strerror(rc));
318 return 1;
321 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
323 gchar *line = NULL;
324 struct client_s *client = assuan_get_pointer(ctx);
325 gchar buf[ASSUAN_LINELENGTH];
326 gchar *status = NULL;
328 switch (which) {
329 case STATUS_CACHE:
330 CACHE_LOCK(client->ctx);
331 line = print_fmt(buf, sizeof(buf), "%i %i",
332 cache_file_count(),
333 (cache_size % sizeof(file_cache_t)) ?
334 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
335 (cache_size / sizeof(file_cache_t)) - cache_file_count());
336 CACHE_UNLOCK;
337 status = "CACHE";
338 break;
339 case STATUS_CLIENTS:
340 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
341 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
342 pth_mutex_release(&cn_mutex);
343 status = "CLIENTS";
344 break;
345 case STATUS_CONFIG:
346 status = "CONFIG";
347 break;
348 case STATUS_KEEPALIVE:
349 status = "KEEPALIVE";
350 break;
351 case STATUS_LOCKED:
352 status = "LOCKED";
353 line = N_("Waiting for lock");
354 break;
357 return assuan_write_status(ctx, status, line);
360 void send_status_all(status_msg_t which)
362 guint i, t;
364 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
366 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
367 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
368 pth_msgport_t m = pth_msgport_find(cn->msg_name);
370 if (m) {
371 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
373 msg->m_data = (status_msg_t *)which;
374 pth_msgport_put(m, msg);
378 pth_mutex_release(&cn_mutex);
381 static void xml_error_cb(void *data, xmlErrorPtr e)
383 struct client_s *client = data;
386 * Keep the first reported error as the one to show in the error
387 * description. Reset in send_error().
389 if (client->xml_error)
390 return;
392 xmlCopyError(e, client->xml_error);
396 * This is called after a child_thread terminates. Set with
397 * pth_cleanup_push().
399 static void cleanup_cb(void *arg)
401 struct client_thread_s *cn = arg;
402 gpointer value;
403 struct client_s *cl = cn->cl;
405 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
406 log_write(N_("exiting, fd=%i"), cn->fd);
408 if (cn->msg_tid) {
409 pth_cancel(cn->msg_tid);
410 pth_join(cn->msg_tid, &value);
411 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
414 if (cn->msg_name)
415 g_free(cn->msg_name);
417 if (cn->msg) {
418 while (pth_msgport_pending(cn->msg) > 0) {
419 pth_message_t *m = pth_msgport_get(cn->msg);
421 g_free(m);
424 pth_msgport_destroy(cn->msg);
427 pth_join(cn->tid, &value);
429 if (cl && cl->freed == FALSE)
430 cleanup_client(cl);
432 #ifdef WITH_GNUTLS
433 if (cn->tls) {
434 gnutls_deinit(cn->tls->ses);
436 if (cn->tls->fp)
437 g_free(cn->tls->fp);
439 g_free(cn->tls);
441 #endif
443 if (cl && cl->ctx)
444 assuan_deinit_server(cl->ctx);
446 #ifdef WITH_PINENTRY
447 if (cl && cl->pinentry)
448 cleanup_pinentry(cl->pinentry);
449 #endif
451 g_free(cl);
452 cn_thread_list = g_slist_remove(cn_thread_list, cn);
453 g_free(cn);
454 pth_mutex_release(&cn_mutex);
455 send_status_all(STATUS_CLIENTS);
458 static void *client_msg_thread(void *data)
460 struct client_s *cl = data;
461 pth_status_t ev_status;
463 for (;;) {
464 pth_wait(cl->thd->msg_ev);
465 ev_status = pth_event_status(cl->thd->msg_ev);
467 if (ev_status == PTH_STATUS_FAILED) {
468 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
469 __FUNCTION__);
470 continue;
473 if (ev_status == PTH_STATUS_OCCURRED) {
474 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
476 while (pth_msgport_pending(cl->thd->msg) > 0) {
477 pth_message_t *m = pth_msgport_get(cl->thd->msg);
478 status_msg_t n = (status_msg_t)m->m_data;
479 gpg_error_t rc = send_status(cl->ctx, n);
481 g_free(m);
483 if (rc) {
484 pth_mutex_release(&cn_mutex);
485 log_write("%s", gpg_strerror(rc));
486 break;
490 pth_mutex_release(&cn_mutex);
496 * Called every time a connection is made via pth_spawn(). This is the thread
497 * entry point.
499 static void *client_thread(void *data)
501 struct client_thread_s *thd = data;
502 pth_event_t ev;
503 struct client_s *cl = g_malloc0(sizeof(struct client_s));
504 gpg_error_t rc;
505 pth_attr_t attr;
508 * Prevent a race condition with init_new_connection() if this thread
509 * fails (returns) for some reason before init_new_connection() releases
510 * the cn_mutex.
512 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
513 pth_mutex_release(&cn_mutex);
515 if (!cl) {
516 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
517 goto fail;
520 thd->cl = cl;
521 cl->thd = thd;
522 pth_cleanup_push(cleanup_cb, thd);
524 #ifdef WITH_GNUTLS
526 * Do the TLS handshake before anything else.
528 if (thd->remote) {
529 thd->tls = tls_init(thd->fd);
531 if (!thd->tls) {
532 close(thd->fd);
533 goto fail;
536 #endif
539 * This is a "child" thread. Don't catch any signals. Let the master
540 * thread take care of signals in server_loop().
542 if (new_connection(cl))
543 goto fail;
545 #ifdef WITH_PINENTRY
546 cl->pinentry = pinentry_init();
548 if (!cl->pinentry) {
549 g_free(cl);
550 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
551 goto fail;
553 #endif
555 thd->msg_name = g_strdup_printf("%p", thd->tid);
557 if (!thd->msg_name) {
558 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
559 goto fail;
562 thd->msg = pth_msgport_create(thd->msg_name);
564 if (!thd->msg) {
565 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
566 goto fail;
569 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
570 attr = pth_attr_new();
571 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
572 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
573 pth_attr_destroy(attr);
575 if (!thd->msg_tid) {
576 log_write(N_("pth_spawn() failed"));
577 goto fail;
580 #ifdef HAVE_MLOCKALL
581 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
582 log_write("mlockall(): %s", strerror(errno));
583 goto fail;
585 #endif
587 rc = send_status(cl->ctx, STATUS_CACHE);
589 if (rc) {
590 log_write("%s", gpg_strerror(rc));
591 goto fail;
594 send_status_all(STATUS_CLIENTS);
595 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
596 xmlInitParser();
597 xmlXPathInit();
598 xmlSetStructuredErrorFunc(cl, xml_error_cb);
600 for (;;) {
601 pth_status_t ev_status;
603 pth_wait(ev);
604 ev_status = pth_event_status(ev);
606 if (ev_status == PTH_STATUS_FAILED) {
607 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
608 __FUNCTION__);
609 goto done;
611 else if (ev_status == PTH_STATUS_OCCURRED) {
612 rc = assuan_process_next(cl->ctx);
614 if (rc) {
615 cl->inquire_status = INQUIRE_INIT;
617 if (gpg_err_code(rc) == GPG_ERR_EOF)
618 goto done;
620 log_write("assuan_process_next(): %s", gpg_strerror(rc));
621 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
623 if (rc) {
624 log_write("assuan_process_done(): %s", gpg_strerror(rc));
625 goto done;
628 else {
629 #ifdef WITH_PINENTRY
630 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
631 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
632 pth_event_concat(ev, cl->pinentry->ev, NULL);
633 cl->pinentry->status = PINENTRY_RUNNING;
635 #endif
637 switch (cl->inquire_status) {
638 case INQUIRE_BUSY:
639 case INQUIRE_INIT:
640 break;
641 case INQUIRE_DONE:
642 cl->inquire_status = INQUIRE_INIT;
643 rc = assuan_process_done(cl->ctx, 0);
644 break;
649 #ifdef WITH_PINENTRY
650 ev = pinentry_iterate(cl, ev);
651 #endif
655 * Client cleanup (including XML data) is done in cleanup_cb() from
656 * the cleanup thread.
658 done:
659 pth_event_free(ev, PTH_FREE_ALL);
661 fail:
662 pth_exit(NULL);
663 return NULL;
666 static void setup_logging(GKeyFile *kf)
668 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
670 if (n == TRUE) {
671 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
673 if (*p == '~') {
674 gchar buf[PATH_MAX];
676 p++;
677 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
678 g_free(p);
680 if (logfile)
681 g_free(logfile);
683 logfile = g_strdup(buf);
685 else {
686 if (logfile)
687 g_free(logfile);
689 logfile = p;
693 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
697 * Make sure all settings are set to either the specified setting or a
698 * default.
700 static void set_rcfile_defaults(GKeyFile *kf)
702 gchar buf[PATH_MAX];
704 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
705 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
706 g_key_file_set_string(kf, "global", "socket_path", buf);
709 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
710 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
711 g_key_file_set_string(kf, "global", "data_directory", buf);
714 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
715 g_key_file_set_boolean(kf, "global", "backup", TRUE);
717 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
718 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
719 g_key_file_set_string(kf, "global", "log_path", buf);
722 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
723 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
725 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
726 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
728 #ifdef HAVE_MLOCKALL
729 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
730 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
731 #endif
733 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
734 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
736 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
737 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
738 g_key_file_set_integer(kf, "global", "iterations", 1);
740 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
741 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
743 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
744 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
746 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
747 g_key_file_set_integer(kf, "global", "compression_level", 6);
749 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
750 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
752 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
753 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
755 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
757 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
758 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
760 #ifdef HAVE_MLOCKALL
761 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
762 #endif
764 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
765 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
767 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
768 g_key_file_set_integer(kf, "global", "keepalive", 30);
770 #ifdef WITH_PINENTRY
771 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
772 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
774 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
775 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
776 #endif
778 #ifdef WITH_GNUTLS
779 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
780 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
782 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
783 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
785 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
786 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
788 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
789 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
790 #endif
792 setup_logging(kf);
795 static GKeyFile *parse_rcfile()
797 GKeyFile *kf = g_key_file_new();
798 GError *rc = NULL;
800 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
801 log_write("%s: %s", rcfile, rc->message);
803 if (cmdline)
804 exit(EXIT_FAILURE);
806 if (rc->code == G_FILE_ERROR_NOENT) {
807 g_clear_error(&rc);
808 set_rcfile_defaults(kf);
809 return kf;
812 g_clear_error(&rc);
813 return NULL;
815 else
816 set_rcfile_defaults(kf);
818 return kf;
821 static gchar *do_get_password(const gchar *prompt)
823 gchar buf[LINE_MAX] = {0}, *p;
824 struct termios told, tnew;
825 gchar *key;
827 if (tcgetattr(STDIN_FILENO, &told) == -1) {
828 log_write("tcgetattr()");
829 return NULL;
832 memcpy(&tnew, &told, sizeof(struct termios));
833 tnew.c_lflag &= ~(ECHO);
834 tnew.c_lflag |= ICANON|ECHONL;
836 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
837 log_write("tcsetattr()");
838 tcsetattr(STDIN_FILENO, TCSANOW, &told);
839 return NULL;
842 fprintf(stderr, "%s", prompt);
844 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
845 tcsetattr(STDIN_FILENO, TCSANOW, &told);
846 return NULL;
849 tcsetattr(STDIN_FILENO, TCSANOW, &told);
850 p[strlen(p) - 1] = 0;
852 if (!buf[0]) {
853 key = gcry_malloc(1);
854 key[0] = 0;
856 else {
857 key = gcry_malloc(strlen(p) + 1);
858 sprintf(key, "%s", p);
861 memset(&buf, 0, sizeof(buf));
862 return key;
865 /* Only used when "enable_pinentry" is "false". */
866 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
867 guchar *key, pinentry_cmd_t which)
869 gint try = 0;
870 gchar *password;
871 gchar *prompt;
873 if (which == PINENTRY_SAVE) {
874 gchar *key1, *key2;
876 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
877 key1 = do_get_password(prompt);
878 g_free(prompt);
880 if (!key1) {
881 log_write(N_("%s: Skipping file"), filename);
882 return FALSE;
885 prompt = g_strdup_printf(N_("Repeat passphrase: "));
886 key2 = do_get_password(prompt);
887 g_free(prompt);
889 if (!key2) {
890 gcry_free(key1);
891 log_write(N_("%s: Skipping file"), filename);
892 return FALSE;
895 if (strcmp(key1, key2)) {
896 gcry_free(key1);
897 gcry_free(key2);
898 log_write(N_("%s: Passphrase mismatch"), filename);
899 return FALSE;
902 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
903 strlen(key1) ? strlen(key1) : 1);
904 gcry_free(key1);
905 gcry_free(key2);
906 return TRUE;
909 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
911 do {
912 gpg_error_t rc;
914 if ((password = do_get_password(prompt)) == NULL) {
915 log_write(N_("%s: Skipping file"), filename);
916 g_free(prompt);
917 return FALSE;
920 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
921 gcry_free(password);
923 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
925 if (!rc)
926 break;
928 log_write(N_("%s: Invalid passphrase"), filename);
929 } while (try++ < 2);
931 g_free(prompt);
933 if (try == 3) {
934 log_write(N_("%s: Invalid passphrase, skipping"), filename);
935 return FALSE;
938 return TRUE;
942 * inbuf must have been allocated with gcry_malloc().
944 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
945 guchar *shakey, gpointer inbuf, gulong insize)
947 gcry_cipher_hd_t gh;
948 gpg_error_t rc;
949 gint level, zrc;
950 glong outsize;
951 gpointer outbuf;
953 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
955 if (rc)
956 return rc;
958 level = get_key_file_integer(filename, "compression_level");
960 if (level < 0)
961 level = 0;
963 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
964 == FALSE) {
965 gcry_cipher_close(gh);
966 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
968 else {
969 gcry_free(inbuf);
970 inbuf = outbuf;
971 insize = outsize;
974 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
975 gcry_cipher_close(gh);
976 return rc;
979 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
980 guchar *md5file, guchar *key, pinentry_cmd_t which)
982 #ifdef WITH_PINENTRY
983 gpg_error_t rc = 0;
985 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
986 == FALSE) {
987 #endif
988 return get_input(filename, fh, key, which);
989 #ifdef WITH_PINENTRY
991 else {
992 gchar *result = NULL;
993 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
994 gint try = 0;
996 set_pinentry_defaults(pin);
997 pin->which = which;
998 pin->filename = g_strdup(filename);
999 again:
1000 rc = pinentry_getpin(pin, &result);
1002 if (rc) {
1003 log_write("%s", gpg_strerror(rc));
1004 xfree(result);
1005 goto done;
1008 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1009 xfree(result);
1011 if (which == PINENTRY_SAVE) {
1012 cleanup_pinentry(pin);
1013 goto done;
1016 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1018 if (rc == EPWMD_BADKEY) {
1019 if (try++ == 2)
1020 log_write("%s: %s", filename, pwmd_strerror(rc));
1021 else {
1022 g_free(pin->title);
1023 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1024 goto again;
1027 else if (rc)
1028 log_write("%s", pwmd_strerror(rc));
1030 cleanup_pinentry(pin);
1033 done:
1034 return rc ? FALSE : TRUE;
1035 #endif
1038 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1040 FILE *fp;
1041 gchar buf[LINE_MAX] = {0}, *p;
1042 gchar *str = NULL;
1043 gint len;
1045 *rc = 0;
1047 if ((fp = fopen(file, "r")) == NULL) {
1048 *rc = gpg_error_from_syserror();
1049 return FALSE;
1052 p = fgets(buf, sizeof(buf), fp);
1053 fclose(fp);
1054 len = strlen(buf);
1056 if (len && buf[len - 1] == '\n')
1057 buf[--len] = 0;
1059 str = gcry_malloc(len + 1);
1061 if (!str) {
1062 *rc = gpg_error_from_errno(ENOMEM);
1063 return FALSE;
1066 memcpy(str, buf, len ? len : 1);
1067 str[len] = 0;
1068 memset(&buf, 0, sizeof(buf));
1069 *result = str;
1070 return TRUE;
1073 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import)
1075 GError *rv = NULL;
1076 gchar *t, *file = NULL, *str;
1077 gpg_error_t rc;
1079 if (import == FALSE) {
1080 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1081 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1083 if (!file) {
1084 if (rv) {
1085 if (cmdline)
1086 log_write("%s", rv->message);
1087 else
1088 log_write("rvfile: %s", rv->message);
1089 g_clear_error(&rv);
1092 return NULL;
1095 t = expand_homedir(file);
1097 if (!t) {
1098 log_write("%s", pwmd_strerror(gpg_error_from_errno(ENOMEM)));
1099 return NULL;
1102 g_free(file);
1103 file = t;
1106 else {
1107 /* -I or -C. The filename is a key file. */
1108 file = g_strdup(filename);
1110 if (!file) {
1111 log_write("%s", pwmd_strerror(gpg_error_from_errno(ENOMEM)));
1112 return NULL;
1116 if (rv) {
1117 if (cmdline)
1118 log_write("%s", rv->message);
1119 else
1120 log_write("rvfile: %s", rv->message);
1121 g_clear_error(&rv);
1122 return NULL;
1125 if (!file)
1126 return NULL;
1128 if (_getline(file, &str, &rc) == FALSE) {
1129 if (cmdline)
1130 log_write("%s: %s", file, pwmd_strerror(rc));
1131 else
1132 log_write("%s: %s", file, pwmd_strerror(rc));
1133 g_free(file);
1134 return NULL;
1137 g_free(file);
1138 return str;
1141 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1142 const gchar *keyfile, gulong iter)
1144 xmlDocPtr doc;
1145 gint fd;
1146 struct stat st;
1147 gint len;
1148 xmlChar *xmlbuf;
1149 xmlChar *xml;
1150 guchar shakey[gcrykeysize];
1151 gpg_error_t rc;
1152 file_header_internal_t fh;
1154 if (stat(filename, &st) == -1) {
1155 log_write("%s", filename);
1156 return FALSE;
1159 if (iter && keyfile) {
1160 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1162 if (!tmp)
1163 return FALSE;
1165 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1166 strlen(tmp) ? strlen(tmp) : 1);
1168 else if (iter && get_password(filename, NULL, NULL, shakey, PINENTRY_SAVE)
1169 == FALSE)
1170 return FALSE;
1172 if ((fd = open(filename, O_RDONLY)) == -1) {
1173 memset(shakey, 0, sizeof(shakey));
1174 log_write("%s", filename);
1175 return FALSE;
1178 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1179 close(fd);
1180 memset(shakey, 0, sizeof(shakey));
1181 log_write("%s", strerror(ENOMEM));
1182 return FALSE;
1185 if (read(fd, xmlbuf, st.st_size) == -1) {
1186 memset(shakey, 0, sizeof(shakey));
1187 rc = errno;
1188 close(fd);
1189 errno = rc;
1190 err(EXIT_FAILURE, "read()");
1193 close(fd);
1194 xmlbuf[st.st_size] = 0;
1197 * Make sure the document validates.
1199 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1200 log_write("xmlReadDoc()");
1201 close(fd);
1202 gcry_free(xmlbuf);
1203 memset(shakey, 0, sizeof(shakey));
1204 return FALSE;
1207 gcry_free(xmlbuf);
1208 xmlDocDumpMemory(doc, &xml, &len);
1209 xmlFreeDoc(doc);
1211 if (!iter)
1212 memset(shakey, '!', sizeof(shakey));
1214 memset(&fh, 0, sizeof(fh));
1215 fh.fh2.iter = iter;
1216 rc = export_common(outfile, &fh, shakey, xml, len);
1217 memset(shakey, 0, sizeof(shakey));
1219 if (rc)
1220 send_error(NULL, rc);
1222 return rc ? FALSE : TRUE;
1225 gchar *get_key_file_string(const gchar *section, const gchar *what)
1227 gchar *val = NULL;
1228 GError *grc = NULL;
1230 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1231 val = g_key_file_get_string(keyfileh, section, what, &grc);
1233 if (grc) {
1234 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1235 g_clear_error(&grc);
1238 else {
1239 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1240 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1242 if (grc) {
1243 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1244 g_clear_error(&grc);
1249 return val;
1252 gint get_key_file_integer(const gchar *section, const gchar *what)
1254 gint val = -1;
1255 GError *grc = NULL;
1257 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1258 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1260 if (grc) {
1261 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1262 g_clear_error(&grc);
1265 else {
1266 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1267 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1269 if (grc) {
1270 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1271 g_clear_error(&grc);
1276 return val;
1279 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1281 gboolean val = FALSE;
1282 GError *grc = NULL;
1284 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1285 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1287 if (grc) {
1288 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1289 g_clear_error(&grc);
1292 else {
1293 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1294 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1296 if (grc) {
1297 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1298 g_clear_error(&grc);
1303 return val;
1306 static gboolean parse_rcfile_keys()
1308 gsize n;
1309 gchar **groups;
1310 gchar **p;
1311 gchar *str;
1313 groups = g_key_file_get_groups(keyfileh, &n);
1315 for (p = groups; *p; p++) {
1316 GError *rc = NULL;
1318 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1319 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1321 if (!str) {
1322 if (rc) {
1323 if (cmdline)
1324 log_write("%s", rc->message);
1325 else
1326 log_write("rcfile: %s", rc->message);
1328 g_clear_error(&rc);
1330 continue;
1333 do_cache_push(*p, str);
1334 g_free(str);
1335 continue;
1338 if (rc) {
1339 if (cmdline)
1340 log_write("%s", rc->message);
1341 else
1342 log_write("rcfile: %s", rc->message);
1343 g_clear_error(&rc);
1344 continue;
1347 str = parse_rcfile_keyfile(*p, FALSE);
1349 if (!str)
1350 continue;
1352 do_cache_push(*p, str);
1353 gcry_free(str);
1356 g_strfreev(groups);
1357 return TRUE;
1360 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1362 guchar *md5file;
1363 guchar *key;
1364 gint timeout;
1365 const gchar *p = filename;
1366 file_header_internal_t *fh;
1367 gpg_error_t rc;
1369 while (isspace(*p))
1370 p++;
1372 if (!*p)
1373 return FALSE;
1375 if (valid_filename(p) == FALSE) {
1376 log_write(N_("%s: Invalid characters in filename"), p);
1377 return FALSE;
1380 md5file = gcry_malloc(16);
1381 key = gcry_malloc(gcrykeysize);
1382 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1384 if (access(p, R_OK|W_OK) != 0) {
1385 gcry_free(md5file);
1386 gcry_free(key);
1388 if (errno != ENOENT) {
1389 log_write("%s", p);
1390 return FALSE;
1393 log_write("%s", p);
1394 return TRUE;
1397 fh = read_file_header(filename, FALSE, &rc);
1399 if (!fh) {
1400 gcry_free(md5file);
1401 gcry_free(key);
1402 log_write("%s", pwmd_strerror(rc));
1403 return FALSE;
1406 if (fh->fh2.iter <= 0) {
1407 memset(key, '!', gcrykeysize);
1408 goto try_decrypt;
1411 if (!password) {
1412 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1413 g_free(fh);
1414 return FALSE;
1417 else
1418 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1419 strlen(password) ? strlen(password) : 1);
1421 try_decrypt:
1422 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1424 if (rc) {
1425 log_write("%s: %s", filename, pwmd_strerror(rc));
1426 gcry_free(key);
1427 gcry_free(md5file);
1428 g_free(fh);
1429 return FALSE;
1432 if (cache_update_key(md5file, key) == FALSE) {
1433 log_write("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1434 gcry_free(key);
1435 gcry_free(md5file);
1436 g_free(fh);
1437 return FALSE;
1440 timeout = get_key_file_integer(p, "cache_timeout");
1441 cache_set_timeout(md5file, timeout);
1442 log_write(N_("%s: File added to the cache"), filename);
1443 gcry_free(key);
1444 gcry_free(md5file);
1445 g_free(fh);
1446 return TRUE;
1449 static void init_new_connection(gint fd, gchar *addr)
1451 pth_t tid;
1452 pth_attr_t attr;
1453 struct client_thread_s *new;
1454 gchar buf[41];
1456 new = g_malloc0(sizeof(struct client_thread_s));
1458 if (!new) {
1459 log_write("%s", strerror(ENOMEM));
1460 return;
1464 * Thread priority is inherited from the calling thread. This
1465 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1466 * priority.
1468 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1469 new->fd = fd;
1471 if (addr)
1472 new->remote = TRUE;
1474 attr = pth_attr_new();
1475 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1476 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1477 tid = pth_spawn(attr, client_thread, new);
1478 pth_attr_destroy(attr);
1480 if (!tid) {
1481 g_free(new);
1482 log_write(N_("pth_spawn() failed"));
1483 pth_mutex_release(&cn_mutex);
1484 return;
1487 g_snprintf(buf, sizeof(buf), "%p", tid);
1489 if (addr)
1490 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1491 else
1492 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1494 attr = pth_attr_of(tid);
1495 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1496 pth_attr_destroy(attr);
1497 new->tid = tid;
1498 cn_thread_list = g_slist_append(cn_thread_list, new);
1499 pth_mutex_release(&cn_mutex);
1502 #ifdef WITH_GNUTLS
1503 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1504 static void *get_in_addr(struct sockaddr *sa)
1506 if (sa->sa_family == AF_INET)
1507 return &(((struct sockaddr_in*)sa)->sin_addr);
1509 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1512 static void *tcp_accept_thread(void *arg)
1514 gint sockfd = (gint)arg;
1516 for (;;) {
1517 struct sockaddr_storage raddr;
1518 socklen_t slen = sizeof(raddr);
1519 gint fd = -1;
1520 gulong n;
1521 gchar *t;
1523 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1524 if (errno != EAGAIN) {
1525 if (!quit) // probably EBADF
1526 log_write("accept(): %s", strerror(errno));
1528 break;
1532 if (quit)
1533 break;
1535 if (fd >= 0) {
1536 gchar s[INET6_ADDRSTRLEN];
1538 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1539 s, sizeof s);
1540 init_new_connection(fd, s);
1543 t = get_key_file_string("global", "tcp_wait");
1544 g_free(t);
1545 n = strtol(t, NULL, 10);
1547 if (n < 0)
1548 n = 0;
1550 pth_usleep(n*100000);
1553 /* Just in case pth_accept() failed for some reason other than EBADF */
1554 quit = 1;
1555 pth_exit(PTH_CANCELED);
1556 return NULL;
1558 #endif
1560 static void *accept_thread(void *arg)
1562 gint sockfd = (gint)arg;
1564 for (;;) {
1565 socklen_t slen = sizeof(struct sockaddr_un);
1566 struct sockaddr_un raddr;
1567 gint fd = -1;
1569 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1570 if (errno != EAGAIN) {
1571 if (!quit) // probably EBADF
1572 log_write("accept(): %s", strerror(errno));
1574 break;
1578 if (fd >= 0)
1579 init_new_connection(fd, NULL);
1582 /* Just in case pth_accept() failed for some reason other than EBADF */
1583 quit = 1;
1584 pth_exit(PTH_CANCELED);
1585 return NULL;
1589 * This thread isn't joinable. For operations that block, these threads will
1590 * stack.
1592 static void *adjust_timer_thread(void *arg)
1594 CACHE_LOCK(NULL);
1595 cache_adjust_timer();
1596 CACHE_UNLOCK;
1597 return NULL;
1600 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1601 pth_attr_t attr)
1603 pth_status_t ev_status;
1605 if (timeout_ev) {
1606 pth_event_isolate(timeout_ev);
1607 ev_status = pth_event_status(timeout_ev);
1608 pth_event_free(timeout_ev, PTH_FREE_THIS);
1610 if (ev_status == PTH_STATUS_OCCURRED) {
1612 * The timer event has expired. Update the file cache. When the
1613 * cache mutex is locked and the timer expires again, the threads
1614 * will stack.
1616 pth_spawn(attr, adjust_timer_thread, NULL);
1620 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1623 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1624 gint keepalive)
1626 pth_event_t ev = NULL;
1627 pth_status_t ev_status;
1629 if (keepalive_ev) {
1630 pth_event_isolate(keepalive_ev);
1631 ev_status = pth_event_status(keepalive_ev);
1633 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1634 if (ev_status == PTH_STATUS_OCCURRED)
1635 send_status_all(STATUS_KEEPALIVE);
1637 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1639 else
1640 ev = keepalive_ev;
1643 if (keepalive > 0 && !ev)
1644 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1646 return ev;
1649 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1651 pth_t accept_tid;
1652 #ifdef WITH_GNUTLS
1653 pth_t tcp_accept_tid;
1654 #endif
1655 guint n;
1656 sigset_t set;
1657 gint n_clients = 0;
1658 pth_attr_t attr;
1659 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1660 gint keepalive = get_key_file_integer("global", "keepalive");
1661 gpointer value;
1663 pth_mutex_init(&cn_mutex);
1664 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1665 sigemptyset(&set);
1666 sigaddset(&set, SIGTERM);
1667 sigaddset(&set, SIGINT);
1668 sigaddset(&set, SIGUSR1);
1669 sigaddset(&set, SIGHUP);
1670 sigaddset(&set, SIGABRT);
1672 attr = pth_attr_new();
1673 pth_attr_init(attr);
1674 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1675 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1676 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1678 #ifdef WITH_GNUTLS
1679 if (sockfd_r != -1) {
1680 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1681 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1683 #endif
1685 pth_attr_init(attr);
1686 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1687 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1690 * For the cache_timeout configuration parameter.
1692 timeout_ev = timeout_event_iterate(NULL, attr);
1693 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1694 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1696 do {
1697 gint sig = 0;
1699 pth_sigwait_ev(&set, &sig, timeout_ev);
1700 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1701 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1702 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1704 if (sig > 0) {
1705 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1707 /* Caught a signal. */
1708 switch (sig) {
1709 case SIGHUP:
1710 reload_rcfile();
1711 keepalive = get_key_file_integer("global", "keepalive");
1712 break;
1713 case SIGABRT:
1714 CACHE_LOCK(NULL);
1715 cache_clear(NULL, 2);
1716 CACHE_UNLOCK;
1717 #ifndef MEM_DEBUG
1718 xpanic();
1719 #endif
1720 exit(EXIT_FAILURE);
1721 case SIGUSR1:
1722 CACHE_LOCK(NULL);
1723 log_write(N_("clearing file cache"));
1724 cache_clear(NULL, 2);
1725 CACHE_UNLOCK;
1726 break;
1727 default:
1728 quit = 1;
1729 shutdown(sockfd, SHUT_RDWR);
1730 close(sockfd);
1732 if (sockfd_r != -1) {
1733 shutdown(sockfd_r, SHUT_RDWR);
1734 close(sockfd_r);
1736 break;
1739 } while (!quit);
1742 * We're out of the main server loop. This happens when a signal was sent
1743 * to terminate the daemon. We'll wait for all clients to disconnect
1744 * before exiting and ignore any following signals.
1746 pth_join(accept_tid, &value);
1748 #ifdef WITH_GNUTLS
1749 if (sockfd_r != -1) {
1750 pth_cancel(tcp_accept_tid);
1751 pth_join(tcp_accept_tid, &value);
1753 #endif
1755 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1756 unlink(*socketpath);
1757 g_free(*socketpath);
1758 *socketpath = NULL;
1760 if (n > 1)
1761 log_write(N_("waiting for all threads to terminate"));
1763 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1765 while (n > 1) {
1766 if (n != n_clients) {
1767 log_write(N_("%i threads remain"), n-1);
1768 n_clients = n;
1771 pth_wait(ev_quit);
1772 pth_event_isolate(ev_quit);
1773 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1774 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1775 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1776 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1779 pth_event_free(timeout_ev, PTH_FREE_THIS);
1780 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1781 pth_event_free(ev_quit, PTH_FREE_THIS);
1782 pth_attr_destroy(attr);
1786 * Called from pinentry_fork() in the child process.
1788 void free_client_list()
1790 gint i, t = g_slist_length(cn_thread_list);
1792 for (i = 0; i < t; i++) {
1793 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1795 free_client(cn->cl);
1798 memset(key_cache, 0, cache_size);
1801 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1802 const gchar *outfile)
1804 file_header_internal_t *fh;
1805 gpg_error_t rc;
1806 guchar *md5file;
1807 guchar *shakey;
1808 guint iter;
1810 md5file = gcry_malloc(16);
1811 if (!md5file)
1812 return GPG_ERR_ENOMEM;
1814 shakey = gcry_malloc(gcrykeysize);
1815 if (!shakey) {
1816 gcry_free(md5file);
1817 return GPG_ERR_ENOMEM;
1820 fh = read_file_header(filename, TRUE, &rc);
1822 if (!fh)
1823 goto done;
1825 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1827 /* The header in version 1 had a bug where the iterations were off-by-one.
1828 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1829 * header.
1831 if (fh->fh1.iter >= 0) {
1832 if (keyfile) {
1833 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1835 if (!tmp) {
1836 rc = GPG_ERR_UNKNOWN_ERRNO;
1837 goto done;
1840 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1841 strlen(tmp) ? strlen(tmp) : 1);
1842 gcry_free(tmp);
1843 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1845 else {
1846 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1847 == FALSE) {
1848 rc = GPG_ERR_UNKNOWN_ERRNO;
1849 close(fh->fd);
1850 goto done;
1854 else
1855 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1857 close(fh->fd);
1859 if (rc)
1860 goto done;
1862 rc = convert_xml((gchar **)&fh->doc, &fh->len);
1864 if (rc) {
1865 gcry_free(fh->doc);
1866 log_write("%s: %s", filename, pwmd_strerror(rc));
1867 goto done;
1870 fh->v1 = FALSE;
1871 iter = fh->fh1.iter;
1872 memset(&fh->fh2, 0, sizeof(fh->fh2));
1873 /* Keep the iterations and key from the original file. */
1874 fh->fh2.iter = iter+1;
1875 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1877 if (rc)
1878 send_error(NULL, rc);
1880 done:
1881 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1882 gcry_free(shakey);
1883 gcry_free(md5file);
1884 g_free(fh);
1885 return rc;
1888 int main(int argc, char *argv[])
1890 gint opt;
1891 struct sockaddr_un addr;
1892 struct passwd *pw = getpwuid(getuid());
1893 gchar buf[PATH_MAX];
1894 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1895 gchar *socketarg = NULL;
1896 gchar *datadir = NULL;
1897 gboolean n;
1898 gchar *p;
1899 gchar **cache_push = NULL;
1900 gint iter = 0;
1901 gchar *import = NULL, *keyfile = NULL;
1902 gulong cmd_iterations = -1;
1903 gint default_timeout;
1904 gint rcfile_spec = 0;
1905 gint estatus = EXIT_FAILURE;
1906 gint sockfd, sockfd_r = -1;
1907 gchar *outfile = NULL;
1908 #ifndef MEM_DEBUG
1909 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1910 #endif
1911 gint do_unlink = 1;
1912 gboolean secure = FALSE;
1913 guint ptotal = 0;
1914 gint background = 1;
1915 sigset_t set;
1916 gchar *convert = NULL;
1917 #ifdef WITH_PINENTRY
1918 gboolean disable_pinentry = FALSE;
1919 #endif
1920 #ifdef WITH_GNUTLS
1921 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1922 gint ret;
1923 #endif
1924 #ifndef DEBUG
1925 #ifdef HAVE_SETRLIMIT
1926 struct rlimit rl;
1928 rl.rlim_cur = rl.rlim_max = 0;
1930 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1931 err(EXIT_FAILURE, "setrlimit()");
1932 #endif
1933 #endif
1935 #ifdef ENABLE_NLS
1936 setlocale(LC_ALL, "");
1937 bindtextdomain("pwmd", LOCALEDIR);
1938 textdomain("pwmd");
1939 #endif
1941 gpg_err_init();
1942 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1943 #ifndef MEM_DEBUG
1944 g_mem_set_vtable(&mtable);
1945 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1946 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1947 xmlInitMemory();
1948 #ifdef WITH_GNUTLS
1949 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1950 xrealloc, xfree);
1951 #endif
1952 #endif
1953 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1954 #ifdef WITH_GNUTLS
1955 gnutls_global_init();
1956 gnutls_global_set_log_function(tls_log);
1957 gnutls_global_set_log_level(1);
1958 assuan_set_io_hooks(&io_hooks);
1959 #endif
1960 pth_init();
1961 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1963 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1964 err(EXIT_FAILURE, "%s", buf);
1966 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1968 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1969 err(EXIT_FAILURE, "%s", buf);
1971 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1973 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1974 err(EXIT_FAILURE, "sysconf()");
1976 cache_size = page_size;
1977 cmdline = TRUE;
1979 while ((opt = getopt(argc, argv, "Po:C:bnI:i:k:hvf:D")) != EOF) {
1980 switch (opt) {
1981 #ifdef WITH_PINENTRY
1982 case 'P':
1983 disable_pinentry = TRUE;
1984 break;
1985 #endif
1986 case 'o':
1987 outfile = optarg;
1988 break;
1989 case 'C':
1990 convert = optarg;
1991 break;
1992 case 'b':
1993 /* Compatibility for version < 1.11 */
1994 break;
1995 case 'n':
1996 background = 0;
1997 break;
1998 case 'D':
1999 secure = TRUE;
2000 break;
2001 case 'I':
2002 import = optarg;
2003 break;
2004 case 'i':
2005 cmd_iterations = strtol(optarg, NULL, 10);
2006 break;
2007 case 'k':
2008 keyfile = optarg;
2009 break;
2010 case 'f':
2011 g_free(rcfile);
2012 rcfile = g_strdup(optarg);
2013 rcfile_spec = 1;
2014 break;
2015 case 'v':
2016 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,
2017 PACKAGE_BUGREPORT,
2018 #ifdef WITH_PINENTRY
2019 "+WITH_PINENTRY\n"
2020 #else
2021 "-WITH_PINENTRY\n"
2022 #endif
2023 #ifdef WITH_QUALITY
2024 "+WITH_QUALITY\n"
2025 #else
2026 "-WITH_QUALITY\n"
2027 #endif
2028 #ifdef WITH_GNUTLS
2029 "+WITH_GNUTLS\n"
2030 #else
2031 "-WITH_GNUTLS\n"
2032 #endif
2033 #ifdef DEBUG
2034 "+DEBUG\n"
2035 #else
2036 "-DEBUG\n"
2037 #endif
2038 #ifdef MEM_DEBUG
2039 "+MEM_DEBUG\n"
2040 #else
2041 "-MEM_DEBUG\n"
2042 #endif
2044 exit(EXIT_SUCCESS);
2045 case 'h':
2046 default:
2047 usage(argv[0]);
2051 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2052 exit(EXIT_FAILURE);
2054 #ifdef WITH_PINENTRY
2055 if (disable_pinentry == TRUE)
2056 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2057 #endif
2059 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2060 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2062 if (log_syslog == TRUE)
2063 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2065 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2066 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2067 errno = 0;
2069 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2070 log_write("setpriority()");
2071 goto do_exit;
2075 #ifdef HAVE_MLOCKALL
2076 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2077 log_write("mlockall()");
2078 goto do_exit;
2080 #endif
2082 setup_gcrypt();
2084 if (convert) {
2085 if (!outfile)
2086 usage(argv[0]);
2088 opt = convert_file(convert, keyfile, outfile);
2089 g_key_file_free(keyfileh);
2090 g_free(rcfile);
2091 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2094 if (import) {
2095 if (!outfile)
2096 usage(argv[0]);
2098 if (cmd_iterations == -1)
2099 cmd_iterations = get_key_file_integer("global", "iterations");
2101 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2102 g_key_file_free(keyfileh);
2103 g_free(rcfile);
2104 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2107 g_key_file_set_list_separator(keyfileh, ',');
2109 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2110 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2112 if (*p == '~') {
2113 p++;
2114 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2115 g_free(p);
2116 socketarg = g_strdup(buf);
2118 else
2119 socketarg = p;
2121 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2122 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2124 datadir = expand_homedir(p);
2125 g_free(p);
2127 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2128 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2129 disable_list_and_dump = n;
2131 else
2132 disable_list_and_dump = secure;
2134 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2135 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2136 else
2137 default_timeout = -1;
2139 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
2140 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
2142 if (cache_size < page_size || cache_size % page_size)
2143 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
2146 setup_logging(keyfileh);
2148 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2149 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2151 if (argc != optind) {
2152 if (cache_push)
2153 ptotal = g_strv_length(cache_push);
2155 for (; optind < argc; optind++) {
2156 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2157 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2161 if (strchr(socketarg, '/') == NULL) {
2162 socketdir = g_get_current_dir();
2163 socketname = g_strdup(socketarg);
2164 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2166 else {
2167 socketname = g_strdup(strrchr(socketarg, '/'));
2168 socketname++;
2169 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2170 socketdir = g_strdup(socketarg);
2171 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2174 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
2175 #ifdef MMAP_ANONYMOUS
2176 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
2177 #else
2178 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
2179 #endif
2180 err(EXIT_FAILURE, "mmap()");
2183 if (mlock(key_cache, cache_size) == -1)
2184 log_write("mlock(): %s", strerror(errno));
2186 memset(key_cache, 0, cache_size);
2188 if (chdir(datadir)) {
2189 log_write("%s", datadir);
2190 unlink(socketpath);
2191 goto do_exit;
2194 if (parse_rcfile_keys(TRUE) == FALSE)
2195 goto do_exit;
2197 clear_rcfile_keys();
2200 * Set the cache entry for a file. Prompts for the password.
2202 if (cache_push) {
2203 for (opt = 0; cache_push[opt]; opt++)
2204 do_cache_push(cache_push[opt], NULL);
2206 g_strfreev(cache_push);
2207 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2211 * bind() doesn't like the full pathname of the socket or any non alphanum
2212 * characters so change to the directory where the socket is wanted then
2213 * create it then change to datadir.
2215 if (chdir(socketdir)) {
2216 log_write("%s", socketdir);
2217 goto do_exit;
2220 g_free(socketdir);
2222 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2223 log_write("socket()");
2224 goto do_exit;
2227 addr.sun_family = AF_UNIX;
2228 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2230 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2231 log_write("bind()");
2233 if (errno == EADDRINUSE)
2234 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2235 "stale socket. Please remove it manually."), socketpath);
2237 do_unlink = 0;
2238 goto do_exit;
2241 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2242 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2243 mode_t mode = strtol(t, NULL, 8);
2244 mode_t mask = umask(0);
2246 g_free(t);
2248 if (chmod(socketname, mode) == -1) {
2249 log_write("%s", socketname);
2250 close(sockfd);
2251 unlink(socketpath);
2252 umask(mask);
2253 goto do_exit;
2256 umask(mask);
2259 g_free(--socketname);
2261 if (chdir(datadir)) {
2262 log_write("%s", datadir);
2263 close(sockfd);
2264 unlink(socketpath);
2265 goto do_exit;
2268 g_free(datadir);
2269 pth_mutex_init(&cache_mutex);
2270 #ifdef WITH_PINENTRY
2271 pth_mutex_init(&pin_mutex);
2272 #endif
2274 if (listen(sockfd, 0) == -1) {
2275 log_write("listen()");
2276 goto do_exit;
2279 #ifdef WITH_GNUTLS
2280 if (get_key_file_boolean("global", "enable_tcp")) {
2281 gchar *tmp, *tmp2;
2282 struct addrinfo hints, *servinfo, *p;
2283 gint port = get_key_file_integer("global", "tcp_port");
2284 char buf[7];
2286 memset(&hints, 0, sizeof(hints));
2287 hints.ai_family = AF_UNSPEC;
2288 hints.ai_socktype = SOCK_STREAM;
2289 hints.ai_flags = AI_PASSIVE;
2291 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2292 &hints, &servinfo)) == -1) {
2293 log_write("getaddrinfo(): %s", gai_strerror(opt));
2294 goto do_exit;
2297 for(p = servinfo; p != NULL; p = p->ai_next) {
2298 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2299 p->ai_protocol)) == -1) {
2300 log_write("socket()");
2301 continue;
2304 opt = 1;
2306 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2307 sizeof(int)) == -1) {
2308 log_write("setsockopt()");
2309 goto do_exit;
2312 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2313 close(sockfd_r);
2314 log_write("bind()");
2315 continue;
2318 opt++;
2319 break;
2322 freeaddrinfo(servinfo);
2324 if (!p) {
2325 log_write("%s", N_("could not bind"));
2326 goto do_exit;
2329 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2330 gchar *tmp = get_key_file_string("global", "tcp_interface");
2332 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2333 == -1) {
2334 log_write("setsockopt");
2335 g_free(tmp);
2336 goto do_exit;
2339 g_free(tmp);
2342 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2344 if (ret != GNUTLS_E_SUCCESS) {
2345 log_write("%s", gnutls_strerror(ret));
2346 goto do_exit;
2349 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2351 if (!tmp) {
2352 log_write("%s", strerror(ENOMEM));
2353 goto do_exit;
2356 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2357 GNUTLS_X509_FMT_PEM);
2358 g_free(tmp);
2360 if (ret < 0) {
2361 log_write("%s", gnutls_strerror(ret));
2362 goto do_exit;
2365 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2367 if (!tmp) {
2368 log_write("%s", strerror(ENOMEM));
2369 goto do_exit;
2372 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2374 if (!tmp2) {
2375 xfree(tmp);
2376 log_write("%s", strerror(ENOMEM));
2377 goto do_exit;
2380 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2381 GNUTLS_X509_FMT_PEM);
2382 g_free(tmp);
2383 g_free(tmp2);
2385 if (ret != GNUTLS_E_SUCCESS) {
2386 log_write("%s", gnutls_strerror(ret));
2387 goto do_exit;
2390 #endif
2392 if (background) {
2393 switch (fork()) {
2394 case -1:
2395 log_write("fork()");
2396 goto do_exit;
2397 case 0:
2398 close(0);
2399 close(1);
2400 close(2);
2401 setsid();
2402 break;
2403 default:
2404 exit(EXIT_SUCCESS);
2408 cmdline = FALSE;
2410 #ifdef WITH_GNUTLS
2411 if (get_key_file_boolean("global", "enable_tcp")) {
2412 log_write("%s", N_("Generating key exchange parameters..."));
2413 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2415 if (ret) {
2416 log_write("%s", gpg_strerror(ret));
2417 goto do_exit;
2420 ret = gnutls_dh_params_init(&dh_params);
2422 if (ret != GNUTLS_E_SUCCESS) {
2423 log_write("%s", gnutls_strerror(ret));
2424 goto do_exit;
2427 ret = gnutls_dh_params_generate2(dh_params, 1024);
2429 if (ret != GNUTLS_E_SUCCESS) {
2430 log_write("%s", gnutls_strerror(ret));
2431 goto do_exit;
2434 gnutls_certificate_set_dh_params(x509_cred, dh_params);
2435 ret = gnutls_rsa_params_init(&rsa_params);
2437 if (ret != GNUTLS_E_SUCCESS) {
2438 log_write("%s", gnutls_strerror(ret));
2439 goto do_exit;
2442 ret = gnutls_rsa_params_generate2(rsa_params, 512);
2444 if (ret != GNUTLS_E_SUCCESS) {
2445 log_write("%s", gnutls_strerror(ret));
2446 goto do_exit;
2449 gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
2450 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2452 if (listen(sockfd_r, 0) == -1) {
2453 log_write("listen()");
2454 goto do_exit;
2457 #endif
2460 * These are the signals that we use in threads. libpth can catch signals
2461 * itself so ignore them everywhere else. Note that using
2462 * signal(N, SIG_IGN) doesn't work like you might think.
2464 sigemptyset(&set);
2466 /* Termination */
2467 sigaddset(&set, SIGTERM);
2468 sigaddset(&set, SIGINT);
2470 /* Configuration file reloading. */
2471 sigaddset(&set, SIGUSR1);
2473 /* Clears the file cache. */
2474 sigaddset(&set, SIGHUP);
2476 /* Caught in client_thread(). Sends a cache status message. */
2477 sigaddset(&set, SIGUSR2);
2479 /* Ignored everywhere. When a client disconnects abnormally this signal
2480 * gets raised. It isn't needed though because client_thread() will check
2481 * for rcs even after the client disconnects. */
2482 signal(SIGPIPE, SIG_IGN);
2483 pth_sigmask(SIG_BLOCK, &set, NULL);
2484 server_loop(sockfd, sockfd_r, &socketpath);
2485 estatus = EXIT_SUCCESS;
2487 do_exit:
2488 if (socketpath && do_unlink) {
2489 unlink(socketpath);
2490 g_free(socketpath);
2493 #ifdef WITH_GNUTLS
2494 if (sockfd_r != -1) {
2495 gnutls_dh_params_deinit(dh_params);
2496 gnutls_rsa_params_deinit(rsa_params);
2498 if (x509_cred)
2499 gnutls_certificate_free_credentials(x509_cred);
2501 gnutls_global_deinit();
2503 #endif
2505 g_key_file_free(keyfileh);
2506 g_free(rcfile);
2507 xmlCleanupParser();
2509 if (key_cache) {
2510 cache_clear(NULL, 2);
2511 memset(key_cache, 0, cache_size);
2514 if (key_cache && munmap(key_cache, cache_size) == -1)
2515 log_write("munmap(): %s", strerror(errno));
2517 if (estatus == EXIT_SUCCESS)
2518 log_write(N_("pwmd exiting normally"));
2520 pth_kill();
2521 #if defined(DEBUG) && !defined(MEM_DEBUG)
2522 xdump();
2523 #endif
2524 exit(estatus);