Added configuration parameter "access". This controls which client
[pwmd.git] / src / pwmd.c
blob1bc0a0abdc64fea85ebbe243a97aa877dec155b7
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("%s", 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 " -o output file for use with the -C and -I options\n"
246 " -v version\n"
247 " -h this help text\n"
248 ), pn);
249 exit(EXIT_FAILURE);
252 #ifndef MEM_DEBUG
253 static int gcry_SecureCheck(const void *ptr)
255 return 1;
257 #endif
259 static void setup_gcrypt()
261 gcry_check_version(NULL);
263 #ifndef MEM_DEBUG
264 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
265 xfree);
266 #endif
268 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
269 NULL) != 0)
270 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
272 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
273 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
276 static gint new_connection(struct client_s *cl)
278 gpg_error_t rc;
279 gchar ver[ASSUAN_LINELENGTH];
281 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
283 if (rc)
284 goto fail;
286 assuan_set_pointer(cl->ctx, cl);
287 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
288 assuan_set_hello_line(cl->ctx, ver);
289 rc = register_commands(cl->ctx);
291 if (rc)
292 goto fail;
294 rc = assuan_accept(cl->ctx);
296 if (rc)
297 goto fail;
299 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
300 return 0;
302 fail:
303 log_write("%s", gpg_strerror(rc));
304 return 1;
307 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
309 gchar *line = NULL;
310 struct client_s *client = assuan_get_pointer(ctx);
311 gchar buf[ASSUAN_LINELENGTH];
312 gchar *status = NULL;
314 switch (which) {
315 case STATUS_CACHE:
316 CACHE_LOCK(client->ctx);
317 line = print_fmt(buf, sizeof(buf), "%i %i",
318 cache_file_count(),
319 (cache_size % sizeof(file_cache_t)) ?
320 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
321 (cache_size / sizeof(file_cache_t)) - cache_file_count());
322 CACHE_UNLOCK;
323 status = "CACHE";
324 break;
325 case STATUS_CLIENTS:
326 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
327 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
328 pth_mutex_release(&cn_mutex);
329 status = "CLIENTS";
330 break;
331 case STATUS_CONFIG:
332 status = "CONFIG";
333 break;
334 case STATUS_KEEPALIVE:
335 status = "KEEPALIVE";
336 break;
337 case STATUS_LOCKED:
338 status = "LOCKED";
339 line = N_("Waiting for lock");
340 break;
343 return assuan_write_status(ctx, status, line);
346 void send_status_all(status_msg_t which)
348 guint i, t;
350 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
352 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
353 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
354 pth_msgport_t m = pth_msgport_find(cn->msg_name);
356 if (m) {
357 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
359 msg->m_data = (status_msg_t *)which;
360 pth_msgport_put(m, msg);
364 pth_mutex_release(&cn_mutex);
367 static void xml_error_cb(void *data, xmlErrorPtr e)
369 struct client_s *client = data;
372 * Keep the first reported error as the one to show in the error
373 * description. Reset in send_error().
375 if (client->xml_error)
376 return;
378 xmlCopyError(e, client->xml_error);
382 * This is called after a child_thread terminates. Set with
383 * pth_cleanup_push().
385 static void cleanup_cb(void *arg)
387 struct client_thread_s *cn = arg;
388 gpointer value;
389 struct client_s *cl = cn->cl;
391 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
392 log_write(N_("exiting, fd=%i"), cn->fd);
394 if (cn->msg_tid) {
395 pth_cancel(cn->msg_tid);
396 pth_join(cn->msg_tid, &value);
397 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
400 if (cn->msg_name)
401 g_free(cn->msg_name);
403 if (cn->msg) {
404 while (pth_msgport_pending(cn->msg) > 0) {
405 pth_message_t *m = pth_msgport_get(cn->msg);
407 g_free(m);
410 pth_msgport_destroy(cn->msg);
413 pth_join(cn->tid, &value);
415 if (cl && cl->freed == FALSE)
416 cleanup_client(cl);
418 #ifdef WITH_GNUTLS
419 if (cn->tls) {
420 gnutls_deinit(cn->tls->ses);
422 if (cn->tls->fp)
423 g_free(cn->tls->fp);
425 g_free(cn->tls);
427 #endif
429 if (cl && cl->ctx)
430 assuan_deinit_server(cl->ctx);
432 #ifdef WITH_PINENTRY
433 if (cl && cl->pinentry)
434 cleanup_pinentry(cl->pinentry);
435 #endif
437 g_free(cl);
438 cn_thread_list = g_slist_remove(cn_thread_list, cn);
439 g_free(cn);
440 pth_mutex_release(&cn_mutex);
441 send_status_all(STATUS_CLIENTS);
444 #ifdef WITH_GNUTLS
445 static int read_hook(assuan_context_t ctx, assuan_fd_t fd, void *data,
446 size_t len, ssize_t *ret)
448 struct client_s *cl = assuan_get_pointer(ctx);
450 if (!cl || !cl->thd->remote)
451 *ret = pth_read((int)fd, data, len);
452 else {
453 do {
454 *ret = gnutls_record_recv(cl->thd->tls->ses, data, len);
456 if (*ret == GNUTLS_E_REHANDSHAKE) {
457 *ret = gnutls_rehandshake(cl->thd->tls->ses);
459 if (*ret == GNUTLS_E_WARNING_ALERT_RECEIVED ||
460 *ret == GNUTLS_A_NO_RENEGOTIATION) {
461 log_write("%s", gnutls_strerror(*ret));
462 continue;
465 if (*ret != GNUTLS_E_SUCCESS) {
466 log_write("%s", gnutls_strerror(*ret));
467 *ret = 0;
468 break;
471 *ret = gnutls_handshake(cl->thd->tls->ses);
473 if (*ret != GNUTLS_E_SUCCESS) {
474 log_write("%s", gnutls_strerror(*ret));
475 *ret = 0;
476 break;
479 continue;
481 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
484 return *ret <= 0 ? 0 : 1;
487 static int write_hook(assuan_context_t ctx, assuan_fd_t fd, const void *data,
488 size_t len, ssize_t *ret)
490 struct client_s *cl = assuan_get_pointer(ctx);
492 if (!cl || !cl->thd->remote)
493 *ret = pth_write((int)fd, data, len);
494 else {
495 do {
496 *ret = gnutls_record_send(cl->thd->tls->ses, data, len);
497 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
500 return *ret <= 0 ? 0 : 1;
502 #endif
504 static void *client_msg_thread(void *data)
506 struct client_s *cl = data;
507 pth_status_t ev_status;
509 for (;;) {
510 pth_wait(cl->thd->msg_ev);
511 ev_status = pth_event_status(cl->thd->msg_ev);
513 if (ev_status == PTH_STATUS_FAILED) {
514 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
515 __FUNCTION__);
516 continue;
519 if (ev_status == PTH_STATUS_OCCURRED) {
520 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
522 while (pth_msgport_pending(cl->thd->msg) > 0) {
523 pth_message_t *m = pth_msgport_get(cl->thd->msg);
524 status_msg_t n = (status_msg_t)m->m_data;
525 gpg_error_t rc = send_status(cl->ctx, n);
527 g_free(m);
529 if (rc) {
530 pth_mutex_release(&cn_mutex);
531 log_write("%s", gpg_strerror(rc));
532 break;
536 pth_mutex_release(&cn_mutex);
542 * Called every time a connection is made via pth_spawn(). This is the thread
543 * entry point.
545 static void *client_thread(void *data)
547 struct client_thread_s *thd = data;
548 pth_event_t ev;
549 struct client_s *cl = g_malloc0(sizeof(struct client_s));
550 gpg_error_t rc;
551 pth_attr_t attr;
554 * Prevent a race condition with init_new_connection() if this thread
555 * fails (returns) for some reason before init_new_connection() releases
556 * the cn_mutex.
558 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
559 pth_mutex_release(&cn_mutex);
561 if (!cl) {
562 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
563 goto fail;
566 thd->cl = cl;
567 cl->thd = thd;
568 pth_cleanup_push(cleanup_cb, thd);
570 #ifdef WITH_GNUTLS
572 * Do the TLS handshake before anything else.
574 if (thd->remote) {
575 thd->tls = tls_init(thd->fd);
577 if (!thd->tls) {
578 close(thd->fd);
579 goto fail;
582 #endif
585 * This is a "child" thread. Don't catch any signals. Let the master
586 * thread take care of signals in server_loop().
588 if (new_connection(cl))
589 goto fail;
591 #ifdef WITH_PINENTRY
592 cl->pinentry = pinentry_init();
594 if (!cl->pinentry) {
595 g_free(cl);
596 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
597 goto fail;
599 #endif
601 thd->msg_name = g_strdup_printf("%p", thd->tid);
603 if (!thd->msg_name) {
604 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
605 goto fail;
608 thd->msg = pth_msgport_create(thd->msg_name);
610 if (!thd->msg) {
611 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
612 goto fail;
615 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
616 attr = pth_attr_new();
617 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
618 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
619 pth_attr_destroy(attr);
621 if (!thd->msg_tid) {
622 log_write(N_("pth_spawn() failed"));
623 goto fail;
626 #ifdef HAVE_MLOCKALL
627 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
628 log_write("mlockall(): %s", strerror(errno));
629 goto fail;
631 #endif
633 rc = send_status(cl->ctx, STATUS_CACHE);
635 if (rc) {
636 log_write("%s", gpg_strerror(rc));
637 goto fail;
640 send_status_all(STATUS_CLIENTS);
641 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
642 xmlInitParser();
643 xmlXPathInit();
644 xmlSetStructuredErrorFunc(cl, xml_error_cb);
646 for (;;) {
647 pth_status_t ev_status;
649 pth_wait(ev);
650 ev_status = pth_event_status(ev);
652 if (ev_status == PTH_STATUS_FAILED) {
653 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
654 __FUNCTION__);
655 goto done;
657 else if (ev_status == PTH_STATUS_OCCURRED) {
658 rc = assuan_process_next(cl->ctx);
660 if (rc) {
661 cl->inquire_status = INQUIRE_INIT;
663 if (gpg_err_code(rc) == GPG_ERR_EOF)
664 goto done;
666 log_write("assuan_process_next(): %s", gpg_strerror(rc));
667 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
669 if (rc) {
670 log_write("assuan_process_done(): %s", gpg_strerror(rc));
671 goto done;
674 else {
675 #ifdef WITH_PINENTRY
676 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
677 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
678 pth_event_concat(ev, cl->pinentry->ev, NULL);
679 cl->pinentry->status = PINENTRY_RUNNING;
681 #endif
683 switch (cl->inquire_status) {
684 case INQUIRE_BUSY:
685 case INQUIRE_INIT:
686 break;
687 case INQUIRE_DONE:
688 cl->inquire_status = INQUIRE_INIT;
689 rc = assuan_process_done(cl->ctx, 0);
690 break;
695 #ifdef WITH_PINENTRY
696 ev = pinentry_iterate(cl, ev);
697 #endif
701 * Client cleanup (including XML data) is done in cleanup_cb() from
702 * the cleanup thread.
704 done:
705 pth_event_free(ev, PTH_FREE_ALL);
707 fail:
708 pth_exit(NULL);
709 return NULL;
712 static void setup_logging(GKeyFile *kf)
714 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
716 if (n == TRUE) {
717 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
719 if (*p == '~') {
720 gchar buf[PATH_MAX];
722 p++;
723 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
724 g_free(p);
726 if (logfile)
727 g_free(logfile);
729 logfile = g_strdup(buf);
731 else {
732 if (logfile)
733 g_free(logfile);
735 logfile = p;
739 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
743 * Make sure all settings are set to either the specified setting or a
744 * default.
746 static void set_rcfile_defaults(GKeyFile *kf)
748 gchar buf[PATH_MAX];
750 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
751 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
752 g_key_file_set_string(kf, "global", "socket_path", buf);
755 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
756 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
757 g_key_file_set_string(kf, "global", "data_directory", buf);
760 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
761 g_key_file_set_boolean(kf, "global", "backup", TRUE);
763 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
764 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
765 g_key_file_set_string(kf, "global", "log_path", buf);
768 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
769 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
771 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
772 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
774 #ifdef HAVE_MLOCKALL
775 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
776 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
777 #endif
779 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
780 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
782 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
783 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
784 g_key_file_set_integer(kf, "global", "iterations", 1);
786 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
787 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
789 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
790 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
792 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
793 g_key_file_set_integer(kf, "global", "compression_level", 6);
795 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
796 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
798 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
799 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
801 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
803 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
804 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
806 #ifdef HAVE_MLOCKALL
807 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
808 #endif
810 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
811 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
813 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
814 g_key_file_set_integer(kf, "global", "keepalive", 30);
816 #ifdef WITH_PINENTRY
817 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
818 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
820 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
821 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
822 #endif
824 #ifdef WITH_GNUTLS
825 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
826 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
828 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
829 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
830 #endif
832 setup_logging(kf);
835 static GKeyFile *parse_rcfile(int cmdline)
837 GKeyFile *kf = g_key_file_new();
838 GError *rc = NULL;
840 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
841 log_write("%s: %s", rcfile, rc->message);
843 if (cmdline)
844 exit(EXIT_FAILURE);
846 if (rc->code == G_FILE_ERROR_NOENT) {
847 g_clear_error(&rc);
848 set_rcfile_defaults(kf);
849 return kf;
852 g_clear_error(&rc);
853 return NULL;
855 else
856 set_rcfile_defaults(kf);
858 return kf;
861 static gchar *do_get_password(const gchar *prompt)
863 gchar buf[LINE_MAX] = {0}, *p;
864 struct termios told, tnew;
865 gchar *key;
867 if (tcgetattr(STDIN_FILENO, &told) == -1) {
868 warn("tcgetattr()");
869 return NULL;
872 memcpy(&tnew, &told, sizeof(struct termios));
873 tnew.c_lflag &= ~(ECHO);
874 tnew.c_lflag |= ICANON|ECHONL;
876 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
877 warn("tcsetattr()");
878 tcsetattr(STDIN_FILENO, TCSANOW, &told);
879 return NULL;
882 fprintf(stderr, "%s", prompt);
884 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
885 tcsetattr(STDIN_FILENO, TCSANOW, &told);
886 return NULL;
889 tcsetattr(STDIN_FILENO, TCSANOW, &told);
890 p[strlen(p) - 1] = 0;
892 if (!buf[0]) {
893 key = gcry_malloc(1);
894 key[0] = 0;
896 else {
897 key = gcry_malloc(strlen(p) + 1);
898 sprintf(key, "%s", p);
901 memset(&buf, 0, sizeof(buf));
902 return key;
905 /* Only used when "enable_pinentry" is "false". */
906 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
907 guchar *key, pinentry_cmd_t which)
909 gint try = 0;
910 gchar *password;
911 gchar *prompt;
913 if (which == PINENTRY_SAVE) {
914 gchar *key1, *key2;
916 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
917 key1 = do_get_password(prompt);
918 g_free(prompt);
920 if (!key1) {
921 warnx(N_("%s: Skipping file"), filename);
922 return FALSE;
925 prompt = g_strdup_printf(N_("Repeat passphrase: "));
926 key2 = do_get_password(prompt);
927 g_free(prompt);
929 if (!key2) {
930 gcry_free(key1);
931 warnx(N_("%s: Skipping file"), filename);
932 return FALSE;
935 if (strcmp(key1, key2)) {
936 gcry_free(key1);
937 gcry_free(key2);
938 warnx(N_("%s: Passphrase mismatch"), filename);
939 return FALSE;
942 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
943 strlen(key1) ? strlen(key1) : 1);
944 gcry_free(key1);
945 gcry_free(key2);
946 return TRUE;
949 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
951 do {
952 gpg_error_t rc;
954 if ((password = do_get_password(prompt)) == NULL) {
955 warnx(N_("%s: Skipping file"), filename);
956 g_free(prompt);
957 return FALSE;
960 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
961 gcry_free(password);
963 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
965 if (!rc)
966 break;
968 fprintf(stderr, N_("%s: Invalid passphrase"), filename);
969 } while (try++ < 2);
971 g_free(prompt);
973 if (try == 3) {
974 fprintf(stderr, N_("%s: Invalid passphrase, skipping"), filename);
975 return FALSE;
978 return TRUE;
982 * inbuf must have been allocated with gcry_malloc().
984 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
985 guchar *shakey, gpointer inbuf, gulong insize)
987 gcry_cipher_hd_t gh;
988 gpg_error_t rc;
989 gint level, zrc;
990 glong outsize;
991 gpointer outbuf;
993 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
995 if (rc)
996 return rc;
998 level = get_key_file_integer(filename, "compression_level");
1000 if (level < 0)
1001 level = 0;
1003 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
1004 == FALSE) {
1005 gcry_cipher_close(gh);
1006 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
1008 else {
1009 gcry_free(inbuf);
1010 inbuf = outbuf;
1011 insize = outsize;
1014 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
1015 gcry_cipher_close(gh);
1016 return rc;
1019 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
1020 guchar *md5file, guchar *key, pinentry_cmd_t which)
1022 #ifdef WITH_PINENTRY
1023 gpg_error_t rc = 0;
1025 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
1026 == FALSE) {
1027 #endif
1028 return get_input(filename, fh, key, which);
1029 #ifdef WITH_PINENTRY
1031 else {
1032 gchar *result = NULL;
1033 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1034 gint try = 0;
1036 set_pinentry_defaults(pin);
1037 pin->which = which;
1038 pin->filename = g_strdup(filename);
1039 again:
1040 rc = pinentry_getpin(pin, &result);
1042 if (rc) {
1043 warnx("%s", gpg_strerror(rc));
1044 xfree(result);
1045 goto done;
1048 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1049 xfree(result);
1051 if (which == PINENTRY_SAVE) {
1052 cleanup_pinentry(pin);
1053 goto done;
1056 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1058 if (rc == EPWMD_BADKEY) {
1059 if (try++ == 2)
1060 warnx("%s: %s", filename, pwmd_strerror(rc));
1061 else {
1062 g_free(pin->title);
1063 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1064 goto again;
1067 else if (rc)
1068 warnx("%s", pwmd_strerror(rc));
1070 cleanup_pinentry(pin);
1073 done:
1074 return rc ? FALSE : TRUE;
1075 #endif
1078 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1079 gulong iter)
1081 xmlDocPtr doc;
1082 gint fd;
1083 struct stat st;
1084 gint len;
1085 xmlChar *xmlbuf;
1086 xmlChar *xml;
1087 guchar shakey[gcrykeysize];
1088 gpg_error_t rc;
1089 file_header_internal_t fh;
1091 if (stat(filename, &st) == -1) {
1092 warn("%s", filename);
1093 return FALSE;
1096 if (iter && get_password(filename, NULL, NULL, shakey, PINENTRY_SAVE)
1097 == FALSE)
1098 return FALSE;
1100 if ((fd = open(filename, O_RDONLY)) == -1) {
1101 memset(shakey, 0, sizeof(shakey));
1102 warn("%s", filename);
1103 return FALSE;
1106 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1107 close(fd);
1108 memset(shakey, 0, sizeof(shakey));
1109 log_write("%s", strerror(ENOMEM));
1110 return FALSE;
1113 if (read(fd, xmlbuf, st.st_size) == -1) {
1114 memset(shakey, 0, sizeof(shakey));
1115 rc = errno;
1116 close(fd);
1117 errno = rc;
1118 err(EXIT_FAILURE, "read()");
1121 close(fd);
1122 xmlbuf[st.st_size] = 0;
1125 * Make sure the document validates.
1127 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1128 log_write("xmlReadDoc()");
1129 close(fd);
1130 gcry_free(xmlbuf);
1131 memset(shakey, 0, sizeof(shakey));
1132 return FALSE;
1135 gcry_free(xmlbuf);
1136 xmlDocDumpMemory(doc, &xml, &len);
1137 xmlFreeDoc(doc);
1139 if (!iter)
1140 memset(shakey, '!', sizeof(shakey));
1142 memset(&fh, 0, sizeof(fh));
1143 fh.fh2.iter = iter;
1144 rc = export_common(outfile, &fh, shakey, xml, len);
1145 memset(shakey, 0, sizeof(shakey));
1147 if (rc)
1148 send_error(NULL, rc);
1150 return rc ? FALSE : TRUE;
1153 gchar *get_key_file_string(const gchar *section, const gchar *what)
1155 gchar *val = NULL;
1156 GError *grc = NULL;
1158 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1159 val = g_key_file_get_string(keyfileh, section, what, &grc);
1161 if (grc) {
1162 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1163 g_clear_error(&grc);
1166 else {
1167 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1168 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1170 if (grc) {
1171 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1172 g_clear_error(&grc);
1177 return val;
1180 gint get_key_file_integer(const gchar *section, const gchar *what)
1182 gint val = -1;
1183 GError *grc = NULL;
1185 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1186 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1188 if (grc) {
1189 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1190 g_clear_error(&grc);
1193 else {
1194 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1195 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1197 if (grc) {
1198 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1199 g_clear_error(&grc);
1204 return val;
1207 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1209 gboolean val = FALSE;
1210 GError *grc = NULL;
1212 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1213 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1215 if (grc) {
1216 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1217 g_clear_error(&grc);
1220 else {
1221 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1222 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1224 if (grc) {
1225 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1226 g_clear_error(&grc);
1231 return val;
1234 static gboolean _getline(const gchar *file, gchar **result)
1236 FILE *fp;
1237 gchar buf[LINE_MAX] = {0}, *p;
1238 gchar *str = NULL;
1239 gint len;
1241 if ((fp = fopen(file, "r")) == NULL) {
1242 warn("%s", file);
1243 return FALSE;
1246 p = fgets(buf, sizeof(buf), fp);
1247 fclose(fp);
1248 len = strlen(buf);
1250 if (len && buf[len - 1] == '\n')
1251 buf[--len] = 0;
1253 str = gcry_malloc(len + 1);
1254 memcpy(str, buf, len ? len : 1);
1255 str[len] = 0;
1256 memset(&buf, 0, sizeof(buf));
1257 *result = str;
1258 return TRUE;
1261 static gboolean parse_keyfile_key()
1263 gsize n;
1264 gchar **groups;
1265 gchar **p;
1266 gchar *str;
1268 groups = g_key_file_get_groups(keyfileh, &n);
1270 for (p = groups; *p; p++) {
1271 GError *rc = NULL;
1273 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1274 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1276 if (!str) {
1277 if (rc) {
1278 warnx("%s", rc->message);
1279 g_clear_error(&rc);
1282 continue;
1285 do_cache_push(*p, str);
1286 g_free(str);
1287 continue;
1290 if (rc) {
1291 warnx("%s", rc->message);
1292 g_clear_error(&rc);
1293 continue;
1296 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1297 gchar *t;
1298 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1300 if (!file) {
1301 if (rc) {
1302 warnx("%s", rc->message);
1303 g_clear_error(&rc);
1306 continue;
1309 t = expand_homedir(file);
1310 g_free(file);
1311 file = t;
1313 if (_getline(file, &str) == FALSE) {
1314 g_free(file);
1315 continue;
1318 g_free(file);
1319 do_cache_push(*p, str);
1320 gcry_free(str);
1321 continue;
1324 if (rc) {
1325 warnx("%s", rc->message);
1326 g_clear_error(&rc);
1330 g_strfreev(groups);
1331 return TRUE;
1334 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1336 guchar *md5file;
1337 guchar *key;
1338 gint timeout;
1339 const gchar *p = filename;
1340 file_header_internal_t *fh;
1341 gpg_error_t rc;
1343 while (isspace(*p))
1344 p++;
1346 if (!*p)
1347 return FALSE;
1349 if (valid_filename(p) == FALSE) {
1350 warnx(N_("%s: Invalid characters in filename"), p);
1351 return FALSE;
1354 md5file = gcry_malloc(16);
1355 key = gcry_malloc(gcrykeysize);
1356 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1358 if (cache_iscached(md5file) == TRUE) {
1359 warnx(N_("%s: File already cached, skipping"), p);
1360 gcry_free(md5file);
1361 gcry_free(key);
1362 return FALSE;
1365 if (access(p, R_OK|W_OK) != 0) {
1366 gcry_free(md5file);
1367 gcry_free(key);
1369 if (errno != ENOENT) {
1370 warn("%s", p);
1371 return FALSE;
1374 warn("%s", p);
1375 return TRUE;
1378 fh = read_file_header(filename, FALSE, &rc);
1380 if (!fh) {
1381 gcry_free(md5file);
1382 gcry_free(key);
1383 warnx("%s", pwmd_strerror(rc));
1384 return FALSE;
1387 if (fh->fh2.iter <= 0) {
1388 memset(key, '!', gcrykeysize);
1389 goto try_decrypt;
1392 if (!password) {
1393 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1394 g_free(fh);
1395 return FALSE;
1398 else
1399 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1400 strlen(password) ? strlen(password) : 1);
1402 try_decrypt:
1403 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1405 if (rc) {
1406 warnx("%s: %s", filename, pwmd_strerror(rc));
1407 gcry_free(key);
1408 gcry_free(md5file);
1409 g_free(fh);
1410 return FALSE;
1413 if (cache_add_file(md5file, key) == FALSE) {
1414 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1415 gcry_free(key);
1416 gcry_free(md5file);
1417 g_free(fh);
1418 return FALSE;
1421 timeout = get_key_file_integer(p, "cache_timeout");
1422 cache_set_timeout(md5file, timeout);
1423 warnx(N_("%s: File added to the cache"), filename);
1424 gcry_free(key);
1425 gcry_free(md5file);
1426 g_free(fh);
1427 return TRUE;
1430 static void init_new_connection(gint fd, gchar *addr)
1432 pth_t tid;
1433 pth_attr_t attr;
1434 struct client_thread_s *new;
1435 gchar buf[41];
1437 new = g_malloc0(sizeof(struct client_thread_s));
1439 if (!new) {
1440 log_write("%s", strerror(ENOMEM));
1441 return;
1445 * Thread priority is inherited from the calling thread. This
1446 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1447 * priority.
1449 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1450 new->fd = fd;
1452 if (addr)
1453 new->remote = TRUE;
1455 attr = pth_attr_new();
1456 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1457 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1458 tid = pth_spawn(attr, client_thread, new);
1459 pth_attr_destroy(attr);
1461 if (!tid) {
1462 g_free(new);
1463 log_write(N_("pth_spawn() failed"));
1464 pth_mutex_release(&cn_mutex);
1465 return;
1468 g_snprintf(buf, sizeof(buf), "%p", tid);
1470 if (addr)
1471 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1472 else
1473 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1475 attr = pth_attr_of(tid);
1476 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1477 pth_attr_destroy(attr);
1478 new->tid = tid;
1479 cn_thread_list = g_slist_append(cn_thread_list, new);
1480 pth_mutex_release(&cn_mutex);
1483 #ifdef WITH_GNUTLS
1484 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1485 static void *get_in_addr(struct sockaddr *sa)
1487 if (sa->sa_family == AF_INET)
1488 return &(((struct sockaddr_in*)sa)->sin_addr);
1490 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1493 static void *tcp_accept_thread(void *arg)
1495 gint sockfd = (gint)arg;
1497 for (;;) {
1498 struct sockaddr_storage raddr;
1499 socklen_t slen = sizeof(raddr);
1500 gint fd = -1;
1502 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1503 if (errno != EAGAIN) {
1504 if (!quit) // probably EBADF
1505 log_write("accept(): %s", strerror(errno));
1507 break;
1511 if (quit)
1512 break;
1514 if (fd >= 0) {
1515 gchar s[INET6_ADDRSTRLEN];
1517 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1518 s, sizeof s);
1519 init_new_connection(fd, s);
1523 /* Just in case pth_accept() failed for some reason other than EBADF */
1524 quit = 1;
1525 pth_exit(PTH_CANCELED);
1526 return NULL;
1528 #endif
1530 static void *accept_thread(void *arg)
1532 gint sockfd = (gint)arg;
1534 for (;;) {
1535 socklen_t slen = sizeof(struct sockaddr_un);
1536 struct sockaddr_un 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 (fd >= 0)
1549 init_new_connection(fd, NULL);
1552 /* Just in case pth_accept() failed for some reason other than EBADF */
1553 quit = 1;
1554 pth_exit(PTH_CANCELED);
1555 return NULL;
1559 * This thread isn't joinable. For operations that block, these threads will
1560 * stack.
1562 static void *adjust_timer_thread(void *arg)
1564 CACHE_LOCK(NULL);
1565 cache_adjust_timer();
1566 CACHE_UNLOCK;
1567 return NULL;
1570 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1571 pth_attr_t attr)
1573 pth_status_t ev_status;
1575 if (timeout_ev) {
1576 pth_event_isolate(timeout_ev);
1577 ev_status = pth_event_status(timeout_ev);
1578 pth_event_free(timeout_ev, PTH_FREE_THIS);
1580 if (ev_status == PTH_STATUS_OCCURRED) {
1582 * The timer event has expired. Update the file cache. When the
1583 * cache mutex is locked and the timer expires again, the threads
1584 * will stack.
1586 pth_spawn(attr, adjust_timer_thread, NULL);
1590 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1593 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1594 gint keepalive)
1596 pth_event_t ev = NULL;
1597 pth_status_t ev_status;
1599 if (keepalive_ev) {
1600 pth_event_isolate(keepalive_ev);
1601 ev_status = pth_event_status(keepalive_ev);
1603 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1604 if (ev_status == PTH_STATUS_OCCURRED)
1605 send_status_all(STATUS_KEEPALIVE);
1607 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1609 else
1610 ev = keepalive_ev;
1613 if (keepalive > 0 && !ev)
1614 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1616 return ev;
1619 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1621 pth_t accept_tid;
1622 #ifdef WITH_GNUTLS
1623 pth_t tcp_accept_tid;
1624 #endif
1625 guint n;
1626 sigset_t set;
1627 gint n_clients = 0;
1628 pth_attr_t attr;
1629 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1630 gint keepalive = get_key_file_integer("global", "keepalive");
1631 gpointer value;
1633 pth_mutex_init(&cn_mutex);
1634 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1635 sigemptyset(&set);
1636 sigaddset(&set, SIGTERM);
1637 sigaddset(&set, SIGINT);
1638 sigaddset(&set, SIGUSR1);
1639 sigaddset(&set, SIGHUP);
1640 sigaddset(&set, SIGABRT);
1642 attr = pth_attr_new();
1643 pth_attr_init(attr);
1644 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1645 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1646 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1648 #ifdef WITH_GNUTLS
1649 if (sockfd_r != -1) {
1650 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1651 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1653 #endif
1655 pth_attr_init(attr);
1656 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1657 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1660 * For the cache_timeout configuration parameter.
1662 timeout_ev = timeout_event_iterate(NULL, attr);
1663 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1664 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1666 do {
1667 gint sig = 0;
1669 pth_sigwait_ev(&set, &sig, timeout_ev);
1670 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1671 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1672 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1674 if (sig > 0) {
1675 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1677 /* Caught a signal. */
1678 switch (sig) {
1679 case SIGHUP:
1680 reload_rcfile();
1681 keepalive = get_key_file_integer("global", "keepalive");
1682 break;
1683 case SIGABRT:
1684 CACHE_LOCK(NULL);
1685 cache_clear(NULL, 2);
1686 CACHE_UNLOCK;
1687 #ifndef MEM_DEBUG
1688 xpanic();
1689 #endif
1690 exit(EXIT_FAILURE);
1691 case SIGUSR1:
1692 CACHE_LOCK(NULL);
1693 log_write(N_("clearing file cache"));
1694 cache_clear(NULL, 2);
1695 CACHE_UNLOCK;
1696 break;
1697 default:
1698 quit = 1;
1699 shutdown(sockfd, SHUT_RDWR);
1700 close(sockfd);
1702 if (sockfd_r != -1) {
1703 shutdown(sockfd_r, SHUT_RDWR);
1704 close(sockfd_r);
1706 break;
1709 } while (!quit);
1712 * We're out of the main server loop. This happens when a signal was sent
1713 * to terminate the daemon. We'll wait for all clients to disconnect
1714 * before exiting and ignore any following signals.
1716 pth_join(accept_tid, &value);
1718 #ifdef WITH_GNUTLS
1719 if (sockfd_r != -1) {
1720 pth_cancel(tcp_accept_tid);
1721 pth_join(tcp_accept_tid, &value);
1723 #endif
1725 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1726 unlink(*socketpath);
1727 g_free(*socketpath);
1728 *socketpath = NULL;
1730 if (n > 1)
1731 log_write(N_("waiting for all threads to terminate"));
1733 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1735 while (n > 1) {
1736 if (n != n_clients) {
1737 log_write(N_("%i threads remain"), n-1);
1738 n_clients = n;
1741 pth_wait(ev_quit);
1742 pth_event_isolate(ev_quit);
1743 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1744 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1745 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1746 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1749 pth_event_free(timeout_ev, PTH_FREE_THIS);
1750 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1751 pth_event_free(ev_quit, PTH_FREE_THIS);
1752 pth_attr_destroy(attr);
1756 * Called from pinentry_fork() in the child process.
1758 void free_client_list()
1760 gint i, t = g_slist_length(cn_thread_list);
1762 for (i = 0; i < t; i++) {
1763 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1765 free_client(cn->cl);
1768 memset(key_cache, 0, cache_size);
1771 static gpg_error_t convert_file(const gchar *filename, const gchar *outfile)
1773 file_header_internal_t *fh;
1774 gpg_error_t rc;
1775 guchar *md5file;
1776 guchar *shakey;
1777 guint iter;
1779 md5file = gcry_malloc(16);
1780 if (!md5file)
1781 return GPG_ERR_ENOMEM;
1783 shakey = gcry_malloc(gcrykeysize);
1784 if (!shakey) {
1785 gcry_free(md5file);
1786 return GPG_ERR_ENOMEM;
1789 fh = read_file_header(filename, TRUE, &rc);
1791 if (!fh)
1792 goto done;
1794 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1796 /* The header in version 1 had a bug where the iterations were off-by-one.
1797 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1798 * header.
1800 if (fh->fh1.iter >= 0) {
1801 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1802 == FALSE) {
1803 rc = GPG_ERR_UNKNOWN_ERRNO;
1804 close(fh->fd);
1805 goto done;
1808 else
1809 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1811 close(fh->fd);
1813 if (rc)
1814 goto done;
1816 rc = convert_xml((gchar **)&fh->doc, &fh->len);
1818 if (rc) {
1819 gcry_free(fh->doc);
1820 warnx("%s: %s", filename, pwmd_strerror(rc));
1821 goto done;
1824 fh->v1 = FALSE;
1825 iter = fh->fh1.iter;
1826 memset(&fh->fh2, 0, sizeof(fh->fh2));
1827 /* Keep the iterations and key from the original file. */
1828 fh->fh2.iter = iter+1;
1829 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1831 if (rc)
1832 send_error(NULL, rc);
1834 done:
1835 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1836 gcry_free(shakey);
1837 gcry_free(md5file);
1838 g_free(fh);
1839 return rc;
1842 int main(int argc, char *argv[])
1844 gint opt;
1845 struct sockaddr_un addr;
1846 struct passwd *pw = getpwuid(getuid());
1847 gchar buf[PATH_MAX];
1848 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1849 gchar *socketarg = NULL;
1850 gchar *datadir = NULL;
1851 gboolean n;
1852 gchar *p;
1853 gchar **cache_push = NULL;
1854 gint iter = 0;
1855 gchar *import = NULL;
1856 gulong cmd_iterations = -1;
1857 gint default_timeout;
1858 gint rcfile_spec = 0;
1859 gint estatus = EXIT_FAILURE;
1860 gint sockfd, sockfd_r = -1;
1861 gchar *outfile = NULL;
1862 #ifndef MEM_DEBUG
1863 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1864 #endif
1865 gint do_unlink = 1;
1866 gboolean secure = FALSE;
1867 guint ptotal = 0;
1868 gint background = 1;
1869 sigset_t set;
1870 gchar *convert = NULL;
1871 #ifdef WITH_GNUTLS
1872 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1873 gint ret;
1874 #endif
1875 #ifndef DEBUG
1876 #ifdef HAVE_SETRLIMIT
1877 struct rlimit rl;
1879 rl.rlim_cur = rl.rlim_max = 0;
1881 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1882 err(EXIT_FAILURE, "setrlimit()");
1883 #endif
1884 #endif
1886 #ifdef ENABLE_NLS
1887 setlocale(LC_ALL, "");
1888 bindtextdomain("pwmd", LOCALEDIR);
1889 textdomain("pwmd");
1890 #endif
1892 gpg_err_init();
1893 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1894 #ifndef MEM_DEBUG
1895 g_mem_set_vtable(&mtable);
1896 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1897 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1898 xmlInitMemory();
1899 #ifdef WITH_GNUTLS
1900 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1901 xrealloc, xfree);
1902 #endif
1903 #endif
1904 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1905 #ifdef WITH_GNUTLS
1906 gnutls_global_init();
1907 gnutls_global_set_log_function(tls_log);
1908 gnutls_global_set_log_level(1);
1909 assuan_set_io_hooks(&io_hooks);
1910 #endif
1911 pth_init();
1912 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1914 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1915 err(EXIT_FAILURE, "%s", buf);
1917 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1919 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1920 err(EXIT_FAILURE, "%s", buf);
1922 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1924 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1925 err(EXIT_FAILURE, "sysconf()");
1927 cache_size = page_size;
1929 while ((opt = getopt(argc, argv, "o:C:bnI:i:hvf:D")) != EOF) {
1930 switch (opt) {
1931 case 'o':
1932 outfile = optarg;
1933 break;
1934 case 'C':
1935 convert = optarg;
1936 break;
1937 case 'b':
1938 /* Compatibility for version < 1.11 */
1939 break;
1940 case 'n':
1941 background = 0;
1942 break;
1943 case 'D':
1944 secure = TRUE;
1945 break;
1946 case 'I':
1947 import = optarg;
1948 break;
1949 case 'i':
1950 cmd_iterations = strtol(optarg, NULL, 10);
1951 break;
1952 case 'f':
1953 g_free(rcfile);
1954 rcfile = g_strdup(optarg);
1955 rcfile_spec = 1;
1956 break;
1957 case 'v':
1958 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,
1959 PACKAGE_BUGREPORT,
1960 #ifdef WITH_PINENTRY
1961 "+WITH_PINENTRY\n"
1962 #else
1963 "-WITH_PINENTRY\n"
1964 #endif
1965 #ifdef WITH_QUALITY
1966 "+WITH_QUALITY\n"
1967 #else
1968 "-WITH_QUALITY\n"
1969 #endif
1970 #ifdef WITH_GNUTLS
1971 "+WITH_GNUTLS\n"
1972 #else
1973 "-WITH_GNUTLS\n"
1974 #endif
1975 #ifdef DEBUG
1976 "+DEBUG\n"
1977 #else
1978 "-DEBUG\n"
1979 #endif
1980 #ifdef MEM_DEBUG
1981 "+MEM_DEBUG\n"
1982 #else
1983 "-MEM_DEBUG\n"
1984 #endif
1986 exit(EXIT_SUCCESS);
1987 case 'h':
1988 default:
1989 usage(argv[0]);
1993 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1994 exit(EXIT_FAILURE);
1996 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1997 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1999 if (log_syslog == TRUE)
2000 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2002 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2003 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2004 errno = 0;
2006 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2007 warn("setpriority()");
2008 goto do_exit;
2012 #ifdef HAVE_MLOCKALL
2013 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2014 warn("mlockall()");
2015 goto do_exit;
2017 #endif
2019 setup_gcrypt();
2021 if (convert) {
2022 if (!outfile)
2023 usage(argv[0]);
2025 opt = convert_file(convert, outfile);
2026 g_key_file_free(keyfileh);
2027 g_free(rcfile);
2028 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2031 if (import) {
2032 if (!outfile)
2033 usage(argv[0]);
2035 if (cmd_iterations == -1)
2036 cmd_iterations = get_key_file_integer("global", "iterations");
2038 opt = xml_import(import, outfile, cmd_iterations);
2039 g_key_file_free(keyfileh);
2040 g_free(rcfile);
2041 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2044 g_key_file_set_list_separator(keyfileh, ',');
2046 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2047 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2049 if (*p == '~') {
2050 p++;
2051 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2052 g_free(p);
2053 socketarg = g_strdup(buf);
2055 else
2056 socketarg = p;
2058 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2059 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2061 datadir = expand_homedir(p);
2062 g_free(p);
2064 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2065 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2066 disable_list_and_dump = n;
2068 else
2069 disable_list_and_dump = secure;
2071 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2072 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2073 else
2074 default_timeout = -1;
2076 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
2077 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
2079 if (cache_size < page_size || cache_size % page_size)
2080 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
2083 setup_logging(keyfileh);
2085 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2086 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2088 if (argc != optind) {
2089 if (cache_push)
2090 ptotal = g_strv_length(cache_push);
2092 for (; optind < argc; optind++) {
2093 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2094 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2098 if (strchr(socketarg, '/') == NULL) {
2099 socketdir = g_get_current_dir();
2100 socketname = g_strdup(socketarg);
2101 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2103 else {
2104 socketname = g_strdup(strrchr(socketarg, '/'));
2105 socketname++;
2106 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2107 socketdir = g_strdup(socketarg);
2108 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2111 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
2112 #ifdef MMAP_ANONYMOUS
2113 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
2114 #else
2115 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
2116 #endif
2117 err(EXIT_FAILURE, "mmap()");
2120 if (mlock(key_cache, cache_size) == -1)
2121 log_write("mlock(): %s", strerror(errno));
2123 memset(key_cache, 0, cache_size);
2125 if (chdir(datadir)) {
2126 warn("%s", datadir);
2127 unlink(socketpath);
2128 goto do_exit;
2131 if (parse_keyfile_key() == FALSE)
2132 goto do_exit;
2134 clear_errorfile_key();
2137 * Set the cache entry for a file. Prompts for the password.
2139 if (cache_push) {
2140 for (opt = 0; cache_push[opt]; opt++)
2141 do_cache_push(cache_push[opt], NULL);
2143 g_strfreev(cache_push);
2144 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2148 * bind() doesn't like the full pathname of the socket or any non alphanum
2149 * characters so change to the directory where the socket is wanted then
2150 * create it then change to datadir.
2152 if (chdir(socketdir)) {
2153 warn("%s", socketdir);
2154 goto do_exit;
2157 g_free(socketdir);
2159 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2160 warn("socket()");
2161 goto do_exit;
2164 addr.sun_family = AF_UNIX;
2165 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2167 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2168 warn("bind()");
2170 if (errno == EADDRINUSE)
2171 warnx(N_("Either there is another pwmd running or '%s' is a \n"
2172 "stale socket. Please remove it manually."), socketpath);
2174 do_unlink = 0;
2175 goto do_exit;
2178 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2179 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2180 mode_t mode = strtol(t, NULL, 8);
2181 mode_t mask = umask(0);
2183 g_free(t);
2185 if (chmod(socketname, mode) == -1) {
2186 warn("%s", socketname);
2187 close(sockfd);
2188 unlink(socketpath);
2189 umask(mask);
2190 goto do_exit;
2193 umask(mask);
2196 g_free(--socketname);
2198 if (chdir(datadir)) {
2199 warn("%s", datadir);
2200 close(sockfd);
2201 unlink(socketpath);
2202 goto do_exit;
2205 g_free(datadir);
2206 pth_mutex_init(&cache_mutex);
2207 #ifdef WITH_PINENTRY
2208 pth_mutex_init(&pin_mutex);
2209 #endif
2211 if (listen(sockfd, 0) == -1) {
2212 warn("listen()");
2213 goto do_exit;
2216 #ifdef WITH_GNUTLS
2217 if (get_key_file_boolean("global", "enable_tcp")) {
2218 gchar *tmp, *tmp2;
2219 struct addrinfo hints, *servinfo, *p;
2220 gint port = get_key_file_integer("global", "tcp_port");
2221 char buf[7];
2223 memset(&hints, 0, sizeof(hints));
2224 hints.ai_family = AF_UNSPEC;
2225 hints.ai_socktype = SOCK_STREAM;
2226 hints.ai_flags = AI_PASSIVE;
2228 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2229 &hints, &servinfo)) == -1) {
2230 warnx("getaddrinfo(): %s", gai_strerror(opt));
2231 goto do_exit;
2234 for(p = servinfo; p != NULL; p = p->ai_next) {
2235 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2236 p->ai_protocol)) == -1) {
2237 warn("socket()");
2238 continue;
2241 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2242 sizeof(int)) == -1) {
2243 warn("setsockopt()");
2244 goto do_exit;
2247 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2248 close(sockfd_r);
2249 warn("bind()");
2250 continue;
2253 opt++;
2254 break;
2257 freeaddrinfo(servinfo);
2259 if (!p) {
2260 warnx("%s", N_("could not bind"));
2261 goto do_exit;
2264 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2265 gchar *tmp = get_key_file_string("global", "tcp_interface");
2267 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2268 == -1) {
2269 warn("setsockopt");
2270 g_free(tmp);
2271 goto do_exit;
2274 g_free(tmp);
2277 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2279 if (ret != GNUTLS_E_SUCCESS) {
2280 warnx("%s", gnutls_strerror(ret));
2281 goto do_exit;
2284 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2286 if (!tmp) {
2287 warnx("%s", strerror(ENOMEM));
2288 goto do_exit;
2291 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2292 GNUTLS_X509_FMT_PEM);
2293 g_free(tmp);
2295 if (ret < 0) {
2296 warnx("%s", gnutls_strerror(ret));
2297 goto do_exit;
2300 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2302 if (!tmp) {
2303 warnx("%s", strerror(ENOMEM));
2304 goto do_exit;
2307 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2309 if (!tmp2) {
2310 xfree(tmp);
2311 warnx("%s", strerror(ENOMEM));
2312 goto do_exit;
2315 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2316 GNUTLS_X509_FMT_PEM);
2317 g_free(tmp);
2318 g_free(tmp2);
2320 if (ret != GNUTLS_E_SUCCESS) {
2321 warnx("%s", gnutls_strerror(ret));
2322 goto do_exit;
2325 #endif
2327 if (background) {
2328 switch (fork()) {
2329 case -1:
2330 warn("fork()");
2331 goto do_exit;
2332 case 0:
2333 close(0);
2334 close(1);
2335 close(2);
2336 setsid();
2337 break;
2338 default:
2339 exit(EXIT_SUCCESS);
2343 #ifdef WITH_GNUTLS
2344 if (get_key_file_boolean("global", "enable_tcp")) {
2345 log_write("%s", N_("Generating key exchange parameters..."));
2346 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2348 if (ret) {
2349 warnx("%s", gpg_strerror(ret));
2350 goto do_exit;
2353 ret = gnutls_dh_params_init(&dh_params);
2355 if (ret != GNUTLS_E_SUCCESS) {
2356 warnx("%s", gnutls_strerror(ret));
2357 goto do_exit;
2360 ret = gnutls_dh_params_generate2(dh_params, 1024);
2362 if (ret != GNUTLS_E_SUCCESS) {
2363 warnx("%s", gnutls_strerror(ret));
2364 goto do_exit;
2367 gnutls_certificate_set_dh_params(x509_cred, dh_params);
2368 ret = gnutls_rsa_params_init(&rsa_params);
2370 if (ret != GNUTLS_E_SUCCESS) {
2371 warnx("%s", gnutls_strerror(ret));
2372 goto do_exit;
2375 ret = gnutls_rsa_params_generate2(rsa_params, 512);
2377 if (ret != GNUTLS_E_SUCCESS) {
2378 warnx("%s", gnutls_strerror(ret));
2379 goto do_exit;
2382 gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
2383 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2385 if (listen(sockfd_r, 0) == -1) {
2386 warn("listen()");
2387 goto do_exit;
2390 #endif
2393 * These are the signals that we use in threads. libpth can catch signals
2394 * itself so ignore them everywhere else. Note that using
2395 * signal(N, SIG_IGN) doesn't work like you might think.
2397 sigemptyset(&set);
2399 /* Termination */
2400 sigaddset(&set, SIGTERM);
2401 sigaddset(&set, SIGINT);
2403 /* Configuration file reloading. */
2404 sigaddset(&set, SIGUSR1);
2406 /* Clears the file cache. */
2407 sigaddset(&set, SIGHUP);
2409 /* Caught in client_thread(). Sends a cache status message. */
2410 sigaddset(&set, SIGUSR2);
2412 /* Ignored everywhere. When a client disconnects abnormally this signal
2413 * gets raised. It isn't needed though because client_thread() will check
2414 * for rcs even after the client disconnects. */
2415 signal(SIGPIPE, SIG_IGN);
2416 pth_sigmask(SIG_BLOCK, &set, NULL);
2417 server_loop(sockfd, sockfd_r, &socketpath);
2418 estatus = EXIT_SUCCESS;
2420 do_exit:
2421 if (socketpath && do_unlink) {
2422 unlink(socketpath);
2423 g_free(socketpath);
2426 #ifdef WITH_GNUTLS
2427 if (sockfd_r != -1) {
2428 gnutls_dh_params_deinit(dh_params);
2429 gnutls_rsa_params_deinit(rsa_params);
2431 if (x509_cred)
2432 gnutls_certificate_free_credentials(x509_cred);
2434 gnutls_global_deinit();
2436 #endif
2438 g_key_file_free(keyfileh);
2439 g_free(rcfile);
2440 xmlCleanupParser();
2442 if (key_cache) {
2443 cache_clear(NULL, 2);
2444 memset(key_cache, 0, cache_size);
2447 if (key_cache && munmap(key_cache, cache_size) == -1)
2448 log_write("munmap(): %s", strerror(errno));
2450 if (estatus == EXIT_SUCCESS)
2451 log_write(N_("pwmd exiting normally"));
2453 pth_kill();
2454 #if defined(DEBUG) && !defined(MEM_DEBUG)
2455 xdump();
2456 #endif
2457 exit(estatus);