WITH_GNUTLS fixes.
[pwmd.git] / src / pwmd.c
blobe03b74deb183f24eda5eb244b37739c38eb528c3
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/un.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <glib.h>
38 #include <glib/gprintf.h>
39 #include <sys/mman.h>
40 #include <termios.h>
41 #include <assert.h>
42 #include <syslog.h>
43 #include <zlib.h>
44 #include <gcrypt.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
49 #ifdef HAVE_SETRLIMIT
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #endif
54 #ifdef TM_IN_SYS_TIME
55 #include <sys/time.h>
56 #else
57 #include <time.h>
58 #endif
60 #ifndef MEM_DEBUG
61 #include "mem.h"
62 #endif
64 #include "xml.h"
65 #include "common.h"
67 #ifdef WITH_PINENTRY
68 #include "pinentry.h"
69 #endif
71 #ifdef WITH_GNUTLS
72 #include "tls.h"
73 #endif
74 #include "commands.h"
75 #include "pwmd_error.h"
76 #include "cache.h"
77 #include "misc.h"
78 #include "pwmd.h"
80 GCRY_THREAD_OPTION_PTH_IMPL;
82 static void clear_rcfile_keys()
84 gsize n;
85 gchar **groups;
86 gchar **p;
88 groups = g_key_file_get_groups(keyfileh, &n);
90 for (p = groups; *p; p++) {
91 GError *rc = NULL;
93 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
94 g_key_file_set_string(keyfileh, *p, "key", "");
97 g_strfreev(groups);
100 static void reload_rcfile()
102 gboolean b = disable_list_and_dump;
104 log_write(N_("reloading configuration file '%s'"), rcfile);
105 g_key_file_free(keyfileh);
106 keyfileh = parse_rcfile(0);
107 parse_rcfile_keys(FALSE);
108 clear_rcfile_keys();
109 disable_list_and_dump = b;
110 send_status_all(STATUS_CONFIG);
113 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
115 gpg_error_t n = gpg_error_from_errno(e);
117 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
120 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
122 gpg_err_code_t n = gpg_err_code(e);
123 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
124 struct client_s *client = assuan_get_pointer(ctx);
126 if (!e)
127 return assuan_process_done(ctx, 0);
129 if (!ctx) {
130 log_write("%s", pwmd_strerror(e));
131 return e;
134 if (n == EPWMD_LIBXML_ERROR) {
135 xmlErrorPtr xe = client->xml_error;
137 if (!xe)
138 xe = xmlGetLastError();
140 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
141 log_write("%s", xe->message);
143 if (xe == client->xml_error)
144 xmlResetError(xe);
145 else
146 xmlResetLastError();
148 client->xml_error = NULL;
149 return e;
152 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
155 void log_write(const gchar *fmt, ...)
157 gchar *args, *line;
158 va_list ap;
159 struct tm *tm;
160 time_t now;
161 gchar tbuf[21];
162 gint fd = -1;
163 pth_attr_t attr;
164 gchar *name;
165 pth_t tid = pth_self();
166 gchar tid_str[12], *p;
168 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
169 return;
171 if (!cmdline && logfile) {
172 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
173 warn("%s", logfile);
174 return;
178 va_start(ap, fmt);
180 if (g_vasprintf(&args, fmt, ap) == -1) {
181 if (logfile)
182 close(fd);
184 va_end(ap);
185 return;
188 if (cmdline) {
189 warnx("%s", args);
190 fflush(stderr);
191 g_free(args);
192 return;
195 attr = pth_attr_of(tid);
197 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
198 name = "unknown";
200 pth_attr_destroy(attr);
201 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
202 p = tid_str;
204 if (strncmp(p+1, name, 9) == 0)
205 p = NULL;
207 if (!cmdline && log_syslog == TRUE)
208 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
210 va_end(ap);
211 time(&now);
212 tm = localtime(&now);
213 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
214 tbuf[sizeof(tbuf) - 1] = 0;
216 if (args[strlen(args)-1] == '\n')
217 args[strlen(args)-1] = 0;
219 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
220 p ? p : "", args);
221 g_free(args);
223 if (!line) {
224 if (logfile)
225 close(fd);
227 return;
230 if (logfile) {
231 write(fd, line, strlen(line));
232 fsync(fd);
233 close(fd);
236 if (isatty(STDERR_FILENO)) {
237 fprintf(stderr, "%s", line);
238 fflush(stderr);
241 g_free(line);
244 static void usage(gchar *pn)
246 g_fprintf(stderr, N_(
247 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
248 "[-I <filename> [-i <iter>]]\n "
249 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
250 " -n run as a foreground process\n"
251 " -f load the specified rcfile (~/.pwmd/config)\n"
252 " -C convert a version 1 data file to version 2\n"
253 " -I import an XML file\n"
254 " -i encrypt with the specified number of iterations when importing\n"
255 " (config default in the \"global\" section)\n"
256 " -k obtain the key from the specified file\n"
257 " -o output file for use with the -C and -I options\n"
258 " -D disable use of the LIST and DUMP commands\n"
259 " -P disable pinentry\n"
260 " -v version\n"
261 " -h this help text\n"
262 ), pn);
263 exit(EXIT_FAILURE);
266 #ifndef MEM_DEBUG
267 static int gcry_SecureCheck(const void *ptr)
269 return 1;
271 #endif
273 static void setup_gcrypt()
275 gcry_check_version(NULL);
277 #ifndef MEM_DEBUG
278 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
279 xfree);
280 #endif
282 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
283 NULL) != 0)
284 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
286 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
287 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
290 static gint new_connection(struct client_s *cl)
292 gpg_error_t rc;
293 gchar ver[ASSUAN_LINELENGTH];
295 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
297 if (rc)
298 goto fail;
300 assuan_set_pointer(cl->ctx, cl);
301 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
302 assuan_set_hello_line(cl->ctx, ver);
303 rc = register_commands(cl->ctx);
305 if (rc)
306 goto fail;
308 rc = assuan_accept(cl->ctx);
310 if (rc)
311 goto fail;
313 return 0;
315 fail:
316 log_write("%s", gpg_strerror(rc));
317 return 1;
320 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
322 gchar *line = NULL;
323 struct client_s *client = assuan_get_pointer(ctx);
324 gchar buf[ASSUAN_LINELENGTH];
325 gchar *status = NULL;
327 switch (which) {
328 case STATUS_CACHE:
329 CACHE_LOCK(client->ctx);
330 line = print_fmt(buf, sizeof(buf), "%i", cache_file_count());
331 CACHE_UNLOCK;
332 status = "CACHE";
333 break;
334 case STATUS_CLIENTS:
335 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
336 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
337 pth_mutex_release(&cn_mutex);
338 status = "CLIENTS";
339 break;
340 case STATUS_CONFIG:
341 status = "CONFIG";
342 break;
343 case STATUS_KEEPALIVE:
344 status = "KEEPALIVE";
345 break;
346 case STATUS_LOCKED:
347 status = "LOCKED";
348 line = N_("Waiting for lock");
349 break;
352 return assuan_write_status(ctx, status, line);
355 void send_status_all(status_msg_t which)
357 guint i, t;
359 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
361 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
362 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
363 pth_msgport_t m = pth_msgport_find(cn->msg_name);
365 if (m) {
366 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
368 msg->m_data = (status_msg_t *)which;
369 pth_msgport_put(m, msg);
373 pth_mutex_release(&cn_mutex);
376 static void xml_error_cb(void *data, xmlErrorPtr e)
378 struct client_s *client = data;
381 * Keep the first reported error as the one to show in the error
382 * description. Reset in send_error().
384 if (client->xml_error)
385 return;
387 xmlCopyError(e, client->xml_error);
391 * This is called after a child_thread terminates. Set with
392 * pth_cleanup_push().
394 static void cleanup_cb(void *arg)
396 struct client_thread_s *cn = arg;
397 gpointer value;
398 struct client_s *cl = cn->cl;
400 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
401 log_write(N_("exiting, fd=%i"), cn->fd);
403 if (cn->msg_tid) {
404 pth_cancel(cn->msg_tid);
405 pth_join(cn->msg_tid, &value);
406 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
409 if (cn->msg_name)
410 g_free(cn->msg_name);
412 if (cn->msg) {
413 while (pth_msgport_pending(cn->msg) > 0) {
414 pth_message_t *m = pth_msgport_get(cn->msg);
416 g_free(m);
419 pth_msgport_destroy(cn->msg);
422 pth_join(cn->tid, &value);
424 if (cl && cl->freed == FALSE)
425 cleanup_client(cl);
427 #ifdef WITH_GNUTLS
428 if (cn->tls) {
429 gnutls_deinit(cn->tls->ses);
431 if (cn->tls->fp)
432 g_free(cn->tls->fp);
434 g_free(cn->tls);
436 #endif
438 if (cl && cl->ctx)
439 assuan_deinit_server(cl->ctx);
441 #ifdef WITH_PINENTRY
442 if (cl && cl->pinentry)
443 cleanup_pinentry(cl->pinentry);
444 #endif
446 g_free(cl);
447 cn_thread_list = g_slist_remove(cn_thread_list, cn);
448 g_free(cn);
449 pth_mutex_release(&cn_mutex);
450 send_status_all(STATUS_CLIENTS);
453 static void *client_msg_thread(void *data)
455 struct client_s *cl = data;
456 pth_status_t ev_status;
458 for (;;) {
459 pth_wait(cl->thd->msg_ev);
460 ev_status = pth_event_status(cl->thd->msg_ev);
462 if (ev_status == PTH_STATUS_FAILED) {
463 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
464 __FUNCTION__);
465 continue;
468 if (ev_status == PTH_STATUS_OCCURRED) {
469 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
471 while (pth_msgport_pending(cl->thd->msg) > 0) {
472 pth_message_t *m = pth_msgport_get(cl->thd->msg);
473 status_msg_t n = (status_msg_t)m->m_data;
474 gpg_error_t rc = send_status(cl->ctx, n);
476 g_free(m);
478 if (rc) {
479 pth_mutex_release(&cn_mutex);
480 log_write("%s", gpg_strerror(rc));
481 break;
485 pth_mutex_release(&cn_mutex);
491 * Called every time a connection is made via pth_spawn(). This is the thread
492 * entry point.
494 static void *client_thread(void *data)
496 struct client_thread_s *thd = data;
497 pth_event_t ev;
498 struct client_s *cl = g_malloc0(sizeof(struct client_s));
499 gpg_error_t rc;
500 pth_attr_t attr;
503 * Prevent a race condition with init_new_connection() if this thread
504 * fails (returns) for some reason before init_new_connection() releases
505 * the cn_mutex.
507 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
508 pth_mutex_release(&cn_mutex);
510 if (!cl) {
511 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
512 goto fail;
515 thd->cl = cl;
516 cl->thd = thd;
517 pth_cleanup_push(cleanup_cb, thd);
519 #ifdef WITH_GNUTLS
521 * Do the TLS handshake before anything else.
523 if (thd->remote) {
524 thd->tls = tls_init(thd->fd);
526 if (!thd->tls) {
527 close(thd->fd);
528 goto fail;
531 #endif
534 * This is a "child" thread. Don't catch any signals. Let the master
535 * thread take care of signals in server_loop().
537 if (new_connection(cl))
538 goto fail;
540 #ifdef WITH_PINENTRY
541 cl->pinentry = pinentry_init();
543 if (!cl->pinentry) {
544 g_free(cl);
545 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
546 goto fail;
548 #endif
550 thd->msg_name = g_strdup_printf("%p", thd->tid);
552 if (!thd->msg_name) {
553 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
554 goto fail;
557 thd->msg = pth_msgport_create(thd->msg_name);
559 if (!thd->msg) {
560 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
561 goto fail;
564 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
565 attr = pth_attr_new();
566 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
567 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
568 pth_attr_destroy(attr);
570 if (!thd->msg_tid) {
571 log_write(N_("pth_spawn() failed"));
572 goto fail;
575 #ifdef HAVE_MLOCKALL
576 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
577 log_write("mlockall(): %s", strerror(errno));
578 goto fail;
580 #endif
582 rc = send_status(cl->ctx, STATUS_CACHE);
584 if (rc) {
585 log_write("%s", gpg_strerror(rc));
586 goto fail;
589 send_status_all(STATUS_CLIENTS);
590 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
591 xmlInitParser();
592 xmlXPathInit();
593 xmlSetStructuredErrorFunc(cl, xml_error_cb);
595 for (;;) {
596 pth_status_t ev_status;
598 pth_wait(ev);
599 ev_status = pth_event_status(ev);
601 if (ev_status == PTH_STATUS_FAILED) {
602 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
603 __FUNCTION__);
604 goto done;
606 else if (ev_status == PTH_STATUS_OCCURRED) {
607 rc = assuan_process_next(cl->ctx);
609 if (rc) {
610 cl->inquire_status = INQUIRE_INIT;
612 if (gpg_err_code(rc) == GPG_ERR_EOF)
613 goto done;
615 log_write("assuan_process_next(): %s", gpg_strerror(rc));
616 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
618 if (rc) {
619 log_write("assuan_process_done(): %s", gpg_strerror(rc));
620 goto done;
623 else {
624 #ifdef WITH_PINENTRY
625 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
626 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
627 pth_event_concat(ev, cl->pinentry->ev, NULL);
628 cl->pinentry->status = PINENTRY_RUNNING;
630 #endif
632 switch (cl->inquire_status) {
633 case INQUIRE_BUSY:
634 case INQUIRE_INIT:
635 break;
636 case INQUIRE_DONE:
637 cl->inquire_status = INQUIRE_INIT;
638 rc = assuan_process_done(cl->ctx, 0);
639 break;
644 #ifdef WITH_PINENTRY
645 ev = pinentry_iterate(cl, ev);
646 #endif
650 * Client cleanup (including XML data) is done in cleanup_cb() from
651 * the cleanup thread.
653 done:
654 pth_event_free(ev, PTH_FREE_ALL);
656 fail:
657 pth_exit(NULL);
658 return NULL;
661 static void setup_logging(GKeyFile *kf)
663 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
665 if (n == TRUE) {
666 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
668 if (*p == '~') {
669 gchar buf[PATH_MAX];
671 p++;
672 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
673 g_free(p);
675 if (logfile)
676 g_free(logfile);
678 logfile = g_strdup(buf);
680 else {
681 if (logfile)
682 g_free(logfile);
684 logfile = p;
688 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
692 * Make sure all settings are set to either the specified setting or a
693 * default.
695 static void set_rcfile_defaults(GKeyFile *kf)
697 gchar buf[PATH_MAX];
699 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
700 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
701 g_key_file_set_string(kf, "global", "socket_path", buf);
704 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
705 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
706 g_key_file_set_string(kf, "global", "data_directory", buf);
709 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
710 g_key_file_set_boolean(kf, "global", "backup", TRUE);
712 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
713 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
714 g_key_file_set_string(kf, "global", "log_path", buf);
717 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
718 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
720 #ifdef HAVE_MLOCKALL
721 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
722 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
723 #endif
725 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
726 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
728 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
729 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
730 g_key_file_set_integer(kf, "global", "iterations", 1);
732 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
733 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
735 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
736 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
738 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
739 g_key_file_set_integer(kf, "global", "compression_level", 6);
741 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
742 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
744 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
745 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
747 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
749 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
750 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
752 #ifdef HAVE_MLOCKALL
753 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
754 #endif
756 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
757 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
759 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
760 g_key_file_set_integer(kf, "global", "keepalive", 30);
762 #ifdef WITH_PINENTRY
763 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
764 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
766 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
767 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
768 #endif
770 #ifdef WITH_GNUTLS
771 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
772 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
774 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
775 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
777 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
778 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
780 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
781 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
782 #endif
784 setup_logging(kf);
787 static GKeyFile *parse_rcfile()
789 GKeyFile *kf = g_key_file_new();
790 GError *rc = NULL;
792 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
793 log_write("%s: %s", rcfile, rc->message);
795 if (cmdline)
796 return NULL;
798 if (rc->code == G_FILE_ERROR_NOENT) {
799 g_clear_error(&rc);
800 set_rcfile_defaults(kf);
801 return kf;
804 g_clear_error(&rc);
805 return NULL;
807 else
808 set_rcfile_defaults(kf);
810 return kf;
813 static gchar *do_get_password(const gchar *prompt)
815 gchar buf[LINE_MAX] = {0}, *p;
816 struct termios told, tnew;
817 gchar *key;
819 if (tcgetattr(STDIN_FILENO, &told) == -1) {
820 log_write("tcgetattr(): %s", strerror(errno));
821 return NULL;
824 memcpy(&tnew, &told, sizeof(struct termios));
825 tnew.c_lflag &= ~(ECHO);
826 tnew.c_lflag |= ICANON|ECHONL;
828 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
829 log_write("tcsetattr(): %s", strerror(errno));
830 tcsetattr(STDIN_FILENO, TCSANOW, &told);
831 return NULL;
834 fprintf(stderr, "%s", prompt);
836 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
837 tcsetattr(STDIN_FILENO, TCSANOW, &told);
838 return NULL;
841 tcsetattr(STDIN_FILENO, TCSANOW, &told);
842 p[strlen(p) - 1] = 0;
844 if (!buf[0]) {
845 key = gcry_malloc(1);
846 key[0] = 0;
848 else {
849 key = gcry_malloc(strlen(p) + 1);
850 sprintf(key, "%s", p);
853 memset(&buf, 0, sizeof(buf));
854 return key;
857 /* Only used when "enable_pinentry" is "false". */
858 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
859 guchar *key, pinentry_cmd_t which)
861 gint try = 0;
862 gchar *password;
863 gchar *prompt;
865 if (which == PINENTRY_SAVE) {
866 gchar *key1, *key2;
868 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
869 key1 = do_get_password(prompt);
870 g_free(prompt);
872 if (!key1) {
873 log_write(N_("%s: Skipping file"), filename);
874 return FALSE;
877 prompt = g_strdup_printf(N_("Repeat passphrase: "));
878 key2 = do_get_password(prompt);
879 g_free(prompt);
881 if (!key2) {
882 gcry_free(key1);
883 log_write(N_("%s: Skipping file"), filename);
884 return FALSE;
887 if (strcmp(key1, key2)) {
888 gcry_free(key1);
889 gcry_free(key2);
890 log_write(N_("%s: Passphrase mismatch"), filename);
891 return FALSE;
894 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
895 strlen(key1) ? strlen(key1) : 1);
896 gcry_free(key1);
897 gcry_free(key2);
898 return TRUE;
901 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
903 do {
904 gpg_error_t rc;
906 if ((password = do_get_password(prompt)) == NULL) {
907 log_write(N_("%s: Skipping file"), filename);
908 g_free(prompt);
909 return FALSE;
912 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
913 gcry_free(password);
915 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
917 if (!rc)
918 break;
920 log_write(N_("%s: Invalid passphrase"), filename);
921 } while (try++ < 2);
923 g_free(prompt);
925 if (try == 3) {
926 log_write(N_("%s: Invalid passphrase, skipping"), filename);
927 return FALSE;
930 return TRUE;
934 * inbuf must have been allocated with gcry_malloc().
936 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
937 guchar *shakey, gpointer inbuf, gulong insize)
939 gcry_cipher_hd_t gh;
940 gpg_error_t rc;
941 gint level, zrc;
942 glong outsize;
943 gpointer outbuf;
945 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
947 if (rc)
948 return rc;
950 level = get_key_file_integer(filename, "compression_level");
952 if (level < 0)
953 level = 0;
955 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
956 == FALSE) {
957 gcry_cipher_close(gh);
958 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
960 else {
961 gcry_free(inbuf);
962 inbuf = outbuf;
963 insize = outsize;
966 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
967 gcry_cipher_close(gh);
968 return rc;
971 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
972 guchar *md5file, guchar *key, pinentry_cmd_t which)
974 #ifdef WITH_PINENTRY
975 gpg_error_t rc = 0;
977 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
978 == FALSE) {
979 #endif
980 return get_input(filename, fh, key, which);
981 #ifdef WITH_PINENTRY
983 else {
984 gchar *result = NULL;
985 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
986 gint try = 0;
988 set_pinentry_defaults(pin);
989 pin->which = which;
990 pin->filename = g_strdup(filename);
991 again:
992 rc = pinentry_getpin(pin, &result);
994 if (rc) {
995 log_write("%s", gpg_strerror(rc));
996 xfree(result);
997 goto done;
1000 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1001 xfree(result);
1003 if (which == PINENTRY_SAVE) {
1004 cleanup_pinentry(pin);
1005 goto done;
1008 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1010 if (rc == EPWMD_BADKEY) {
1011 if (try++ == 2)
1012 log_write("%s: %s", filename, pwmd_strerror(rc));
1013 else {
1014 g_free(pin->title);
1015 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1016 goto again;
1019 else if (rc)
1020 log_write("%s", pwmd_strerror(rc));
1022 cleanup_pinentry(pin);
1025 done:
1026 return rc ? FALSE : TRUE;
1027 #endif
1030 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1032 FILE *fp;
1033 gchar buf[LINE_MAX] = {0}, *p;
1034 gchar *str = NULL;
1035 gint len;
1037 *rc = 0;
1039 if ((fp = fopen(file, "r")) == NULL) {
1040 *rc = gpg_error_from_syserror();
1041 return FALSE;
1044 p = fgets(buf, sizeof(buf), fp);
1045 fclose(fp);
1046 len = strlen(buf);
1048 if (len && buf[len - 1] == '\n')
1049 buf[--len] = 0;
1051 str = gcry_malloc(len + 1);
1053 if (!str) {
1054 *rc = gpg_error_from_errno(ENOMEM);
1055 return FALSE;
1058 memcpy(str, buf, len ? len : 1);
1059 str[len] = 0;
1060 memset(&buf, 0, sizeof(buf));
1061 *result = str;
1062 return TRUE;
1065 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import)
1067 GError *rv = NULL;
1068 gchar *t, *file = NULL, *str;
1069 gpg_error_t rc;
1071 if (import == FALSE) {
1072 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1073 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1075 if (!file) {
1076 if (rv) {
1077 log_write("%s: key_file: %s", rcfile, rv->message);
1078 g_clear_error(&rv);
1081 return NULL;
1084 t = expand_homedir(file);
1086 if (!t) {
1087 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1088 return NULL;
1091 g_free(file);
1092 file = t;
1095 else {
1096 /* -I or -C. The filename is a key file. */
1097 file = g_strdup(filename);
1099 if (!file) {
1100 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1101 return NULL;
1105 if (rv) {
1106 log_write("%s: key_file: %s", rcfile, rv->message);
1107 g_clear_error(&rv);
1108 return NULL;
1111 if (!file)
1112 return NULL;
1114 if (_getline(file, &str, &rc) == FALSE) {
1115 log_write("%s: %s", file, pwmd_strerror(rc));
1116 g_free(file);
1117 return NULL;
1120 g_free(file);
1121 return str;
1124 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1125 const gchar *keyfile, gulong iter)
1127 xmlDocPtr doc;
1128 gint fd;
1129 struct stat st;
1130 gint len;
1131 xmlChar *xmlbuf;
1132 xmlChar *xml;
1133 guchar shakey[gcrykeysize];
1134 gpg_error_t rc;
1135 file_header_internal_t fh;
1137 if (stat(filename, &st) == -1) {
1138 log_write("%s: %s", filename, strerror(errno));
1139 return FALSE;
1142 if (iter && keyfile) {
1143 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1145 if (!tmp)
1146 return FALSE;
1148 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1149 strlen(tmp) ? strlen(tmp) : 1);
1151 else if (iter && get_password(filename, NULL, NULL, shakey, PINENTRY_SAVE)
1152 == FALSE)
1153 return FALSE;
1155 if ((fd = open(filename, O_RDONLY)) == -1) {
1156 memset(shakey, 0, sizeof(shakey));
1157 log_write("%s: %s", filename, strerror(errno));
1158 return FALSE;
1161 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1162 close(fd);
1163 memset(shakey, 0, sizeof(shakey));
1164 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1165 return FALSE;
1168 if (read(fd, xmlbuf, st.st_size) == -1) {
1169 memset(shakey, 0, sizeof(shakey));
1170 rc = errno;
1171 close(fd);
1172 errno = rc;
1173 err(EXIT_FAILURE, "read()");
1176 close(fd);
1177 xmlbuf[st.st_size] = 0;
1180 * Make sure the document validates.
1182 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1183 log_write("xmlReadDoc() failed");
1184 close(fd);
1185 gcry_free(xmlbuf);
1186 memset(shakey, 0, sizeof(shakey));
1187 return FALSE;
1190 gcry_free(xmlbuf);
1191 xmlDocDumpMemory(doc, &xml, &len);
1192 xmlFreeDoc(doc);
1194 if (!iter)
1195 memset(shakey, '!', sizeof(shakey));
1197 memset(&fh, 0, sizeof(fh));
1198 fh.fh2.iter = iter;
1199 rc = export_common(outfile, &fh, shakey, xml, len);
1200 memset(shakey, 0, sizeof(shakey));
1202 if (rc)
1203 send_error(NULL, rc);
1205 return rc ? FALSE : TRUE;
1208 gchar *get_key_file_string(const gchar *section, const gchar *what)
1210 gchar *val = NULL;
1211 GError *grc = NULL;
1213 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1214 val = g_key_file_get_string(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_string(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 gint get_key_file_integer(const gchar *section, const gchar *what)
1237 gint val = -1;
1238 GError *grc = NULL;
1240 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1241 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1243 if (grc) {
1244 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1245 g_clear_error(&grc);
1248 else {
1249 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1250 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1252 if (grc) {
1253 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1254 g_clear_error(&grc);
1259 return val;
1262 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1264 gboolean val = FALSE;
1265 GError *grc = NULL;
1267 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1268 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1270 if (grc) {
1271 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1272 g_clear_error(&grc);
1275 else {
1276 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1277 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1279 if (grc) {
1280 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1281 g_clear_error(&grc);
1286 return val;
1289 static gboolean parse_rcfile_keys()
1291 gsize n;
1292 gchar **groups;
1293 gchar **p;
1294 gchar *str;
1296 groups = g_key_file_get_groups(keyfileh, &n);
1298 for (p = groups; *p; p++) {
1299 GError *rc = NULL;
1301 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1302 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1304 if (!str) {
1305 if (rc) {
1306 log_write("%s: key: %s", rcfile, rc->message);
1307 g_clear_error(&rc);
1309 continue;
1312 do_cache_push(*p, str);
1313 g_free(str);
1314 continue;
1317 if (rc) {
1318 log_write("%s: key: %s", rcfile, rc->message);
1319 g_clear_error(&rc);
1320 continue;
1323 str = parse_rcfile_keyfile(*p, FALSE);
1325 if (!str)
1326 continue;
1328 do_cache_push(*p, str);
1329 gcry_free(str);
1332 g_strfreev(groups);
1333 return TRUE;
1336 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1338 guchar *md5file;
1339 guchar *key;
1340 gint timeout;
1341 const gchar *p = filename;
1342 file_header_internal_t *fh;
1343 gpg_error_t rc;
1345 while (isspace(*p))
1346 p++;
1348 if (!*p)
1349 return FALSE;
1351 if (valid_filename(p) == FALSE) {
1352 log_write(N_("%s: Invalid characters in filename"), p);
1353 return FALSE;
1356 md5file = gcry_malloc(16);
1357 key = gcry_malloc(gcrykeysize);
1358 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1360 if (access(p, R_OK|W_OK) != 0) {
1361 gcry_free(md5file);
1362 gcry_free(key);
1364 if (errno != ENOENT) {
1365 log_write("%s: %s", p, strerror(errno));
1366 return FALSE;
1369 return TRUE;
1372 fh = read_file_header(filename, FALSE, &rc);
1374 if (!fh) {
1375 gcry_free(md5file);
1376 gcry_free(key);
1377 log_write("%s: %s", p, pwmd_strerror(rc));
1378 return FALSE;
1381 if (fh->fh2.iter <= 0) {
1382 memset(key, '!', gcrykeysize);
1383 goto try_decrypt;
1386 if (!password) {
1387 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1388 g_free(fh);
1389 return FALSE;
1392 else
1393 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1394 strlen(password) ? strlen(password) : 1);
1396 try_decrypt:
1397 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1399 if (rc) {
1400 log_write("%s: %s", filename, pwmd_strerror(rc));
1401 gcry_free(key);
1402 gcry_free(md5file);
1403 g_free(fh);
1404 return FALSE;
1407 if (cache_update_key(md5file, key) == FALSE) {
1408 log_write("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1409 gcry_free(key);
1410 gcry_free(md5file);
1411 g_free(fh);
1412 return FALSE;
1415 timeout = get_key_file_integer(p, "cache_timeout");
1416 cache_set_timeout(md5file, timeout);
1417 log_write(N_("%s: File added to the cache"), filename);
1418 gcry_free(key);
1419 gcry_free(md5file);
1420 g_free(fh);
1421 return TRUE;
1424 static void init_new_connection(gint fd, gchar *addr)
1426 pth_t tid;
1427 pth_attr_t attr;
1428 struct client_thread_s *new;
1429 gchar buf[41];
1431 new = g_malloc0(sizeof(struct client_thread_s));
1433 if (!new) {
1434 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1435 return;
1439 * Thread priority is inherited from the calling thread. This
1440 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1441 * priority.
1443 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1444 new->fd = fd;
1446 #ifdef WITH_GNUTLS
1447 if (addr)
1448 new->remote = TRUE;
1449 #endif
1451 attr = pth_attr_new();
1452 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1453 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1454 tid = pth_spawn(attr, client_thread, new);
1455 pth_attr_destroy(attr);
1457 if (!tid) {
1458 g_free(new);
1459 log_write(N_("pth_spawn() failed"));
1460 pth_mutex_release(&cn_mutex);
1461 return;
1464 g_snprintf(buf, sizeof(buf), "%p", tid);
1466 if (addr)
1467 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1468 else
1469 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1471 attr = pth_attr_of(tid);
1472 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1473 pth_attr_destroy(attr);
1474 new->tid = tid;
1475 cn_thread_list = g_slist_append(cn_thread_list, new);
1476 pth_mutex_release(&cn_mutex);
1479 #ifdef WITH_GNUTLS
1480 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1481 static void *get_in_addr(struct sockaddr *sa)
1483 if (sa->sa_family == AF_INET)
1484 return &(((struct sockaddr_in*)sa)->sin_addr);
1486 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1489 static void *tcp_accept_thread(void *arg)
1491 gint sockfd = (gint)arg;
1493 for (;;) {
1494 struct sockaddr_storage raddr;
1495 socklen_t slen = sizeof(raddr);
1496 gint fd = -1;
1497 gulong n;
1498 gchar *t;
1500 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1501 if (errno != EAGAIN) {
1502 if (!quit) // probably EBADF
1503 log_write("accept(): %s", strerror(errno));
1505 break;
1509 if (quit)
1510 break;
1512 if (fd >= 0) {
1513 gchar s[INET6_ADDRSTRLEN];
1515 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1516 s, sizeof s);
1517 init_new_connection(fd, s);
1520 t = get_key_file_string("global", "tcp_wait");
1521 g_free(t);
1522 n = strtol(t, NULL, 10);
1524 if (n < 0)
1525 n = 0;
1527 pth_usleep(n*100000);
1530 /* Just in case pth_accept() failed for some reason other than EBADF */
1531 quit = 1;
1532 pth_exit(PTH_CANCELED);
1533 return NULL;
1535 #endif
1537 static void *accept_thread(void *arg)
1539 gint sockfd = (gint)arg;
1541 for (;;) {
1542 socklen_t slen = sizeof(struct sockaddr_un);
1543 struct sockaddr_un raddr;
1544 gint fd = -1;
1546 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1547 if (errno != EAGAIN) {
1548 if (!quit) // probably EBADF
1549 log_write("accept(): %s", strerror(errno));
1551 break;
1555 if (fd >= 0)
1556 init_new_connection(fd, NULL);
1559 /* Just in case pth_accept() failed for some reason other than EBADF */
1560 quit = 1;
1561 pth_exit(PTH_CANCELED);
1562 return NULL;
1566 * This thread isn't joinable. For operations that block, these threads will
1567 * stack.
1569 static void *adjust_timer_thread(void *arg)
1571 CACHE_LOCK(NULL);
1572 cache_adjust_timer();
1573 CACHE_UNLOCK;
1574 return NULL;
1577 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1578 pth_attr_t attr)
1580 pth_status_t ev_status;
1582 if (timeout_ev) {
1583 pth_event_isolate(timeout_ev);
1584 ev_status = pth_event_status(timeout_ev);
1585 pth_event_free(timeout_ev, PTH_FREE_THIS);
1587 if (ev_status == PTH_STATUS_OCCURRED) {
1589 * The timer event has expired. Update the file cache. When the
1590 * cache mutex is locked and the timer expires again, the threads
1591 * will stack.
1593 pth_spawn(attr, adjust_timer_thread, NULL);
1597 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1600 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1601 gint keepalive)
1603 pth_event_t ev = NULL;
1604 pth_status_t ev_status;
1606 if (keepalive_ev) {
1607 pth_event_isolate(keepalive_ev);
1608 ev_status = pth_event_status(keepalive_ev);
1610 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1611 if (ev_status == PTH_STATUS_OCCURRED)
1612 send_status_all(STATUS_KEEPALIVE);
1614 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1616 else
1617 ev = keepalive_ev;
1620 if (keepalive > 0 && !ev)
1621 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1623 return ev;
1626 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1628 pth_t accept_tid;
1629 #ifdef WITH_GNUTLS
1630 pth_t tcp_accept_tid;
1631 #endif
1632 guint n;
1633 sigset_t set;
1634 gint n_clients = 0;
1635 pth_attr_t attr;
1636 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1637 gint keepalive = get_key_file_integer("global", "keepalive");
1638 gpointer value;
1640 pth_mutex_init(&cn_mutex);
1641 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1642 sigemptyset(&set);
1643 sigaddset(&set, SIGTERM);
1644 sigaddset(&set, SIGINT);
1645 sigaddset(&set, SIGUSR1);
1646 sigaddset(&set, SIGHUP);
1647 sigaddset(&set, SIGABRT);
1649 attr = pth_attr_new();
1650 pth_attr_init(attr);
1651 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1652 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1653 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1655 #ifdef WITH_GNUTLS
1656 if (sockfd_r != -1) {
1657 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1658 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1660 #endif
1662 pth_attr_init(attr);
1663 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1664 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1667 * For the cache_timeout configuration parameter.
1669 timeout_ev = timeout_event_iterate(NULL, attr);
1670 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1671 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1673 do {
1674 gint sig = 0;
1676 pth_sigwait_ev(&set, &sig, timeout_ev);
1677 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1678 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1679 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1681 if (sig > 0) {
1682 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1684 /* Caught a signal. */
1685 switch (sig) {
1686 case SIGHUP:
1687 reload_rcfile();
1688 keepalive = get_key_file_integer("global", "keepalive");
1689 break;
1690 case SIGABRT:
1691 CACHE_LOCK(NULL);
1692 cache_clear(NULL, 2);
1693 CACHE_UNLOCK;
1694 #ifndef MEM_DEBUG
1695 xpanic();
1696 #endif
1697 exit(EXIT_FAILURE);
1698 case SIGUSR1:
1699 CACHE_LOCK(NULL);
1700 log_write(N_("clearing file cache"));
1701 cache_clear(NULL, 2);
1702 CACHE_UNLOCK;
1703 break;
1704 default:
1705 quit = 1;
1706 shutdown(sockfd, SHUT_RDWR);
1707 close(sockfd);
1709 if (sockfd_r != -1) {
1710 shutdown(sockfd_r, SHUT_RDWR);
1711 close(sockfd_r);
1713 break;
1716 } while (!quit);
1719 * We're out of the main server loop. This happens when a signal was sent
1720 * to terminate the daemon. We'll wait for all clients to disconnect
1721 * before exiting and ignore any following signals.
1723 pth_join(accept_tid, &value);
1725 #ifdef WITH_GNUTLS
1726 if (sockfd_r != -1) {
1727 pth_cancel(tcp_accept_tid);
1728 pth_join(tcp_accept_tid, &value);
1730 #endif
1732 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1733 unlink(*socketpath);
1734 g_free(*socketpath);
1735 *socketpath = NULL;
1737 if (n > 1)
1738 log_write(N_("waiting for all threads to terminate"));
1740 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1742 while (n > 1) {
1743 if (n != n_clients) {
1744 log_write(N_("%i threads remain"), n-1);
1745 n_clients = n;
1748 pth_wait(ev_quit);
1749 pth_event_isolate(ev_quit);
1750 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1751 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1752 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1753 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1756 pth_event_free(timeout_ev, PTH_FREE_THIS);
1757 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1758 pth_event_free(ev_quit, PTH_FREE_THIS);
1759 pth_attr_destroy(attr);
1760 cache_free();
1764 * Called from pinentry_fork() in the child process.
1766 void free_client_list()
1768 gint i, t = g_slist_length(cn_thread_list);
1770 for (i = 0; i < t; i++) {
1771 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1773 free_client(cn->cl);
1776 cache_free();
1779 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1780 const gchar *outfile)
1782 file_header_internal_t *fh;
1783 gpg_error_t rc;
1784 guchar *md5file;
1785 guchar *shakey;
1786 guint iter;
1788 md5file = gcry_malloc(16);
1789 if (!md5file)
1790 return GPG_ERR_ENOMEM;
1792 shakey = gcry_malloc(gcrykeysize);
1793 if (!shakey) {
1794 gcry_free(md5file);
1795 return GPG_ERR_ENOMEM;
1798 fh = read_file_header(filename, TRUE, &rc);
1800 if (!fh)
1801 goto done;
1803 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1805 /* The header in version 1 had a bug where the iterations were off-by-one.
1806 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1807 * header.
1809 if (fh->fh1.iter >= 0) {
1810 if (keyfile) {
1811 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1813 if (!tmp) {
1814 rc = GPG_ERR_UNKNOWN_ERRNO;
1815 goto done;
1818 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1819 strlen(tmp) ? strlen(tmp) : 1);
1820 gcry_free(tmp);
1821 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1823 else {
1824 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1825 == FALSE) {
1826 rc = GPG_ERR_UNKNOWN_ERRNO;
1827 close(fh->fd);
1828 goto done;
1832 else
1833 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1835 close(fh->fd);
1837 if (rc)
1838 goto done;
1840 rc = convert_xml((gchar **)&fh->doc, &fh->len);
1842 if (rc) {
1843 gcry_free(fh->doc);
1844 log_write("%s: %s", filename, pwmd_strerror(rc));
1845 goto done;
1848 fh->v1 = FALSE;
1849 iter = fh->fh1.iter;
1850 memset(&fh->fh2, 0, sizeof(fh->fh2));
1851 /* Keep the iterations and key from the original file. */
1852 fh->fh2.iter = iter+1;
1853 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1855 if (rc)
1856 send_error(NULL, rc);
1858 done:
1859 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1860 gcry_free(shakey);
1861 gcry_free(md5file);
1862 g_free(fh);
1863 return rc;
1866 int main(int argc, char *argv[])
1868 gint opt;
1869 struct sockaddr_un addr;
1870 struct passwd *pw = getpwuid(getuid());
1871 gchar buf[PATH_MAX];
1872 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1873 gchar *socketarg = NULL;
1874 gchar *datadir = NULL;
1875 gboolean n;
1876 gchar *p;
1877 gchar **cache_push = NULL;
1878 gint iter = 0;
1879 gchar *import = NULL, *keyfile = NULL;
1880 gulong cmd_iterations = -1;
1881 gint default_timeout;
1882 gint rcfile_spec = 0;
1883 gint estatus = EXIT_FAILURE;
1884 gint sockfd, sockfd_r = -1;
1885 gchar *outfile = NULL;
1886 #ifndef MEM_DEBUG
1887 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1888 #endif
1889 gint do_unlink = 1;
1890 gboolean secure = FALSE;
1891 guint ptotal = 0;
1892 gint background = 1;
1893 sigset_t set;
1894 gchar *convert = NULL;
1895 #ifdef WITH_PINENTRY
1896 gboolean disable_pinentry = FALSE;
1897 #endif
1898 #ifdef WITH_GNUTLS
1899 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1900 gint ret;
1901 #endif
1902 #ifndef DEBUG
1903 #ifdef HAVE_SETRLIMIT
1904 struct rlimit rl;
1906 rl.rlim_cur = rl.rlim_max = 0;
1908 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1909 err(EXIT_FAILURE, "setrlimit()");
1910 #endif
1911 #endif
1913 #ifdef ENABLE_NLS
1914 setlocale(LC_ALL, "");
1915 bindtextdomain("pwmd", LOCALEDIR);
1916 textdomain("pwmd");
1917 #endif
1919 gpg_err_init();
1920 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1921 #ifndef MEM_DEBUG
1922 g_mem_set_vtable(&mtable);
1923 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1924 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1925 xmlInitMemory();
1926 #ifdef WITH_GNUTLS
1927 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1928 xrealloc, xfree);
1929 #endif
1930 #endif
1931 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1932 #ifdef WITH_GNUTLS
1933 gnutls_global_init();
1934 gnutls_global_set_log_function(tls_log);
1935 gnutls_global_set_log_level(1);
1936 assuan_set_io_hooks(&io_hooks);
1937 #endif
1938 pth_init();
1939 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1941 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1942 err(EXIT_FAILURE, "%s", buf);
1944 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1946 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1947 err(EXIT_FAILURE, "%s", buf);
1949 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1951 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1952 err(EXIT_FAILURE, "sysconf()");
1954 cmdline = TRUE;
1956 while ((opt = getopt(argc, argv, "Po:C:bnI:i:k:hvf:D")) != EOF) {
1957 switch (opt) {
1958 #ifdef WITH_PINENTRY
1959 case 'P':
1960 disable_pinentry = TRUE;
1961 break;
1962 #endif
1963 case 'o':
1964 outfile = optarg;
1965 break;
1966 case 'C':
1967 convert = optarg;
1968 break;
1969 case 'b':
1970 /* Compatibility for version < 1.11 */
1971 break;
1972 case 'n':
1973 background = 0;
1974 break;
1975 case 'D':
1976 secure = TRUE;
1977 break;
1978 case 'I':
1979 import = optarg;
1980 break;
1981 case 'i':
1982 cmd_iterations = strtol(optarg, NULL, 10);
1983 break;
1984 case 'k':
1985 keyfile = optarg;
1986 break;
1987 case 'f':
1988 g_free(rcfile);
1989 rcfile = g_strdup(optarg);
1990 rcfile_spec = 1;
1991 break;
1992 case 'v':
1993 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,
1994 PACKAGE_BUGREPORT,
1995 #ifdef WITH_PINENTRY
1996 "+WITH_PINENTRY\n"
1997 #else
1998 "-WITH_PINENTRY\n"
1999 #endif
2000 #ifdef WITH_QUALITY
2001 "+WITH_QUALITY\n"
2002 #else
2003 "-WITH_QUALITY\n"
2004 #endif
2005 #ifdef WITH_GNUTLS
2006 "+WITH_GNUTLS\n"
2007 #else
2008 "-WITH_GNUTLS\n"
2009 #endif
2010 #ifdef DEBUG
2011 "+DEBUG\n"
2012 #else
2013 "-DEBUG\n"
2014 #endif
2015 #ifdef MEM_DEBUG
2016 "+MEM_DEBUG\n"
2017 #else
2018 "-MEM_DEBUG\n"
2019 #endif
2021 exit(EXIT_SUCCESS);
2022 case 'h':
2023 default:
2024 usage(argv[0]);
2028 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2029 exit(EXIT_FAILURE);
2031 #ifdef WITH_PINENTRY
2032 if (disable_pinentry == TRUE)
2033 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2034 #endif
2036 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2037 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2039 if (log_syslog == TRUE)
2040 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2042 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2043 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2044 errno = 0;
2046 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2047 log_write("setpriority(): %s", strerror(errno));
2048 goto do_exit;
2052 #ifdef HAVE_MLOCKALL
2053 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2054 log_write("mlockall(): %s", strerror(errno));
2055 goto do_exit;
2057 #endif
2059 setup_gcrypt();
2061 if (convert) {
2062 if (!outfile)
2063 usage(argv[0]);
2065 opt = convert_file(convert, keyfile, outfile);
2066 g_key_file_free(keyfileh);
2067 g_free(rcfile);
2068 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2071 if (import) {
2072 if (!outfile)
2073 usage(argv[0]);
2075 if (cmd_iterations == -1)
2076 cmd_iterations = get_key_file_integer("global", "iterations");
2078 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2079 g_key_file_free(keyfileh);
2080 g_free(rcfile);
2081 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2084 g_key_file_set_list_separator(keyfileh, ',');
2086 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2087 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2089 if (*p == '~') {
2090 p++;
2091 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2092 g_free(p);
2093 socketarg = g_strdup(buf);
2095 else
2096 socketarg = p;
2098 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2099 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2101 datadir = expand_homedir(p);
2102 g_free(p);
2104 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2105 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2106 disable_list_and_dump = n;
2108 else
2109 disable_list_and_dump = secure;
2111 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2112 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2113 else
2114 default_timeout = -1;
2116 setup_logging(keyfileh);
2118 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2119 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2121 if (argc != optind) {
2122 if (cache_push)
2123 ptotal = g_strv_length(cache_push);
2125 for (; optind < argc; optind++) {
2126 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2127 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2131 if (strchr(socketarg, '/') == NULL) {
2132 socketdir = g_get_current_dir();
2133 socketname = g_strdup(socketarg);
2134 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2136 else {
2137 socketname = g_strdup(strrchr(socketarg, '/'));
2138 socketname++;
2139 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2140 socketdir = g_strdup(socketarg);
2141 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2144 if (chdir(datadir)) {
2145 log_write("%s: %s", datadir, strerror(errno));
2146 unlink(socketpath);
2147 goto do_exit;
2150 if (parse_rcfile_keys(TRUE) == FALSE)
2151 goto do_exit;
2153 clear_rcfile_keys();
2156 * Set the cache entry for a file. Prompts for the password.
2158 if (cache_push) {
2159 for (opt = 0; cache_push[opt]; opt++)
2160 do_cache_push(cache_push[opt], NULL);
2162 g_strfreev(cache_push);
2163 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2167 * bind() doesn't like the full pathname of the socket or any non alphanum
2168 * characters so change to the directory where the socket is wanted then
2169 * create it then change to datadir.
2171 if (chdir(socketdir)) {
2172 log_write("%s: %s", socketdir, strerror(errno));
2173 goto do_exit;
2176 g_free(socketdir);
2178 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2179 log_write("socket(): %s", strerror(errno));
2180 goto do_exit;
2183 addr.sun_family = AF_UNIX;
2184 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2186 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2187 log_write("bind(): %s", strerror(errno));
2189 if (errno == EADDRINUSE)
2190 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2191 "stale socket. Please remove it manually."), socketpath);
2193 do_unlink = 0;
2194 goto do_exit;
2197 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2198 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2199 mode_t mode = strtol(t, NULL, 8);
2200 mode_t mask = umask(0);
2202 g_free(t);
2204 if (chmod(socketname, mode) == -1) {
2205 log_write("%s: %s", socketname, strerror(errno));
2206 close(sockfd);
2207 unlink(socketpath);
2208 umask(mask);
2209 goto do_exit;
2212 umask(mask);
2215 g_free(--socketname);
2217 if (chdir(datadir)) {
2218 log_write("%s: %s", datadir, strerror(errno));
2219 close(sockfd);
2220 unlink(socketpath);
2221 goto do_exit;
2224 g_free(datadir);
2225 pth_mutex_init(&cache_mutex);
2226 #ifdef WITH_PINENTRY
2227 pth_mutex_init(&pin_mutex);
2228 #endif
2230 if (listen(sockfd, 0) == -1) {
2231 log_write("listen(): %s", strerror(errno));
2232 goto do_exit;
2235 #ifdef WITH_GNUTLS
2236 if (get_key_file_boolean("global", "enable_tcp")) {
2237 gchar *tmp, *tmp2;
2238 struct addrinfo hints, *servinfo, *p;
2239 gint port = get_key_file_integer("global", "tcp_port");
2240 char buf[7];
2242 memset(&hints, 0, sizeof(hints));
2243 hints.ai_family = AF_UNSPEC;
2244 hints.ai_socktype = SOCK_STREAM;
2245 hints.ai_flags = AI_PASSIVE;
2247 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2248 &hints, &servinfo)) == -1) {
2249 log_write("getaddrinfo(): %s", gai_strerror(opt));
2250 goto do_exit;
2253 for(p = servinfo; p != NULL; p = p->ai_next) {
2254 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2255 p->ai_protocol)) == -1) {
2256 log_write("socket(): %s", strerror(errno));
2257 continue;
2260 opt = 1;
2262 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2263 sizeof(int)) == -1) {
2264 log_write("setsockopt(): %s", strerror(errno));
2265 goto do_exit;
2268 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2269 close(sockfd_r);
2270 log_write("bind(): %s", strerror(errno));
2271 continue;
2274 opt++;
2275 break;
2278 freeaddrinfo(servinfo);
2280 if (!p) {
2281 log_write("%s", N_("could not bind"));
2282 goto do_exit;
2285 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2286 gchar *tmp = get_key_file_string("global", "tcp_interface");
2288 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2289 == -1) {
2290 log_write("setsockopt(): %s", strerror(errno));
2291 g_free(tmp);
2292 goto do_exit;
2295 g_free(tmp);
2298 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2300 if (ret != GNUTLS_E_SUCCESS) {
2301 log_write("%s", gnutls_strerror(ret));
2302 goto do_exit;
2305 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2307 if (!tmp) {
2308 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2309 goto do_exit;
2312 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2313 GNUTLS_X509_FMT_PEM);
2314 g_free(tmp);
2316 if (ret < 0) {
2317 log_write("%s", gnutls_strerror(ret));
2318 goto do_exit;
2321 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2323 if (!tmp) {
2324 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2325 goto do_exit;
2328 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2330 if (!tmp2) {
2331 xfree(tmp);
2332 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2333 goto do_exit;
2336 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2337 GNUTLS_X509_FMT_PEM);
2338 g_free(tmp);
2339 g_free(tmp2);
2341 if (ret != GNUTLS_E_SUCCESS) {
2342 log_write("%s", gnutls_strerror(ret));
2343 goto do_exit;
2346 #endif
2348 if (background) {
2349 switch (fork()) {
2350 case -1:
2351 log_write("fork(): %s", strerror(errno));
2352 goto do_exit;
2353 case 0:
2354 close(0);
2355 close(1);
2356 close(2);
2357 setsid();
2358 break;
2359 default:
2360 exit(EXIT_SUCCESS);
2364 cmdline = FALSE;
2366 #ifdef WITH_GNUTLS
2367 if (get_key_file_boolean("global", "enable_tcp")) {
2368 log_write("%s", N_("Generating key exchange parameters..."));
2369 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2371 if (ret) {
2372 log_write("%s", gpg_strerror(ret));
2373 goto do_exit;
2376 ret = gnutls_dh_params_init(&dh_params);
2378 if (ret != GNUTLS_E_SUCCESS) {
2379 log_write("%s", gnutls_strerror(ret));
2380 goto do_exit;
2383 ret = gnutls_dh_params_generate2(dh_params, 1024);
2385 if (ret != GNUTLS_E_SUCCESS) {
2386 log_write("%s", gnutls_strerror(ret));
2387 goto do_exit;
2390 gnutls_certificate_set_dh_params(x509_cred, dh_params);
2391 ret = gnutls_rsa_params_init(&rsa_params);
2393 if (ret != GNUTLS_E_SUCCESS) {
2394 log_write("%s", gnutls_strerror(ret));
2395 goto do_exit;
2398 ret = gnutls_rsa_params_generate2(rsa_params, 512);
2400 if (ret != GNUTLS_E_SUCCESS) {
2401 log_write("%s", gnutls_strerror(ret));
2402 goto do_exit;
2405 gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
2406 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2408 if (listen(sockfd_r, 0) == -1) {
2409 log_write("listen(): %s", strerror(errno));
2410 goto do_exit;
2413 #endif
2416 * These are the signals that we use in threads. libpth can catch signals
2417 * itself so ignore them everywhere else. Note that using
2418 * signal(N, SIG_IGN) doesn't work like you might think.
2420 sigemptyset(&set);
2422 /* Termination */
2423 sigaddset(&set, SIGTERM);
2424 sigaddset(&set, SIGINT);
2426 /* Configuration file reloading. */
2427 sigaddset(&set, SIGUSR1);
2429 /* Clears the file cache. */
2430 sigaddset(&set, SIGHUP);
2432 /* Caught in client_thread(). Sends a cache status message. */
2433 sigaddset(&set, SIGUSR2);
2435 /* Ignored everywhere. When a client disconnects abnormally this signal
2436 * gets raised. It isn't needed though because client_thread() will check
2437 * for rcs even after the client disconnects. */
2438 signal(SIGPIPE, SIG_IGN);
2439 pth_sigmask(SIG_BLOCK, &set, NULL);
2440 server_loop(sockfd, sockfd_r, &socketpath);
2441 estatus = EXIT_SUCCESS;
2443 do_exit:
2444 if (socketpath && do_unlink) {
2445 unlink(socketpath);
2446 g_free(socketpath);
2449 #ifdef WITH_GNUTLS
2450 if (sockfd_r != -1) {
2451 gnutls_dh_params_deinit(dh_params);
2452 gnutls_rsa_params_deinit(rsa_params);
2454 if (x509_cred)
2455 gnutls_certificate_free_credentials(x509_cred);
2457 gnutls_global_deinit();
2459 #endif
2461 g_key_file_free(keyfileh);
2462 g_free(rcfile);
2463 xmlCleanupParser();
2465 if (estatus == EXIT_SUCCESS)
2466 log_write(N_("pwmd exiting normally"));
2468 pth_kill();
2469 #if defined(DEBUG) && !defined(MEM_DEBUG)
2470 xdump();
2471 #endif
2472 exit(estatus);