Fixed starting up without an rcfile.
[pwmd.git] / src / pwmd.c
blob7612551d879c542e2dad717917427a14324d7698
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(FALSE);
108 if (!k)
109 return;
111 g_key_file_free(keyfileh);
112 keyfileh = k;
113 parse_rcfile_keys();
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);
423 void cleanup_crypto(struct client_crypto_s **c)
425 struct client_crypto_s *cr = *c;
427 if (!cr)
428 return;
430 if (cr->iv)
431 gcry_free(cr->iv);
433 if (cr->key)
434 gcry_free(cr->key);
436 if (cr->tkey)
437 gcry_free(cr->tkey);
439 if (cr->tkey2)
440 gcry_free(cr->tkey2);
442 if (cr->inbuf)
443 gcry_free(cr->inbuf);
445 if (cr->outbuf)
446 gcry_free(cr->outbuf);
448 if (cr->fh) {
449 if (cr->fh->fd != -1 ||
450 (cmdline == TRUE && cr->fh->fd != STDOUT_FILENO))
451 close(cr->fh->fd);
453 if (cr->fh->doc)
454 gcry_free(cr->fh->doc);
456 g_free(cr->fh);
459 if (cr->gh)
460 gcry_cipher_close(cr->gh);
462 g_free(cr);
463 *c = NULL;
467 * This is called after a child_thread terminates. Set with
468 * pth_cleanup_push().
470 static void cleanup_cb(void *arg)
472 struct client_thread_s *cn = arg;
473 gpointer value;
474 struct client_s *cl = cn->cl;
476 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
477 log_write(N_("exiting, fd=%i"), cn->fd);
479 if (cn->msg_tid) {
480 pth_cancel(cn->msg_tid);
481 pth_join(cn->msg_tid, &value);
482 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
485 if (cn->msg_name)
486 g_free(cn->msg_name);
488 if (cn->msg) {
489 while (pth_msgport_pending(cn->msg) > 0) {
490 pth_message_t *m = pth_msgport_get(cn->msg);
492 g_free(m);
495 pth_msgport_destroy(cn->msg);
498 pth_join(cn->tid, &value);
500 if (cl && cl->freed == FALSE)
501 cleanup_client(cl);
503 #ifdef WITH_GNUTLS
504 if (cn->tls) {
505 gnutls_deinit(cn->tls->ses);
507 if (cn->tls->fp)
508 g_free(cn->tls->fp);
510 g_free(cn->tls);
512 #endif
514 if (cl && cl->ctx)
515 assuan_deinit_server(cl->ctx);
517 #ifdef WITH_PINENTRY
518 if (cl && cl->pinentry)
519 cleanup_pinentry(cl->pinentry);
520 #endif
522 if (cl->crypto)
523 cleanup_crypto(&cl->crypto);
525 g_free(cl);
526 cn_thread_list = g_slist_remove(cn_thread_list, cn);
527 g_free(cn);
528 pth_mutex_release(&cn_mutex);
529 send_status_all(STATUS_CLIENTS);
532 static void *client_msg_thread(void *data)
534 struct client_s *cl = data;
535 pth_status_t ev_status;
537 for (;;) {
538 pth_wait(cl->thd->msg_ev);
539 ev_status = pth_event_status(cl->thd->msg_ev);
541 if (ev_status == PTH_STATUS_FAILED) {
542 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
543 __FUNCTION__);
544 continue;
547 if (ev_status == PTH_STATUS_OCCURRED) {
548 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
550 while (pth_msgport_pending(cl->thd->msg) > 0) {
551 pth_message_t *m = pth_msgport_get(cl->thd->msg);
552 status_msg_t n = (status_msg_t)m->m_data;
553 gpg_error_t rc = send_status(cl->ctx, n, NULL);
555 g_free(m);
557 if (rc) {
558 pth_mutex_release(&cn_mutex);
559 log_write("%s", gpg_strerror(rc));
560 break;
564 pth_mutex_release(&cn_mutex);
570 * Called every time a connection is made via pth_spawn(). This is the thread
571 * entry point.
573 static void *client_thread(void *data)
575 struct client_thread_s *thd = data;
576 pth_event_t ev;
577 struct client_s *cl = g_malloc0(sizeof(struct client_s));
578 gpg_error_t rc;
579 pth_attr_t attr;
580 int n;
583 * Prevent a race condition with init_new_connection() if this thread
584 * fails (returns) for some reason before init_new_connection() releases
585 * the cn_mutex.
587 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
588 pth_mutex_release(&cn_mutex);
590 if (!cl) {
591 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
592 goto fail;
595 thd->cl = cl;
596 cl->thd = thd;
597 pth_cleanup_push(cleanup_cb, thd);
599 #ifdef WITH_GNUTLS
601 * Do the TLS handshake before anything else.
603 if (thd->remote) {
604 gchar *prio = get_key_file_string("global", "cipher_suite");
606 thd->tls = tls_init(thd->fd, prio);
607 g_free(prio);
609 if (!thd->tls) {
610 close(thd->fd);
611 goto fail;
614 #endif
617 * This is a "child" thread. Don't catch any signals. Let the master
618 * thread take care of signals in server_loop().
620 if (new_connection(cl))
621 goto fail;
623 #ifdef WITH_PINENTRY
624 cl->pinentry = pinentry_init();
626 if (!cl->pinentry) {
627 g_free(cl);
628 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
629 goto fail;
631 #endif
633 thd->msg_name = g_strdup_printf("%p", thd->tid);
635 if (!thd->msg_name) {
636 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
637 goto fail;
640 thd->msg = pth_msgport_create(thd->msg_name);
642 if (!thd->msg) {
643 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
644 goto fail;
647 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
648 attr = pth_attr_new();
649 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
650 pth_attr_set(attr, PTH_ATTR_NAME, "client_msg");
651 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
652 n = errno;
653 pth_attr_destroy(attr);
655 if (!thd->msg_tid) {
656 log_write("pth_spawn(): %s", strerror(n));
657 goto fail;
660 #ifdef HAVE_MLOCKALL
661 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
662 log_write("mlockall(): %s", strerror(errno));
663 goto fail;
665 #endif
667 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
669 if (rc) {
670 log_write("%s", gpg_strerror(rc));
671 goto fail;
674 send_status_all(STATUS_CLIENTS);
675 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
676 xmlSetStructuredErrorFunc(cl, xml_error_cb);
678 for (;;) {
679 pth_status_t ev_status;
681 pth_wait(ev);
682 ev_status = pth_event_status(ev);
684 if (ev_status == PTH_STATUS_FAILED) {
685 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
686 __FUNCTION__);
687 goto done;
689 else if (ev_status == PTH_STATUS_OCCURRED) {
690 rc = assuan_process_next(cl->ctx);
692 if (rc) {
693 cl->inquire_status = INQUIRE_INIT;
695 if (gpg_err_code(rc) == GPG_ERR_EOF)
696 goto done;
698 log_write("assuan_process_next(): %s", gpg_strerror(rc));
699 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
701 if (rc) {
702 log_write("assuan_process_done(): %s", gpg_strerror(rc));
703 goto done;
706 else {
707 #ifdef WITH_PINENTRY
708 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
709 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
710 pth_event_concat(ev, cl->pinentry->ev, NULL);
711 cl->pinentry->status = PINENTRY_RUNNING;
713 #endif
715 switch (cl->inquire_status) {
716 case INQUIRE_BUSY:
717 case INQUIRE_INIT:
718 break;
719 case INQUIRE_DONE:
720 cl->inquire_status = INQUIRE_INIT;
721 rc = assuan_process_done(cl->ctx, 0);
722 break;
727 #ifdef WITH_PINENTRY
728 ev = pinentry_iterate(cl, ev);
729 #endif
733 * Client cleanup (including XML data) is done in cleanup_cb() from
734 * the cleanup thread.
736 done:
737 pth_event_free(ev, PTH_FREE_ALL);
739 fail:
740 pth_exit(NULL);
741 return NULL;
744 static void setup_logging(GKeyFile *kf)
746 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
748 if (n == TRUE) {
749 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
751 if (*p == '~') {
752 gchar buf[PATH_MAX];
754 p++;
755 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
756 g_free(p);
758 if (logfile)
759 g_free(logfile);
761 logfile = g_strdup(buf);
763 else {
764 if (logfile)
765 g_free(logfile);
767 logfile = p;
771 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
775 * Make sure all settings are set to either the specified setting or a
776 * default.
778 static void set_rcfile_defaults(GKeyFile *kf)
780 gchar buf[PATH_MAX];
782 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
783 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
784 g_key_file_set_string(kf, "global", "socket_path", buf);
787 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
788 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
789 g_key_file_set_string(kf, "global", "data_directory", buf);
792 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
793 g_key_file_set_boolean(kf, "global", "backup", TRUE);
795 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
796 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
797 g_key_file_set_string(kf, "global", "log_path", buf);
800 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
801 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
803 #ifdef HAVE_MLOCKALL
804 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
805 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
806 #endif
808 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
809 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
811 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
812 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
813 g_key_file_set_integer(kf, "global", "iterations", 1);
815 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
816 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
818 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
819 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
821 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
822 g_key_file_set_integer(kf, "global", "compression_level", 6);
824 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
825 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
827 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
828 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
830 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
832 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
833 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
835 #ifdef HAVE_MLOCKALL
836 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
837 #endif
839 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
840 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
842 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
843 g_key_file_set_integer(kf, "global", "keepalive", 30);
845 #ifdef WITH_PINENTRY
846 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
847 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
849 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
850 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
851 #endif
853 #ifdef WITH_GNUTLS
854 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
855 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
857 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
858 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
860 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
861 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
863 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
864 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
866 if (g_key_file_has_key(kf, "global", "cipher_suite", NULL) == FALSE)
867 g_key_file_set_string(kf, "global", "cipher_suite", "SECURE256");
868 #endif
870 setup_logging(kf);
873 static GKeyFile *parse_rcfile(gboolean specified)
875 GKeyFile *kf = g_key_file_new();
876 GError *rc = NULL;
878 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
879 log_write("%s: %s", rcfile, rc->message);
881 if (cmdline && specified) {
882 g_clear_error(&rc);
883 return NULL;
886 if (rc->code == G_FILE_ERROR_NOENT) {
887 g_clear_error(&rc);
888 set_rcfile_defaults(kf);
889 return kf;
892 g_clear_error(&rc);
893 return NULL;
896 set_rcfile_defaults(kf);
897 return kf;
900 static gchar *do_get_password(const gchar *prompt)
902 gchar buf[LINE_MAX] = {0}, *p;
903 struct termios told, tnew;
904 gchar *key;
906 if (tcgetattr(STDIN_FILENO, &told) == -1) {
907 log_write("tcgetattr(): %s", strerror(errno));
908 return NULL;
911 memcpy(&tnew, &told, sizeof(struct termios));
912 tnew.c_lflag &= ~(ECHO);
913 tnew.c_lflag |= ICANON|ECHONL;
915 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
916 log_write("tcsetattr(): %s", strerror(errno));
917 tcsetattr(STDIN_FILENO, TCSANOW, &told);
918 return NULL;
921 fprintf(stderr, "%s", prompt);
923 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
924 tcsetattr(STDIN_FILENO, TCSANOW, &told);
925 return NULL;
928 tcsetattr(STDIN_FILENO, TCSANOW, &told);
929 p[strlen(p) - 1] = 0;
931 if (!buf[0]) {
932 key = gcry_malloc(1);
933 key[0] = 0;
935 else {
936 key = gcry_malloc(strlen(p) + 1);
937 sprintf(key, "%s", p);
940 memset(&buf, 0, sizeof(buf));
941 return key;
944 /* Only used when "enable_pinentry" is "false" or -P. */
945 static gpg_error_t get_input(const gchar *filename,
946 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
948 gchar *prompt;
950 if (which == PINENTRY_SAVE) {
951 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
952 crypto->tkey = do_get_password(prompt);
953 g_free(prompt);
955 if (!crypto->tkey) {
956 log_write(N_("%s: Skipping file"), filename);
957 return GPG_ERR_BAD_PASSPHRASE;
960 prompt = g_strdup_printf(N_("Repeat passphrase: "));
961 crypto->tkey2 = do_get_password(prompt);
962 g_free(prompt);
964 if (!crypto->tkey2) {
965 log_write(N_("%s: Skipping file"), filename);
966 return GPG_ERR_BAD_PASSPHRASE;
969 if (strcmp(crypto->tkey, crypto->tkey2)) {
970 log_write(N_("%s: Passphrase mismatch"), filename);
971 return EPWMD_BADKEY;
974 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
975 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
976 return 0;
979 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
981 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
982 log_write(N_("%s: Skipping file"), filename);
983 g_free(prompt);
984 return GPG_ERR_BAD_PASSPHRASE;
987 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
988 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
989 g_free(prompt);
990 return 0;
994 * inbuf must have been allocated with gcry_malloc().
996 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
997 gpointer inbuf, gulong insize)
999 gpg_error_t rc;
1000 gint level, zrc;
1001 gulong outsize;
1002 gpointer outbuf;
1004 level = get_key_file_integer(filename, "compression_level");
1006 if (level < 0)
1007 level = 0;
1009 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
1010 == FALSE) {
1011 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
1014 rc = do_xml_encrypt(NULL, crypto, filename, outbuf, outsize);
1015 return rc;
1018 static gpg_error_t get_password(const gchar *filename,
1019 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
1020 pinentry_cmd_t which)
1022 #ifdef WITH_PINENTRY
1023 gpg_error_t rc = 0;
1025 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
1026 == FALSE) {
1027 #endif
1028 return get_input(filename, crypto, key, which);
1029 #ifdef WITH_PINENTRY
1031 else {
1032 gchar *result = NULL;
1033 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1035 set_pinentry_defaults(pin);
1036 pin->which = which;
1037 pin->filename = g_strdup(filename);
1038 rc = pinentry_getpin(pin, &result);
1040 if (rc) {
1041 xfree(result);
1042 goto done;
1045 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1046 xfree(result);
1047 cleanup_pinentry(pin);
1050 done:
1051 return rc;
1052 #endif
1055 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1057 FILE *fp;
1058 gchar buf[LINE_MAX] = {0}, *p;
1059 gchar *str = NULL;
1060 gint len;
1062 *rc = 0;
1064 if ((fp = fopen(file, "r")) == NULL) {
1065 *rc = gpg_error_from_syserror();
1066 return FALSE;
1069 p = fgets(buf, sizeof(buf), fp);
1070 fclose(fp);
1071 len = strlen(buf);
1073 if (len && buf[len - 1] == '\n')
1074 buf[--len] = 0;
1076 str = gcry_malloc(len + 1);
1078 if (!str) {
1079 *rc = gpg_error_from_errno(ENOMEM);
1080 return FALSE;
1083 memcpy(str, buf, len ? len : 1);
1084 str[len] = 0;
1085 memset(&buf, 0, sizeof(buf));
1086 *result = str;
1087 return TRUE;
1090 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
1091 gpg_error_t *rc)
1093 GError *rv = NULL;
1094 gchar *t, *file = NULL, *str;
1096 *rc = GPG_ERR_UNKNOWN_ERRNO;
1098 if (import == FALSE) {
1099 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1100 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1102 if (!file) {
1103 if (rv) {
1104 log_write("%s: key_file: %s", rcfile, rv->message);
1105 g_clear_error(&rv);
1108 return NULL;
1111 t = expand_homedir(file);
1113 if (!t) {
1114 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1115 *rc = gpg_error_from_errno(ENOMEM);
1116 return NULL;
1119 g_free(file);
1120 file = t;
1123 else {
1124 /* -I or -C. The filename is a key file. */
1125 file = g_strdup(filename);
1127 if (!file) {
1128 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1129 *rc = gpg_error_from_errno(ENOMEM);
1130 return NULL;
1134 if (rv) {
1135 log_write("%s: key_file: %s", rcfile, rv->message);
1136 g_clear_error(&rv);
1137 return NULL;
1140 if (!file)
1141 return NULL;
1143 if (_getline(file, &str, rc) == FALSE) {
1144 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1145 g_free(file);
1146 return NULL;
1149 g_free(file);
1150 *rc = 0;
1151 return str;
1154 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1155 const gchar *keyfile, gulong iter)
1157 xmlDocPtr doc;
1158 gint fd;
1159 struct stat st;
1160 gint len;
1161 xmlChar *xmlbuf;
1162 xmlChar *xml;
1163 gpg_error_t rc;
1164 struct client_crypto_s *crypto;
1166 if (stat(filename, &st) == -1) {
1167 log_write("%s: %s", filename, strerror(errno));
1168 return FALSE;
1171 crypto = init_client_crypto();
1173 if (!crypto)
1174 return FALSE;
1176 crypto->key = gcry_malloc(gcrykeysize);
1177 memset(crypto->key, 0, gcrykeysize);
1179 if (!crypto->key) {
1180 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1181 goto fail;
1184 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1185 filename, outfile);
1187 if (iter && keyfile) {
1188 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1190 if (!crypto->tkey)
1191 goto fail;
1193 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1194 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1196 else if (iter) {
1197 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1199 if (rc)
1200 goto fail;
1203 if ((fd = open(filename, O_RDONLY)) == -1) {
1204 log_write("%s: %s", filename, strerror(errno));
1205 goto fail;
1208 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1209 close(fd);
1210 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1211 goto fail;
1214 if (read(fd, xmlbuf, st.st_size) == -1) {
1215 rc = errno;
1216 close(fd);
1217 errno = rc;
1218 log_write("%s: %s", filename, strerror(errno));
1219 goto fail;
1222 close(fd);
1223 xmlbuf[st.st_size] = 0;
1226 * Make sure the document validates.
1228 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1229 log_write("xmlReadDoc() failed");
1230 gcry_free(xmlbuf);
1231 goto fail;
1234 gcry_free(xmlbuf);
1235 xmlDocDumpMemory(doc, &xml, &len);
1236 xmlFreeDoc(doc);
1238 if (!iter)
1239 memset(crypto->key, '!', gcrykeysize);
1241 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1243 if (!crypto->fh) {
1244 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1245 goto fail;
1248 crypto->fh->fh2.iter = iter;
1249 rc = export_common(outfile, crypto, xml, len);
1250 xmlFree(xml);
1252 if (rc) {
1253 send_error(NULL, rc);
1254 goto fail;
1257 cleanup_crypto(&crypto);
1258 return TRUE;
1260 fail:
1261 cleanup_crypto(&crypto);
1262 return FALSE;
1265 gchar *get_key_file_string(const gchar *section, const gchar *what)
1267 gchar *val = NULL;
1268 GError *grc = NULL;
1270 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1271 val = g_key_file_get_string(keyfileh, section, what, &grc);
1273 if (grc) {
1274 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1275 g_clear_error(&grc);
1278 else {
1279 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1280 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1282 if (grc) {
1283 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1284 g_clear_error(&grc);
1289 return val;
1292 gint get_key_file_integer(const gchar *section, const gchar *what)
1294 gint val = -1;
1295 GError *grc = NULL;
1297 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1298 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1300 if (grc) {
1301 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1302 g_clear_error(&grc);
1305 else {
1306 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1307 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1309 if (grc) {
1310 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1311 g_clear_error(&grc);
1316 return val;
1319 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1321 gboolean val = FALSE;
1322 GError *grc = NULL;
1324 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1325 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1327 if (grc) {
1328 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1329 g_clear_error(&grc);
1332 else {
1333 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1334 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1336 if (grc) {
1337 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1338 g_clear_error(&grc);
1343 return val;
1346 static gboolean parse_rcfile_keys()
1348 gsize n;
1349 gchar **groups;
1350 gchar **p;
1351 gchar *str;
1353 groups = g_key_file_get_groups(keyfileh, &n);
1355 for (p = groups; *p; p++) {
1356 GError *rc = NULL;
1358 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1359 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1361 if (!str) {
1362 if (rc) {
1363 log_write("%s: key: %s", rcfile, rc->message);
1364 g_clear_error(&rc);
1366 continue;
1369 do_cache_push(*p, str);
1370 g_free(str);
1371 continue;
1374 if (rc) {
1375 log_write("%s: key: %s", rcfile, rc->message);
1376 g_clear_error(&rc);
1377 continue;
1380 gpg_error_t ret;
1381 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1383 if (!str)
1384 continue;
1386 do_cache_push(*p, str);
1387 gcry_free(str);
1390 g_strfreev(groups);
1391 return TRUE;
1394 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1396 guchar md5file[16];
1397 gint timeout;
1398 const gchar *p = filename;
1399 struct client_crypto_s *crypto;
1400 gpg_error_t rc;
1402 while (isspace(*p))
1403 p++;
1405 if (!*p)
1406 return FALSE;
1408 if (valid_filename(p) == FALSE) {
1409 log_write(N_("%s: Invalid characters in filename"), p);
1410 return FALSE;
1413 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1415 if (access(p, R_OK|W_OK) != 0) {
1416 log_write("%s: %s", p, strerror(errno));
1417 return FALSE;
1420 crypto = init_client_crypto();
1422 if (!crypto)
1423 return FALSE;
1425 crypto->fh = read_file_header(filename, FALSE, &rc);
1427 if (!crypto->fh) {
1428 log_write("%s: %s", p, pwmd_strerror(rc));
1429 cleanup_crypto(&crypto);
1430 return FALSE;
1433 crypto->key = gcry_malloc(gcrykeysize);
1435 if (!crypto->key) {
1436 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1437 cleanup_crypto(&crypto);
1438 return FALSE;
1441 log_write(N_("Adding '%s' to the file cache ..."), filename);
1443 if (crypto->fh->fh2.iter <= 0) {
1444 memset(crypto->key, '!', gcrykeysize);
1445 goto try_decrypt;
1448 if (!password) {
1449 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1451 if (rc) {
1452 send_error(NULL, rc);
1453 cleanup_crypto(&crypto);
1454 return FALSE;
1457 gcry_free(crypto->fh->doc);
1458 crypto->fh->doc = NULL;
1460 else
1461 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1462 strlen(password) ? strlen(password) : 1);
1464 try_decrypt:
1465 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1467 if (rc) {
1468 log_write("%s: %s", filename, pwmd_strerror(rc));
1469 cleanup_crypto(&crypto);
1470 return FALSE;
1473 if (cache_update_key(md5file, crypto->key) == FALSE) {
1474 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1475 cleanup_crypto(&crypto);
1476 return FALSE;
1479 timeout = get_key_file_integer(p, "cache_timeout");
1480 cache_set_timeout(md5file, timeout);
1481 log_write(N_("File '%s' now cached"), filename);
1482 cleanup_crypto(&crypto);
1483 return TRUE;
1486 static void init_new_connection(gint fd, gchar *addr)
1488 pth_t tid;
1489 pth_attr_t attr;
1490 struct client_thread_s *new;
1491 gchar buf[41];
1492 int n;
1494 new = g_malloc0(sizeof(struct client_thread_s));
1496 if (!new) {
1497 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1498 return;
1502 * Thread priority is inherited from the calling thread. This
1503 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1504 * priority.
1506 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1507 new->fd = fd;
1509 #ifdef WITH_GNUTLS
1510 if (addr)
1511 new->remote = TRUE;
1512 #endif
1514 attr = pth_attr_new();
1515 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1516 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1517 pth_attr_set(attr, PTH_ATTR_NAME, "client");
1518 tid = pth_spawn(attr, client_thread, new);
1519 n = errno;
1520 pth_attr_destroy(attr);
1522 if (!tid) {
1523 g_free(new);
1524 log_write("pth_spawn(): %s", strerror(n));
1525 pth_mutex_release(&cn_mutex);
1526 return;
1529 g_snprintf(buf, sizeof(buf), "%p", tid);
1531 if (addr)
1532 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1533 else
1534 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1536 attr = pth_attr_of(tid);
1537 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1538 pth_attr_destroy(attr);
1539 new->tid = tid;
1540 cn_thread_list = g_slist_append(cn_thread_list, new);
1541 pth_mutex_release(&cn_mutex);
1544 #ifdef WITH_GNUTLS
1545 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1546 static void *get_in_addr(struct sockaddr *sa)
1548 if (sa->sa_family == AF_INET)
1549 return &(((struct sockaddr_in*)sa)->sin_addr);
1551 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1554 static void *tcp_accept_thread(void *arg)
1556 gint sockfd = (gint)arg;
1558 for (;;) {
1559 struct sockaddr_storage raddr;
1560 socklen_t slen = sizeof(raddr);
1561 gint fd = -1;
1562 gulong n;
1563 gchar *t;
1565 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1566 if (errno != EAGAIN) {
1567 if (!quit) // probably EBADF
1568 log_write("accept(): %s", strerror(errno));
1570 break;
1574 if (quit)
1575 break;
1577 if (fd >= 0) {
1578 gchar s[INET6_ADDRSTRLEN];
1580 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1581 s, sizeof s);
1582 init_new_connection(fd, s);
1585 t = get_key_file_string("global", "tcp_wait");
1586 n = strtol(t, NULL, 10);
1587 g_free(t);
1589 if (n < 0)
1590 n = 0;
1592 pth_usleep(n*100000);
1595 /* Just in case pth_accept() failed for some reason other than EBADF */
1596 quit = 1;
1597 pth_exit(PTH_CANCELED);
1598 return NULL;
1600 #endif
1602 static void *accept_thread(void *arg)
1604 gint sockfd = (gint)arg;
1606 for (;;) {
1607 socklen_t slen = sizeof(struct sockaddr_un);
1608 struct sockaddr_un raddr;
1609 gint fd = -1;
1611 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1612 if (errno != EAGAIN) {
1613 if (!quit) // probably EBADF
1614 log_write("accept(): %s", strerror(errno));
1616 break;
1620 if (fd >= 0)
1621 init_new_connection(fd, NULL);
1624 /* Just in case pth_accept() failed for some reason other than EBADF */
1625 quit = 1;
1626 pth_exit(PTH_CANCELED);
1627 return NULL;
1631 * This thread isn't joinable. For operations that block, these threads will
1632 * stack.
1634 static void *adjust_timer_thread(void *arg)
1636 CACHE_LOCK(NULL);
1637 cache_adjust_timer();
1638 CACHE_UNLOCK;
1639 return NULL;
1642 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1643 pth_attr_t attr)
1645 pth_status_t ev_status;
1647 if (timeout_ev) {
1648 pth_event_isolate(timeout_ev);
1649 ev_status = pth_event_status(timeout_ev);
1650 pth_event_free(timeout_ev, PTH_FREE_THIS);
1652 if (ev_status == PTH_STATUS_OCCURRED) {
1654 * The timer event has expired. Update the file cache. When the
1655 * cache mutex is locked and the timer expires again, the threads
1656 * will stack.
1658 pth_t tid = pth_spawn(attr, adjust_timer_thread, NULL);
1660 if (!tid)
1661 log_write("pth_spawn(): %s", strerror(errno));
1665 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1668 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1669 gint keepalive)
1671 pth_event_t ev = NULL;
1672 pth_status_t ev_status;
1674 if (keepalive_ev) {
1675 pth_event_isolate(keepalive_ev);
1676 ev_status = pth_event_status(keepalive_ev);
1678 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1679 if (ev_status == PTH_STATUS_OCCURRED)
1680 send_status_all(STATUS_KEEPALIVE);
1682 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1684 else
1685 ev = keepalive_ev;
1688 if (keepalive > 0 && !ev)
1689 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1691 return ev;
1694 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1696 pth_t accept_tid;
1697 #ifdef WITH_GNUTLS
1698 pth_t tcp_accept_tid;
1699 #endif
1700 guint n;
1701 sigset_t set;
1702 gint n_clients = 0;
1703 pth_attr_t attr;
1704 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1705 gint keepalive = get_key_file_integer("global", "keepalive");
1706 gpointer value;
1708 pth_mutex_init(&cn_mutex);
1709 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1710 sigemptyset(&set);
1711 sigaddset(&set, SIGTERM);
1712 sigaddset(&set, SIGINT);
1713 sigaddset(&set, SIGUSR1);
1714 sigaddset(&set, SIGHUP);
1715 sigaddset(&set, SIGABRT);
1717 attr = pth_attr_new();
1718 pth_attr_init(attr);
1719 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1720 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1721 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1723 if (!accept_tid) {
1724 log_write("pth_spawn(): %s", strerror(errno));
1725 goto done;
1728 #ifdef WITH_GNUTLS
1729 if (sockfd_r != -1) {
1730 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1731 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1733 if (!tcp_accept_tid) {
1734 log_write("pth_spawn(): %s", strerror(errno));
1735 goto done;
1738 #endif
1740 pth_attr_init(attr);
1741 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1742 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1745 * For the cache_timeout configuration parameter.
1747 timeout_ev = timeout_event_iterate(NULL, attr);
1748 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1749 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1751 do {
1752 gint sig = 0;
1754 pth_sigwait_ev(&set, &sig, timeout_ev);
1755 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1756 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1757 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1759 if (sig > 0) {
1760 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1762 /* Caught a signal. */
1763 switch (sig) {
1764 case SIGHUP:
1765 reload_rcfile();
1766 keepalive = get_key_file_integer("global", "keepalive");
1767 break;
1768 case SIGABRT:
1769 CACHE_LOCK(NULL);
1770 cache_clear(NULL, 2);
1771 CACHE_UNLOCK;
1772 #ifndef MEM_DEBUG
1773 xpanic();
1774 #endif
1775 exit(EXIT_FAILURE);
1776 case SIGUSR1:
1777 CACHE_LOCK(NULL);
1778 log_write(N_("clearing file cache"));
1779 cache_clear(NULL, 2);
1780 CACHE_UNLOCK;
1781 break;
1782 default:
1783 quit = 1;
1784 shutdown(sockfd, SHUT_RDWR);
1785 close(sockfd);
1787 if (sockfd_r != -1) {
1788 shutdown(sockfd_r, SHUT_RDWR);
1789 close(sockfd_r);
1791 break;
1794 } while (!quit);
1797 * We're out of the main server loop. This happens when a signal was sent
1798 * to terminate the daemon. We'll wait for all clients to disconnect
1799 * before exiting and ignore any following signals.
1801 pth_join(accept_tid, &value);
1803 #ifdef WITH_GNUTLS
1804 if (sockfd_r != -1) {
1805 pth_cancel(tcp_accept_tid);
1806 pth_join(tcp_accept_tid, &value);
1808 #endif
1810 done:
1811 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1812 unlink(*socketpath);
1813 g_free(*socketpath);
1814 *socketpath = NULL;
1816 if (n > 1)
1817 log_write(N_("waiting for all threads to terminate"));
1819 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1821 while (n > 1) {
1822 if (n != n_clients) {
1823 log_write(N_("%i threads remain"), n-1);
1824 n_clients = n;
1827 pth_wait(ev_quit);
1828 pth_event_isolate(ev_quit);
1829 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1830 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1831 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1832 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1835 pth_event_free(timeout_ev, PTH_FREE_THIS);
1836 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1837 pth_event_free(ev_quit, PTH_FREE_THIS);
1838 pth_attr_destroy(attr);
1839 cache_free();
1843 * Called from pinentry_fork() in the child process.
1845 void free_client_list()
1847 gint i, t = g_slist_length(cn_thread_list);
1849 for (i = 0; i < t; i++) {
1850 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1852 free_client(cn->cl);
1855 cache_free();
1858 struct client_crypto_s *init_client_crypto()
1860 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1861 gpg_error_t rc;
1863 if (!new) {
1864 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1865 return NULL;
1868 rc = gcry_cipher_open(&new->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
1870 if (rc) {
1871 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
1872 g_free(new);
1873 return NULL;
1876 return new;
1879 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1880 const gchar *outfile)
1882 gpg_error_t rc;
1883 guchar md5file[16];
1884 guint iter;
1885 struct client_crypto_s *crypto = init_client_crypto();
1887 if (!crypto)
1888 return GPG_ERR_ENOMEM;
1890 crypto->key = gcry_malloc(gcrykeysize);
1892 if (!crypto->key) {
1893 cleanup_crypto(&crypto);
1894 return GPG_ERR_ENOMEM;
1897 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1898 filename);
1899 crypto->fh = read_file_header(filename, TRUE, &rc);
1901 if (!crypto->fh)
1902 goto done;
1904 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1906 /* The header in version 1 had a bug where the iterations were off-by-one.
1907 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1908 * header.
1910 if (crypto->fh->fh1.iter >= 0) {
1911 if (keyfile) {
1912 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1914 if (!crypto->tkey)
1915 goto done;
1917 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1918 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1920 else {
1921 rc = get_password(filename, crypto, md5file, crypto->key,
1922 PINENTRY_OPEN);
1924 if (rc)
1925 goto done;
1929 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
1930 &crypto->fh->len);
1932 if (rc)
1933 goto done;
1935 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
1937 if (rc) {
1938 log_write("%s: %s", filename, pwmd_strerror(rc));
1939 goto done;
1942 crypto->fh->v1 = FALSE;
1943 iter = crypto->fh->fh1.iter;
1944 memset(&crypto->fh->fh2, 0, sizeof(crypto->fh->fh2));
1945 /* Keep the iterations and key from the original file. */
1946 crypto->fh->fh2.iter = iter+1; // Bugfix for v1 data files.
1947 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
1949 done:
1950 if (rc)
1951 send_error(NULL, rc);
1953 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1954 cleanup_crypto(&crypto);
1955 return rc;
1958 int main(int argc, char *argv[])
1960 gint opt;
1961 struct sockaddr_un addr;
1962 struct passwd *pw = getpwuid(getuid());
1963 gchar buf[PATH_MAX];
1964 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1965 gchar *socketarg = NULL;
1966 gchar *datadir = NULL;
1967 gboolean n;
1968 gchar *p;
1969 gchar **cache_push = NULL;
1970 gint iter = 0;
1971 gchar *import = NULL, *keyfile = NULL;
1972 gulong cmd_iterations = -1;
1973 gint default_timeout;
1974 gboolean rcfile_spec = FALSE;
1975 gint estatus = EXIT_FAILURE;
1976 gint sockfd, sockfd_r = -1;
1977 gchar *outfile = NULL;
1978 #ifndef MEM_DEBUG
1979 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1980 #endif
1981 gint do_unlink = 1;
1982 gboolean secure = FALSE;
1983 guint ptotal = 0;
1984 gint background = 1;
1985 sigset_t set;
1986 gchar *convert = NULL;
1987 #ifdef WITH_PINENTRY
1988 gboolean disable_pinentry = FALSE;
1989 #endif
1990 #ifdef WITH_GNUTLS
1991 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1992 gint ret;
1993 #endif
1994 #if 0
1995 #ifndef DEBUG
1996 #ifdef HAVE_SETRLIMIT
1997 struct rlimit rl;
1999 rl.rlim_cur = rl.rlim_max = 0;
2001 if (setrlimit(RLIMIT_CORE, &rl) != 0)
2002 err(EXIT_FAILURE, "setrlimit()");
2003 #endif
2004 #endif
2005 #endif
2007 #ifdef ENABLE_NLS
2008 setlocale(LC_ALL, "");
2009 bindtextdomain("pwmd", LOCALEDIR);
2010 textdomain("pwmd");
2011 #endif
2013 gpg_err_init();
2014 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
2015 #ifndef MEM_DEBUG
2016 g_mem_set_vtable(&mtable);
2017 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
2018 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
2019 xmlInitMemory();
2020 #ifdef WITH_GNUTLS
2021 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
2022 xrealloc, xfree);
2023 #endif
2024 #endif
2025 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
2026 #ifdef WITH_GNUTLS
2027 gnutls_global_init();
2028 gnutls_global_set_log_function(tls_log);
2029 gnutls_global_set_log_level(1);
2030 assuan_set_io_hooks(&io_hooks);
2031 #endif
2032 xmlInitGlobals();
2033 xmlInitParser();
2034 xmlXPathInit();
2035 pth_init();
2036 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
2038 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2039 err(EXIT_FAILURE, "%s", buf);
2041 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
2043 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2044 err(EXIT_FAILURE, "%s", buf);
2046 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
2047 cmdline = TRUE;
2049 while ((opt = getopt(argc, argv, "Po:C:bnI:i:k:hvf:D")) != EOF) {
2050 switch (opt) {
2051 #ifdef WITH_PINENTRY
2052 case 'P':
2053 disable_pinentry = TRUE;
2054 break;
2055 #endif
2056 case 'o':
2057 outfile = optarg;
2058 break;
2059 case 'C':
2060 convert = optarg;
2061 break;
2062 case 'b':
2063 /* Compatibility for version < 1.11 */
2064 break;
2065 case 'n':
2066 background = 0;
2067 break;
2068 case 'D':
2069 secure = TRUE;
2070 break;
2071 case 'I':
2072 import = optarg;
2073 break;
2074 case 'i':
2075 cmd_iterations = strtol(optarg, NULL, 10);
2076 break;
2077 case 'k':
2078 keyfile = optarg;
2079 break;
2080 case 'f':
2081 g_free(rcfile);
2082 rcfile = g_strdup(optarg);
2083 rcfile_spec = TRUE;
2084 break;
2085 case 'v':
2086 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,
2087 PACKAGE_BUGREPORT,
2088 #ifdef WITH_PINENTRY
2089 "+WITH_PINENTRY\n"
2090 #else
2091 "-WITH_PINENTRY\n"
2092 #endif
2093 #ifdef WITH_QUALITY
2094 "+WITH_QUALITY\n"
2095 #else
2096 "-WITH_QUALITY\n"
2097 #endif
2098 #ifdef WITH_GNUTLS
2099 "+WITH_GNUTLS\n"
2100 #else
2101 "-WITH_GNUTLS\n"
2102 #endif
2103 #ifdef DEBUG
2104 "+DEBUG\n"
2105 #else
2106 "-DEBUG\n"
2107 #endif
2108 #ifdef MEM_DEBUG
2109 "+MEM_DEBUG\n"
2110 #else
2111 "-MEM_DEBUG\n"
2112 #endif
2114 exit(EXIT_SUCCESS);
2115 case 'h':
2116 default:
2117 usage(argv[0]);
2121 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2122 exit(EXIT_FAILURE);
2124 #ifdef WITH_PINENTRY
2125 if (disable_pinentry == TRUE)
2126 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2127 #endif
2129 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2130 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2132 if (log_syslog == TRUE)
2133 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2135 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2136 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2137 errno = 0;
2139 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2140 log_write("setpriority(): %s", strerror(errno));
2141 goto do_exit;
2145 #ifdef HAVE_MLOCKALL
2146 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2147 log_write("mlockall(): %s", strerror(errno));
2148 goto do_exit;
2150 #endif
2152 setup_gcrypt();
2154 if (convert) {
2155 if (!outfile)
2156 usage(argv[0]);
2158 opt = convert_file(convert, keyfile, outfile);
2159 g_key_file_free(keyfileh);
2160 g_free(rcfile);
2161 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2164 if (import) {
2165 if (!outfile)
2166 usage(argv[0]);
2168 if (cmd_iterations == -1)
2169 cmd_iterations = get_key_file_integer("global", "iterations");
2171 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2172 g_key_file_free(keyfileh);
2173 g_free(rcfile);
2174 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2177 g_key_file_set_list_separator(keyfileh, ',');
2179 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2180 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2182 if (*p == '~') {
2183 p++;
2184 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2185 g_free(p);
2186 socketarg = g_strdup(buf);
2188 else
2189 socketarg = p;
2191 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2192 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2194 datadir = expand_homedir(p);
2195 g_free(p);
2197 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2198 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2199 disable_list_and_dump = n;
2201 else
2202 disable_list_and_dump = secure;
2204 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2205 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2206 else
2207 default_timeout = -1;
2209 setup_logging(keyfileh);
2211 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2212 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2214 if (argc != optind) {
2215 if (cache_push)
2216 ptotal = g_strv_length(cache_push);
2218 for (; optind < argc; optind++) {
2219 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2220 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2224 if (strchr(socketarg, '/') == NULL) {
2225 socketdir = g_get_current_dir();
2226 socketname = g_strdup(socketarg);
2227 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2229 else {
2230 socketname = g_strdup(strrchr(socketarg, '/'));
2231 socketname++;
2232 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2233 socketdir = g_strdup(socketarg);
2234 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2237 if (chdir(datadir)) {
2238 log_write("%s: %s", datadir, strerror(errno));
2239 unlink(socketpath);
2240 goto do_exit;
2243 if (parse_rcfile_keys() == FALSE)
2244 goto do_exit;
2246 clear_rcfile_keys();
2249 * Set the cache entry for a file. Prompts for the password.
2251 if (cache_push) {
2252 for (opt = 0; cache_push[opt]; opt++)
2253 do_cache_push(cache_push[opt], NULL);
2255 g_strfreev(cache_push);
2256 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2260 * bind() doesn't like the full pathname of the socket or any non alphanum
2261 * characters so change to the directory where the socket is wanted then
2262 * create it then change to datadir.
2264 if (chdir(socketdir)) {
2265 log_write("%s: %s", socketdir, strerror(errno));
2266 goto do_exit;
2269 g_free(socketdir);
2271 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2272 log_write("socket(): %s", strerror(errno));
2273 goto do_exit;
2276 addr.sun_family = AF_UNIX;
2277 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2279 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2280 log_write("bind(): %s", strerror(errno));
2282 if (errno == EADDRINUSE)
2283 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2284 "stale socket. Please remove it manually."), socketpath);
2286 do_unlink = 0;
2287 goto do_exit;
2290 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2291 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2292 mode_t mode = strtol(t, NULL, 8);
2293 mode_t mask = umask(0);
2295 g_free(t);
2297 if (chmod(socketname, mode) == -1) {
2298 log_write("%s: %s", socketname, strerror(errno));
2299 close(sockfd);
2300 unlink(socketpath);
2301 umask(mask);
2302 goto do_exit;
2305 umask(mask);
2308 g_free(--socketname);
2310 if (chdir(datadir)) {
2311 log_write("%s: %s", datadir, strerror(errno));
2312 close(sockfd);
2313 unlink(socketpath);
2314 goto do_exit;
2317 g_free(datadir);
2318 pth_mutex_init(&cache_mutex);
2319 #ifdef WITH_PINENTRY
2320 pth_mutex_init(&pin_mutex);
2321 #endif
2323 if (listen(sockfd, 0) == -1) {
2324 log_write("listen(): %s", strerror(errno));
2325 goto do_exit;
2328 #ifdef WITH_GNUTLS
2329 if (get_key_file_boolean("global", "enable_tcp")) {
2330 gchar *tmp, *tmp2;
2331 struct addrinfo hints, *servinfo, *p;
2332 gint port = get_key_file_integer("global", "tcp_port");
2333 char buf[7];
2335 memset(&hints, 0, sizeof(hints));
2336 hints.ai_family = AF_UNSPEC;
2337 hints.ai_socktype = SOCK_STREAM;
2338 hints.ai_flags = AI_PASSIVE;
2340 if ((opt = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2341 &hints, &servinfo)) == -1) {
2342 log_write("getaddrinfo(): %s", gai_strerror(opt));
2343 goto do_exit;
2346 for(p = servinfo; p != NULL; p = p->ai_next) {
2347 if ((sockfd_r = socket(p->ai_family, p->ai_socktype,
2348 p->ai_protocol)) == -1) {
2349 log_write("socket(): %s", strerror(errno));
2350 continue;
2353 opt = 1;
2355 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &opt,
2356 sizeof(int)) == -1) {
2357 log_write("setsockopt(): %s", strerror(errno));
2358 goto do_exit;
2361 if (bind(sockfd_r, p->ai_addr, p->ai_addrlen) == -1) {
2362 close(sockfd_r);
2363 log_write("bind(): %s", strerror(errno));
2364 continue;
2367 opt++;
2368 break;
2371 freeaddrinfo(servinfo);
2373 if (!p) {
2374 log_write("%s", N_("could not bind"));
2375 goto do_exit;
2378 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2379 gchar *tmp = get_key_file_string("global", "tcp_interface");
2381 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2382 == -1) {
2383 log_write("setsockopt(): %s", strerror(errno));
2384 g_free(tmp);
2385 goto do_exit;
2388 g_free(tmp);
2391 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2393 if (ret != GNUTLS_E_SUCCESS) {
2394 log_write("%s", gnutls_strerror(ret));
2395 goto do_exit;
2398 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2400 if (!tmp) {
2401 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2402 goto do_exit;
2405 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2406 GNUTLS_X509_FMT_PEM);
2407 g_free(tmp);
2409 if (ret < 0) {
2410 log_write("%s", gnutls_strerror(ret));
2411 goto do_exit;
2414 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2416 if (!tmp) {
2417 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2418 goto do_exit;
2421 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2423 if (!tmp2) {
2424 xfree(tmp);
2425 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2426 goto do_exit;
2429 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2430 GNUTLS_X509_FMT_PEM);
2431 g_free(tmp);
2432 g_free(tmp2);
2434 if (ret != GNUTLS_E_SUCCESS) {
2435 log_write("%s", gnutls_strerror(ret));
2436 goto do_exit;
2439 #endif
2441 if (background) {
2442 switch (fork()) {
2443 case -1:
2444 log_write("fork(): %s", strerror(errno));
2445 goto do_exit;
2446 case 0:
2447 close(0);
2448 close(1);
2449 close(2);
2450 setsid();
2451 break;
2452 default:
2453 exit(EXIT_SUCCESS);
2457 cmdline = FALSE;
2459 #ifdef WITH_GNUTLS
2460 if (get_key_file_boolean("global", "enable_tcp")) {
2461 log_write("%s", N_("Generating key exchange parameters..."));
2462 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2464 if (ret) {
2465 log_write("%s", gpg_strerror(ret));
2466 goto do_exit;
2469 ret = gnutls_dh_params_init(&dh_params);
2471 if (ret != GNUTLS_E_SUCCESS) {
2472 log_write("%s", gnutls_strerror(ret));
2473 goto do_exit;
2476 ret = gnutls_dh_params_generate2(dh_params, 1024);
2478 if (ret != GNUTLS_E_SUCCESS) {
2479 log_write("%s", gnutls_strerror(ret));
2480 goto do_exit;
2483 gnutls_certificate_set_dh_params(x509_cred, dh_params);
2484 ret = gnutls_rsa_params_init(&rsa_params);
2486 if (ret != GNUTLS_E_SUCCESS) {
2487 log_write("%s", gnutls_strerror(ret));
2488 goto do_exit;
2491 ret = gnutls_rsa_params_generate2(rsa_params, 512);
2493 if (ret != GNUTLS_E_SUCCESS) {
2494 log_write("%s", gnutls_strerror(ret));
2495 goto do_exit;
2498 gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
2499 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2501 if (listen(sockfd_r, 0) == -1) {
2502 log_write("listen(): %s", strerror(errno));
2503 goto do_exit;
2506 #endif
2509 * These are the signals that we use in threads. libpth can catch signals
2510 * itself so ignore them everywhere else. Note that using
2511 * signal(N, SIG_IGN) doesn't work like you might think.
2513 sigemptyset(&set);
2515 /* Termination */
2516 sigaddset(&set, SIGTERM);
2517 sigaddset(&set, SIGINT);
2519 /* Configuration file reloading. */
2520 sigaddset(&set, SIGUSR1);
2522 /* Clears the file cache. */
2523 sigaddset(&set, SIGHUP);
2525 /* Caught in client_thread(). Sends a cache status message. */
2526 sigaddset(&set, SIGUSR2);
2528 /* Ignored everywhere. When a client disconnects abnormally this signal
2529 * gets raised. It isn't needed though because client_thread() will check
2530 * for rcs even after the client disconnects. */
2531 signal(SIGPIPE, SIG_IGN);
2532 pth_sigmask(SIG_BLOCK, &set, NULL);
2533 server_loop(sockfd, sockfd_r, &socketpath);
2534 estatus = EXIT_SUCCESS;
2536 do_exit:
2537 if (socketpath && do_unlink) {
2538 unlink(socketpath);
2539 g_free(socketpath);
2542 #ifdef WITH_GNUTLS
2543 if (sockfd_r != -1) {
2544 gnutls_dh_params_deinit(dh_params);
2545 gnutls_rsa_params_deinit(rsa_params);
2547 if (x509_cred)
2548 gnutls_certificate_free_credentials(x509_cred);
2550 gnutls_global_deinit();
2552 #endif
2554 g_key_file_free(keyfileh);
2555 g_free(rcfile);
2556 xmlCleanupParser();
2557 xmlCleanupGlobals();
2559 if (estatus == EXIT_SUCCESS)
2560 log_write(N_("pwmd exiting normally"));
2562 pth_kill();
2563 #if defined(DEBUG) && !defined(MEM_DEBUG)
2564 xdump();
2565 #endif
2566 exit(estatus);