Fixed keepalive_thread() to use a local condition and mutex.
[pwmd.git] / src / pwmd.c
blobaf41c9d173227b8c4be3347af414493f5c20a025
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 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>
48 #include <sys/time.h>
49 #include <sys/resource.h>
51 #ifdef TM_IN_SYS_TIME
52 #include <sys/time.h>
53 #else
54 #include <time.h>
55 #endif
57 #include "mem.h"
58 #include "xml.h"
59 #include "common.h"
61 #ifdef WITH_PINENTRY
62 #include "pinentry.h"
63 #endif
65 #ifdef WITH_GNUTLS
66 #include "tls.h"
67 #endif
68 #include "commands.h"
69 #include "pwmd_error.h"
70 #include "cache.h"
71 #include "misc.h"
72 #include "pwmd.h"
73 #include "lock.h"
75 GCRY_THREAD_OPTION_PTHREAD_IMPL;
77 static void clear_rcfile_keys()
79 gsize n;
80 gchar **groups;
81 gchar **p;
83 groups = g_key_file_get_groups(keyfileh, &n);
85 for (p = groups; *p; p++) {
86 GError *rc = NULL;
88 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
89 g_key_file_set_string(keyfileh, *p, "key", "");
92 g_strfreev(groups);
95 static void *reload_rcfile_thread(void *arg)
97 gboolean b = disable_list_and_dump;
98 GKeyFile *k;
100 pthread_mutex_lock(&rcfile_mutex);
101 log_write(N_("reloading configuration file '%s'"), rcfile);
102 k = parse_rcfile(FALSE);
104 if (!k)
105 goto done;
107 g_key_file_free(keyfileh);
108 keyfileh = k;
109 parse_rcfile_keys();
110 clear_rcfile_keys();
111 disable_list_and_dump = b;
112 #ifdef WITH_GNUTLS
113 startStopTcp(FALSE);
114 #endif
115 startStopKeepAlive(FALSE);
116 send_status_all(STATUS_CONFIG);
117 done:
118 pthread_mutex_unlock(&rcfile_mutex);
119 return NULL;
122 static void reload_rcfile()
124 pthread_t tid;
125 pthread_attr_t attr;
127 pthread_attr_init(&attr);
128 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
129 pthread_create(&tid, &attr, reload_rcfile_thread, NULL);
130 pthread_attr_destroy(&attr);
133 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
135 gpg_error_t n = gpg_error_from_errno(e);
137 pthread_testcancel();
138 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
141 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
143 gpg_err_code_t n = gpg_err_code(e);
144 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
145 struct client_s *client = assuan_get_pointer(ctx);
147 pthread_testcancel();
149 if (!e)
150 return assuan_process_done(ctx, 0);
152 if (!ctx) {
153 log_write("%s", pwmd_strerror(e));
154 return e;
157 if (n == EPWMD_LIBXML_ERROR) {
158 xmlErrorPtr xe = client->xml_error;
160 if (!xe)
161 xe = xmlGetLastError();
163 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
164 log_write("%s", xe->message);
166 if (xe == client->xml_error)
167 xmlResetError(xe);
168 else
169 xmlResetLastError();
171 client->xml_error = NULL;
172 return e;
175 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
178 static struct client_thread_s *find_cn(pthread_t tid)
180 guint t, i;
182 if (!cn_thread_list)
183 return NULL;
185 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
186 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
188 if (cn->tid == tid)
189 return cn;
192 return NULL;
195 void log_write(const gchar *fmt, ...)
197 gchar *args, *line;
198 va_list ap;
199 struct tm *tm;
200 time_t now;
201 gchar tbuf[21];
202 gint fd = -1;
203 struct client_thread_s *cn;
204 gchar *name = "";
205 gchar buf[255];
207 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
208 return;
210 if (!cmdline && logfile) {
211 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
212 warn("%s", logfile);
213 return;
217 va_start(ap, fmt);
219 if (g_vasprintf(&args, fmt, ap) == -1) {
220 if (logfile)
221 close(fd);
223 va_end(ap);
224 return;
227 va_end(ap);
229 if (cmdline) {
230 fprintf(stderr, "%s\n", args);
231 fflush(stderr);
232 g_free(args);
233 return;
236 pthread_mutex_lock(&cn_mutex);
237 cn = find_cn(pthread_self());
239 if (cn) {
240 if (!cn->name)
241 name = print_fmt(buf, sizeof(buf), "%i: ", cn->fd);
242 else
243 name = print_fmt(buf, sizeof(buf), "%s(%i): ", cn->name, cn->fd);
246 pthread_mutex_unlock(&cn_mutex);
248 if (!cmdline && log_syslog == TRUE)
249 syslog(LOG_INFO, "%s%s", name, args);
251 time(&now);
252 tm = localtime(&now);
253 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
254 tbuf[sizeof(tbuf) - 1] = 0;
256 if (args[strlen(args)-1] == '\n')
257 args[strlen(args)-1] = 0;
259 line = g_strdup_printf("%s %i %s%s\n", tbuf, getpid(), name, args);
260 g_free(args);
262 if (!line) {
263 if (logfile)
264 close(fd);
266 return;
269 if (logfile) {
270 write(fd, line, strlen(line));
271 fsync(fd);
272 close(fd);
275 if (isatty(STDERR_FILENO)) {
276 fprintf(stderr, "%s", line);
277 fflush(stderr);
280 g_free(line);
283 static void usage(gchar *pn)
285 g_fprintf(stderr, N_(
286 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
287 "[-I <filename> [-i <iter>]]\n "
288 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
289 " -n run as a foreground process\n"
290 " -f load the specified rcfile (~/.pwmd/config)\n"
291 " -C convert a version 1 data file to version 2\n"
292 " -I import an XML file\n"
293 " -i encrypt with the specified number of iterations when importing\n"
294 " (config default in the \"global\" section)\n"
295 " -k obtain the key from the specified file\n"
296 " -o output file for use with the -C and -I options\n"
297 " -D disable use of the LIST and DUMP commands\n"
298 " -P disable pinentry\n"
299 " -v version\n"
300 " -h this help text\n"
301 ), pn);
302 exit(EXIT_FAILURE);
305 static int gcry_SecureCheck(const void *ptr)
307 return 1;
310 static void setup_gcrypt()
312 gcry_check_version(NULL);
314 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
315 xfree);
317 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
318 NULL) != 0)
319 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
321 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
322 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
325 static gint new_connection(struct client_s *cl)
327 gpg_error_t rc;
328 gchar ver[ASSUAN_LINELENGTH];
330 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
332 if (rc)
333 goto fail;
335 assuan_set_pointer(cl->ctx, cl);
336 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
337 assuan_set_hello_line(cl->ctx, ver);
338 rc = register_commands(cl->ctx);
340 if (rc)
341 goto fail;
343 rc = assuan_accept(cl->ctx);
345 if (rc)
346 goto fail;
348 return 0;
350 fail:
351 log_write("%s", gpg_strerror(rc));
352 close(cl->thd->fd);
353 cl->thd->fd = -1;
354 return 1;
357 static void xml_error_cb(void *data, xmlErrorPtr e)
359 struct client_s *client = data;
362 * Keep the first reported error as the one to show in the error
363 * description. Reset in send_error().
365 if (client->xml_error)
366 return;
368 xmlCopyError(e, client->xml_error);
371 static void cleanup_crypto_handler(void *arg)
373 struct client_crypto_s **a = (struct client_crypto_s **)arg;
374 struct client_crypto_s *cr = *a;
376 if (cr->fh) {
377 if (cr->fh->fd != -1 ||
378 (cmdline == TRUE && cr->fh->fd != STDOUT_FILENO))
379 close(cr->fh->fd);
381 if (cr->fh->doc)
382 gcry_free(cr->fh->doc);
384 g_free(cr->fh);
387 if (cr->gh)
388 gcry_cipher_close(cr->gh);
390 g_free(cr);
391 *a = NULL;
394 void cleanup_crypto(struct client_crypto_s **c)
396 struct client_crypto_s *cr = *c;
398 if (!cr)
399 return;
401 if (cr->iv)
402 gcry_free(cr->iv);
404 if (cr->key)
405 gcry_free(cr->key);
407 if (cr->tkey)
408 gcry_free(cr->tkey);
410 if (cr->tkey2)
411 gcry_free(cr->tkey2);
413 if (cr->inbuf)
414 gcry_free(cr->inbuf);
416 if (cr->outbuf)
417 gcry_free(cr->outbuf);
419 pthread_cleanup_push(cleanup_crypto_handler, c);
420 pthread_testcancel();
421 pthread_cleanup_pop(1);
425 * This is called after a child_thread terminates. Set with
426 * pthread_cleanup_push().
428 static void cleanup_cb(void *arg)
430 struct client_thread_s *cn = arg;
431 struct client_s *cl = cn->cl;
433 cn->quit = TRUE;
434 log_write(N_("exiting, fd=%i"), cn->fd);
436 if (cl->thd && (cl->thd->msg_fd[0] || cl->thd->msg_fd[1])) {
437 pthread_cancel(cn->msg_tid);
438 pthread_cancel(cn->msg_sender_tid);
439 pthread_join(cn->msg_sender_tid, NULL);
440 pthread_cond_destroy(&cn->msg_cond);
441 close(cl->thd->msg_fd[0]);
442 close(cl->thd->msg_fd[1]);
445 pthread_join(cn->tid, NULL);
446 MUTEX_LOCK(&cn_mutex);
447 cn_thread_list = g_slist_remove(cn_thread_list, cn);
448 MUTEX_UNLOCK(&cn_mutex);
450 if (pthread_mutex_trylock(&cn->msg_sender_mutex) == EBUSY) {
451 MUTEX_UNLOCK(&cn->msg_sender_mutex);
453 else
454 pthread_mutex_unlock(&cn->msg_sender_mutex);
456 pthread_mutex_destroy(&cn->msg_sender_mutex);
457 pthread_cond_destroy(&cn->msg_sender_cond);
459 for (;;) {
460 struct status_msg_s *m = g_slist_nth_data(cn->msg_queue, 0);
462 if (!m)
463 break;
465 cn->msg_queue = g_slist_remove(cn->msg_queue, m);
466 g_free(m);
469 if (cl && cl->freed == FALSE)
470 cleanup_client(cl);
472 #ifdef WITH_GNUTLS
473 if (cn->tls) {
474 gnutls_deinit(cn->tls->ses);
476 if (cn->tls->fp)
477 g_free(cn->tls->fp);
479 g_free(cn->tls);
481 #endif
483 if (cl && cl->ctx)
484 assuan_deinit_server(cl->ctx);
485 else if (cl && cl->thd && cl->thd->fd != -1)
486 close(cl->thd->fd);
488 #ifdef WITH_PINENTRY
489 if (cl && cl->pinentry)
490 cleanup_pinentry(cl->pinentry);
491 #endif
493 if (cl->crypto)
494 cleanup_crypto(&cl->crypto);
496 g_free(cl);
498 if (cn->name)
499 g_free(cn->name);
501 g_free(cn);
502 send_status_all(STATUS_CLIENTS);
506 * Called every time a connection is made from init_new_connection(). This is
507 * the thread entry point.
509 static void *client_thread(void *data)
511 struct client_thread_s *thd = data;
512 struct client_s *cl = g_malloc0(sizeof(struct client_s));
513 gpg_error_t rc;
514 pthread_attr_t attr;
517 * Prevent a race condition with init_new_connection() if this thread
518 * fails (returns) for some reason before init_new_connection() releases
519 * the cn_mutex.
521 MUTEX_LOCK(&cn_mutex);
522 MUTEX_UNLOCK(&cn_mutex);
523 pthread_cleanup_push(cleanup_cb, thd);
525 if (!cl) {
526 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
527 goto fail;
530 thd->cl = cl;
532 #ifdef WITH_GNUTLS
534 * Do the TLS handshake before anything else.
536 if (thd->remote) {
537 gchar *prio = get_key_file_string("global", "cipher_suite");
539 thd->tls = tls_init(thd->fd, prio);
540 g_free(prio);
542 if (!thd->tls) {
543 close(thd->fd);
544 thd->fd = -1;
545 goto fail;
548 pthread_testcancel();
550 #endif
552 cl->thd = thd;
554 if (new_connection(cl))
555 goto fail;
557 #ifdef WITH_PINENTRY
558 cl->pinentry = pinentry_init();
560 if (!cl->pinentry) {
561 g_free(cl);
562 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
563 goto fail;
566 #ifdef WITH_GNUTLS
567 /* Require the client to explicity set OPTION PINENTRY since the DISPLAY
568 * might be automatically set from the client. Connections to the X11
569 * server usually aren't encrypted and the client might unintentionally
570 * send the passphrase in the clear.
572 if (thd->remote)
573 cl->pinentry->enable = FALSE;
574 #endif
575 #endif
577 #ifdef HAVE_MLOCKALL
578 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
579 log_write("mlockall(): %s", strerror(errno));
580 goto fail;
582 #endif
584 if (pipe(thd->msg_fd) == -1) {
585 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
586 goto fail;
589 pthread_attr_init(&attr);
590 pthread_cond_init(&thd->msg_sender_cond, NULL);
591 pthread_mutex_init(&thd->msg_sender_mutex, NULL);
592 MUTEX_LOCK(&thd->msg_sender_mutex);
593 pthread_create(&thd->msg_sender_tid, &attr, client_msg_sender_thread, thd);
594 pthread_attr_destroy(&attr);
596 pthread_cond_init(&thd->msg_cond, NULL);
597 pthread_attr_init(&attr);
598 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
599 pthread_create(&thd->msg_tid, &attr, client_msg_thread, thd);
600 pthread_attr_destroy(&attr);
602 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
604 if (rc) {
605 log_write("%s", gpg_strerror(rc));
606 goto fail;
609 send_status_all(STATUS_CLIENTS);
610 xmlSetStructuredErrorFunc(cl, xml_error_cb);
612 for (;;) {
613 fd_set rfds;
614 int n;
616 FD_ZERO(&rfds);
617 FD_SET(cl->thd->fd, &rfds);
619 #ifdef WITH_PINENTRY
620 if (cl->pinentry->status == PINENTRY_RUNNING)
621 FD_SET(cl->pinentry->fd, &rfds);
623 n = cl->thd->fd > cl->pinentry->fd ? cl->thd->fd : cl->pinentry->fd;
624 #else
625 n = cl->thd->fd;
626 #endif
627 n = select(n+1, &rfds, NULL, NULL, NULL);
628 pthread_testcancel();
630 if (n <= 0)
631 continue;
633 if (FD_ISSET(cl->thd->fd, &rfds)) {
634 rc = assuan_process_next(cl->ctx);
635 pthread_testcancel();
637 if (rc) {
638 cl->inquire_status = INQUIRE_INIT;
640 if (gpg_err_code(rc) == GPG_ERR_EOF)
641 goto done;
643 log_write("assuan_process_next(): %s", gpg_strerror(rc));
644 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
646 if (rc) {
647 log_write("assuan_process_done(): %s", gpg_strerror(rc));
648 goto done;
651 else {
652 #ifdef WITH_PINENTRY
653 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT)
654 cl->pinentry->status = PINENTRY_RUNNING;
655 #endif
657 switch (cl->inquire_status) {
658 case INQUIRE_BUSY:
659 case INQUIRE_INIT:
660 break;
661 case INQUIRE_DONE:
662 cl->inquire_status = INQUIRE_INIT;
663 pthread_testcancel();
664 rc = assuan_process_done(cl->ctx, 0);
665 break;
670 #ifdef WITH_PINENTRY
671 pinentry_iterate(cl,
672 cl->pinentry->fd != -1 && FD_ISSET(cl->pinentry->fd, &rfds));
673 #endif
677 * Client cleanup (including XML data) is done in cleanup_cb() from
678 * the cleanup thread.
680 done:
681 fail:
682 if (1) {} // Fixes compile time error with pthread_cleanup_push().
683 pthread_cleanup_pop(1);
684 pthread_exit(PTHREAD_CANCELED);
685 return NULL;
688 static void setup_logging(GKeyFile *kf)
690 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
692 if (n == TRUE) {
693 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
695 if (*p == '~') {
696 gchar buf[PATH_MAX];
698 p++;
699 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
700 g_free(p);
702 if (logfile)
703 g_free(logfile);
705 logfile = g_strdup(buf);
707 else {
708 if (logfile)
709 g_free(logfile);
711 logfile = p;
715 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
719 * Make sure all settings are set to either the specified setting or a
720 * default.
722 static void set_rcfile_defaults(GKeyFile *kf)
724 gchar buf[PATH_MAX];
726 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
727 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
728 g_key_file_set_string(kf, "global", "socket_path", buf);
731 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
732 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
733 g_key_file_set_string(kf, "global", "data_directory", buf);
736 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
737 g_key_file_set_boolean(kf, "global", "backup", TRUE);
739 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
740 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
741 g_key_file_set_string(kf, "global", "log_path", buf);
744 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
745 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
747 #ifdef HAVE_MLOCKALL
748 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
749 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
750 #endif
752 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
753 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
755 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
756 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
757 g_key_file_set_integer(kf, "global", "iterations", 1);
759 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
760 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
762 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
763 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
765 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
766 g_key_file_set_integer(kf, "global", "compression_level", 6);
768 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
769 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
771 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
772 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
774 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
776 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
777 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
779 #ifdef HAVE_MLOCKALL
780 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
781 #endif
783 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
784 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
786 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
787 g_key_file_set_integer(kf, "global", "keepalive", DEFAULT_KEEPALIVE_TO);
789 #ifdef WITH_PINENTRY
790 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
791 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
793 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
794 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
795 #endif
797 #ifdef WITH_GNUTLS
798 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
799 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
801 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
802 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
804 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
805 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
807 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
808 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
810 if (g_key_file_has_key(kf, "global", "cipher_suite", NULL) == FALSE)
811 g_key_file_set_string(kf, "global", "cipher_suite", "SECURE256");
813 if (g_key_file_has_key(kf, "global", "tcp_use_crl", NULL) == FALSE)
814 g_key_file_set_boolean(kf, "global", "tcp_use_crl", FALSE);
815 #endif
817 setup_logging(kf);
820 static GKeyFile *parse_rcfile(gboolean specified)
822 GKeyFile *kf = g_key_file_new();
823 GError *rc = NULL;
825 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
826 log_write("%s: %s", rcfile, rc->message);
828 if (cmdline && specified) {
829 g_clear_error(&rc);
830 return NULL;
833 if (rc->code == G_FILE_ERROR_NOENT) {
834 g_clear_error(&rc);
835 set_rcfile_defaults(kf);
836 return kf;
839 g_clear_error(&rc);
840 return NULL;
843 set_rcfile_defaults(kf);
844 return kf;
847 static gchar *do_get_password(const gchar *prompt)
849 gchar buf[LINE_MAX] = {0}, *p;
850 struct termios told, tnew;
851 gchar *key;
853 if (tcgetattr(STDIN_FILENO, &told) == -1) {
854 log_write("tcgetattr(): %s", strerror(errno));
855 return NULL;
858 memcpy(&tnew, &told, sizeof(struct termios));
859 tnew.c_lflag &= ~(ECHO);
860 tnew.c_lflag |= ICANON|ECHONL;
862 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
863 log_write("tcsetattr(): %s", strerror(errno));
864 tcsetattr(STDIN_FILENO, TCSANOW, &told);
865 return NULL;
868 fprintf(stderr, "%s", prompt);
870 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
871 tcsetattr(STDIN_FILENO, TCSANOW, &told);
872 return NULL;
875 tcsetattr(STDIN_FILENO, TCSANOW, &told);
876 p[strlen(p) - 1] = 0;
878 if (!buf[0]) {
879 key = gcry_malloc(1);
880 key[0] = 0;
882 else {
883 key = gcry_malloc(strlen(p) + 1);
884 sprintf(key, "%s", p);
887 memset(&buf, 0, sizeof(buf));
888 return key;
891 /* Only used when "enable_pinentry" is "false" or -P. */
892 static gpg_error_t get_input(const gchar *filename,
893 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
895 gchar *prompt;
897 if (which == PINENTRY_SAVE) {
898 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
899 crypto->tkey = do_get_password(prompt);
900 g_free(prompt);
902 if (!crypto->tkey) {
903 log_write(N_("%s: Skipping file"), filename);
904 return GPG_ERR_BAD_PASSPHRASE;
907 prompt = g_strdup_printf(N_("Repeat passphrase: "));
908 crypto->tkey2 = do_get_password(prompt);
909 g_free(prompt);
911 if (!crypto->tkey2) {
912 log_write(N_("%s: Skipping file"), filename);
913 return GPG_ERR_BAD_PASSPHRASE;
916 if (strcmp(crypto->tkey, crypto->tkey2)) {
917 log_write(N_("%s: Passphrase mismatch"), filename);
918 return EPWMD_BADKEY;
921 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
922 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
923 return 0;
926 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
928 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
929 log_write(N_("%s: Skipping file"), filename);
930 g_free(prompt);
931 return GPG_ERR_BAD_PASSPHRASE;
934 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
935 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
936 g_free(prompt);
937 return 0;
941 * inbuf must have been allocated with gcry_malloc().
943 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
944 gpointer inbuf, gulong insize)
946 gpg_error_t rc;
947 gint level, zrc;
948 gulong outsize;
949 gpointer outbuf;
951 level = get_key_file_integer(filename, "compression_level");
953 if (level < 0)
954 level = 0;
956 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
957 == FALSE) {
958 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
961 crypto->inbuf = outbuf;
962 crypto->insize = outsize;
963 rc = do_xml_encrypt(NULL, crypto, filename);
964 return rc;
967 static gpg_error_t get_password(const gchar *filename,
968 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
969 pinentry_cmd_t which)
971 #ifdef WITH_PINENTRY
972 gpg_error_t rc = 0;
974 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
975 == FALSE) {
976 #endif
977 return get_input(filename, crypto, key, which);
978 #ifdef WITH_PINENTRY
980 else {
981 gchar *result = NULL;
982 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
984 set_pinentry_defaults(pin);
985 pin->which = which;
986 pin->filename = g_strdup(filename);
987 rc = pinentry_getpin(pin, &result);
989 if (rc) {
990 xfree(result);
991 goto done;
994 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
995 xfree(result);
996 cleanup_pinentry(pin);
999 done:
1000 return rc;
1001 #endif
1004 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1006 FILE *fp;
1007 gchar buf[LINE_MAX] = {0}, *p;
1008 gchar *str = NULL;
1009 gint len;
1011 *rc = 0;
1013 if ((fp = fopen(file, "r")) == NULL) {
1014 *rc = gpg_error_from_syserror();
1015 return FALSE;
1018 p = fgets(buf, sizeof(buf), fp);
1019 fclose(fp);
1020 len = strlen(buf);
1022 if (len && buf[len - 1] == '\n')
1023 buf[--len] = 0;
1025 str = gcry_malloc(len + 1);
1027 if (!str) {
1028 *rc = gpg_error_from_errno(ENOMEM);
1029 return FALSE;
1032 memcpy(str, buf, len ? len : 1);
1033 str[len] = 0;
1034 memset(&buf, 0, sizeof(buf));
1035 *result = str;
1036 return TRUE;
1039 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
1040 gpg_error_t *rc)
1042 GError *rv = NULL;
1043 gchar *t, *file = NULL, *str;
1045 *rc = GPG_ERR_UNKNOWN_ERRNO;
1047 if (import == FALSE) {
1048 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1049 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1051 if (!file) {
1052 if (rv) {
1053 log_write("%s: key_file: %s", rcfile, rv->message);
1054 g_clear_error(&rv);
1057 return NULL;
1060 t = expand_homedir(file);
1062 if (!t) {
1063 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1064 *rc = gpg_error_from_errno(ENOMEM);
1065 return NULL;
1068 g_free(file);
1069 file = t;
1072 else {
1073 /* -I or -C. The filename is a key file. */
1074 file = g_strdup(filename);
1076 if (!file) {
1077 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1078 *rc = gpg_error_from_errno(ENOMEM);
1079 return NULL;
1083 if (rv) {
1084 log_write("%s: key_file: %s", rcfile, rv->message);
1085 g_clear_error(&rv);
1086 return NULL;
1089 if (!file)
1090 return NULL;
1092 if (_getline(file, &str, rc) == FALSE) {
1093 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1094 g_free(file);
1095 return NULL;
1098 g_free(file);
1099 *rc = 0;
1100 return str;
1103 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1104 const gchar *keyfile, guint64 iter)
1106 xmlDocPtr doc;
1107 gint fd;
1108 struct stat st;
1109 gint len;
1110 xmlChar *xmlbuf;
1111 xmlChar *xml;
1112 gpg_error_t rc;
1113 struct client_crypto_s *crypto;
1115 if (stat(filename, &st) == -1) {
1116 log_write("%s: %s", filename, strerror(errno));
1117 return FALSE;
1120 crypto = init_client_crypto();
1122 if (!crypto)
1123 return FALSE;
1125 crypto->key = gcry_malloc(gcrykeysize);
1126 memset(crypto->key, 0, gcrykeysize);
1128 if (!crypto->key) {
1129 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1130 goto fail;
1133 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1134 filename, outfile);
1136 if (iter && keyfile) {
1137 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1139 if (!crypto->tkey)
1140 goto fail;
1142 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1143 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1145 else if (iter) {
1146 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1148 if (rc)
1149 goto fail;
1152 if ((fd = open(filename, O_RDONLY)) == -1) {
1153 log_write("%s: %s", filename, strerror(errno));
1154 goto fail;
1157 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1158 close(fd);
1159 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1160 goto fail;
1163 if (read(fd, xmlbuf, st.st_size) == -1) {
1164 rc = errno;
1165 close(fd);
1166 errno = rc;
1167 log_write("%s: %s", filename, strerror(errno));
1168 goto fail;
1171 close(fd);
1172 xmlbuf[st.st_size] = 0;
1175 * Make sure the document validates.
1177 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1178 log_write("xmlReadDoc() failed");
1179 gcry_free(xmlbuf);
1180 goto fail;
1183 gcry_free(xmlbuf);
1184 xmlDocDumpMemory(doc, &xml, &len);
1185 xmlFreeDoc(doc);
1187 if (!iter)
1188 memset(crypto->key, '!', gcrykeysize);
1190 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1192 if (!crypto->fh) {
1193 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1194 goto fail;
1197 crypto->fh->fh2.iter = iter;
1198 rc = export_common(outfile, crypto, xml, len);
1199 xmlFree(xml);
1201 if (rc) {
1202 send_error(NULL, rc);
1203 goto fail;
1206 cleanup_crypto(&crypto);
1207 return TRUE;
1209 fail:
1210 cleanup_crypto(&crypto);
1211 return FALSE;
1214 gchar *get_key_file_string(const gchar *section, const gchar *what)
1216 gchar *val = NULL;
1217 GError *grc = NULL;
1219 MUTEX_LOCK(&rcfile_mutex);
1221 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1222 val = g_key_file_get_string(keyfileh, section, what, &grc);
1224 if (grc) {
1225 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1226 g_clear_error(&grc);
1229 else {
1230 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1231 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1233 if (grc) {
1234 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1235 g_clear_error(&grc);
1240 MUTEX_UNLOCK(&rcfile_mutex);
1241 return val;
1244 gint get_key_file_integer(const gchar *section, const gchar *what)
1246 gint val = -1;
1247 GError *grc = NULL;
1249 MUTEX_LOCK(&rcfile_mutex);
1251 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1252 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1254 if (grc) {
1255 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1256 g_clear_error(&grc);
1259 else {
1260 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1261 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1263 if (grc) {
1264 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1265 g_clear_error(&grc);
1270 MUTEX_UNLOCK(&rcfile_mutex);
1271 return val;
1274 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1276 gboolean val = FALSE;
1277 GError *grc = NULL;
1279 MUTEX_LOCK(&rcfile_mutex);
1281 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1282 val = g_key_file_get_boolean(keyfileh, section, 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_boolean(keyfileh, "global", what, &grc);
1293 if (grc) {
1294 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1295 g_clear_error(&grc);
1300 MUTEX_UNLOCK(&rcfile_mutex);
1301 return val;
1304 static gboolean parse_rcfile_keys()
1306 gsize n;
1307 gchar **groups;
1308 gchar **p;
1309 gchar *str;
1311 groups = g_key_file_get_groups(keyfileh, &n);
1313 for (p = groups; *p; p++) {
1314 GError *rc = NULL;
1316 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1317 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1319 if (!str) {
1320 if (rc) {
1321 log_write("%s: key: %s", rcfile, rc->message);
1322 g_clear_error(&rc);
1324 continue;
1327 do_cache_push(*p, str);
1328 g_free(str);
1329 continue;
1332 if (rc) {
1333 log_write("%s: key: %s", rcfile, rc->message);
1334 g_clear_error(&rc);
1335 continue;
1338 gpg_error_t ret;
1339 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1341 if (!str)
1342 continue;
1344 do_cache_push(*p, str);
1345 gcry_free(str);
1348 g_strfreev(groups);
1349 return TRUE;
1352 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1354 guchar md5file[16];
1355 gint timeout;
1356 const gchar *p = filename;
1357 struct client_crypto_s *crypto;
1358 gpg_error_t rc;
1360 while (isspace(*p))
1361 p++;
1363 if (!*p)
1364 return FALSE;
1366 if (valid_filename(p) == FALSE) {
1367 log_write(N_("%s: Invalid characters in filename"), p);
1368 return FALSE;
1371 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1373 if (access(p, R_OK|W_OK) != 0) {
1374 log_write("%s: %s", p, strerror(errno));
1375 return FALSE;
1378 crypto = init_client_crypto();
1380 if (!crypto)
1381 return FALSE;
1383 crypto->fh = read_file_header(filename, FALSE, &rc);
1385 if (!crypto->fh) {
1386 log_write("%s: %s", p, pwmd_strerror(rc));
1387 cleanup_crypto(&crypto);
1388 return FALSE;
1391 crypto->key = gcry_malloc(gcrykeysize);
1393 if (!crypto->key) {
1394 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1395 cleanup_crypto(&crypto);
1396 return FALSE;
1399 log_write(N_("Adding '%s' to the file cache ..."), filename);
1401 if (crypto->fh->fh2.iter <= 0) {
1402 memset(crypto->key, '!', gcrykeysize);
1403 goto try_decrypt;
1406 if (!password) {
1407 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1409 if (rc) {
1410 send_error(NULL, rc);
1411 cleanup_crypto(&crypto);
1412 return FALSE;
1415 gcry_free(crypto->fh->doc);
1416 crypto->fh->doc = NULL;
1418 else
1419 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1420 strlen(password) ? strlen(password) : 1);
1422 try_decrypt:
1423 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1425 if (rc) {
1426 log_write("%s: %s", filename, pwmd_strerror(rc));
1427 cleanup_crypto(&crypto);
1428 return FALSE;
1431 if (cache_update_key(md5file, crypto->key) == FALSE) {
1432 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1433 cleanup_crypto(&crypto);
1434 return FALSE;
1437 timeout = get_key_file_integer(p, "cache_timeout");
1438 cache_set_timeout(md5file, timeout);
1439 log_write(N_("File '%s' now cached"), filename);
1440 cleanup_crypto(&crypto);
1441 return TRUE;
1444 static void init_new_connection(gint fd, gchar *addr)
1446 pthread_t tid;
1447 pthread_attr_t attr;
1448 struct client_thread_s *new;
1449 int n;
1451 new = g_malloc0(sizeof(struct client_thread_s));
1453 if (!new) {
1454 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1455 close(fd);
1456 return;
1459 MUTEX_LOCK(&cn_mutex);
1460 new->fd = fd;
1462 #ifdef WITH_GNUTLS
1463 if (addr)
1464 new->remote = TRUE;
1465 #endif
1467 pthread_attr_init(&attr);
1468 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1469 n = pthread_create(&tid, &attr, client_thread, new);
1470 pthread_attr_destroy(&attr);
1472 if (n) {
1473 g_free(new);
1474 close(fd);
1475 log_write("pthread_create(): %s", strerror(n));
1476 MUTEX_UNLOCK(&cn_mutex);
1477 return;
1480 new->tid = tid;
1481 cn_thread_list = g_slist_append(cn_thread_list, new);
1482 MUTEX_UNLOCK(&cn_mutex);
1484 if (addr)
1485 log_write(N_("new connection: fd=%i, addr=%s"), fd, addr);
1486 else
1487 log_write(N_("new connection: fd=%i"), fd);
1490 #ifdef WITH_GNUTLS
1491 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1492 static void *get_in_addr(struct sockaddr *sa)
1494 if (sa->sa_family == AF_INET)
1495 return &(((struct sockaddr_in*)sa)->sin_addr);
1497 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1500 static void *tcp_accept_thread(void *arg)
1502 gint sockfd = (gint)arg;
1504 for (;;) {
1505 struct sockaddr_storage raddr;
1506 socklen_t slen = sizeof(raddr);
1507 gint fd = -1;
1508 gulong n;
1509 gchar *t;
1511 fd = accept(sockfd, (struct sockaddr *)&raddr, &slen);
1512 pthread_testcancel();
1514 if (fd == -1) {
1515 if (errno != EAGAIN) {
1516 if (!quit) // probably EBADF
1517 log_write("accept(): %s", strerror(errno));
1519 break;
1522 continue;
1525 if (quit)
1526 break;
1528 if (fd >= 0) {
1529 gchar s[INET6_ADDRSTRLEN];
1531 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1532 s, sizeof s);
1533 init_new_connection(fd, s);
1536 t = get_key_file_string("global", "tcp_wait");
1537 n = strtol(t, NULL, 10);
1538 g_free(t);
1540 if (n < 0)
1541 n = 0;
1543 usleep(n*100000);
1546 /* Just in case accept() failed for some reason other than EBADF */
1547 quit = 1;
1548 pthread_exit(PTHREAD_CANCELED);
1549 return NULL;
1551 #endif
1553 static void *accept_thread(void *arg)
1555 gint sockfd = (gint)arg;
1557 for (;;) {
1558 socklen_t slen = sizeof(struct sockaddr_un);
1559 struct sockaddr_un raddr;
1560 gint fd = -1;
1562 fd = accept(sockfd, (struct sockaddr *)&raddr, &slen);
1563 pthread_testcancel();
1565 if (fd == -1) {
1566 if (errno != EAGAIN) {
1567 if (!quit) // probably EBADF
1568 log_write("accept(): %s", strerror(errno));
1570 break;
1573 continue;
1576 if (fd >= 0)
1577 init_new_connection(fd, NULL);
1580 /* Just in case accept() failed for some reason other than EBADF */
1581 quit = 1;
1582 pthread_exit(PTHREAD_CANCELED);
1583 return NULL;
1586 static void *adjust_cache_timer_thread(void *arg)
1588 for (;;) {
1589 sleep(1);
1590 pthread_testcancel();
1591 CACHE_LOCK(NULL);
1592 cache_adjust_timer();
1593 CACHE_UNLOCK;
1596 return NULL;
1599 static void *keepalive_thread(void *arg)
1601 struct timespec ts;
1602 gint to = (gint)arg;
1603 pthread_mutex_t m;
1604 pthread_cond_t cond;
1606 pthread_cond_init(&cond, NULL);
1607 pthread_mutex_init(&m, NULL);
1608 pthread_mutex_lock(&m);
1610 for (;;) {
1611 pthread_cleanup_push(pthread_mutex_destroy, &m);
1612 pthread_cleanup_push(pthread_cond_destroy, &m);
1613 pthread_cleanup_push(pthread_mutex_unlock, &m);
1614 clock_gettime(CLOCK_REALTIME, &ts);
1615 ts.tv_sec += to;
1616 pthread_cond_timedwait(&cond, &m, &ts);
1617 pthread_testcancel();
1618 send_status_all(STATUS_KEEPALIVE);
1619 pthread_cleanup_pop(0);
1620 pthread_cleanup_pop(0);
1621 pthread_cleanup_pop(0);
1624 return NULL;
1627 static void startStopKeepAlive(gboolean term)
1629 pthread_attr_t attr;
1630 gint n = get_key_file_integer("global", "keepalive");
1632 if (keepalive_tid)
1633 pthread_cancel(keepalive_tid);
1635 keepalive_tid = 0;
1637 if (term)
1638 return;
1640 if (n > 0) {
1641 pthread_attr_init(&attr);
1642 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1643 pthread_create(&keepalive_tid, &attr, keepalive_thread, (void *)n);
1644 pthread_attr_destroy(&attr);
1648 static void server_loop(gint sockfd, gchar **socketpath)
1650 pthread_t accept_tid;
1651 guint n;
1652 sigset_t sigset;
1653 gint n_clients = 0;
1654 pthread_attr_t attr;
1655 pthread_t cache_timeout_tid;
1656 pthread_mutexattr_t mattr;
1658 sigemptyset(&sigset);
1660 /* Termination */
1661 sigaddset(&sigset, SIGTERM);
1662 sigaddset(&sigset, SIGINT);
1664 /* Clears the file cache. */
1665 sigaddset(&sigset, SIGUSR1);
1667 /* Configuration file reloading. */
1668 sigaddset(&sigset, SIGHUP);
1670 /* Caught in client_thread(). Sends a cache status message. */
1671 sigaddset(&sigset, SIGUSR2);
1673 /* Ignored everywhere. When a client disconnects abnormally this signal
1674 * gets raised. It isn't needed though because client_thread() will check
1675 * for rcs even after the client disconnects. */
1676 signal(SIGPIPE, SIG_IGN);
1677 sigprocmask(SIG_BLOCK, &sigset, NULL);
1679 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1680 pthread_mutexattr_init(&mattr);
1681 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
1682 pthread_mutex_init(&cn_mutex, &mattr);
1683 pthread_mutexattr_destroy(&mattr);
1684 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1685 pthread_attr_init(&attr);
1686 pthread_create(&accept_tid, &attr, accept_thread, (void *)sockfd);
1687 startStopKeepAlive(FALSE);
1688 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1689 pthread_create(&cache_timeout_tid, &attr, adjust_cache_timer_thread, NULL);
1690 pthread_attr_destroy(&attr);
1692 do {
1693 gint sig;
1695 sigwait(&sigset, &sig);
1696 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1698 /* Caught a signal. */
1699 switch (sig) {
1700 case SIGHUP:
1701 reload_rcfile();
1702 break;
1703 case SIGABRT:
1704 CACHE_LOCK(NULL);
1705 cache_clear(NULL, 2);
1706 CACHE_UNLOCK;
1707 #ifndef MEM_DEBUG
1708 xpanic();
1709 #endif
1710 exit(EXIT_FAILURE);
1711 case SIGUSR1:
1712 CACHE_LOCK(NULL);
1713 log_write(N_("clearing file cache"));
1714 cache_clear(NULL, 2);
1715 CACHE_UNLOCK;
1716 break;
1717 default:
1718 quit = 1;
1719 break;
1721 } while (!quit);
1724 * We're out of the main server loop. This happens when a signal was sent
1725 * to terminate the daemon. We'll wait for all clients to disconnect
1726 * before exiting and ignore any following signals.
1728 shutdown(sockfd, SHUT_RDWR);
1729 close(sockfd);
1730 pthread_cancel(accept_tid);
1731 pthread_join(accept_tid, NULL);
1732 #ifdef WITH_GNUTLS
1733 startStopTcp(TRUE);
1734 #endif
1735 unlink(*socketpath);
1736 g_free(*socketpath);
1737 *socketpath = NULL;
1738 MUTEX_LOCK(&cn_mutex);
1739 n = g_slist_length(cn_thread_list);
1740 MUTEX_UNLOCK(&cn_mutex);
1742 if (n)
1743 log_write(N_("waiting for all clients to disconnect"));
1745 while (n) {
1746 if (n != n_clients) {
1747 log_write(N_("%i clients remain"), n);
1748 n_clients = n;
1751 sleep(1);
1752 MUTEX_LOCK(&cn_mutex);
1753 n = g_slist_length(cn_thread_list);
1754 MUTEX_UNLOCK(&cn_mutex);
1757 startStopKeepAlive(TRUE);
1758 pthread_cancel(cache_timeout_tid);
1759 cache_free();
1763 * Called from pinentry_fork() in the child process.
1765 void free_client_list()
1767 gint i, t = g_slist_length(cn_thread_list);
1769 for (i = 0; i < t; i++) {
1770 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1772 free_client(cn->cl);
1775 cache_free();
1778 struct client_crypto_s *init_client_crypto()
1780 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1781 gpg_error_t rc;
1783 if (!new) {
1784 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1785 return NULL;
1788 rc = gcry_cipher_open(&new->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
1790 if (rc) {
1791 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
1792 g_free(new);
1793 return NULL;
1796 return new;
1799 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1800 const gchar *outfile)
1802 gpg_error_t rc;
1803 guchar md5file[16];
1804 guint64 iter;
1805 struct client_crypto_s *crypto = init_client_crypto();
1807 if (!crypto)
1808 return GPG_ERR_ENOMEM;
1810 crypto->key = gcry_malloc(gcrykeysize);
1812 if (!crypto->key) {
1813 cleanup_crypto(&crypto);
1814 return GPG_ERR_ENOMEM;
1817 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1818 filename);
1819 crypto->fh = read_file_header(filename, TRUE, &rc);
1821 if (!crypto->fh)
1822 goto done;
1824 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1826 /* The header in version 1 had a bug where the iterations were off-by-one.
1827 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1828 * header.
1830 if (crypto->fh->fh1.iter >= 0) {
1831 if (keyfile) {
1832 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1834 if (!crypto->tkey)
1835 goto done;
1837 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1838 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1840 else {
1841 rc = get_password(filename, crypto, md5file, crypto->key,
1842 PINENTRY_OPEN);
1844 if (rc)
1845 goto done;
1849 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
1850 &crypto->fh->len);
1852 if (rc)
1853 goto done;
1855 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
1857 if (rc) {
1858 log_write("%s: %s", filename, pwmd_strerror(rc));
1859 goto done;
1862 crypto->fh->v1 = FALSE;
1863 iter = crypto->fh->fh1.iter;
1864 memset(&crypto->fh->fh2, 0, sizeof(crypto->fh->fh2));
1865 /* Keep the iterations and key from the original file. */
1866 crypto->fh->fh2.iter = iter+1; // Bugfix for v1 data files.
1867 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
1869 done:
1870 if (rc)
1871 send_error(NULL, rc);
1873 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1874 cleanup_crypto(&crypto);
1875 return rc;
1878 #ifdef WITH_GNUTLS
1879 static gboolean startStopTcp(gboolean term)
1881 struct addrinfo hints, *servinfo, *p;
1882 gint port = get_key_file_integer("global", "tcp_port");
1883 char buf[7];
1884 int n;
1885 pthread_attr_t attr;
1887 if (term || get_key_file_boolean("global", "enable_tcp") == FALSE) {
1888 if (tcpSockFd != -1) {
1889 pthread_cancel(tcpAcceptTid);
1890 pthread_join(tcpAcceptTid, NULL);
1891 shutdown(tcpSockFd, SHUT_RDWR);
1892 close(tcpSockFd);
1893 tcpSockFd = -1;
1895 /* A client may still be connected. */
1896 if (!quit)
1897 deinitTlsParams();
1900 return TRUE;
1903 if (tcpSockFd != -1)
1904 return TRUE;
1906 memset(&hints, 0, sizeof(hints));
1907 hints.ai_family = AF_UNSPEC;
1908 hints.ai_socktype = SOCK_STREAM;
1909 hints.ai_flags = AI_PASSIVE;
1911 if ((n = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
1912 &hints, &servinfo)) == -1) {
1913 log_write("getaddrinfo(): %s", gai_strerror(n));
1914 return FALSE;
1917 for(p = servinfo; p != NULL; p = p->ai_next) {
1918 if ((tcpSockFd = socket(p->ai_family, p->ai_socktype,
1919 p->ai_protocol)) == -1) {
1920 log_write("socket(): %s", strerror(errno));
1921 continue;
1924 n = 1;
1926 if (setsockopt(tcpSockFd, SOL_SOCKET, SO_REUSEADDR, &n,
1927 sizeof(int)) == -1) {
1928 log_write("setsockopt(): %s", strerror(errno));
1929 freeaddrinfo(servinfo);
1930 goto fail;
1933 if (bind(tcpSockFd, p->ai_addr, p->ai_addrlen) == -1) {
1934 close(tcpSockFd);
1935 log_write("bind(): %s", strerror(errno));
1936 continue;
1939 n++;
1940 break;
1943 freeaddrinfo(servinfo);
1945 if (!p) {
1946 log_write("%s", N_("could not bind"));
1947 goto fail;
1950 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
1951 gchar *tmp = get_key_file_string("global", "tcp_interface");
1953 if (setsockopt(tcpSockFd, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
1954 == -1) {
1955 log_write("setsockopt(): %s", strerror(errno));
1956 g_free(tmp);
1957 goto fail;
1960 g_free(tmp);
1963 if (!initTlsParams())
1964 goto fail;
1966 if (listen(tcpSockFd, 0) == -1) {
1967 log_write("listen(): %s", strerror(errno));
1968 goto fail;
1971 pthread_attr_init(&attr);
1972 pthread_create(&tcpAcceptTid, &attr, tcp_accept_thread, (void *)tcpSockFd);
1973 pthread_attr_destroy(&attr);
1974 return TRUE;
1976 fail:
1977 deinitTlsParams();
1979 if (tcpSockFd != -1)
1980 close(tcpSockFd);
1982 tcpSockFd = -1;
1983 return FALSE;
1985 #endif
1987 int main(int argc, char *argv[])
1989 gint opt;
1990 struct sockaddr_un addr;
1991 struct passwd *pw = getpwuid(getuid());
1992 gchar buf[PATH_MAX];
1993 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1994 gchar *socketarg = NULL;
1995 gchar *datadir = NULL;
1996 gboolean n;
1997 gchar *p;
1998 gchar **cache_push = NULL;
1999 guint64 iter = 0;
2000 gchar *import = NULL, *keyfile = NULL;
2001 guint64 cmd_iterations = -1;
2002 gint default_timeout;
2003 gboolean rcfile_spec = FALSE;
2004 gint estatus = EXIT_FAILURE;
2005 gint sockfd;
2006 gchar *outfile = NULL;
2007 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
2008 gint do_unlink = 1;
2009 gboolean secure = FALSE;
2010 guint ptotal = 0;
2011 gint background = 1;
2012 gchar *convert = NULL;
2013 pthread_mutexattr_t mattr;
2014 #ifdef WITH_PINENTRY
2015 gboolean disable_pinentry = FALSE;
2016 #endif
2017 #ifdef WITH_GNUTLS
2018 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
2019 #endif
2020 #if 0
2021 #ifndef DEBUG
2022 #ifdef HAVE_SETRLIMIT
2023 struct rlimit rl;
2025 rl.rlim_cur = rl.rlim_max = 0;
2027 if (setrlimit(RLIMIT_CORE, &rl) != 0)
2028 err(EXIT_FAILURE, "setrlimit()");
2029 #endif
2030 #endif
2031 #endif
2033 #ifdef ENABLE_NLS
2034 setlocale(LC_ALL, "");
2035 bindtextdomain("pwmd", LOCALEDIR);
2036 textdomain("pwmd");
2037 #endif
2039 #ifndef MEM_DEBUG
2040 xmem_init();
2041 #endif
2042 gpg_err_init();
2043 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
2044 g_mem_set_vtable(&mtable);
2045 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
2046 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
2047 xmlInitMemory();
2048 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
2049 gcry_check_version(GCRYPT_VERSION);
2050 #ifdef WITH_GNUTLS
2051 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
2052 xrealloc, xfree);
2053 gnutls_global_init();
2054 gnutls_global_set_log_function(tls_log);
2055 gnutls_global_set_log_level(1);
2056 assuan_set_io_hooks(&io_hooks);
2057 #endif
2058 xmlInitGlobals();
2059 xmlInitParser();
2060 xmlXPathInit();
2061 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
2063 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2064 err(EXIT_FAILURE, "%s", buf);
2066 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
2068 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2069 err(EXIT_FAILURE, "%s", buf);
2071 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
2072 cmdline = TRUE;
2073 #ifdef WITH_GNUTLS
2074 tcpSockFd = -1;
2075 #endif
2077 while ((opt = getopt(argc, argv, "Po:C:nI:i:k:hvf:D")) != EOF) {
2078 switch (opt) {
2079 #ifdef WITH_PINENTRY
2080 case 'P':
2081 disable_pinentry = TRUE;
2082 break;
2083 #endif
2084 case 'o':
2085 outfile = optarg;
2086 break;
2087 case 'C':
2088 convert = optarg;
2089 break;
2090 case 'n':
2091 background = 0;
2092 break;
2093 case 'D':
2094 secure = TRUE;
2095 break;
2096 case 'I':
2097 import = optarg;
2098 break;
2099 case 'i':
2100 cmd_iterations = strtol(optarg, NULL, 10);
2101 break;
2102 case 'k':
2103 keyfile = optarg;
2104 break;
2105 case 'f':
2106 g_free(rcfile);
2107 rcfile = g_strdup(optarg);
2108 rcfile_spec = TRUE;
2109 break;
2110 case 'v':
2111 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,
2112 PACKAGE_BUGREPORT,
2113 #ifdef WITH_PINENTRY
2114 "+WITH_PINENTRY\n"
2115 #else
2116 "-WITH_PINENTRY\n"
2117 #endif
2118 #ifdef WITH_QUALITY
2119 "+WITH_QUALITY\n"
2120 #else
2121 "-WITH_QUALITY\n"
2122 #endif
2123 #ifdef WITH_GNUTLS
2124 "+WITH_GNUTLS\n"
2125 #else
2126 "-WITH_GNUTLS\n"
2127 #endif
2128 #ifdef DEBUG
2129 "+DEBUG\n"
2130 #else
2131 "-DEBUG\n"
2132 #endif
2133 #ifdef MEM_DEBUG
2134 "+MEM_DEBUG\n"
2135 #else
2136 "-MEM_DEBUG\n"
2137 #endif
2139 exit(EXIT_SUCCESS);
2140 case 'h':
2141 default:
2142 usage(argv[0]);
2146 pthread_mutexattr_init(&mattr);
2147 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
2148 pthread_mutex_init(&rcfile_mutex, &mattr);
2149 pthread_mutexattr_destroy(&mattr);
2151 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2152 exit(EXIT_FAILURE);
2154 #ifdef WITH_PINENTRY
2155 if (disable_pinentry == TRUE)
2156 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2157 #endif
2159 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2160 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2162 if (log_syslog == TRUE)
2163 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2165 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2166 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2167 errno = 0;
2169 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2170 log_write("setpriority(): %s", strerror(errno));
2171 goto do_exit;
2175 #ifdef HAVE_MLOCKALL
2176 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2177 log_write("mlockall(): %s", strerror(errno));
2178 goto do_exit;
2180 #endif
2182 setup_gcrypt();
2184 if (convert) {
2185 if (!outfile)
2186 usage(argv[0]);
2188 opt = convert_file(convert, keyfile, outfile);
2189 g_key_file_free(keyfileh);
2190 g_free(rcfile);
2191 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2194 if (import) {
2195 if (!outfile)
2196 usage(argv[0]);
2198 if (cmd_iterations == -1)
2199 cmd_iterations = (guint64)get_key_file_integer("global", "iterations");
2201 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2202 g_key_file_free(keyfileh);
2203 g_free(rcfile);
2204 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2207 g_key_file_set_list_separator(keyfileh, ',');
2209 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2210 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2212 if (*p == '~') {
2213 p++;
2214 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2215 g_free(p);
2216 socketarg = g_strdup(buf);
2218 else
2219 socketarg = p;
2221 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2222 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2224 datadir = expand_homedir(p);
2225 g_free(p);
2227 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2228 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2229 disable_list_and_dump = n;
2231 else
2232 disable_list_and_dump = secure;
2234 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2235 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2236 else
2237 default_timeout = -1;
2239 setup_logging(keyfileh);
2241 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2242 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2244 if (argc != optind) {
2245 if (cache_push)
2246 ptotal = g_strv_length(cache_push);
2248 for (; optind < argc; optind++) {
2249 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2250 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2254 if (strchr(socketarg, '/') == NULL) {
2255 socketdir = g_get_current_dir();
2256 socketname = g_strdup(socketarg);
2257 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2259 else {
2260 socketname = g_strdup(strrchr(socketarg, '/'));
2261 socketname++;
2262 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2263 socketdir = g_strdup(socketarg);
2264 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2267 if (chdir(datadir)) {
2268 log_write("%s: %s", datadir, strerror(errno));
2269 unlink(socketpath);
2270 goto do_exit;
2273 if (parse_rcfile_keys() == FALSE)
2274 goto do_exit;
2276 clear_rcfile_keys();
2279 * Set the cache entry for a file. Prompts for the password.
2281 if (cache_push) {
2282 for (opt = 0; cache_push[opt]; opt++)
2283 do_cache_push(cache_push[opt], NULL);
2285 g_strfreev(cache_push);
2286 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2290 * bind() doesn't like the full pathname of the socket or any non alphanum
2291 * characters so change to the directory where the socket is wanted then
2292 * create it then change to datadir.
2294 if (chdir(socketdir)) {
2295 log_write("%s: %s", socketdir, strerror(errno));
2296 goto do_exit;
2299 g_free(socketdir);
2301 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2302 log_write("socket(): %s", strerror(errno));
2303 goto do_exit;
2306 addr.sun_family = AF_UNIX;
2307 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2309 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2310 log_write("bind(): %s", strerror(errno));
2312 if (errno == EADDRINUSE)
2313 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2314 "stale socket. Please remove it manually."), socketpath);
2316 do_unlink = 0;
2317 goto do_exit;
2320 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2321 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2322 mode_t mode = strtol(t, NULL, 8);
2323 mode_t mask = umask(0);
2325 g_free(t);
2327 if (chmod(socketname, mode) == -1) {
2328 log_write("%s: %s", socketname, strerror(errno));
2329 close(sockfd);
2330 unlink(socketpath);
2331 umask(mask);
2332 goto do_exit;
2335 umask(mask);
2338 g_free(--socketname);
2340 if (chdir(datadir)) {
2341 log_write("%s: %s", datadir, strerror(errno));
2342 close(sockfd);
2343 unlink(socketpath);
2344 goto do_exit;
2347 g_free(datadir);
2348 pthread_mutexattr_init(&mattr);
2349 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
2350 pthread_mutex_init(&cache_mutex, &mattr);
2351 pthread_mutexattr_destroy(&mattr);
2352 #ifdef WITH_PINENTRY
2353 pthread_mutex_init(&pin_mutex, NULL);
2354 #endif
2356 if (listen(sockfd, 0) == -1) {
2357 log_write("listen(): %s", strerror(errno));
2358 goto do_exit;
2361 cmdline = FALSE;
2363 #ifdef WITH_GNUTLS
2364 if (startStopTcp(FALSE) == FALSE)
2365 goto do_exit;
2366 #endif
2368 if (background) {
2369 switch (fork()) {
2370 case -1:
2371 log_write("fork(): %s", strerror(errno));
2372 goto do_exit;
2373 case 0:
2374 close(0);
2375 close(1);
2376 close(2);
2377 setsid();
2378 break;
2379 default:
2380 exit(EXIT_SUCCESS);
2384 server_loop(sockfd, &socketpath);
2385 estatus = EXIT_SUCCESS;
2387 do_exit:
2388 if (socketpath && do_unlink) {
2389 unlink(socketpath);
2390 g_free(socketpath);
2393 #ifdef WITH_GNUTLS
2394 startStopTcp(TRUE);
2395 gnutls_global_deinit();
2396 #endif
2398 g_key_file_free(keyfileh);
2399 g_free(rcfile);
2400 xmlCleanupParser();
2401 xmlCleanupGlobals();
2403 if (estatus == EXIT_SUCCESS)
2404 log_write(N_("pwmd exiting normally"));
2406 #if defined(DEBUG) && !defined(MEM_DEBUG)
2407 xdump();
2408 #endif
2409 #ifndef MEM_DEBUG
2410 xmem_deinit();
2411 #endif
2412 exit(estatus);