Show the output filename and not stdout in the import notify string when
[pwmd.git] / src / pwmd.c
blob248f401bac83d9d344834928b89d70dd4c52ca06
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;
103 GKeyFile *k;
105 log_write(N_("reloading configuration file '%s'"), rcfile);
106 k = parse_rcfile(0);
108 if (!k)
109 return;
111 g_key_file_free(keyfileh);
112 keyfileh = k;
113 parse_rcfile_keys(FALSE);
114 clear_rcfile_keys();
115 disable_list_and_dump = b;
116 send_status_all(STATUS_CONFIG);
119 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
121 gpg_error_t n = gpg_error_from_errno(e);
123 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
126 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
128 gpg_err_code_t n = gpg_err_code(e);
129 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
130 struct client_s *client = assuan_get_pointer(ctx);
132 if (!e)
133 return assuan_process_done(ctx, 0);
135 if (!ctx) {
136 log_write("%s", pwmd_strerror(e));
137 return e;
140 if (n == EPWMD_LIBXML_ERROR) {
141 xmlErrorPtr xe = client->xml_error;
143 if (!xe)
144 xe = xmlGetLastError();
146 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
147 log_write("%s", xe->message);
149 if (xe == client->xml_error)
150 xmlResetError(xe);
151 else
152 xmlResetLastError();
154 client->xml_error = NULL;
155 return e;
158 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
161 void log_write(const gchar *fmt, ...)
163 gchar *args, *line;
164 va_list ap;
165 struct tm *tm;
166 time_t now;
167 gchar tbuf[21];
168 gint fd = -1;
169 pth_attr_t attr;
170 gchar *name;
171 pth_t tid = pth_self();
172 gchar tid_str[12], *p;
174 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
175 return;
177 if (!cmdline && logfile) {
178 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
179 warn("%s", logfile);
180 return;
184 va_start(ap, fmt);
186 if (g_vasprintf(&args, fmt, ap) == -1) {
187 if (logfile)
188 close(fd);
190 va_end(ap);
191 return;
194 va_end(ap);
196 if (cmdline) {
197 fprintf(stderr, "%s\n", args);
198 fflush(stderr);
199 g_free(args);
200 return;
203 attr = pth_attr_of(tid);
205 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
206 name = "unknown";
208 pth_attr_destroy(attr);
209 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
210 p = tid_str;
212 if (strncmp(p+1, name, 9) == 0)
213 p = NULL;
215 if (!cmdline && log_syslog == TRUE)
216 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
218 time(&now);
219 tm = localtime(&now);
220 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
221 tbuf[sizeof(tbuf) - 1] = 0;
223 if (args[strlen(args)-1] == '\n')
224 args[strlen(args)-1] = 0;
226 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
227 p ? p : "", args);
228 g_free(args);
230 if (!line) {
231 if (logfile)
232 close(fd);
234 return;
237 if (logfile) {
238 write(fd, line, strlen(line));
239 fsync(fd);
240 close(fd);
243 if (isatty(STDERR_FILENO)) {
244 fprintf(stderr, "%s", line);
245 fflush(stderr);
248 g_free(line);
251 static void usage(gchar *pn)
253 g_fprintf(stderr, N_(
254 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
255 "[-I <filename> [-i <iter>]]\n "
256 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
257 " -n run as a foreground process\n"
258 " -f load the specified rcfile (~/.pwmd/config)\n"
259 " -C convert a version 1 data file to version 2\n"
260 " -I import an XML file\n"
261 " -i encrypt with the specified number of iterations when importing\n"
262 " (config default in the \"global\" section)\n"
263 " -k obtain the key from the specified file\n"
264 " -o output file for use with the -C and -I options\n"
265 " -D disable use of the LIST and DUMP commands\n"
266 " -P disable pinentry\n"
267 " -v version\n"
268 " -h this help text\n"
269 ), pn);
270 exit(EXIT_FAILURE);
273 #ifndef MEM_DEBUG
274 static int gcry_SecureCheck(const void *ptr)
276 return 1;
278 #endif
280 static void setup_gcrypt()
282 gcry_check_version(NULL);
284 #ifndef MEM_DEBUG
285 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
286 xfree);
287 #endif
289 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
290 NULL) != 0)
291 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
293 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
294 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
297 static gint new_connection(struct client_s *cl)
299 gpg_error_t rc;
300 gchar ver[ASSUAN_LINELENGTH];
302 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
304 if (rc)
305 goto fail;
307 assuan_set_pointer(cl->ctx, cl);
308 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
309 assuan_set_hello_line(cl->ctx, ver);
310 rc = register_commands(cl->ctx);
312 if (rc)
313 goto fail;
315 rc = assuan_accept(cl->ctx);
317 if (rc)
318 goto fail;
320 return 0;
322 fail:
323 log_write("%s", gpg_strerror(rc));
324 return 1;
327 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which,
328 const gchar *fmt, ...)
330 gchar *line = NULL;
331 struct client_s *client = assuan_get_pointer(ctx);
332 gchar buf[ASSUAN_LINELENGTH];
333 gchar *status = NULL;
334 va_list ap;
336 if (fmt) {
337 va_start(ap, fmt);
338 g_vsnprintf(buf, sizeof(buf), fmt, ap);
339 va_end(ap);
340 line = buf;
343 switch (which) {
344 case STATUS_CACHE:
345 CACHE_LOCK(client->ctx);
346 line = print_fmt(buf, sizeof(buf), "%i", cache_file_count());
347 CACHE_UNLOCK;
348 status = "CACHE";
349 break;
350 case STATUS_CLIENTS:
351 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
352 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
353 pth_mutex_release(&cn_mutex);
354 status = "CLIENTS";
355 break;
356 case STATUS_CONFIG:
357 status = "CONFIG";
358 break;
359 case STATUS_KEEPALIVE:
360 status = "KEEPALIVE";
361 break;
362 case STATUS_LOCKED:
363 status = "LOCKED";
364 line = N_("Waiting for lock");
365 break;
366 case STATUS_ENCRYPT:
367 status = "ENCRYPT";
368 break;
369 case STATUS_DECRYPT:
370 status = "DECRYPT";
371 break;
372 case STATUS_DECOMPRESS:
373 status = "DECOMPRESS";
374 break;
375 case STATUS_COMPRESS:
376 status = "COMPRESS";
377 break;
380 if (!ctx) {
381 log_write("%s %s", status, line);
382 return 0;
385 return assuan_write_status(ctx, status, line);
388 void send_status_all(status_msg_t which)
390 guint i, t;
392 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
394 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
395 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
396 pth_msgport_t m = pth_msgport_find(cn->msg_name);
398 if (m) {
399 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
401 msg->m_data = (status_msg_t *)which;
402 pth_msgport_put(m, msg);
406 pth_mutex_release(&cn_mutex);
409 static void xml_error_cb(void *data, xmlErrorPtr e)
411 struct client_s *client = data;
414 * Keep the first reported error as the one to show in the error
415 * description. Reset in send_error().
417 if (client->xml_error)
418 return;
420 xmlCopyError(e, client->xml_error);
424 * This is called after a child_thread terminates. Set with
425 * pth_cleanup_push().
427 static void cleanup_cb(void *arg)
429 struct client_thread_s *cn = arg;
430 gpointer value;
431 struct client_s *cl = cn->cl;
433 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
434 log_write(N_("exiting, fd=%i"), cn->fd);
436 if (cn->msg_tid) {
437 pth_cancel(cn->msg_tid);
438 pth_join(cn->msg_tid, &value);
439 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
442 if (cn->msg_name)
443 g_free(cn->msg_name);
445 if (cn->msg) {
446 while (pth_msgport_pending(cn->msg) > 0) {
447 pth_message_t *m = pth_msgport_get(cn->msg);
449 g_free(m);
452 pth_msgport_destroy(cn->msg);
455 pth_join(cn->tid, &value);
457 if (cl && cl->freed == FALSE)
458 cleanup_client(cl);
460 #ifdef WITH_GNUTLS
461 if (cn->tls) {
462 gnutls_deinit(cn->tls->ses);
464 if (cn->tls->fp)
465 g_free(cn->tls->fp);
467 g_free(cn->tls);
469 #endif
471 if (cl && cl->ctx)
472 assuan_deinit_server(cl->ctx);
474 #ifdef WITH_PINENTRY
475 if (cl && cl->pinentry)
476 cleanup_pinentry(cl->pinentry);
477 #endif
479 g_free(cl);
480 cn_thread_list = g_slist_remove(cn_thread_list, cn);
481 g_free(cn);
482 pth_mutex_release(&cn_mutex);
483 send_status_all(STATUS_CLIENTS);
486 static void *client_msg_thread(void *data)
488 struct client_s *cl = data;
489 pth_status_t ev_status;
491 for (;;) {
492 pth_wait(cl->thd->msg_ev);
493 ev_status = pth_event_status(cl->thd->msg_ev);
495 if (ev_status == PTH_STATUS_FAILED) {
496 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
497 __FUNCTION__);
498 continue;
501 if (ev_status == PTH_STATUS_OCCURRED) {
502 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
504 while (pth_msgport_pending(cl->thd->msg) > 0) {
505 pth_message_t *m = pth_msgport_get(cl->thd->msg);
506 status_msg_t n = (status_msg_t)m->m_data;
507 gpg_error_t rc = send_status(cl->ctx, n, NULL);
509 g_free(m);
511 if (rc) {
512 pth_mutex_release(&cn_mutex);
513 log_write("%s", gpg_strerror(rc));
514 break;
518 pth_mutex_release(&cn_mutex);
524 * Called every time a connection is made via pth_spawn(). This is the thread
525 * entry point.
527 static void *client_thread(void *data)
529 struct client_thread_s *thd = data;
530 pth_event_t ev;
531 struct client_s *cl = g_malloc0(sizeof(struct client_s));
532 gpg_error_t rc;
533 pth_attr_t attr;
534 int n;
537 * Prevent a race condition with init_new_connection() if this thread
538 * fails (returns) for some reason before init_new_connection() releases
539 * the cn_mutex.
541 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
542 pth_mutex_release(&cn_mutex);
544 if (!cl) {
545 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
546 goto fail;
549 thd->cl = cl;
550 cl->thd = thd;
551 pth_cleanup_push(cleanup_cb, thd);
553 #ifdef WITH_GNUTLS
555 * Do the TLS handshake before anything else.
557 if (thd->remote) {
558 gchar *prio = get_key_file_string("global", "cipher_suite");
560 thd->tls = tls_init(thd->fd, prio);
561 g_free(prio);
563 if (!thd->tls) {
564 close(thd->fd);
565 goto fail;
568 #endif
571 * This is a "child" thread. Don't catch any signals. Let the master
572 * thread take care of signals in server_loop().
574 if (new_connection(cl))
575 goto fail;
577 #ifdef WITH_PINENTRY
578 cl->pinentry = pinentry_init();
580 if (!cl->pinentry) {
581 g_free(cl);
582 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
583 goto fail;
585 #endif
587 thd->msg_name = g_strdup_printf("%p", thd->tid);
589 if (!thd->msg_name) {
590 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
591 goto fail;
594 thd->msg = pth_msgport_create(thd->msg_name);
596 if (!thd->msg) {
597 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
598 goto fail;
601 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
602 attr = pth_attr_new();
603 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
604 pth_attr_set(attr, PTH_ATTR_NAME, "client_msg");
605 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
606 n = errno;
607 pth_attr_destroy(attr);
609 if (!thd->msg_tid) {
610 log_write("pth_spawn(): %s", strerror(n));
611 goto fail;
614 #ifdef HAVE_MLOCKALL
615 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
616 log_write("mlockall(): %s", strerror(errno));
617 goto fail;
619 #endif
621 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
623 if (rc) {
624 log_write("%s", gpg_strerror(rc));
625 goto fail;
628 send_status_all(STATUS_CLIENTS);
629 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
630 xmlInitParser();
631 xmlXPathInit();
632 xmlSetStructuredErrorFunc(cl, xml_error_cb);
634 for (;;) {
635 pth_status_t ev_status;
637 pth_wait(ev);
638 ev_status = pth_event_status(ev);
640 if (ev_status == PTH_STATUS_FAILED) {
641 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
642 __FUNCTION__);
643 goto done;
645 else if (ev_status == PTH_STATUS_OCCURRED) {
646 rc = assuan_process_next(cl->ctx);
648 if (rc) {
649 cl->inquire_status = INQUIRE_INIT;
651 if (gpg_err_code(rc) == GPG_ERR_EOF)
652 goto done;
654 log_write("assuan_process_next(): %s", gpg_strerror(rc));
655 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
657 if (rc) {
658 log_write("assuan_process_done(): %s", gpg_strerror(rc));
659 goto done;
662 else {
663 #ifdef WITH_PINENTRY
664 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
665 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
666 pth_event_concat(ev, cl->pinentry->ev, NULL);
667 cl->pinentry->status = PINENTRY_RUNNING;
669 #endif
671 switch (cl->inquire_status) {
672 case INQUIRE_BUSY:
673 case INQUIRE_INIT:
674 break;
675 case INQUIRE_DONE:
676 cl->inquire_status = INQUIRE_INIT;
677 rc = assuan_process_done(cl->ctx, 0);
678 break;
683 #ifdef WITH_PINENTRY
684 ev = pinentry_iterate(cl, ev);
685 #endif
689 * Client cleanup (including XML data) is done in cleanup_cb() from
690 * the cleanup thread.
692 done:
693 pth_event_free(ev, PTH_FREE_ALL);
695 fail:
696 pth_exit(NULL);
697 return NULL;
700 static void setup_logging(GKeyFile *kf)
702 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
704 if (n == TRUE) {
705 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
707 if (*p == '~') {
708 gchar buf[PATH_MAX];
710 p++;
711 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
712 g_free(p);
714 if (logfile)
715 g_free(logfile);
717 logfile = g_strdup(buf);
719 else {
720 if (logfile)
721 g_free(logfile);
723 logfile = p;
727 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
731 * Make sure all settings are set to either the specified setting or a
732 * default.
734 static void set_rcfile_defaults(GKeyFile *kf)
736 gchar buf[PATH_MAX];
738 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
739 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
740 g_key_file_set_string(kf, "global", "socket_path", buf);
743 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
744 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
745 g_key_file_set_string(kf, "global", "data_directory", buf);
748 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
749 g_key_file_set_boolean(kf, "global", "backup", TRUE);
751 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
752 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
753 g_key_file_set_string(kf, "global", "log_path", buf);
756 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
757 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
759 #ifdef HAVE_MLOCKALL
760 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
761 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
762 #endif
764 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
765 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
767 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
768 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
769 g_key_file_set_integer(kf, "global", "iterations", 1);
771 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
772 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
774 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
775 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
777 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
778 g_key_file_set_integer(kf, "global", "compression_level", 6);
780 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
781 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
783 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
784 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
786 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
788 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
789 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
791 #ifdef HAVE_MLOCKALL
792 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
793 #endif
795 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
796 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
798 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
799 g_key_file_set_integer(kf, "global", "keepalive", 30);
801 #ifdef WITH_PINENTRY
802 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
803 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
805 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
806 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
807 #endif
809 #ifdef WITH_GNUTLS
810 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
811 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
813 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
814 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
816 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
817 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
819 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
820 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
822 if (g_key_file_has_key(kf, "global", "cipher_suite", NULL) == FALSE)
823 g_key_file_set_string(kf, "global", "cipher_suite", "SECURE256");
824 #endif
826 setup_logging(kf);
829 static GKeyFile *parse_rcfile()
831 GKeyFile *kf = g_key_file_new();
832 GError *rc = NULL;
834 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
835 log_write("%s: %s", rcfile, rc->message);
836 g_clear_error(&rc);
838 if (cmdline)
839 return NULL;
841 if (rc->code == G_FILE_ERROR_NOENT) {
842 set_rcfile_defaults(kf);
843 return kf;
846 return NULL;
849 set_rcfile_defaults(kf);
850 return kf;
853 static gchar *do_get_password(const gchar *prompt)
855 gchar buf[LINE_MAX] = {0}, *p;
856 struct termios told, tnew;
857 gchar *key;
859 if (tcgetattr(STDIN_FILENO, &told) == -1) {
860 log_write("tcgetattr(): %s", strerror(errno));
861 return NULL;
864 memcpy(&tnew, &told, sizeof(struct termios));
865 tnew.c_lflag &= ~(ECHO);
866 tnew.c_lflag |= ICANON|ECHONL;
868 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
869 log_write("tcsetattr(): %s", strerror(errno));
870 tcsetattr(STDIN_FILENO, TCSANOW, &told);
871 return NULL;
874 fprintf(stderr, "%s", prompt);
876 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
877 tcsetattr(STDIN_FILENO, TCSANOW, &told);
878 return NULL;
881 tcsetattr(STDIN_FILENO, TCSANOW, &told);
882 p[strlen(p) - 1] = 0;
884 if (!buf[0]) {
885 key = gcry_malloc(1);
886 key[0] = 0;
888 else {
889 key = gcry_malloc(strlen(p) + 1);
890 sprintf(key, "%s", p);
893 memset(&buf, 0, sizeof(buf));
894 return key;
897 /* Only used when "enable_pinentry" is "false". */
898 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
899 guchar *key, pinentry_cmd_t which)
901 gint try = 0;
902 gchar *password;
903 gchar *prompt;
905 if (which == PINENTRY_SAVE) {
906 gchar *key1, *key2;
908 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
909 key1 = do_get_password(prompt);
910 g_free(prompt);
912 if (!key1) {
913 log_write(N_("%s: Skipping file"), filename);
914 return FALSE;
917 prompt = g_strdup_printf(N_("Repeat passphrase: "));
918 key2 = do_get_password(prompt);
919 g_free(prompt);
921 if (!key2) {
922 gcry_free(key1);
923 log_write(N_("%s: Skipping file"), filename);
924 return FALSE;
927 if (strcmp(key1, key2)) {
928 gcry_free(key1);
929 gcry_free(key2);
930 log_write(N_("%s: Passphrase mismatch"), filename);
931 return FALSE;
934 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
935 strlen(key1) ? strlen(key1) : 1);
936 gcry_free(key1);
937 gcry_free(key2);
938 return TRUE;
941 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
943 do {
944 gpg_error_t rc;
946 if ((password = do_get_password(prompt)) == NULL) {
947 log_write(N_("%s: Skipping file"), filename);
948 g_free(prompt);
949 return FALSE;
952 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
953 gcry_free(password);
955 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
957 if (!rc)
958 break;
960 log_write(N_("%s: Invalid passphrase"), filename);
961 } while (try++ < 2);
963 g_free(prompt);
965 if (try == 3)
966 return FALSE;
968 return TRUE;
972 * inbuf must have been allocated with gcry_malloc().
974 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
975 guchar *shakey, gpointer inbuf, gulong insize)
977 gcry_cipher_hd_t gh;
978 gpg_error_t rc;
979 gint level, zrc;
980 gulong outsize;
981 gpointer outbuf;
983 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
985 if (rc)
986 return rc;
988 level = get_key_file_integer(filename, "compression_level");
990 if (level < 0)
991 level = 0;
993 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
994 == FALSE) {
995 gcry_cipher_close(gh);
996 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
998 else {
999 gcry_free(inbuf);
1000 inbuf = outbuf;
1001 insize = outsize;
1004 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
1005 gcry_cipher_close(gh);
1006 return rc;
1009 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
1010 guchar *md5file, guchar *key, pinentry_cmd_t which)
1012 #ifdef WITH_PINENTRY
1013 gpg_error_t rc = 0;
1015 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
1016 == FALSE) {
1017 #endif
1018 return get_input(filename, fh, key, which);
1019 #ifdef WITH_PINENTRY
1021 else {
1022 gchar *result = NULL;
1023 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1024 gint try = 0;
1026 set_pinentry_defaults(pin);
1027 pin->which = which;
1028 pin->filename = g_strdup(filename);
1029 again:
1030 rc = pinentry_getpin(pin, &result);
1032 if (rc) {
1033 log_write("%s", gpg_strerror(rc));
1034 xfree(result);
1035 goto done;
1038 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1039 xfree(result);
1041 if (which == PINENTRY_SAVE) {
1042 cleanup_pinentry(pin);
1043 goto done;
1046 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1048 if (rc == EPWMD_BADKEY) {
1049 if (try++ == 2)
1050 log_write("%s: %s", filename, pwmd_strerror(rc));
1051 else {
1052 g_free(pin->title);
1053 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1054 goto again;
1057 else if (rc)
1058 log_write("%s", pwmd_strerror(rc));
1060 cleanup_pinentry(pin);
1063 done:
1064 return rc ? FALSE : TRUE;
1065 #endif
1068 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1070 FILE *fp;
1071 gchar buf[LINE_MAX] = {0}, *p;
1072 gchar *str = NULL;
1073 gint len;
1075 *rc = 0;
1077 if ((fp = fopen(file, "r")) == NULL) {
1078 *rc = gpg_error_from_syserror();
1079 return FALSE;
1082 p = fgets(buf, sizeof(buf), fp);
1083 fclose(fp);
1084 len = strlen(buf);
1086 if (len && buf[len - 1] == '\n')
1087 buf[--len] = 0;
1089 str = gcry_malloc(len + 1);
1091 if (!str) {
1092 *rc = gpg_error_from_errno(ENOMEM);
1093 return FALSE;
1096 memcpy(str, buf, len ? len : 1);
1097 str[len] = 0;
1098 memset(&buf, 0, sizeof(buf));
1099 *result = str;
1100 return TRUE;
1103 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import)
1105 GError *rv = NULL;
1106 gchar *t, *file = NULL, *str;
1107 gpg_error_t rc;
1109 if (import == FALSE) {
1110 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1111 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1113 if (!file) {
1114 if (rv) {
1115 log_write("%s: key_file: %s", rcfile, rv->message);
1116 g_clear_error(&rv);
1119 return NULL;
1122 t = expand_homedir(file);
1124 if (!t) {
1125 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1126 return NULL;
1129 g_free(file);
1130 file = t;
1133 else {
1134 /* -I or -C. The filename is a key file. */
1135 file = g_strdup(filename);
1137 if (!file) {
1138 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1139 return NULL;
1143 if (rv) {
1144 log_write("%s: key_file: %s", rcfile, rv->message);
1145 g_clear_error(&rv);
1146 return NULL;
1149 if (!file)
1150 return NULL;
1152 if (_getline(file, &str, &rc) == FALSE) {
1153 log_write("%s: %s", file, pwmd_strerror(rc));
1154 g_free(file);
1155 return NULL;
1158 g_free(file);
1159 return str;
1162 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1163 const gchar *keyfile, gulong iter)
1165 xmlDocPtr doc;
1166 gint fd;
1167 struct stat st;
1168 gint len;
1169 xmlChar *xmlbuf;
1170 xmlChar *xml;
1171 guchar shakey[gcrykeysize];
1172 gpg_error_t rc;
1173 file_header_internal_t fh;
1175 if (stat(filename, &st) == -1) {
1176 log_write("%s: %s", filename, strerror(errno));
1177 return FALSE;
1180 log_write(N_("Importing '%s'. Output will be written to '%s' ..."),
1181 filename, outfile);
1183 if (iter && keyfile) {
1184 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1186 if (!tmp)
1187 return FALSE;
1189 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1190 strlen(tmp) ? strlen(tmp) : 1);
1192 else if (iter && get_password(outfile, NULL, NULL, shakey, PINENTRY_SAVE)
1193 == FALSE)
1194 return FALSE;
1196 if ((fd = open(filename, O_RDONLY)) == -1) {
1197 memset(shakey, 0, sizeof(shakey));
1198 log_write("%s: %s", filename, strerror(errno));
1199 return FALSE;
1202 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1203 close(fd);
1204 memset(shakey, 0, sizeof(shakey));
1205 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1206 return FALSE;
1209 if (read(fd, xmlbuf, st.st_size) == -1) {
1210 memset(shakey, 0, sizeof(shakey));
1211 rc = errno;
1212 close(fd);
1213 errno = rc;
1214 err(EXIT_FAILURE, "%s", filename);
1217 close(fd);
1218 xmlbuf[st.st_size] = 0;
1221 * Make sure the document validates.
1223 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1224 log_write("xmlReadDoc() failed");
1225 close(fd);
1226 gcry_free(xmlbuf);
1227 memset(shakey, 0, sizeof(shakey));
1228 return FALSE;
1231 gcry_free(xmlbuf);
1232 xmlDocDumpMemory(doc, &xml, &len);
1233 xmlFreeDoc(doc);
1235 if (!iter)
1236 memset(shakey, '!', sizeof(shakey));
1238 memset(&fh, 0, sizeof(fh));
1239 fh.fh2.iter = iter;
1240 rc = export_common(outfile, &fh, shakey, xml, len);
1241 memset(shakey, 0, sizeof(shakey));
1243 if (rc)
1244 send_error(NULL, rc);
1246 return rc ? FALSE : TRUE;
1249 gchar *get_key_file_string(const gchar *section, const gchar *what)
1251 gchar *val = NULL;
1252 GError *grc = NULL;
1254 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1255 val = g_key_file_get_string(keyfileh, section, what, &grc);
1257 if (grc) {
1258 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1259 g_clear_error(&grc);
1262 else {
1263 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1264 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1266 if (grc) {
1267 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1268 g_clear_error(&grc);
1273 return val;
1276 gint get_key_file_integer(const gchar *section, const gchar *what)
1278 gint val = -1;
1279 GError *grc = NULL;
1281 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1282 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1284 if (grc) {
1285 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1286 g_clear_error(&grc);
1289 else {
1290 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1291 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1293 if (grc) {
1294 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1295 g_clear_error(&grc);
1300 return val;
1303 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1305 gboolean val = FALSE;
1306 GError *grc = NULL;
1308 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1309 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1311 if (grc) {
1312 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1313 g_clear_error(&grc);
1316 else {
1317 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1318 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1320 if (grc) {
1321 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1322 g_clear_error(&grc);
1327 return val;
1330 static gboolean parse_rcfile_keys()
1332 gsize n;
1333 gchar **groups;
1334 gchar **p;
1335 gchar *str;
1337 groups = g_key_file_get_groups(keyfileh, &n);
1339 for (p = groups; *p; p++) {
1340 GError *rc = NULL;
1342 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1343 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1345 if (!str) {
1346 if (rc) {
1347 log_write("%s: key: %s", rcfile, rc->message);
1348 g_clear_error(&rc);
1350 continue;
1353 do_cache_push(*p, str);
1354 g_free(str);
1355 continue;
1358 if (rc) {
1359 log_write("%s: key: %s", rcfile, rc->message);
1360 g_clear_error(&rc);
1361 continue;
1364 str = parse_rcfile_keyfile(*p, FALSE);
1366 if (!str)
1367 continue;
1369 do_cache_push(*p, str);
1370 gcry_free(str);
1373 g_strfreev(groups);
1374 return TRUE;
1377 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1379 guchar *md5file;
1380 guchar *key;
1381 gint timeout;
1382 const gchar *p = filename;
1383 file_header_internal_t *fh;
1384 gpg_error_t rc;
1386 while (isspace(*p))
1387 p++;
1389 if (!*p)
1390 return FALSE;
1392 if (valid_filename(p) == FALSE) {
1393 log_write(N_("%s: Invalid characters in filename"), p);
1394 return FALSE;
1397 md5file = gcry_malloc(16);
1398 key = gcry_malloc(gcrykeysize);
1399 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1401 if (access(p, R_OK|W_OK) != 0) {
1402 gcry_free(md5file);
1403 gcry_free(key);
1405 if (errno != ENOENT) {
1406 log_write("%s: %s", p, strerror(errno));
1407 return FALSE;
1410 return TRUE;
1413 fh = read_file_header(filename, FALSE, &rc);
1415 if (!fh) {
1416 gcry_free(md5file);
1417 gcry_free(key);
1418 log_write("%s: %s", p, pwmd_strerror(rc));
1419 return FALSE;
1422 log_write(N_("Adding '%s' to the file cache ..."), filename);
1424 if (fh->fh2.iter <= 0) {
1425 memset(key, '!', gcrykeysize);
1426 goto try_decrypt;
1429 if (!password) {
1430 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1431 g_free(fh);
1432 return FALSE;
1435 gcry_free(fh->doc);
1436 goto update_key;
1438 else
1439 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1440 strlen(password) ? strlen(password) : 1);
1442 try_decrypt:
1443 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1445 if (rc) {
1446 log_write("%s: %s", filename, pwmd_strerror(rc));
1447 gcry_free(key);
1448 gcry_free(md5file);
1449 g_free(fh);
1450 return FALSE;
1453 update_key:
1454 if (cache_update_key(md5file, key) == FALSE) {
1455 log_write("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1456 gcry_free(key);
1457 gcry_free(md5file);
1458 g_free(fh);
1459 return FALSE;
1462 timeout = get_key_file_integer(p, "cache_timeout");
1463 cache_set_timeout(md5file, timeout);
1464 log_write(N_("File '%s' now cached"), filename);
1465 gcry_free(key);
1466 gcry_free(md5file);
1467 g_free(fh);
1468 return TRUE;
1471 static void init_new_connection(gint fd, gchar *addr)
1473 pth_t tid;
1474 pth_attr_t attr;
1475 struct client_thread_s *new;
1476 gchar buf[41];
1477 int n;
1479 new = g_malloc0(sizeof(struct client_thread_s));
1481 if (!new) {
1482 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1483 return;
1487 * Thread priority is inherited from the calling thread. This
1488 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1489 * priority.
1491 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1492 new->fd = fd;
1494 #ifdef WITH_GNUTLS
1495 if (addr)
1496 new->remote = TRUE;
1497 #endif
1499 attr = pth_attr_new();
1500 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1501 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1502 pth_attr_set(attr, PTH_ATTR_NAME, "client");
1503 tid = pth_spawn(attr, client_thread, new);
1504 n = errno;
1505 pth_attr_destroy(attr);
1507 if (!tid) {
1508 g_free(new);
1509 log_write("pth_spawn(): %s", strerror(n));
1510 pth_mutex_release(&cn_mutex);
1511 return;
1514 g_snprintf(buf, sizeof(buf), "%p", tid);
1516 if (addr)
1517 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1518 else
1519 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1521 attr = pth_attr_of(tid);
1522 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1523 pth_attr_destroy(attr);
1524 new->tid = tid;
1525 cn_thread_list = g_slist_append(cn_thread_list, new);
1526 pth_mutex_release(&cn_mutex);
1529 #ifdef WITH_GNUTLS
1530 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1531 static void *get_in_addr(struct sockaddr *sa)
1533 if (sa->sa_family == AF_INET)
1534 return &(((struct sockaddr_in*)sa)->sin_addr);
1536 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1539 static void *tcp_accept_thread(void *arg)
1541 gint sockfd = (gint)arg;
1543 for (;;) {
1544 struct sockaddr_storage raddr;
1545 socklen_t slen = sizeof(raddr);
1546 gint fd = -1;
1547 gulong n;
1548 gchar *t;
1550 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1551 if (errno != EAGAIN) {
1552 if (!quit) // probably EBADF
1553 log_write("accept(): %s", strerror(errno));
1555 break;
1559 if (quit)
1560 break;
1562 if (fd >= 0) {
1563 gchar s[INET6_ADDRSTRLEN];
1565 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1566 s, sizeof s);
1567 init_new_connection(fd, s);
1570 t = get_key_file_string("global", "tcp_wait");
1571 n = strtol(t, NULL, 10);
1572 g_free(t);
1574 if (n < 0)
1575 n = 0;
1577 pth_usleep(n*100000);
1580 /* Just in case pth_accept() failed for some reason other than EBADF */
1581 quit = 1;
1582 pth_exit(PTH_CANCELED);
1583 return NULL;
1585 #endif
1587 static void *accept_thread(void *arg)
1589 gint sockfd = (gint)arg;
1591 for (;;) {
1592 socklen_t slen = sizeof(struct sockaddr_un);
1593 struct sockaddr_un raddr;
1594 gint fd = -1;
1596 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1597 if (errno != EAGAIN) {
1598 if (!quit) // probably EBADF
1599 log_write("accept(): %s", strerror(errno));
1601 break;
1605 if (fd >= 0)
1606 init_new_connection(fd, NULL);
1609 /* Just in case pth_accept() failed for some reason other than EBADF */
1610 quit = 1;
1611 pth_exit(PTH_CANCELED);
1612 return NULL;
1616 * This thread isn't joinable. For operations that block, these threads will
1617 * stack.
1619 static void *adjust_timer_thread(void *arg)
1621 CACHE_LOCK(NULL);
1622 cache_adjust_timer();
1623 CACHE_UNLOCK;
1624 return NULL;
1627 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1628 pth_attr_t attr)
1630 pth_status_t ev_status;
1632 if (timeout_ev) {
1633 pth_event_isolate(timeout_ev);
1634 ev_status = pth_event_status(timeout_ev);
1635 pth_event_free(timeout_ev, PTH_FREE_THIS);
1637 if (ev_status == PTH_STATUS_OCCURRED) {
1639 * The timer event has expired. Update the file cache. When the
1640 * cache mutex is locked and the timer expires again, the threads
1641 * will stack.
1643 pth_t tid = pth_spawn(attr, adjust_timer_thread, NULL);
1645 if (!tid)
1646 log_write("pth_spawn(): %s", strerror(errno));
1650 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1653 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1654 gint keepalive)
1656 pth_event_t ev = NULL;
1657 pth_status_t ev_status;
1659 if (keepalive_ev) {
1660 pth_event_isolate(keepalive_ev);
1661 ev_status = pth_event_status(keepalive_ev);
1663 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1664 if (ev_status == PTH_STATUS_OCCURRED)
1665 send_status_all(STATUS_KEEPALIVE);
1667 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1669 else
1670 ev = keepalive_ev;
1673 if (keepalive > 0 && !ev)
1674 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1676 return ev;
1679 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1681 pth_t accept_tid;
1682 #ifdef WITH_GNUTLS
1683 pth_t tcp_accept_tid;
1684 #endif
1685 guint n;
1686 sigset_t set;
1687 gint n_clients = 0;
1688 pth_attr_t attr;
1689 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1690 gint keepalive = get_key_file_integer("global", "keepalive");
1691 gpointer value;
1693 pth_mutex_init(&cn_mutex);
1694 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1695 sigemptyset(&set);
1696 sigaddset(&set, SIGTERM);
1697 sigaddset(&set, SIGINT);
1698 sigaddset(&set, SIGUSR1);
1699 sigaddset(&set, SIGHUP);
1700 sigaddset(&set, SIGABRT);
1702 attr = pth_attr_new();
1703 pth_attr_init(attr);
1704 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1705 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1706 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1708 if (!accept_tid) {
1709 log_write("pth_spawn(): %s", strerror(errno));
1710 goto done;
1713 #ifdef WITH_GNUTLS
1714 if (sockfd_r != -1) {
1715 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1716 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1718 if (!tcp_accept_tid) {
1719 log_write("pth_spawn(): %s", strerror(errno));
1720 goto done;
1723 #endif
1725 pth_attr_init(attr);
1726 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1727 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1730 * For the cache_timeout configuration parameter.
1732 timeout_ev = timeout_event_iterate(NULL, attr);
1733 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1734 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1736 do {
1737 gint sig = 0;
1739 pth_sigwait_ev(&set, &sig, timeout_ev);
1740 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1741 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1742 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1744 if (sig > 0) {
1745 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1747 /* Caught a signal. */
1748 switch (sig) {
1749 case SIGHUP:
1750 reload_rcfile();
1751 keepalive = get_key_file_integer("global", "keepalive");
1752 break;
1753 case SIGABRT:
1754 CACHE_LOCK(NULL);
1755 cache_clear(NULL, 2);
1756 CACHE_UNLOCK;
1757 #ifndef MEM_DEBUG
1758 xpanic();
1759 #endif
1760 exit(EXIT_FAILURE);
1761 case SIGUSR1:
1762 CACHE_LOCK(NULL);
1763 log_write(N_("clearing file cache"));
1764 cache_clear(NULL, 2);
1765 CACHE_UNLOCK;
1766 break;
1767 default:
1768 quit = 1;
1769 shutdown(sockfd, SHUT_RDWR);
1770 close(sockfd);
1772 if (sockfd_r != -1) {
1773 shutdown(sockfd_r, SHUT_RDWR);
1774 close(sockfd_r);
1776 break;
1779 } while (!quit);
1782 * We're out of the main server loop. This happens when a signal was sent
1783 * to terminate the daemon. We'll wait for all clients to disconnect
1784 * before exiting and ignore any following signals.
1786 pth_join(accept_tid, &value);
1788 #ifdef WITH_GNUTLS
1789 if (sockfd_r != -1) {
1790 pth_cancel(tcp_accept_tid);
1791 pth_join(tcp_accept_tid, &value);
1793 #endif
1795 done:
1796 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1797 unlink(*socketpath);
1798 g_free(*socketpath);
1799 *socketpath = NULL;
1801 if (n > 1)
1802 log_write(N_("waiting for all threads to terminate"));
1804 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1806 while (n > 1) {
1807 if (n != n_clients) {
1808 log_write(N_("%i threads remain"), n-1);
1809 n_clients = n;
1812 pth_wait(ev_quit);
1813 pth_event_isolate(ev_quit);
1814 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1815 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1816 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1817 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1820 pth_event_free(timeout_ev, PTH_FREE_THIS);
1821 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1822 pth_event_free(ev_quit, PTH_FREE_THIS);
1823 pth_attr_destroy(attr);
1824 cache_free();
1828 * Called from pinentry_fork() in the child process.
1830 void free_client_list()
1832 gint i, t = g_slist_length(cn_thread_list);
1834 for (i = 0; i < t; i++) {
1835 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1837 free_client(cn->cl);
1840 cache_free();
1843 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1844 const gchar *outfile)
1846 file_header_internal_t *fh;
1847 gpg_error_t rc;
1848 guchar *md5file;
1849 guchar *shakey;
1850 guint iter;
1852 md5file = gcry_malloc(16);
1853 if (!md5file)
1854 return GPG_ERR_ENOMEM;
1856 shakey = gcry_malloc(gcrykeysize);
1857 if (!shakey) {
1858 gcry_free(md5file);
1859 return GPG_ERR_ENOMEM;
1862 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1863 filename);
1864 fh = read_file_header(filename, TRUE, &rc);
1866 if (!fh)
1867 goto done;
1869 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1871 /* The header in version 1 had a bug where the iterations were off-by-one.
1872 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1873 * header.
1875 if (fh->fh1.iter >= 0) {
1876 if (keyfile) {
1877 gchar *tmp = parse_rcfile_keyfile(keyfile, TRUE);
1879 if (!tmp) {
1880 rc = GPG_ERR_UNKNOWN_ERRNO;
1881 goto done;
1884 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, tmp,
1885 strlen(tmp) ? strlen(tmp) : 1);
1886 gcry_free(tmp);
1887 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1889 else {
1890 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1891 == FALSE) {
1892 rc = GPG_ERR_UNKNOWN_ERRNO;
1893 close(fh->fd);
1894 goto done;
1898 else
1899 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1901 close(fh->fd);
1903 if (rc)
1904 goto done;
1906 rc = convert_xml((gchar **)&fh->doc, &fh->len);
1908 if (rc) {
1909 gcry_free(fh->doc);
1910 log_write("%s: %s", filename, pwmd_strerror(rc));
1911 goto done;
1914 fh->v1 = FALSE;
1915 iter = fh->fh1.iter;
1916 memset(&fh->fh2, 0, sizeof(fh->fh2));
1917 /* Keep the iterations and key from the original file. */
1918 fh->fh2.iter = iter+1;
1919 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1921 if (rc)
1922 send_error(NULL, rc);
1924 done:
1925 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1926 gcry_free(shakey);
1927 gcry_free(md5file);
1928 g_free(fh);
1929 return rc;
1932 int main(int argc, char *argv[])
1934 gint opt;
1935 struct sockaddr_un addr;
1936 struct passwd *pw = getpwuid(getuid());
1937 gchar buf[PATH_MAX];
1938 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1939 gchar *socketarg = NULL;
1940 gchar *datadir = NULL;
1941 gboolean n;
1942 gchar *p;
1943 gchar **cache_push = NULL;
1944 gint iter = 0;
1945 gchar *import = NULL, *keyfile = NULL;
1946 gulong cmd_iterations = -1;
1947 gint default_timeout;
1948 gint rcfile_spec = 0;
1949 gint estatus = EXIT_FAILURE;
1950 gint sockfd, sockfd_r = -1;
1951 gchar *outfile = NULL;
1952 #ifndef MEM_DEBUG
1953 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1954 #endif
1955 gint do_unlink = 1;
1956 gboolean secure = FALSE;
1957 guint ptotal = 0;
1958 gint background = 1;
1959 sigset_t set;
1960 gchar *convert = NULL;
1961 #ifdef WITH_PINENTRY
1962 gboolean disable_pinentry = FALSE;
1963 #endif
1964 #ifdef WITH_GNUTLS
1965 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1966 gint ret;
1967 #endif
1968 #ifndef DEBUG
1969 #ifdef HAVE_SETRLIMIT
1970 struct rlimit rl;
1972 rl.rlim_cur = rl.rlim_max = 0;
1974 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1975 err(EXIT_FAILURE, "setrlimit()");
1976 #endif
1977 #endif
1979 #ifdef ENABLE_NLS
1980 setlocale(LC_ALL, "");
1981 bindtextdomain("pwmd", LOCALEDIR);
1982 textdomain("pwmd");
1983 #endif
1985 gpg_err_init();
1986 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1987 #ifndef MEM_DEBUG
1988 g_mem_set_vtable(&mtable);
1989 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1990 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1991 xmlInitMemory();
1992 #ifdef WITH_GNUTLS
1993 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1994 xrealloc, xfree);
1995 #endif
1996 #endif
1997 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1998 #ifdef WITH_GNUTLS
1999 gnutls_global_init();
2000 gnutls_global_set_log_function(tls_log);
2001 gnutls_global_set_log_level(1);
2002 assuan_set_io_hooks(&io_hooks);
2003 #endif
2004 pth_init();
2005 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
2007 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2008 err(EXIT_FAILURE, "%s", buf);
2010 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
2012 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2013 err(EXIT_FAILURE, "%s", buf);
2015 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
2017 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
2018 err(EXIT_FAILURE, "sysconf()");
2020 cmdline = TRUE;
2022 while ((opt = getopt(argc, argv, "Po:C:bnI:i:k:hvf:D")) != EOF) {
2023 switch (opt) {
2024 #ifdef WITH_PINENTRY
2025 case 'P':
2026 disable_pinentry = TRUE;
2027 break;
2028 #endif
2029 case 'o':
2030 outfile = optarg;
2031 break;
2032 case 'C':
2033 convert = optarg;
2034 break;
2035 case 'b':
2036 /* Compatibility for version < 1.11 */
2037 break;
2038 case 'n':
2039 background = 0;
2040 break;
2041 case 'D':
2042 secure = TRUE;
2043 break;
2044 case 'I':
2045 import = optarg;
2046 break;
2047 case 'i':
2048 cmd_iterations = strtol(optarg, NULL, 10);
2049 break;
2050 case 'k':
2051 keyfile = optarg;
2052 break;
2053 case 'f':
2054 g_free(rcfile);
2055 rcfile = g_strdup(optarg);
2056 rcfile_spec = 1;
2057 break;
2058 case 'v':
2059 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,
2060 PACKAGE_BUGREPORT,
2061 #ifdef WITH_PINENTRY
2062 "+WITH_PINENTRY\n"
2063 #else
2064 "-WITH_PINENTRY\n"
2065 #endif
2066 #ifdef WITH_QUALITY
2067 "+WITH_QUALITY\n"
2068 #else
2069 "-WITH_QUALITY\n"
2070 #endif
2071 #ifdef WITH_GNUTLS
2072 "+WITH_GNUTLS\n"
2073 #else
2074 "-WITH_GNUTLS\n"
2075 #endif
2076 #ifdef DEBUG
2077 "+DEBUG\n"
2078 #else
2079 "-DEBUG\n"
2080 #endif
2081 #ifdef MEM_DEBUG
2082 "+MEM_DEBUG\n"
2083 #else
2084 "-MEM_DEBUG\n"
2085 #endif
2087 exit(EXIT_SUCCESS);
2088 case 'h':
2089 default:
2090 usage(argv[0]);
2094 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2095 exit(EXIT_FAILURE);
2097 #ifdef WITH_PINENTRY
2098 if (disable_pinentry == TRUE)
2099 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2100 #endif
2102 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2103 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2105 if (log_syslog == TRUE)
2106 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2108 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2109 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2110 errno = 0;
2112 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2113 log_write("setpriority(): %s", strerror(errno));
2114 goto do_exit;
2118 #ifdef HAVE_MLOCKALL
2119 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2120 log_write("mlockall(): %s", strerror(errno));
2121 goto do_exit;
2123 #endif
2125 setup_gcrypt();
2127 if (convert) {
2128 if (!outfile)
2129 usage(argv[0]);
2131 opt = convert_file(convert, keyfile, outfile);
2132 g_key_file_free(keyfileh);
2133 g_free(rcfile);
2134 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2137 if (import) {
2138 if (!outfile)
2139 usage(argv[0]);
2141 if (cmd_iterations == -1)
2142 cmd_iterations = get_key_file_integer("global", "iterations");
2144 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2145 g_key_file_free(keyfileh);
2146 g_free(rcfile);
2147 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2150 g_key_file_set_list_separator(keyfileh, ',');
2152 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2153 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2155 if (*p == '~') {
2156 p++;
2157 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2158 g_free(p);
2159 socketarg = g_strdup(buf);
2161 else
2162 socketarg = p;
2164 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2165 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2167 datadir = expand_homedir(p);
2168 g_free(p);
2170 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2171 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2172 disable_list_and_dump = n;
2174 else
2175 disable_list_and_dump = secure;
2177 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2178 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2179 else
2180 default_timeout = -1;
2182 setup_logging(keyfileh);
2184 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2185 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2187 if (argc != optind) {
2188 if (cache_push)
2189 ptotal = g_strv_length(cache_push);
2191 for (; optind < argc; optind++) {
2192 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2193 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2197 if (strchr(socketarg, '/') == NULL) {
2198 socketdir = g_get_current_dir();
2199 socketname = g_strdup(socketarg);
2200 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2202 else {
2203 socketname = g_strdup(strrchr(socketarg, '/'));
2204 socketname++;
2205 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2206 socketdir = g_strdup(socketarg);
2207 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2210 if (chdir(datadir)) {
2211 log_write("%s: %s", datadir, strerror(errno));
2212 unlink(socketpath);
2213 goto do_exit;
2216 if (parse_rcfile_keys(TRUE) == FALSE)
2217 goto do_exit;
2219 clear_rcfile_keys();
2222 * Set the cache entry for a file. Prompts for the password.
2224 if (cache_push) {
2225 for (opt = 0; cache_push[opt]; opt++)
2226 do_cache_push(cache_push[opt], NULL);
2228 g_strfreev(cache_push);
2229 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2233 * bind() doesn't like the full pathname of the socket or any non alphanum
2234 * characters so change to the directory where the socket is wanted then
2235 * create it then change to datadir.
2237 if (chdir(socketdir)) {
2238 log_write("%s: %s", socketdir, strerror(errno));
2239 goto do_exit;
2242 g_free(socketdir);
2244 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2245 log_write("socket(): %s", strerror(errno));
2246 goto do_exit;
2249 addr.sun_family = AF_UNIX;
2250 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2252 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2253 log_write("bind(): %s", strerror(errno));
2255 if (errno == EADDRINUSE)
2256 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2257 "stale socket. Please remove it manually."), socketpath);
2259 do_unlink = 0;
2260 goto do_exit;
2263 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2264 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2265 mode_t mode = strtol(t, NULL, 8);
2266 mode_t mask = umask(0);
2268 g_free(t);
2270 if (chmod(socketname, mode) == -1) {
2271 log_write("%s: %s", socketname, strerror(errno));
2272 close(sockfd);
2273 unlink(socketpath);
2274 umask(mask);
2275 goto do_exit;
2278 umask(mask);
2281 g_free(--socketname);
2283 if (chdir(datadir)) {
2284 log_write("%s: %s", datadir, strerror(errno));
2285 close(sockfd);
2286 unlink(socketpath);
2287 goto do_exit;
2290 g_free(datadir);
2291 pth_mutex_init(&cache_mutex);
2292 #ifdef WITH_PINENTRY
2293 pth_mutex_init(&pin_mutex);
2294 #endif
2296 if (listen(sockfd, 0) == -1) {
2297 log_write("listen(): %s", strerror(errno));
2298 goto do_exit;
2301 #ifdef WITH_GNUTLS
2302 if (get_key_file_boolean("global", "enable_tcp")) {
2303 gchar *tmp, *tmp2;
2304 struct addrinfo hints, *servinfo, *p;
2305 gint port = get_key_file_integer("global", "tcp_port");
2306 char buf[7];
2308 memset(&hints, 0, sizeof(hints));
2309 hints.ai_family = AF_UNSPEC;
2310 hints.ai_socktype = SOCK_STREAM;
2311 hints.ai_flags = AI_PASSIVE;
2313 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2314 &hints, &servinfo)) == -1) {
2315 log_write("getaddrinfo(): %s", gai_strerror(opt));
2316 goto do_exit;
2319 for(p = servinfo; p != NULL; p = p->ai_next) {
2320 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2321 p->ai_protocol)) == -1) {
2322 log_write("socket(): %s", strerror(errno));
2323 continue;
2326 opt = 1;
2328 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2329 sizeof(int)) == -1) {
2330 log_write("setsockopt(): %s", strerror(errno));
2331 goto do_exit;
2334 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2335 close(sockfd_r);
2336 log_write("bind(): %s", strerror(errno));
2337 continue;
2340 opt++;
2341 break;
2344 freeaddrinfo(servinfo);
2346 if (!p) {
2347 log_write("%s", N_("could not bind"));
2348 goto do_exit;
2351 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2352 gchar *tmp = get_key_file_string("global", "tcp_interface");
2354 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2355 == -1) {
2356 log_write("setsockopt(): %s", strerror(errno));
2357 g_free(tmp);
2358 goto do_exit;
2361 g_free(tmp);
2364 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2366 if (ret != GNUTLS_E_SUCCESS) {
2367 log_write("%s", gnutls_strerror(ret));
2368 goto do_exit;
2371 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2373 if (!tmp) {
2374 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2375 goto do_exit;
2378 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2379 GNUTLS_X509_FMT_PEM);
2380 g_free(tmp);
2382 if (ret < 0) {
2383 log_write("%s", gnutls_strerror(ret));
2384 goto do_exit;
2387 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2389 if (!tmp) {
2390 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2391 goto do_exit;
2394 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2396 if (!tmp2) {
2397 xfree(tmp);
2398 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2399 goto do_exit;
2402 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2403 GNUTLS_X509_FMT_PEM);
2404 g_free(tmp);
2405 g_free(tmp2);
2407 if (ret != GNUTLS_E_SUCCESS) {
2408 log_write("%s", gnutls_strerror(ret));
2409 goto do_exit;
2412 #endif
2414 if (background) {
2415 switch (fork()) {
2416 case -1:
2417 log_write("fork(): %s", strerror(errno));
2418 goto do_exit;
2419 case 0:
2420 close(0);
2421 close(1);
2422 close(2);
2423 setsid();
2424 break;
2425 default:
2426 exit(EXIT_SUCCESS);
2430 cmdline = FALSE;
2432 #ifdef WITH_GNUTLS
2433 if (get_key_file_boolean("global", "enable_tcp")) {
2434 log_write("%s", N_("Generating key exchange parameters..."));
2435 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2437 if (ret) {
2438 log_write("%s", gpg_strerror(ret));
2439 goto do_exit;
2442 ret = gnutls_dh_params_init(&dh_params);
2444 if (ret != GNUTLS_E_SUCCESS) {
2445 log_write("%s", gnutls_strerror(ret));
2446 goto do_exit;
2449 ret = gnutls_dh_params_generate2(dh_params, 1024);
2451 if (ret != GNUTLS_E_SUCCESS) {
2452 log_write("%s", gnutls_strerror(ret));
2453 goto do_exit;
2456 gnutls_certificate_set_dh_params(x509_cred, dh_params);
2457 ret = gnutls_rsa_params_init(&rsa_params);
2459 if (ret != GNUTLS_E_SUCCESS) {
2460 log_write("%s", gnutls_strerror(ret));
2461 goto do_exit;
2464 ret = gnutls_rsa_params_generate2(rsa_params, 512);
2466 if (ret != GNUTLS_E_SUCCESS) {
2467 log_write("%s", gnutls_strerror(ret));
2468 goto do_exit;
2471 gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
2472 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2474 if (listen(sockfd_r, 0) == -1) {
2475 log_write("listen(): %s", strerror(errno));
2476 goto do_exit;
2479 #endif
2482 * These are the signals that we use in threads. libpth can catch signals
2483 * itself so ignore them everywhere else. Note that using
2484 * signal(N, SIG_IGN) doesn't work like you might think.
2486 sigemptyset(&set);
2488 /* Termination */
2489 sigaddset(&set, SIGTERM);
2490 sigaddset(&set, SIGINT);
2492 /* Configuration file reloading. */
2493 sigaddset(&set, SIGUSR1);
2495 /* Clears the file cache. */
2496 sigaddset(&set, SIGHUP);
2498 /* Caught in client_thread(). Sends a cache status message. */
2499 sigaddset(&set, SIGUSR2);
2501 /* Ignored everywhere. When a client disconnects abnormally this signal
2502 * gets raised. It isn't needed though because client_thread() will check
2503 * for rcs even after the client disconnects. */
2504 signal(SIGPIPE, SIG_IGN);
2505 pth_sigmask(SIG_BLOCK, &set, NULL);
2506 server_loop(sockfd, sockfd_r, &socketpath);
2507 estatus = EXIT_SUCCESS;
2509 do_exit:
2510 if (socketpath && do_unlink) {
2511 unlink(socketpath);
2512 g_free(socketpath);
2515 #ifdef WITH_GNUTLS
2516 if (sockfd_r != -1) {
2517 gnutls_dh_params_deinit(dh_params);
2518 gnutls_rsa_params_deinit(rsa_params);
2520 if (x509_cred)
2521 gnutls_certificate_free_credentials(x509_cred);
2523 gnutls_global_deinit();
2525 #endif
2527 g_key_file_free(keyfileh);
2528 g_free(rcfile);
2529 xmlCleanupParser();
2531 if (estatus == EXIT_SUCCESS)
2532 log_write(N_("pwmd exiting normally"));
2534 pth_kill();
2535 #if defined(DEBUG) && !defined(MEM_DEBUG)
2536 xdump();
2537 #endif
2538 exit(estatus);