Added configuration parameter "tcp_connection_limit". This specifies the
[pwmd.git] / src / pwmd.c
blob7b33d8381ba5dcda002ca84b08461159947d6042
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_errorfile_key()
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 log_write(N_("reloading configuration file '%s'"), rcfile);
103 g_key_file_free(keyfileh);
104 keyfileh = parse_rcfile(0);
105 clear_errorfile_key();
106 send_status_all(STATUS_CONFIG);
109 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
111 gpg_error_t n = gpg_error_from_errno(e);
113 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
116 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
118 gpg_err_code_t n = gpg_err_code(e);
119 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
120 struct client_s *client = assuan_get_pointer(ctx);
122 if (!e)
123 return assuan_process_done(ctx, 0);
125 if (!ctx) {
126 log_write("%s\n", pwmd_strerror(e));
127 return e;
130 if (n == EPWMD_LIBXML_ERROR) {
131 xmlErrorPtr xe = client->xml_error;
133 if (!xe)
134 xe = xmlGetLastError();
136 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
137 log_write("%s", xe->message);
139 if (xe == client->xml_error)
140 xmlResetError(xe);
141 else
142 xmlResetLastError();
144 client->xml_error = NULL;
145 return e;
148 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
151 void log_write(const gchar *fmt, ...)
153 gchar *args, *line;
154 va_list ap;
155 struct tm *tm;
156 time_t now;
157 gchar tbuf[21];
158 gint fd = -1;
159 pth_attr_t attr;
160 gchar *name;
161 pth_t tid = pth_self();
162 gchar tid_str[12], *p;
164 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
165 return;
167 if (logfile) {
168 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
169 warn(N_("logfile"));
170 return;
174 va_start(ap, fmt);
176 if (g_vasprintf(&args, fmt, ap) == -1) {
177 if (logfile)
178 close(fd);
180 va_end(ap);
181 return;
184 attr = pth_attr_of(tid);
186 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
187 name = "unknown";
189 pth_attr_destroy(attr);
190 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
191 p = tid_str;
193 if (strncmp(p+1, name, 9) == 0)
194 p = NULL;
196 if (log_syslog == TRUE)
197 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
199 va_end(ap);
200 time(&now);
201 tm = localtime(&now);
202 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
203 tbuf[sizeof(tbuf) - 1] = 0;
205 if (args[strlen(args)-1] == '\n')
206 args[strlen(args)-1] = 0;
208 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
209 p ? p : "", args);
210 g_free(args);
212 if (!line) {
213 if (logfile)
214 close(fd);
216 return;
219 if (logfile) {
220 write(fd, line, strlen(line));
221 fsync(fd);
222 close(fd);
225 if (isatty(STDERR_FILENO)) {
226 fprintf(stderr, "%s", line);
227 fflush(stderr);
230 g_free(line);
233 static void usage(gchar *pn)
235 g_fprintf(stderr, N_(
236 "Usage: %s [-hvDn] [-f <rcfile>] [-C <filename> -o <outfile>]\n"
237 " [-I <filename> [-i <iter>] -o <outfile>] [file1] [...]\n"
238 " -n run as a foreground process\n"
239 " -f load the specified rcfile (~/.pwmd/config)\n"
240 " -I import an XML file\n"
241 " -i encrypt with the specified number of iterations when importing\n"
242 " (config default in the \"global\" section)\n"
243 " -D disable use of the LIST and DUMP commands\n"
244 " -C convert a version 1 data file to version 2\n"
245 " -v version\n"
246 " -h this help text\n"
247 ), pn);
248 exit(EXIT_FAILURE);
251 #ifndef MEM_DEBUG
252 static int gcry_SecureCheck(const void *ptr)
254 return 1;
256 #endif
258 static void setup_gcrypt()
260 gcry_check_version(NULL);
262 #ifndef MEM_DEBUG
263 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
264 xfree);
265 #endif
267 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
268 NULL) != 0)
269 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
271 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
272 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
275 static gint new_connection(struct client_s *cl)
277 gpg_error_t rc;
278 gchar ver[ASSUAN_LINELENGTH];
280 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
282 if (rc)
283 goto fail;
285 assuan_set_pointer(cl->ctx, cl);
286 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
287 assuan_set_hello_line(cl->ctx, ver);
288 rc = register_commands(cl->ctx);
290 if (rc)
291 goto fail;
293 rc = assuan_accept(cl->ctx);
295 if (rc)
296 goto fail;
298 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
299 return 0;
301 fail:
302 log_write("%s", gpg_strerror(rc));
303 return 1;
306 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
308 gchar *line = NULL;
309 struct client_s *client = assuan_get_pointer(ctx);
310 gchar buf[ASSUAN_LINELENGTH];
311 gchar *status = NULL;
313 switch (which) {
314 case STATUS_CACHE:
315 CACHE_LOCK(client->ctx);
316 line = print_fmt(buf, sizeof(buf), "%i %i",
317 cache_file_count(),
318 (cache_size % sizeof(file_cache_t)) ?
319 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
320 (cache_size / sizeof(file_cache_t)) - cache_file_count());
321 CACHE_UNLOCK;
322 status = "CACHE";
323 break;
324 case STATUS_CLIENTS:
325 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
326 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
327 pth_mutex_release(&cn_mutex);
328 status = "CLIENTS";
329 break;
330 case STATUS_CONFIG:
331 status = "CONFIG";
332 break;
333 case STATUS_KEEPALIVE:
334 status = "KEEPALIVE";
335 break;
336 case STATUS_LOCKED:
337 status = "LOCKED";
338 line = N_("Waiting for lock");
339 break;
342 return assuan_write_status(ctx, status, line);
345 void send_status_all(status_msg_t which)
347 guint i, t;
349 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
351 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
352 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
353 pth_msgport_t m = pth_msgport_find(cn->msg_name);
355 if (m) {
356 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
358 msg->m_data = (status_msg_t *)which;
359 pth_msgport_put(m, msg);
363 pth_mutex_release(&cn_mutex);
366 static void xml_error_cb(void *data, xmlErrorPtr e)
368 struct client_s *client = data;
371 * Keep the first reported error as the one to show in the error
372 * description. Reset in send_error().
374 if (client->xml_error)
375 return;
377 xmlCopyError(e, client->xml_error);
381 * This is called after a child_thread terminates. Set with
382 * pth_cleanup_push().
384 static void cleanup_cb(void *arg)
386 struct client_thread_s *cn = arg;
387 gpointer value;
388 struct client_s *cl = cn->cl;
390 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
391 log_write(N_("exiting, fd=%i"), cn->fd);
393 if (cn->msg_tid) {
394 pth_cancel(cn->msg_tid);
395 pth_join(cn->msg_tid, &value);
396 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
399 if (cn->msg_name)
400 g_free(cn->msg_name);
402 if (cn->msg) {
403 while (pth_msgport_pending(cn->msg) > 0) {
404 pth_message_t *m = pth_msgport_get(cn->msg);
406 g_free(m);
409 pth_msgport_destroy(cn->msg);
412 pth_join(cn->tid, &value);
414 if (cl && cl->freed == FALSE)
415 cleanup_assuan(cl->ctx);
417 if (cl && cl->ctx)
418 assuan_deinit_server(cl->ctx);
420 #ifdef WITH_PINENTRY
421 if (cl && cl->pinentry)
422 cleanup_pinentry(cl->pinentry);
423 #endif
425 #ifdef WITH_GNUTLS
426 if (cn->tls) {
427 gnutls_deinit(cn->tls->ses);
428 g_free(cn->tls);
431 if (cn->addr)
432 g_free(cn->addr);
433 #endif
435 g_free(cl);
436 cn_thread_list = g_slist_remove(cn_thread_list, cn);
437 g_free(cn);
438 pth_mutex_release(&cn_mutex);
439 send_status_all(STATUS_CLIENTS);
442 #ifdef WITH_GNUTLS
443 static int read_hook(assuan_context_t ctx, assuan_fd_t fd, void *data,
444 size_t len, ssize_t *ret)
446 struct client_s *cl = assuan_get_pointer(ctx);
448 if (!cl || !cl->thd->remote)
449 *ret = pth_read((int)fd, data, len);
450 else {
451 do {
452 *ret = gnutls_record_recv(cl->thd->tls->ses, data, len);
454 if (*ret == GNUTLS_E_REHANDSHAKE) {
455 *ret = gnutls_rehandshake(cl->thd->tls->ses);
457 if (*ret == GNUTLS_E_WARNING_ALERT_RECEIVED ||
458 *ret == GNUTLS_A_NO_RENEGOTIATION) {
459 log_write("%s", gnutls_strerror(*ret));
460 continue;
463 if (*ret != GNUTLS_E_SUCCESS) {
464 log_write("%s", gnutls_strerror(*ret));
465 *ret = 0;
466 break;
469 *ret = gnutls_handshake(cl->thd->tls->ses);
471 if (*ret != GNUTLS_E_SUCCESS) {
472 log_write("%s", gnutls_strerror(*ret));
473 *ret = 0;
474 break;
477 continue;
479 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
482 return *ret <= 0 ? 0 : 1;
485 static int write_hook(assuan_context_t ctx, assuan_fd_t fd, const void *data,
486 size_t len, ssize_t *ret)
488 struct client_s *cl = assuan_get_pointer(ctx);
490 if (!cl || !cl->thd->remote)
491 *ret = pth_write((int)fd, data, len);
492 else {
493 do {
494 *ret = gnutls_record_send(cl->thd->tls->ses, data, len);
495 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
498 return *ret <= 0 ? 0 : 1;
500 #endif
502 static void *client_msg_thread(void *data)
504 struct client_s *cl = data;
505 pth_status_t ev_status;
507 for (;;) {
508 pth_wait(cl->thd->msg_ev);
509 ev_status = pth_event_status(cl->thd->msg_ev);
511 if (ev_status == PTH_STATUS_FAILED) {
512 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
513 __FUNCTION__);
514 continue;
517 if (ev_status == PTH_STATUS_OCCURRED) {
518 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
520 while (pth_msgport_pending(cl->thd->msg) > 0) {
521 pth_message_t *m = pth_msgport_get(cl->thd->msg);
522 status_msg_t n = (status_msg_t)m->m_data;
523 gpg_error_t rc = send_status(cl->ctx, n);
525 g_free(m);
527 if (rc) {
528 pth_mutex_release(&cn_mutex);
529 log_write("%s", gpg_strerror(rc));
530 break;
534 pth_mutex_release(&cn_mutex);
540 * Called every time a connection is made via pth_spawn(). This is the thread
541 * entry point.
543 static void *client_thread(void *data)
545 struct client_thread_s *thd = data;
546 pth_event_t ev;
547 struct client_s *cl = g_malloc0(sizeof(struct client_s));
548 gpg_error_t rc;
549 pth_attr_t attr;
552 * Prevent a race condition with init_new_connection() if this thread
553 * fails (returns) for some reason before init_new_connection() releases
554 * the cn_mutex.
556 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
557 pth_mutex_release(&cn_mutex);
559 if (!cl) {
560 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
561 goto fail;
564 thd->cl = cl;
565 cl->thd = thd;
566 pth_cleanup_push(cleanup_cb, thd);
568 #ifdef WITH_GNUTLS
570 * Do the TLS handshake before anything else.
572 if (thd->remote) {
573 thd->tls = tls_init(thd->fd);
575 if (!thd->tls) {
576 close(thd->fd);
577 goto fail;
580 #endif
583 * This is a "child" thread. Don't catch any signals. Let the master
584 * thread take care of signals in server_loop().
586 if (new_connection(cl))
587 goto fail;
589 #ifdef WITH_PINENTRY
590 cl->pinentry = pinentry_init();
592 if (!cl->pinentry) {
593 g_free(cl);
594 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
595 goto fail;
597 #endif
599 thd->msg_name = g_strdup_printf("%p", thd->tid);
601 if (!thd->msg_name) {
602 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
603 goto fail;
606 thd->msg = pth_msgport_create(thd->msg_name);
608 if (!thd->msg) {
609 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
610 goto fail;
613 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
614 attr = pth_attr_new();
615 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
616 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
617 pth_attr_destroy(attr);
619 if (!thd->msg_tid) {
620 log_write(N_("pth_spawn() failed"));
621 goto fail;
624 #ifdef HAVE_MLOCKALL
625 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
626 log_write("mlockall(): %s", strerror(errno));
627 goto fail;
629 #endif
631 rc = send_status(cl->ctx, STATUS_CACHE);
633 if (rc) {
634 log_write("%s", gpg_strerror(rc));
635 goto fail;
638 send_status_all(STATUS_CLIENTS);
639 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
640 xmlInitParser();
641 xmlXPathInit();
642 xmlSetStructuredErrorFunc(cl, xml_error_cb);
644 for (;;) {
645 pth_status_t ev_status;
647 pth_wait(ev);
648 ev_status = pth_event_status(ev);
650 if (ev_status == PTH_STATUS_FAILED) {
651 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
652 __FUNCTION__);
653 goto done;
655 else if (ev_status == PTH_STATUS_OCCURRED) {
656 rc = assuan_process_next(cl->ctx);
658 if (rc) {
659 cl->inquire_status = INQUIRE_INIT;
661 if (gpg_err_code(rc) == GPG_ERR_EOF)
662 goto done;
664 log_write("assuan_process_next(): %s", gpg_strerror(rc));
665 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
667 if (rc) {
668 log_write("assuan_process_done(): %s", gpg_strerror(rc));
669 goto done;
672 else {
673 #ifdef WITH_PINENTRY
674 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
675 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
676 pth_event_concat(ev, cl->pinentry->ev, NULL);
677 cl->pinentry->status = PINENTRY_RUNNING;
679 #endif
681 switch (cl->inquire_status) {
682 case INQUIRE_BUSY:
683 case INQUIRE_INIT:
684 break;
685 case INQUIRE_DONE:
686 cl->inquire_status = INQUIRE_INIT;
687 rc = assuan_process_done(cl->ctx, 0);
688 break;
693 #ifdef WITH_PINENTRY
694 ev = pinentry_iterate(cl, ev);
695 #endif
699 * Client cleanup (including XML data) is done in cleanup_cb() from
700 * the cleanup thread.
702 done:
703 pth_event_free(ev, PTH_FREE_ALL);
705 fail:
706 pth_exit(NULL);
707 return NULL;
710 static void setup_logging(GKeyFile *kf)
712 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
714 if (n == TRUE) {
715 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
717 if (*p == '~') {
718 gchar buf[PATH_MAX];
720 p++;
721 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
722 g_free(p);
724 if (logfile)
725 g_free(logfile);
727 logfile = g_strdup(buf);
729 else {
730 if (logfile)
731 g_free(logfile);
733 logfile = p;
737 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
741 * Make sure all settings are set to either the specified setting or a
742 * default.
744 static void set_rcfile_defaults(GKeyFile *kf)
746 gchar buf[PATH_MAX];
748 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
749 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
750 g_key_file_set_string(kf, "global", "socket_path", buf);
753 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
754 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
755 g_key_file_set_string(kf, "global", "data_directory", buf);
758 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
759 g_key_file_set_boolean(kf, "global", "backup", TRUE);
761 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
762 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
763 g_key_file_set_string(kf, "global", "log_path", buf);
766 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
767 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
769 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
770 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
772 #ifdef HAVE_MLOCKALL
773 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
774 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
775 #endif
777 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
778 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
780 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
781 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
782 g_key_file_set_integer(kf, "global", "iterations", 1);
784 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
785 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
787 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
788 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
790 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
791 g_key_file_set_integer(kf, "global", "compression_level", 6);
793 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
794 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
796 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
797 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
799 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
801 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
802 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
804 #ifdef HAVE_MLOCKALL
805 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
806 #endif
808 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
809 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
811 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
812 g_key_file_set_integer(kf, "global", "keepalive", 30);
814 #ifdef WITH_PINENTRY
815 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
816 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
818 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
819 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
820 #endif
822 #ifdef WITH_GNUTLS
823 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
824 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
826 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
827 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
829 if (g_key_file_has_key(kf, "global", "tcp_connection_limit", NULL) == FALSE)
830 g_key_file_set_integer(kf, "global", "tcp_connection_limit", 5);
831 #endif
833 setup_logging(kf);
836 static GKeyFile *parse_rcfile(int cmdline)
838 GKeyFile *kf = g_key_file_new();
839 GError *rc = NULL;
841 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
842 log_write("%s: %s", rcfile, rc->message);
844 if (cmdline)
845 exit(EXIT_FAILURE);
847 if (rc->code == G_FILE_ERROR_NOENT) {
848 g_clear_error(&rc);
849 set_rcfile_defaults(kf);
850 return kf;
853 g_clear_error(&rc);
854 return NULL;
856 else
857 set_rcfile_defaults(kf);
859 return kf;
862 static gchar *do_get_password(const gchar *prompt)
864 gchar buf[LINE_MAX] = {0}, *p;
865 struct termios told, tnew;
866 gchar *key;
868 if (tcgetattr(STDIN_FILENO, &told) == -1) {
869 warn("tcgetattr()");
870 return NULL;
873 memcpy(&tnew, &told, sizeof(struct termios));
874 tnew.c_lflag &= ~(ECHO);
875 tnew.c_lflag |= ICANON|ECHONL;
877 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
878 warn("tcsetattr()");
879 tcsetattr(STDIN_FILENO, TCSANOW, &told);
880 return NULL;
883 fprintf(stderr, "%s", prompt);
885 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
886 tcsetattr(STDIN_FILENO, TCSANOW, &told);
887 return NULL;
890 tcsetattr(STDIN_FILENO, TCSANOW, &told);
891 p[strlen(p) - 1] = 0;
893 if (!buf[0]) {
894 key = gcry_malloc(1);
895 key[0] = 0;
897 else {
898 key = gcry_malloc(strlen(p) + 1);
899 sprintf(key, "%s", p);
902 memset(&buf, 0, sizeof(buf));
903 return key;
906 /* Only used when "enable_pinentry" is "false". */
907 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
908 guchar *key, pinentry_cmd_t which)
910 gint try = 0;
911 gchar *password;
912 gchar *prompt;
914 if (which == PINENTRY_SAVE) {
915 gchar *key1, *key2;
917 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
918 key1 = do_get_password(prompt);
919 g_free(prompt);
921 if (!key1) {
922 warnx(N_("%s: skipping file"), filename);
923 return FALSE;
926 prompt = g_strdup_printf(N_("Repeat passphrase: "));
927 key2 = do_get_password(prompt);
928 g_free(prompt);
930 if (!key2) {
931 gcry_free(key1);
932 warnx(N_("%s: skipping file"), filename);
933 return FALSE;
936 if (strcmp(key1, key2)) {
937 gcry_free(key1);
938 gcry_free(key2);
939 warnx("passphrase mismatch");
940 return FALSE;
943 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
944 strlen(key1) ? strlen(key1) : 1);
945 gcry_free(key1);
946 gcry_free(key2);
947 return TRUE;
950 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
952 do {
953 gpg_error_t rc;
955 if ((password = do_get_password(prompt)) == NULL) {
956 warnx(N_("%s: skipping file"), filename);
957 g_free(prompt);
958 return FALSE;
961 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
962 gcry_free(password);
964 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
966 if (!rc)
967 break;
969 fprintf(stderr, N_("%s: Invalid passphrase"), filename);
970 } while (try++ < 2);
972 g_free(prompt);
974 if (try == 3) {
975 fprintf(stderr, N_("%s: Invalid passphrase, skipping"), filename);
976 return FALSE;
979 return TRUE;
983 * inbuf must have been allocated with gcry_malloc().
985 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
986 guchar *shakey, gpointer inbuf, gulong insize)
988 gcry_cipher_hd_t gh;
989 gpg_error_t rc;
990 gint level, zrc;
991 glong outsize;
992 gpointer outbuf;
994 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
996 if (rc)
997 return rc;
999 level = get_key_file_integer(filename, "compression_level");
1001 if (level < 0)
1002 level = 0;
1004 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
1005 == FALSE) {
1006 gcry_cipher_close(gh);
1007 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
1009 else {
1010 gcry_free(inbuf);
1011 inbuf = outbuf;
1012 insize = outsize;
1015 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
1016 gcry_cipher_close(gh);
1017 return rc;
1020 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
1021 guchar *md5file, guchar *key, pinentry_cmd_t which)
1023 #ifdef WITH_PINENTRY
1024 gpg_error_t rc = 0;
1026 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
1027 == FALSE) {
1028 #endif
1029 return get_input(filename, fh, key, which);
1030 #ifdef WITH_PINENTRY
1032 else {
1033 gchar *result = NULL;
1034 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1035 gint try = 0;
1037 set_pinentry_defaults(pin);
1038 pin->which = which;
1039 pin->filename = g_strdup(filename);
1040 again:
1041 rc = pinentry_getpin(pin, &result);
1043 if (rc) {
1044 warnx("%s", gpg_strerror(rc));
1045 xfree(result);
1046 goto done;
1049 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1050 xfree(result);
1052 if (which == PINENTRY_SAVE) {
1053 cleanup_pinentry(pin);
1054 goto done;
1057 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1059 if (rc == EPWMD_BADKEY) {
1060 if (try++ == 2)
1061 warnx("%s: %s", filename, pwmd_strerror(rc));
1062 else {
1063 g_free(pin->title);
1064 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1065 goto again;
1068 else if (rc)
1069 warnx("%s", pwmd_strerror(rc));
1071 cleanup_pinentry(pin);
1074 done:
1075 return rc ? FALSE : TRUE;
1076 #endif
1079 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1080 gulong iter)
1082 xmlDocPtr doc;
1083 gint fd;
1084 struct stat st;
1085 gint len;
1086 xmlChar *xmlbuf;
1087 xmlChar *xml;
1088 guchar shakey[gcrykeysize];
1089 gpg_error_t rc;
1090 file_header_internal_t fh;
1092 if (stat(filename, &st) == -1) {
1093 warn("%s", filename);
1094 return FALSE;
1097 if (iter && get_password(filename, NULL, NULL, shakey, PINENTRY_SAVE)
1098 == FALSE)
1099 return FALSE;
1101 if ((fd = open(filename, O_RDONLY)) == -1) {
1102 memset(shakey, 0, sizeof(shakey));
1103 warn("%s", filename);
1104 return FALSE;
1107 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1108 close(fd);
1109 memset(shakey, 0, sizeof(shakey));
1110 log_write("%s", strerror(ENOMEM));
1111 return FALSE;
1114 if (read(fd, xmlbuf, st.st_size) == -1) {
1115 memset(shakey, 0, sizeof(shakey));
1116 rc = errno;
1117 close(fd);
1118 errno = rc;
1119 err(EXIT_FAILURE, "read()");
1122 close(fd);
1123 xmlbuf[st.st_size] = 0;
1126 * Make sure the document validates.
1128 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1129 log_write("xmlReadDoc()");
1130 close(fd);
1131 gcry_free(xmlbuf);
1132 memset(shakey, 0, sizeof(shakey));
1133 return FALSE;
1136 gcry_free(xmlbuf);
1137 xmlDocDumpMemory(doc, &xml, &len);
1138 xmlFreeDoc(doc);
1140 if (!iter)
1141 memset(shakey, '!', sizeof(shakey));
1143 memset(&fh, 0, sizeof(fh));
1144 fh.fh2.iter = iter;
1145 rc = export_common(outfile, &fh, shakey, xml, len);
1146 memset(shakey, 0, sizeof(shakey));
1148 if (rc)
1149 send_error(NULL, rc);
1151 return rc ? FALSE : TRUE;
1154 gchar *get_key_file_string(const gchar *section, const gchar *what)
1156 gchar *val = NULL;
1157 GError *grc = NULL;
1159 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1160 val = g_key_file_get_string(keyfileh, section, what, &grc);
1162 if (grc) {
1163 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1164 g_clear_error(&grc);
1167 else {
1168 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1169 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1171 if (grc) {
1172 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1173 g_clear_error(&grc);
1178 return val;
1181 gint get_key_file_integer(const gchar *section, const gchar *what)
1183 gint val = -1;
1184 GError *grc = NULL;
1186 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1187 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1189 if (grc) {
1190 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1191 g_clear_error(&grc);
1194 else {
1195 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1196 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1198 if (grc) {
1199 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1200 g_clear_error(&grc);
1205 return val;
1208 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1210 gboolean val = FALSE;
1211 GError *grc = NULL;
1213 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1214 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1216 if (grc) {
1217 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1218 g_clear_error(&grc);
1221 else {
1222 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1223 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1225 if (grc) {
1226 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1227 g_clear_error(&grc);
1232 return val;
1235 static gboolean _getline(const gchar *file, gchar **result)
1237 FILE *fp;
1238 gchar buf[LINE_MAX] = {0}, *p;
1239 gchar *str = NULL;
1240 gint len;
1242 if ((fp = fopen(file, "r")) == NULL) {
1243 warn("%s", file);
1244 return FALSE;
1247 p = fgets(buf, sizeof(buf), fp);
1248 fclose(fp);
1249 len = strlen(buf);
1251 if (len && buf[len - 1] == '\n')
1252 buf[--len] = 0;
1254 str = gcry_malloc(len + 1);
1255 memcpy(str, buf, len ? len : 1);
1256 str[len] = 0;
1257 memset(&buf, 0, sizeof(buf));
1258 *result = str;
1259 return TRUE;
1262 static gboolean parse_keyfile_key()
1264 gsize n;
1265 gchar **groups;
1266 gchar **p;
1267 gchar *str;
1269 groups = g_key_file_get_groups(keyfileh, &n);
1271 for (p = groups; *p; p++) {
1272 GError *rc = NULL;
1274 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1275 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1277 if (!str) {
1278 if (rc) {
1279 warnx("%s", rc->message);
1280 g_clear_error(&rc);
1283 continue;
1286 do_cache_push(*p, str);
1287 g_free(str);
1288 continue;
1291 if (rc) {
1292 warnx("%s", rc->message);
1293 g_clear_error(&rc);
1294 continue;
1297 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1298 gchar *t;
1299 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1301 if (!file) {
1302 if (rc) {
1303 warnx("%s", rc->message);
1304 g_clear_error(&rc);
1307 continue;
1310 t = expand_homedir(file);
1311 g_free(file);
1312 file = t;
1314 if (_getline(file, &str) == FALSE) {
1315 g_free(file);
1316 continue;
1319 g_free(file);
1320 do_cache_push(*p, str);
1321 gcry_free(str);
1322 continue;
1325 if (rc) {
1326 warnx("%s", rc->message);
1327 g_clear_error(&rc);
1331 g_strfreev(groups);
1332 return TRUE;
1335 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1337 guchar *md5file;
1338 guchar *key;
1339 gint timeout;
1340 const gchar *p = filename;
1341 file_header_internal_t *fh;
1342 gpg_error_t rc;
1344 while (isspace(*p))
1345 p++;
1347 if (!*p)
1348 return FALSE;
1350 if (valid_filename(p) == FALSE) {
1351 warnx(N_("%s: invalid characters in filename"), p);
1352 return FALSE;
1355 md5file = gcry_malloc(16);
1356 key = gcry_malloc(gcrykeysize);
1357 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1359 if (cache_iscached(md5file) == TRUE) {
1360 warnx(N_("%s: file already cached, skipping"), p);
1361 gcry_free(md5file);
1362 gcry_free(key);
1363 return FALSE;
1366 if (access(p, R_OK|W_OK) != 0) {
1367 gcry_free(md5file);
1368 gcry_free(key);
1370 if (errno != ENOENT) {
1371 warn("%s", p);
1372 return FALSE;
1375 warn("%s", p);
1376 return TRUE;
1379 fh = read_file_header(filename, FALSE, &rc);
1381 if (!fh) {
1382 gcry_free(md5file);
1383 gcry_free(key);
1384 warnx("%s", pwmd_strerror(rc));
1385 return FALSE;
1388 if (fh->fh2.iter <= 0) {
1389 memset(key, '!', gcrykeysize);
1390 goto try_decrypt;
1393 if (!password) {
1394 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1395 g_free(fh);
1396 return FALSE;
1399 else
1400 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1401 strlen(password) ? strlen(password) : 1);
1403 try_decrypt:
1404 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1406 if (rc) {
1407 warnx("%s: %s", filename, pwmd_strerror(rc));
1408 gcry_free(key);
1409 gcry_free(md5file);
1410 g_free(fh);
1411 return FALSE;
1414 if (cache_add_file(md5file, key) == FALSE) {
1415 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1416 gcry_free(key);
1417 gcry_free(md5file);
1418 g_free(fh);
1419 return FALSE;
1422 timeout = get_key_file_integer(p, "cache_timeout");
1423 cache_set_timeout(md5file, timeout);
1424 warnx(N_("%s: file added to the cache"), filename);
1425 gcry_free(key);
1426 gcry_free(md5file);
1427 g_free(fh);
1428 return TRUE;
1431 static gboolean check_host_limit(const gchar *addr)
1433 gint t, i;
1434 gint total = 1;
1435 gint limit = get_key_file_integer("global", "tcp_connection_limit");
1437 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1439 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1440 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1442 if (!cn->remote)
1443 continue;
1445 if (strcmp(addr, cn->addr) == 0)
1446 total++;
1449 if (limit > 0 && total > limit) {
1450 pth_mutex_release(&cn_mutex);
1451 return FALSE;
1454 pth_mutex_release(&cn_mutex);
1455 return TRUE;
1458 static void init_new_connection(gint fd, gchar *addr)
1460 pth_t tid;
1461 pth_attr_t attr;
1462 struct client_thread_s *new;
1463 gchar buf[41];
1465 if (addr && check_host_limit(addr) == FALSE) {
1466 log_write(N_("host %s exceeds host limit"), addr);
1467 close(fd);
1468 return;
1471 new = g_malloc0(sizeof(struct client_thread_s));
1473 if (!new) {
1474 log_write("%s", strerror(ENOMEM));
1475 return;
1479 * Thread priority is inherited from the calling thread. This
1480 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1481 * priority.
1483 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1484 new->fd = fd;
1486 if (addr) {
1487 new->remote = TRUE;
1488 new->addr = g_strdup(addr);
1489 gettimeofday(&new->init, NULL);
1492 attr = pth_attr_new();
1493 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1494 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1495 tid = pth_spawn(attr, client_thread, new);
1496 pth_attr_destroy(attr);
1498 if (!tid) {
1499 g_free(new);
1500 log_write(N_("pth_spawn() failed"));
1501 pth_mutex_release(&cn_mutex);
1502 return;
1505 g_snprintf(buf, sizeof(buf), "%p", tid);
1507 if (addr)
1508 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1509 else
1510 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1512 attr = pth_attr_of(tid);
1513 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1514 pth_attr_destroy(attr);
1515 new->tid = tid;
1516 cn_thread_list = g_slist_append(cn_thread_list, new);
1517 pth_mutex_release(&cn_mutex);
1520 #ifdef WITH_GNUTLS
1521 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1522 static void *get_in_addr(struct sockaddr *sa)
1524 if (sa->sa_family == AF_INET)
1525 return &(((struct sockaddr_in*)sa)->sin_addr);
1527 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1530 static void *tcp_accept_thread(void *arg)
1532 gint sockfd = (gint)arg;
1534 for (;;) {
1535 struct sockaddr_storage raddr;
1536 socklen_t slen = sizeof(raddr);
1537 gint fd = -1;
1539 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1540 if (errno != EAGAIN) {
1541 if (!quit) // probably EBADF
1542 log_write("accept(): %s", strerror(errno));
1544 break;
1548 if (quit)
1549 break;
1551 if (fd >= 0) {
1552 gchar s[INET6_ADDRSTRLEN];
1554 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1555 s, sizeof s);
1556 init_new_connection(fd, s);
1560 /* Just in case pth_accept() failed for some reason other than EBADF */
1561 quit = 1;
1562 pth_exit(PTH_CANCELED);
1563 return NULL;
1565 #endif
1567 static void *accept_thread(void *arg)
1569 gint sockfd = (gint)arg;
1571 for (;;) {
1572 socklen_t slen = sizeof(struct sockaddr_un);
1573 struct sockaddr_un raddr;
1574 gint fd = -1;
1576 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1577 if (errno != EAGAIN) {
1578 if (!quit) // probably EBADF
1579 log_write("accept(): %s", strerror(errno));
1581 break;
1585 if (fd >= 0)
1586 init_new_connection(fd, NULL);
1589 /* Just in case pth_accept() failed for some reason other than EBADF */
1590 quit = 1;
1591 pth_exit(PTH_CANCELED);
1592 return NULL;
1596 * This thread isn't joinable. For operations that block, these threads will
1597 * stack.
1599 static void *adjust_timer_thread(void *arg)
1601 CACHE_LOCK(NULL);
1602 cache_adjust_timer();
1603 CACHE_UNLOCK;
1604 return NULL;
1607 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1608 pth_attr_t attr)
1610 pth_status_t ev_status;
1612 if (timeout_ev) {
1613 pth_event_isolate(timeout_ev);
1614 ev_status = pth_event_status(timeout_ev);
1615 pth_event_free(timeout_ev, PTH_FREE_THIS);
1617 if (ev_status == PTH_STATUS_OCCURRED) {
1619 * The timer event has expired. Update the file cache. When the
1620 * cache mutex is locked and the timer expires again, the threads
1621 * will stack.
1623 pth_spawn(attr, adjust_timer_thread, NULL);
1627 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1630 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1631 gint keepalive)
1633 pth_event_t ev = NULL;
1634 pth_status_t ev_status;
1636 if (keepalive_ev) {
1637 pth_event_isolate(keepalive_ev);
1638 ev_status = pth_event_status(keepalive_ev);
1640 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1641 if (ev_status == PTH_STATUS_OCCURRED)
1642 send_status_all(STATUS_KEEPALIVE);
1644 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1646 else
1647 ev = keepalive_ev;
1650 if (keepalive > 0 && !ev)
1651 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1653 return ev;
1656 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1658 pth_t accept_tid;
1659 #ifdef WITH_GNUTLS
1660 pth_t tcp_accept_tid;
1661 #endif
1662 guint n;
1663 sigset_t set;
1664 gint n_clients = 0;
1665 pth_attr_t attr;
1666 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1667 gint keepalive = get_key_file_integer("global", "keepalive");
1668 gpointer value;
1670 pth_mutex_init(&cn_mutex);
1671 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1672 sigemptyset(&set);
1673 sigaddset(&set, SIGTERM);
1674 sigaddset(&set, SIGINT);
1675 sigaddset(&set, SIGUSR1);
1676 sigaddset(&set, SIGHUP);
1677 sigaddset(&set, SIGABRT);
1679 attr = pth_attr_new();
1680 pth_attr_init(attr);
1681 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1682 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1683 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1685 #ifdef WITH_GNUTLS
1686 if (sockfd_r != -1) {
1687 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1688 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1690 #endif
1692 pth_attr_init(attr);
1693 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1694 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1697 * For the cache_timeout configuration parameter.
1699 timeout_ev = timeout_event_iterate(NULL, attr);
1700 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1701 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1703 do {
1704 gint sig = 0;
1706 pth_sigwait_ev(&set, &sig, timeout_ev);
1707 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1708 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1709 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1711 if (sig > 0) {
1712 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1714 /* Caught a signal. */
1715 switch (sig) {
1716 case SIGHUP:
1717 reload_rcfile();
1718 keepalive = get_key_file_integer("global", "keepalive");
1719 break;
1720 case SIGABRT:
1721 CACHE_LOCK(NULL);
1722 cache_clear(NULL, 2);
1723 CACHE_UNLOCK;
1724 #ifndef MEM_DEBUG
1725 xpanic();
1726 #endif
1727 exit(EXIT_FAILURE);
1728 case SIGUSR1:
1729 CACHE_LOCK(NULL);
1730 log_write(N_("clearing file cache"));
1731 cache_clear(NULL, 2);
1732 CACHE_UNLOCK;
1733 break;
1734 default:
1735 quit = 1;
1736 shutdown(sockfd, SHUT_RDWR);
1737 close(sockfd);
1739 if (sockfd_r != -1) {
1740 shutdown(sockfd_r, SHUT_RDWR);
1741 close(sockfd_r);
1743 break;
1746 } while (!quit);
1749 * We're out of the main server loop. This happens when a signal was sent
1750 * to terminate the daemon. We'll wait for all clients to disconnect
1751 * before exiting and ignore any following signals.
1753 pth_join(accept_tid, &value);
1755 #ifdef WITH_GNUTLS
1756 if (sockfd_r != -1) {
1757 pth_cancel(tcp_accept_tid);
1758 pth_join(tcp_accept_tid, &value);
1760 #endif
1762 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1763 unlink(*socketpath);
1764 g_free(*socketpath);
1765 *socketpath = NULL;
1767 if (n > 1)
1768 log_write(N_("waiting for all threads to terminate"));
1770 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1772 while (n > 1) {
1773 if (n != n_clients) {
1774 log_write(N_("%i threads remain"), n-1);
1775 n_clients = n;
1778 pth_wait(ev_quit);
1779 pth_event_isolate(ev_quit);
1780 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1781 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1782 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1783 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1786 pth_event_free(timeout_ev, PTH_FREE_THIS);
1787 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1788 pth_event_free(ev_quit, PTH_FREE_THIS);
1789 pth_attr_destroy(attr);
1793 * Called from pinentry_fork() in the child process.
1795 void free_client_list()
1797 gint i, t = g_slist_length(cn_thread_list);
1799 for (i = 0; i < t; i++) {
1800 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1802 free_client(cn->cl);
1805 memset(key_cache, 0, cache_size);
1808 static gpg_error_t convert_file(const gchar *filename, const gchar *outfile)
1810 file_header_internal_t *fh;
1811 gpg_error_t rc;
1812 guchar *md5file;
1813 guchar *shakey;
1814 guint iter;
1816 md5file = gcry_malloc(16);
1817 if (!md5file)
1818 return GPG_ERR_ENOMEM;
1820 shakey = gcry_malloc(gcrykeysize);
1821 if (!shakey) {
1822 gcry_free(md5file);
1823 return GPG_ERR_ENOMEM;
1826 fh = read_file_header(filename, TRUE, &rc);
1828 if (!fh)
1829 goto done;
1831 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1833 /* The header in version 1 had a bug where the iterations were off-by-one.
1834 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1835 * header.
1837 if (fh->fh1.iter >= 0) {
1838 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1839 == FALSE) {
1840 rc = GPG_ERR_UNKNOWN_ERRNO;
1841 close(fh->fd);
1842 goto done;
1845 else
1846 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1848 close(fh->fd);
1850 if (rc)
1851 goto done;
1853 rc = convert_xml((gchar **)&fh->doc, &fh->len);
1855 if (rc) {
1856 gcry_free(fh->doc);
1857 warnx("%s: %s", filename, pwmd_strerror(rc));
1858 goto done;
1861 fh->v1 = FALSE;
1862 iter = fh->fh1.iter;
1863 memset(&fh->fh2, 0, sizeof(fh->fh2));
1864 /* Keep the iterations and key from the original file. */
1865 fh->fh2.iter = iter+1;
1866 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1868 if (rc)
1869 send_error(NULL, rc);
1871 done:
1872 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1873 gcry_free(shakey);
1874 gcry_free(md5file);
1875 g_free(fh);
1876 return rc;
1879 int main(int argc, char *argv[])
1881 gint opt;
1882 struct sockaddr_un addr;
1883 struct passwd *pw = getpwuid(getuid());
1884 gchar buf[PATH_MAX];
1885 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1886 gchar *socketarg = NULL;
1887 gchar *datadir = NULL;
1888 gboolean n;
1889 gchar *p;
1890 gchar **cache_push = NULL;
1891 gint iter = 0;
1892 gchar *import = NULL;
1893 gulong cmd_iterations = -1;
1894 gint default_timeout;
1895 gint rcfile_spec = 0;
1896 gint estatus = EXIT_FAILURE;
1897 gint sockfd, sockfd_r = -1;
1898 gchar *outfile = NULL;
1899 #ifndef MEM_DEBUG
1900 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1901 #endif
1902 gint do_unlink = 1;
1903 gboolean secure = FALSE;
1904 guint ptotal = 0;
1905 gint background = 1;
1906 sigset_t set;
1907 gchar *convert = NULL;
1908 #ifdef WITH_GNUTLS
1909 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1910 gint ret;
1911 #endif
1912 #if 0
1913 #ifndef DEBUG
1914 #ifdef HAVE_SETRLIMIT
1915 struct rlimit rl;
1917 rl.rlim_cur = rl.rlim_max = 0;
1919 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1920 err(EXIT_FAILURE, "setrlimit()");
1921 #endif
1922 #endif
1923 #endif
1925 #ifdef ENABLE_NLS
1926 setlocale(LC_ALL, "");
1927 bindtextdomain("pwmd", LOCALEDIR);
1928 textdomain("pwmd");
1929 #endif
1931 gpg_err_init();
1932 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1933 #ifndef MEM_DEBUG
1934 g_mem_set_vtable(&mtable);
1935 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1936 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1937 xmlInitMemory();
1938 #ifdef WITH_GNUTLS
1939 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1940 xrealloc, xfree);
1941 #endif
1942 #endif
1943 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1944 #ifdef WITH_GNUTLS
1945 gnutls_global_init();
1946 gnutls_global_set_log_function(tls_log);
1947 gnutls_global_set_log_level(1);
1948 assuan_set_io_hooks(&io_hooks);
1949 #endif
1950 pth_init();
1951 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1953 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1954 err(EXIT_FAILURE, "%s", buf);
1956 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1958 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1959 err(EXIT_FAILURE, "%s", buf);
1961 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1963 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1964 err(EXIT_FAILURE, "sysconf()");
1966 cache_size = page_size;
1968 while ((opt = getopt(argc, argv, "o:C:bnI:i:hvf:D")) != EOF) {
1969 switch (opt) {
1970 case 'o':
1971 outfile = optarg;
1972 break;
1973 case 'C':
1974 convert = optarg;
1975 break;
1976 case 'b':
1977 /* Compatibility for version < 1.11 */
1978 break;
1979 case 'n':
1980 background = 0;
1981 break;
1982 case 'D':
1983 secure = TRUE;
1984 break;
1985 case 'I':
1986 import = optarg;
1987 break;
1988 case 'i':
1989 cmd_iterations = strtol(optarg, NULL, 10);
1990 break;
1991 case 'f':
1992 g_free(rcfile);
1993 rcfile = g_strdup(optarg);
1994 rcfile_spec = 1;
1995 break;
1996 case 'v':
1997 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1998 exit(EXIT_SUCCESS);
1999 case 'h':
2000 default:
2001 usage(argv[0]);
2005 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2006 exit(EXIT_FAILURE);
2008 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2009 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2011 if (log_syslog == TRUE)
2012 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2014 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2015 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2016 errno = 0;
2018 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2019 warn("setpriority()");
2020 goto do_exit;
2024 #ifdef HAVE_MLOCKALL
2025 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2026 warn("mlockall()");
2027 goto do_exit;
2029 #endif
2031 setup_gcrypt();
2033 if (convert) {
2034 if (!outfile)
2035 usage(argv[0]);
2037 opt = convert_file(convert, outfile);
2038 g_key_file_free(keyfileh);
2039 g_free(rcfile);
2040 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2043 if (import) {
2044 if (!outfile)
2045 usage(argv[0]);
2047 if (cmd_iterations == -1)
2048 cmd_iterations = get_key_file_integer("global", "iterations");
2050 opt = xml_import(import, outfile, cmd_iterations);
2051 g_key_file_free(keyfileh);
2052 g_free(rcfile);
2053 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2056 g_key_file_set_list_separator(keyfileh, ',');
2058 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2059 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2061 if (*p == '~') {
2062 p++;
2063 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2064 g_free(p);
2065 socketarg = g_strdup(buf);
2067 else
2068 socketarg = p;
2070 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2071 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2073 datadir = expand_homedir(p);
2074 g_free(p);
2076 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2077 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2078 disable_list_and_dump = n;
2080 else
2081 disable_list_and_dump = secure;
2083 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2084 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2085 else
2086 default_timeout = -1;
2088 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
2089 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
2091 if (cache_size < page_size || cache_size % page_size)
2092 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
2095 setup_logging(keyfileh);
2097 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2098 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2100 if (argc != optind) {
2101 if (cache_push)
2102 ptotal = g_strv_length(cache_push);
2104 for (; optind < argc; optind++) {
2105 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2106 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2110 if (strchr(socketarg, '/') == NULL) {
2111 socketdir = g_get_current_dir();
2112 socketname = g_strdup(socketarg);
2113 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2115 else {
2116 socketname = g_strdup(strrchr(socketarg, '/'));
2117 socketname++;
2118 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2119 socketdir = g_strdup(socketarg);
2120 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2123 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
2124 #ifdef MMAP_ANONYMOUS
2125 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
2126 #else
2127 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
2128 #endif
2129 err(EXIT_FAILURE, "mmap()");
2132 if (mlock(key_cache, cache_size) == -1)
2133 log_write("mlock(): %s", strerror(errno));
2135 memset(key_cache, 0, cache_size);
2137 if (chdir(datadir)) {
2138 warn("%s", datadir);
2139 unlink(socketpath);
2140 goto do_exit;
2143 if (parse_keyfile_key() == FALSE)
2144 goto do_exit;
2146 clear_errorfile_key();
2149 * Set the cache entry for a file. Prompts for the password.
2151 if (cache_push) {
2152 for (opt = 0; cache_push[opt]; opt++)
2153 do_cache_push(cache_push[opt], NULL);
2155 g_strfreev(cache_push);
2156 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2160 * bind() doesn't like the full pathname of the socket or any non alphanum
2161 * characters so change to the directory where the socket is wanted then
2162 * create it then change to datadir.
2164 if (chdir(socketdir)) {
2165 warn("%s", socketdir);
2166 goto do_exit;
2169 g_free(socketdir);
2171 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2172 warn("socket()");
2173 goto do_exit;
2176 addr.sun_family = AF_UNIX;
2177 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2179 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2180 warn("bind()");
2182 if (errno == EADDRINUSE)
2183 warnx(N_("Either there is another pwmd running or '%s' is a \n"
2184 "stale socket. Please remove it manually."), socketpath);
2186 do_unlink = 0;
2187 goto do_exit;
2190 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2191 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2192 mode_t mode = strtol(t, NULL, 8);
2193 mode_t mask = umask(0);
2195 g_free(t);
2197 if (chmod(socketname, mode) == -1) {
2198 warn("%s", socketname);
2199 close(sockfd);
2200 unlink(socketpath);
2201 umask(mask);
2202 goto do_exit;
2205 umask(mask);
2208 g_free(--socketname);
2210 if (chdir(datadir)) {
2211 warn("%s", datadir);
2212 close(sockfd);
2213 unlink(socketpath);
2214 goto do_exit;
2217 g_free(datadir);
2218 pth_mutex_init(&cache_mutex);
2219 #ifdef WITH_PINENTRY
2220 pth_mutex_init(&pin_mutex);
2221 #endif
2223 if (listen(sockfd, 0) == -1) {
2224 warn("listen()");
2225 goto do_exit;
2228 #ifdef WITH_GNUTLS
2229 if (get_key_file_boolean("global", "enable_tcp")) {
2230 gchar *tmp, *tmp2;
2231 struct addrinfo hints, *servinfo, *p;
2232 gint port = get_key_file_integer("global", "tcp_port");
2233 char buf[7];
2235 memset(&hints, 0, sizeof(hints));
2236 hints.ai_family = AF_UNSPEC;
2237 hints.ai_socktype = SOCK_STREAM;
2238 hints.ai_flags = AI_PASSIVE;
2240 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2241 &hints, &servinfo)) == -1) {
2242 warnx("getaddrinfo(): %s", gai_strerror(opt));
2243 goto do_exit;
2246 for(p = servinfo; p != NULL; p = p->ai_next) {
2247 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2248 p->ai_protocol)) == -1) {
2249 warn("socket()");
2250 continue;
2253 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2254 sizeof(int)) == -1) {
2255 warn("setsockopt()");
2256 goto do_exit;
2259 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2260 close(sockfd_r);
2261 warn("bind()");
2262 continue;
2265 opt++;
2266 break;
2269 freeaddrinfo(servinfo);
2271 if (!p) {
2272 warnx("%s", N_("could not bind"));
2273 goto do_exit;
2276 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2277 gchar *tmp = get_key_file_string("global", "tcp_interface");
2279 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2280 == -1) {
2281 warn("setsockopt");
2282 g_free(tmp);
2283 goto do_exit;
2286 g_free(tmp);
2289 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2291 if (ret != GNUTLS_E_SUCCESS) {
2292 warnx("%s", gnutls_strerror(ret));
2293 goto do_exit;
2296 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2298 if (!tmp) {
2299 warnx("%s", strerror(ENOMEM));
2300 goto do_exit;
2303 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2304 GNUTLS_X509_FMT_PEM);
2305 g_free(tmp);
2307 if (ret < 0) {
2308 warnx("%s", gnutls_strerror(ret));
2309 goto do_exit;
2312 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2314 if (!tmp) {
2315 warnx("%s", strerror(ENOMEM));
2316 goto do_exit;
2319 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2321 if (!tmp2) {
2322 xfree(tmp);
2323 warnx("%s", strerror(ENOMEM));
2324 goto do_exit;
2327 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2328 GNUTLS_X509_FMT_PEM);
2329 g_free(tmp);
2330 g_free(tmp2);
2332 if (ret != GNUTLS_E_SUCCESS) {
2333 warnx("%s", gnutls_strerror(ret));
2334 goto do_exit;
2337 #endif
2339 if (background) {
2340 switch (fork()) {
2341 case -1:
2342 warn("fork()");
2343 goto do_exit;
2344 case 0:
2345 close(0);
2346 close(1);
2347 close(2);
2348 setsid();
2349 break;
2350 default:
2351 exit(EXIT_SUCCESS);
2355 #ifdef WITH_GNUTLS
2356 if (get_key_file_boolean("global", "enable_tcp")) {
2357 log_write("%s", N_("Generating key exchange parameters..."));
2358 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2360 if (ret) {
2361 warnx("%s", gpg_strerror(ret));
2362 goto do_exit;
2365 ret = gnutls_dh_params_init(&dh_params);
2367 if (ret != GNUTLS_E_SUCCESS) {
2368 warnx("%s", gnutls_strerror(ret));
2369 goto do_exit;
2372 ret = gnutls_dh_params_generate2(dh_params, 1024);
2374 if (ret != GNUTLS_E_SUCCESS) {
2375 warnx("%s", gnutls_strerror(ret));
2376 goto do_exit;
2379 gnutls_certificate_set_dh_params (x509_cred, dh_params);
2380 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2382 if (listen(sockfd_r, 0) == -1) {
2383 warn("listen()");
2384 goto do_exit;
2387 #endif
2390 * These are the signals that we use in threads. libpth can catch signals
2391 * itself so ignore them everywhere else. Note that using
2392 * signal(N, SIG_IGN) doesn't work like you might think.
2394 sigemptyset(&set);
2396 /* Termination */
2397 sigaddset(&set, SIGTERM);
2398 sigaddset(&set, SIGINT);
2400 /* Configuration file reloading. */
2401 sigaddset(&set, SIGUSR1);
2403 /* Clears the file cache. */
2404 sigaddset(&set, SIGHUP);
2406 /* Caught in client_thread(). Sends a cache status message. */
2407 sigaddset(&set, SIGUSR2);
2409 /* Ignored everywhere. When a client disconnects abnormally this signal
2410 * gets raised. It isn't needed though because client_thread() will check
2411 * for rcs even after the client disconnects. */
2412 signal(SIGPIPE, SIG_IGN);
2413 pth_sigmask(SIG_BLOCK, &set, NULL);
2414 server_loop(sockfd, sockfd_r, &socketpath);
2415 estatus = EXIT_SUCCESS;
2417 do_exit:
2418 if (socketpath && do_unlink) {
2419 unlink(socketpath);
2420 g_free(socketpath);
2423 #ifdef WITH_GNUTLS
2424 if (sockfd_r != -1) {
2425 gnutls_dh_params_deinit(dh_params);
2427 if (x509_cred)
2428 gnutls_certificate_free_credentials(x509_cred);
2430 gnutls_global_deinit();
2432 #endif
2434 g_key_file_free(keyfileh);
2435 g_free(rcfile);
2436 xmlCleanupParser();
2438 if (key_cache) {
2439 cache_clear(NULL, 2);
2440 memset(key_cache, 0, cache_size);
2443 if (key_cache && munmap(key_cache, cache_size) == -1)
2444 log_write("munmap(): %s", strerror(errno));
2446 if (estatus == EXIT_SUCCESS)
2447 log_write(N_("pwmd exiting normally"));
2449 pth_kill();
2450 #if defined(DEBUG) && !defined(MEM_DEBUG)
2451 xdump();
2452 #endif
2453 exit(estatus);