Merge branch 'gnutls' into v2
[pwmd.git] / src / pwmd.c
blob0784c5f481815f68c608b9cead4acf1545a025e8
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>
48 #ifdef HAVE_SETRLIMIT
49 #include <sys/time.h>
50 #include <sys/resource.h>
51 #endif
53 #ifndef MEM_DEBUG
54 #include "mem.h"
55 #endif
57 #include "xml.h"
58 #include "common.h"
60 #ifdef WITH_PINENTRY
61 #include "pinentry.h"
62 #endif
64 #include "tls.h"
65 #include "commands.h"
66 #include "pwmd_error.h"
67 #include "cache.h"
68 #include "misc.h"
69 #include "pwmd.h"
71 GCRY_THREAD_OPTION_PTH_IMPL;
73 static void clear_errorfile_key()
75 gsize n;
76 gchar **groups;
77 gchar **p;
79 groups = g_key_file_get_groups(keyfileh, &n);
81 for (p = groups; *p; p++) {
82 GError *rc = NULL;
84 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
85 g_key_file_set_string(keyfileh, *p, "key", "");
88 g_strfreev(groups);
91 static void reload_rcfile()
93 log_write(N_("reloading configuration file '%s'"), rcfile);
94 g_key_file_free(keyfileh);
95 keyfileh = parse_rcfile(0);
96 clear_errorfile_key();
97 send_status_all(STATUS_CONFIG);
100 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
102 gpg_error_t n = gpg_error_from_errno(e);
104 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
107 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
109 gpg_err_code_t n = gpg_err_code(e);
110 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
111 struct client_s *client = assuan_get_pointer(ctx);
113 if (!e)
114 return assuan_process_done(ctx, 0);
116 if (!ctx) {
117 log_write("%s\n", pwmd_strerror(e));
118 return e;
121 if (n == EPWMD_LIBXML_ERROR) {
122 xmlErrorPtr xe = client->xml_error;
124 if (!xe)
125 xe = xmlGetLastError();
127 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
128 log_write("%s", xe->message);
130 if (xe == client->xml_error)
131 xmlResetError(xe);
132 else
133 xmlResetLastError();
135 client->xml_error = NULL;
136 return e;
139 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
142 void log_write(const gchar *fmt, ...)
144 gchar *args, *line;
145 va_list ap;
146 struct tm *tm;
147 time_t now;
148 gchar tbuf[21];
149 gint fd = -1;
150 pth_attr_t attr;
151 gchar *name;
152 pth_t tid = pth_self();
153 gchar tid_str[12], *p;
155 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
156 return;
158 if (logfile) {
159 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
160 warn(N_("logfile"));
161 return;
165 va_start(ap, fmt);
167 if (g_vasprintf(&args, fmt, ap) == -1) {
168 if (logfile)
169 close(fd);
171 va_end(ap);
172 return;
175 attr = pth_attr_of(tid);
177 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
178 name = "unknown";
180 pth_attr_destroy(attr);
181 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
182 p = tid_str;
184 if (strncmp(p+1, name, 9) == 0)
185 p = NULL;
187 if (log_syslog == TRUE)
188 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
190 va_end(ap);
191 time(&now);
192 tm = localtime(&now);
193 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
194 tbuf[sizeof(tbuf) - 1] = 0;
196 if (args[strlen(args)-1] == '\n')
197 args[strlen(args)-1] = 0;
199 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
200 p ? p : "", args);
201 g_free(args);
203 if (!line) {
204 if (logfile)
205 close(fd);
207 return;
210 if (logfile) {
211 write(fd, line, strlen(line));
212 fsync(fd);
213 close(fd);
216 if (isatty(STDERR_FILENO)) {
217 fprintf(stderr, "%s", line);
218 fflush(stderr);
221 g_free(line);
224 static void usage(gchar *pn)
226 g_printf(N_(
227 "Usage: %s [-hvDn] [-f <rcfile>] [-I <filename> [-i <iter>]] [file1] [...]\n"
228 " -n run as a foreground process\n"
229 " -f load the specified rcfile (~/.pwmd/config)\n"
230 " -I import an XML file and write the encrypted data to stdout\n"
231 " -i encrypt with the specified number of iterations when importing\n"
232 " (config default in the \"global\" section)\n"
233 " -D disable use of the LIST and DUMP commands\n"
234 " -v version\n"
235 " -h this help text\n"
236 ), pn);
237 exit(EXIT_SUCCESS);
240 #ifndef MEM_DEBUG
241 static int gcry_SecureCheck(const void *ptr)
243 return 1;
245 #endif
247 static void setup_gcrypt()
249 gcry_check_version(NULL);
251 #ifndef MEM_DEBUG
252 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
253 xfree);
254 #endif
256 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
257 NULL) != 0)
258 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
260 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
261 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
264 static gint new_connection(struct client_s *cl)
266 gpg_error_t rc;
267 gchar ver[ASSUAN_LINELENGTH];
269 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
271 if (rc)
272 goto fail;
274 assuan_set_pointer(cl->ctx, cl);
275 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
276 assuan_set_hello_line(cl->ctx, ver);
277 rc = register_commands(cl->ctx);
279 if (rc)
280 goto fail;
282 rc = assuan_accept(cl->ctx);
284 if (rc)
285 goto fail;
287 return 0;
289 fail:
290 assuan_deinit_server(cl->ctx);
291 log_write("%s", gpg_strerror(rc));
292 return 1;
295 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
297 gchar *line = NULL;
298 struct client_s *client = assuan_get_pointer(ctx);
299 gchar buf[ASSUAN_LINELENGTH];
300 gchar *status = NULL;
302 switch (which) {
303 case STATUS_CACHE:
304 CACHE_LOCK(client->ctx);
305 line = print_fmt(buf, sizeof(buf), "%i %i",
306 cache_file_count(),
307 (cache_size / sizeof(file_cache_t)) - cache_file_count());
308 CACHE_UNLOCK;
309 status = "CACHE";
310 break;
311 case STATUS_CLIENTS:
312 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
313 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
314 pth_mutex_release(&cn_mutex);
315 status = "CLIENTS";
316 break;
317 case STATUS_CONFIG:
318 status = "CONFIG";
319 break;
320 case STATUS_KEEPALIVE:
321 status = "KEEPALIVE";
322 break;
323 case STATUS_LOCKED:
324 status = "LOCKED";
325 line = N_("Waiting for lock");
326 break;
329 return assuan_write_status(ctx, status, line);
332 void send_status_all(status_msg_t which)
334 guint i, t;
336 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
338 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
339 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
340 pth_msgport_t m = pth_msgport_find(cn->msg_name);
342 if (m) {
343 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
345 msg->m_data = (status_msg_t *)which;
346 pth_msgport_put(m, msg);
350 pth_mutex_release(&cn_mutex);
353 static void xml_error_cb(void *data, xmlErrorPtr e)
355 struct client_s *client = data;
358 * Keep the first reported error as the one to show in the error
359 * description. Reset in send_error().
361 if (client->xml_error)
362 return;
364 xmlCopyError(e, client->xml_error);
368 * This is called after a child_thread terminates. Set with
369 * pth_cleanup_push().
371 static void cleanup_cb(void *arg)
373 struct client_thread_s *cn = arg;
374 gpointer value;
375 struct client_s *cl = cn->cl;
377 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
378 log_write(N_("exiting, fd=%i"), cn->fd);
379 pth_join(cn->tid, &value);
381 if (cl && cl->freed == FALSE)
382 cleanup_assuan(cl->ctx);
384 if (cl && cl->ctx)
385 assuan_deinit_server(cl->ctx);
387 #ifdef WITH_PINENTRY
388 if (cl && cl->pinentry)
389 cleanup_pinentry(cl->pinentry);
390 #endif
392 if (cn->tls) {
393 gnutls_deinit(cn->tls->ses);
394 g_free(cn->tls);
397 g_free(cl);
399 if (cn->msg_name)
400 g_free(cn->msg_name);
402 if (cn->msg) {
403 while (pth_msgport_pending(cn->msg) > 0) {
404 pth_message_t *m = pth_msgport_get(cn->msg);
406 g_free(m);
409 pth_msgport_destroy(cn->msg);
412 cn_thread_list = g_slist_remove(cn_thread_list, cn);
413 g_free(cn);
414 pth_mutex_release(&cn_mutex);
415 send_status_all(STATUS_CLIENTS);
418 static int read_hook(assuan_context_t ctx, assuan_fd_t fd, void *data,
419 size_t len, ssize_t *ret)
421 struct client_s *cl = assuan_get_pointer(ctx);
423 if (!cl || !cl->thd->remote)
424 *ret = pth_read((int)fd, data, len);
425 else {
426 do {
427 *ret = gnutls_record_recv(cl->thd->tls->ses, data, len);
429 if (*ret == GNUTLS_E_REHANDSHAKE) {
430 *ret = gnutls_rehandshake(cl->thd->tls->ses);
432 if (*ret == GNUTLS_E_WARNING_ALERT_RECEIVED ||
433 *ret == GNUTLS_A_NO_RENEGOTIATION) {
434 log_write("%s", gnutls_strerror(*ret));
435 continue;
438 if (*ret != GNUTLS_E_SUCCESS) {
439 log_write("%s", gnutls_strerror(*ret));
440 *ret = 0;
441 break;
444 *ret = gnutls_handshake(cl->thd->tls->ses);
446 if (*ret != GNUTLS_E_SUCCESS) {
447 log_write("%s", gnutls_strerror(*ret));
448 *ret = 0;
449 break;
452 continue;
454 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
457 return *ret <= 0 ? 0 : 1;
460 static int write_hook(assuan_context_t ctx, assuan_fd_t fd, const void *data,
461 size_t len, ssize_t *ret)
463 struct client_s *cl = assuan_get_pointer(ctx);
465 if (!cl || !cl->thd->remote)
466 *ret = pth_write((int)fd, data, len);
467 else {
468 do {
469 *ret = gnutls_record_send(cl->thd->tls->ses, data, len);
470 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
473 return *ret <= 0 ? 0 : 1;
477 * Called every time a connection is made via pth_spawn(). This is the thread
478 * entry point.
480 static void *client_thread(void *data)
482 struct client_thread_s *thd = data;
483 gint fd = thd->fd;
484 pth_event_t ev, msg_ev;
485 struct client_s *cl = g_malloc0(sizeof(struct client_s));
486 gpg_error_t rc;
488 if (!cl) {
489 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
490 goto fail;
493 thd->cl = cl;
494 cl->thd = thd;
495 pth_cleanup_push(cleanup_cb, thd);
498 * Do the TLS handshake before anything else.
500 if (thd->remote) {
501 thd->tls = tls_init(fd);
503 if (!thd->tls)
504 goto fail;
508 * This is a "child" thread. Don't catch any signals. Let the master
509 * thread take care of signals in accept_thread().
511 if (new_connection(cl))
512 goto fail;
514 #ifdef WITH_PINENTRY
515 cl->pinentry = pinentry_init();
517 if (!cl->pinentry) {
518 g_free(cl);
519 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
520 goto fail;
522 #endif
524 thd->msg_name = g_strdup_printf("%p", thd->tid);
526 if (!thd->msg_name) {
527 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
528 goto fail;
531 thd->msg = pth_msgport_create(thd->msg_name);
533 if (!thd->msg) {
534 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
535 goto fail;
538 #ifdef HAVE_MLOCKALL
539 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
540 log_write("mlockall(): %s", strerror(errno));
541 goto fail;
543 #endif
545 rc = send_status(cl->ctx, STATUS_CACHE);
547 if (rc) {
548 log_write("%s", gpg_strerror(rc));
549 goto fail;
552 send_status_all(STATUS_CLIENTS);
553 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
554 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
555 pth_event_concat(ev, msg_ev, NULL);
556 xmlInitParser();
557 xmlXPathInit();
558 xmlSetStructuredErrorFunc(cl, xml_error_cb);
560 for (;;) {
561 pth_status_t ev_status;
563 pth_wait(ev);
564 pth_event_isolate(ev);
565 pth_event_isolate(msg_ev);
566 ev_status = pth_event_status(msg_ev);
568 if (ev_status == PTH_STATUS_FAILED)
569 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
570 __FUNCTION__);
571 else if (ev_status == PTH_STATUS_OCCURRED) {
572 while (pth_msgport_pending(thd->msg) > 0) {
573 pth_message_t *m = pth_msgport_get(thd->msg);
574 status_msg_t n = (status_msg_t)m->m_data;
576 rc = send_status(cl->ctx, n);
577 g_free(m);
579 if (rc) {
580 log_write("%s", gpg_strerror(rc));
581 goto done;
586 ev_status = pth_event_status(ev);
587 pth_event_concat(ev, msg_ev, NULL);
589 if (ev_status == PTH_STATUS_FAILED) {
590 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
591 __FUNCTION__);
592 goto done;
594 else if (ev_status == PTH_STATUS_OCCURRED) {
595 rc = assuan_process_next(cl->ctx);
597 if (rc) {
598 cl->inquire_status = INQUIRE_INIT;
600 if (gpg_err_code(rc) == GPG_ERR_EOF)
601 goto done;
603 log_write("assuan_process_next(): %s", gpg_strerror(rc));
604 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
606 if (rc) {
607 log_write("assuan_process_done(): %s", gpg_strerror(rc));
608 goto done;
611 else {
612 #ifdef WITH_PINENTRY
613 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
614 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
615 pth_event_concat(ev, cl->pinentry->ev, NULL);
616 cl->pinentry->status = PINENTRY_RUNNING;
618 #endif
620 switch (cl->inquire_status) {
621 case INQUIRE_BUSY:
622 case INQUIRE_INIT:
623 break;
624 case INQUIRE_DONE:
625 cl->inquire_status = INQUIRE_INIT;
626 rc = assuan_process_done(cl->ctx, 0);
627 break;
632 #ifdef WITH_PINENTRY
633 ev = pinentry_iterate(cl, ev);
634 #endif
638 * Client cleanup (including XML data) is done in cleanup_cb() from
639 * the cleanup thread.
641 done:
642 pth_event_free(ev, PTH_FREE_ALL);
644 fail:
645 pth_exit(NULL);
646 return NULL;
649 static void setup_logging(GKeyFile *kf)
651 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
653 if (n == TRUE) {
654 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
656 if (*p == '~') {
657 gchar buf[PATH_MAX];
659 p++;
660 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
661 g_free(p);
663 if (logfile)
664 g_free(logfile);
666 logfile = g_strdup(buf);
668 else {
669 if (logfile)
670 g_free(logfile);
672 logfile = p;
676 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
680 * Make sure all settings are set to either the specified setting or a
681 * default.
683 static void set_rcfile_defaults(GKeyFile *kf)
685 gchar buf[PATH_MAX];
687 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
688 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
689 g_key_file_set_string(kf, "global", "socket_path", buf);
692 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
693 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
694 g_key_file_set_string(kf, "global", "data_directory", buf);
697 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
698 g_key_file_set_boolean(kf, "global", "backup", TRUE);
700 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
701 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
702 g_key_file_set_string(kf, "global", "log_path", buf);
705 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
706 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
708 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
709 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
711 #ifdef HAVE_MLOCKALL
712 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
713 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
714 #endif
716 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
717 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
719 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
720 g_key_file_set_integer(kf, "global", "iterations", 0);
722 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
723 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
725 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
726 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
728 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
729 g_key_file_set_integer(kf, "global", "compression_level", 6);
731 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
732 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
734 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
735 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
737 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
739 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
740 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
742 #ifdef HAVE_MLOCKALL
743 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
744 #endif
746 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
747 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
749 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
750 g_key_file_set_integer(kf, "global", "keepalive", 30);
752 #ifdef WITH_PINENTRY
753 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
754 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
756 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
757 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
758 #endif
760 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
761 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
763 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
764 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
766 setup_logging(kf);
769 static GKeyFile *parse_rcfile(int cmdline)
771 GKeyFile *kf = g_key_file_new();
772 GError *rc = NULL;
774 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
775 log_write("%s: %s", rcfile, rc->message);
777 if (cmdline)
778 exit(EXIT_FAILURE);
780 if (rc->code == G_FILE_ERROR_NOENT) {
781 g_clear_error(&rc);
782 set_rcfile_defaults(kf);
783 return kf;
786 g_clear_error(&rc);
787 return NULL;
789 else
790 set_rcfile_defaults(kf);
792 return kf;
795 static gchar *get_password(const gchar *prompt)
797 gchar buf[LINE_MAX] = {0}, *p;
798 struct termios told, tnew;
799 gchar *key;
801 if (tcgetattr(STDIN_FILENO, &told) == -1)
802 err(EXIT_FAILURE, "tcgetattr()");
804 memcpy(&tnew, &told, sizeof(struct termios));
805 tnew.c_lflag &= ~(ECHO);
806 tnew.c_lflag |= ICANON|ECHONL;
808 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
809 tcsetattr(STDIN_FILENO, TCSANOW, &told);
810 err(EXIT_FAILURE, "tcsetattr()");
813 fprintf(stderr, "%s", prompt);
815 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
816 tcsetattr(STDIN_FILENO, TCSANOW, &told);
817 return NULL;
820 tcsetattr(STDIN_FILENO, TCSANOW, &told);
821 p[strlen(p) - 1] = 0;
823 if (!buf[0]) {
824 key = gcry_malloc(1);
825 key[0] = 0;
827 else {
828 key = gcry_malloc(strlen(p) + 1);
829 sprintf(key, "%s", p);
832 memset(&buf, 0, sizeof(buf));
833 return key;
836 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
838 int fd;
839 struct stat st;
840 gpg_error_t rc;
841 gint iter;
843 if ((fd = open_file(filename, &st)) == -1) {
844 warn("%s", filename);
845 return FALSE;
848 if (st.st_size == 0) {
849 warnx(N_("%s: skipping empty file"), filename);
850 close(fd);
851 return FALSE;
854 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
855 close(fd);
856 return rc ? FALSE : TRUE;
859 static gboolean get_input(const gchar *filename, guchar *key)
861 gint try = 0;
862 gchar *password;
863 gchar *prompt;
865 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
867 again:
868 if ((password = get_password(prompt)) == NULL) {
869 warnx(N_("%s: skipping file"), filename);
870 g_free(prompt);
871 return FALSE;
874 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
875 gcry_free(password);
877 if (do_try_xml_decrypt(filename, key) == FALSE) {
878 if (try++ == 2) {
879 warnx(N_("%s: invalid password, skipping"), filename);
880 g_free(prompt);
881 return FALSE;
883 else {
884 warnx(N_("%s: invalid password"), filename);
885 goto again;
889 g_free(prompt);
890 return TRUE;
893 static gboolean xml_import(const gchar *filename, gint iter)
895 xmlDocPtr doc;
896 gint fd;
897 struct stat st;
898 gint len;
899 xmlChar *xmlbuf;
900 xmlChar *xml;
901 gchar *key = NULL;
902 gchar *key2 = NULL;
903 guchar shakey[gcrykeysize];
904 gcry_cipher_hd_t gh;
905 gpg_error_t rc;
906 gint level;
907 glong outsize;
908 gpointer outbuf;
909 gint zrc;
911 if (stat(filename, &st) == -1) {
912 warn("%s", filename);
913 return FALSE;
916 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
917 send_error(NULL, rc);
918 gcry_cipher_close(gh);
919 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
920 return FALSE;
923 if (iter == -1)
924 goto done;
926 if ((key = get_password(N_("New password: "))) == NULL) {
927 fprintf(stderr, "%s\n", N_("Invalid password."));
928 gcry_cipher_close(gh);
929 return FALSE;
932 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
933 fprintf(stderr, "%s\n", N_("Passwords do not match."));
934 gcry_free(key);
935 gcry_cipher_close(gh);
936 return FALSE;
939 if (g_utf8_collate(key, key2) != 0) {
940 fprintf(stderr, "%s\n", N_("Passwords do not match."));
941 gcry_free(key);
942 gcry_free(key2);
943 gcry_cipher_close(gh);
944 return FALSE;
947 gcry_free(key2);
949 done:
950 if ((fd = open(filename, O_RDONLY)) == -1) {
951 gcry_free(key);
952 warn("%s", filename);
953 gcry_cipher_close(gh);
954 return FALSE;
957 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
958 gcry_free(key);
959 close(fd);
960 log_write("%s", strerror(ENOMEM));
961 gcry_cipher_close(gh);
962 return FALSE;
965 if (read(fd, xmlbuf, st.st_size) == -1) {
966 rc = errno;
967 close(fd);
968 gcry_free(key);
969 gcry_cipher_close(gh);
970 errno = rc;
971 err(EXIT_FAILURE, "read()");
974 close(fd);
975 xmlbuf[st.st_size] = 0;
978 * Make sure the document validates.
980 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
981 log_write("xmlReadDoc()");
982 close(fd);
983 gcry_free(key);
984 gcry_free(xmlbuf);
985 gcry_cipher_close(gh);
986 return FALSE;
989 gcry_free(xmlbuf);
990 xmlDocDumpMemory(doc, &xml, &len);
991 xmlFreeDoc(doc);
993 level = get_key_file_integer(filename, "compression_level");
995 if (level < 0)
996 level = 0;
998 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
999 memset(shakey, 0, sizeof(shakey));
1000 gcry_free(xml);
1002 if (zrc == Z_MEM_ERROR)
1003 warnx("%s", strerror(ENOMEM));
1004 else
1005 warnx("do_compress() failed");
1007 gcry_cipher_close(gh);
1008 return FALSE;
1010 else {
1011 gcry_free(xml);
1012 xml = outbuf;
1013 len = outsize;
1016 if (iter == -1)
1017 memset(shakey, '!', sizeof(shakey));
1018 else{
1019 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
1020 gcry_free(key);
1023 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
1024 gcry_cipher_close(gh);
1026 if (rc) {
1027 memset(shakey, 0, sizeof(shakey));
1028 warnx("%s", gpg_strerror(rc));
1029 return FALSE;
1032 memset(shakey, 0, sizeof(shakey));
1033 return TRUE;
1036 gchar *get_key_file_string(const gchar *section, const gchar *what)
1038 gchar *val = NULL;
1039 GError *grc = NULL;
1041 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1042 val = g_key_file_get_string(keyfileh, section, what, &grc);
1044 if (grc) {
1045 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1046 g_clear_error(&grc);
1049 else {
1050 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1051 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1053 if (grc) {
1054 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1055 g_clear_error(&grc);
1060 return val;
1063 gint get_key_file_integer(const gchar *section, const gchar *what)
1065 gint val = -1;
1066 GError *grc = NULL;
1068 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1069 val = g_key_file_get_integer(keyfileh, section, what, &grc);
1071 if (grc) {
1072 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1073 g_clear_error(&grc);
1076 else {
1077 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1078 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1080 if (grc) {
1081 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1082 g_clear_error(&grc);
1087 return val;
1090 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1092 gboolean val = FALSE;
1093 GError *grc = NULL;
1095 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1096 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1098 if (grc) {
1099 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1100 g_clear_error(&grc);
1103 else {
1104 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1105 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1107 if (grc) {
1108 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1109 g_clear_error(&grc);
1114 return val;
1117 static gboolean _getline(const gchar *file, gchar **result)
1119 FILE *fp;
1120 gchar buf[LINE_MAX] = {0}, *p;
1121 gchar *str = NULL;
1122 gint len;
1124 if ((fp = fopen(file, "r")) == NULL) {
1125 warn("%s", file);
1126 return FALSE;
1129 p = fgets(buf, sizeof(buf), fp);
1130 fclose(fp);
1131 len = strlen(buf);
1133 if (len && buf[len - 1] == '\n')
1134 buf[--len] = 0;
1136 str = gcry_malloc(len + 1);
1137 memcpy(str, buf, len ? len : 1);
1138 str[len] = 0;
1139 memset(&buf, 0, sizeof(buf));
1140 *result = str;
1141 return TRUE;
1144 static gboolean parse_keyfile_key()
1146 gsize n;
1147 gchar **groups;
1148 gchar **p;
1149 gchar *str;
1151 groups = g_key_file_get_groups(keyfileh, &n);
1153 for (p = groups; *p; p++) {
1154 GError *rc = NULL;
1156 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1157 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1159 if (!str) {
1160 if (rc) {
1161 warnx("%s", rc->message);
1162 g_clear_error(&rc);
1165 continue;
1168 do_cache_push(*p, str);
1169 g_free(str);
1170 continue;
1173 if (rc) {
1174 warnx("%s", rc->message);
1175 g_clear_error(&rc);
1176 continue;
1179 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1180 gchar *t;
1181 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1183 if (!file) {
1184 if (rc) {
1185 warnx("%s", rc->message);
1186 g_clear_error(&rc);
1189 continue;
1192 t = expand_homedir(file);
1193 g_free(file);
1194 file = t;
1196 if (_getline(file, &str) == FALSE) {
1197 g_free(file);
1198 continue;
1201 g_free(file);
1202 do_cache_push(*p, str);
1203 gcry_free(str);
1204 continue;
1207 if (rc) {
1208 warnx("%s", rc->message);
1209 g_clear_error(&rc);
1213 g_strfreev(groups);
1214 return TRUE;
1217 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1219 guchar *md5file;
1220 guchar *key;
1221 gint timeout;
1222 const gchar *p = filename;
1223 file_header_t file_header;
1224 gpg_error_t rc;
1226 while (isspace(*p))
1227 p++;
1229 if (!*p)
1230 return FALSE;
1232 if (valid_filename(p) == FALSE) {
1233 warnx(N_("%s: invalid characters in filename"), p);
1234 return FALSE;
1237 md5file = gcry_malloc(16);
1238 key = gcry_malloc(gcrykeysize);
1239 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1241 if (cache_iscached(md5file) == TRUE) {
1242 warnx(N_("%s: file already cached, skipping"), p);
1243 gcry_free(md5file);
1244 gcry_free(key);
1245 return FALSE;
1248 if (access(p, R_OK|W_OK) != 0) {
1249 gcry_free(md5file);
1250 gcry_free(key);
1252 if (errno != ENOENT) {
1253 warn("%s", p);
1254 return FALSE;
1257 warn("%s", p);
1258 return TRUE;
1261 rc = read_file_header(filename, &file_header);
1263 if (rc) {
1264 gcry_free(md5file);
1265 gcry_free(key);
1266 warnx("%s", pwmd_strerror(rc));
1267 return FALSE;
1270 if (file_header.iter == -1) {
1271 memset(key, '!', gcrykeysize);
1272 goto try_decrypt;
1275 if (!password) {
1276 #ifdef WITH_PINENTRY
1277 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1278 #endif
1279 if (get_input(p, key) == FALSE) {
1280 gcry_free(key);
1281 gcry_free(md5file);
1282 return FALSE;
1284 #ifdef WITH_PINENTRY
1286 else {
1287 gchar *result = NULL;
1288 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1289 gint try = 0;
1291 set_pinentry_defaults(pin);
1292 pin->which = PINENTRY_OPEN;
1293 pin->filename = g_strdup(filename);
1294 again:
1295 rc = pinentry_getpin(pin, &result);
1297 if (rc) {
1298 warnx("%s: %s", filename, gpg_strerror(rc));
1299 cleanup_pinentry(pin);
1300 gcry_free(key);
1301 gcry_free(md5file);
1302 xfree(result);
1303 return FALSE;
1306 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1307 xfree(result);
1309 if (do_try_xml_decrypt(filename, key) == FALSE) {
1310 if (try++ == 2) {
1311 cleanup_pinentry(pin);
1312 gcry_free(key);
1313 gcry_free(md5file);
1314 warnx(N_("%s: invalid password, skipping"), filename);
1315 return FALSE;
1317 else {
1318 g_free(pin->title);
1319 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1320 goto again;
1324 cleanup_pinentry(pin);
1326 #endif
1328 else {
1329 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1331 try_decrypt:
1332 if (do_try_xml_decrypt(filename, key) == FALSE) {
1333 warnx(N_("%s: invalid password, skipping"), filename);
1334 gcry_free(key);
1335 gcry_free(md5file);
1336 return FALSE;
1340 if (cache_add_file(md5file, key) == FALSE) {
1341 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1342 gcry_free(key);
1343 gcry_free(md5file);
1344 return FALSE;
1347 timeout = get_key_file_integer(p, "cache_timeout");
1348 cache_set_timeout(md5file, timeout);
1349 warnx(N_("%s: file added to the cache"), filename);
1350 gcry_free(key);
1351 gcry_free(md5file);
1352 return TRUE;
1355 static void init_new_connection(gint fd, gchar *addr)
1357 pth_t tid;
1358 pth_attr_t attr;
1359 struct client_thread_s *new;
1360 gchar buf[41];
1362 new = g_malloc0(sizeof(struct client_thread_s));
1364 if (!new) {
1365 log_write("%s", strerror(ENOMEM));
1366 return;
1370 * Thread priority is inherited from the calling thread. This
1371 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1372 * priority.
1374 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1375 new->fd = fd;
1377 if (addr)
1378 new->remote = TRUE;
1380 attr = pth_attr_new();
1381 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1382 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1383 tid = pth_spawn(attr, client_thread, new);
1384 pth_attr_destroy(attr);
1386 if (!tid) {
1387 g_free(new);
1388 log_write(N_("pth_spawn() failed"));
1389 pth_mutex_release(&cn_mutex);
1390 return;
1393 g_snprintf(buf, sizeof(buf), "%p", tid);
1395 if (addr)
1396 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1397 else
1398 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1400 attr = pth_attr_of(tid);
1401 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1402 pth_attr_destroy(attr);
1403 new->tid = tid;
1404 cn_thread_list = g_slist_append(cn_thread_list, new);
1405 pth_mutex_release(&cn_mutex);
1408 static void *tcp_accept_thread(void *arg)
1410 gint sockfd = (gint)arg;
1412 for (;;) {
1413 struct sockaddr_in raddr;
1414 socklen_t slen = sizeof(raddr);
1415 gint fd = -1;
1417 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1418 if (errno != EAGAIN) {
1419 if (!quit) // probably EBADF
1420 log_write("accept(): %s", strerror(errno));
1422 break;
1426 if (fd >= 0)
1427 init_new_connection(fd, inet_ntoa(raddr.sin_addr));
1430 /* Just in case pth_accept() failed for some reason other than EBADF */
1431 quit = 1;
1432 pth_exit(PTH_CANCELED);
1433 return NULL;
1436 static void *accept_thread(void *arg)
1438 gint sockfd = (gint)arg;
1440 for (;;) {
1441 socklen_t slen = sizeof(struct sockaddr_un);
1442 struct sockaddr_un raddr;
1443 gint fd = -1;
1445 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1446 if (errno != EAGAIN) {
1447 if (!quit) // probably EBADF
1448 log_write("accept(): %s", strerror(errno));
1450 break;
1454 if (fd >= 0)
1455 init_new_connection(fd, NULL);
1458 /* Just in case pth_accept() failed for some reason other than EBADF */
1459 quit = 1;
1460 pth_exit(PTH_CANCELED);
1461 return NULL;
1465 * This thread isn't joinable. For operations that block, these threads will
1466 * stack.
1468 static void *adjust_timer_thread(void *arg)
1470 CACHE_LOCK(NULL);
1471 cache_adjust_timer();
1472 CACHE_UNLOCK;
1473 return NULL;
1476 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1477 pth_attr_t attr)
1479 pth_status_t ev_status;
1480 pth_event_t ev;
1482 if (timeout_ev) {
1483 pth_event_isolate(timeout_ev);
1484 ev_status = pth_event_status(timeout_ev);
1485 pth_event_free(timeout_ev, PTH_FREE_THIS);
1487 if (ev_status == PTH_STATUS_OCCURRED) {
1489 * The timer event has expired. Update the file cache. When the
1490 * cache mutex is locked and the timer expires again, the threads
1491 * will stack.
1493 pth_spawn(attr, adjust_timer_thread, NULL);
1497 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1500 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1501 gint keepalive)
1503 pth_event_t ev = NULL;
1504 pth_status_t ev_status;
1506 if (keepalive_ev) {
1507 pth_event_isolate(keepalive_ev);
1508 ev_status = pth_event_status(keepalive_ev);
1510 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1511 if (ev_status == PTH_STATUS_OCCURRED)
1512 send_status_all(STATUS_KEEPALIVE);
1514 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1516 else
1517 ev = keepalive_ev;
1520 if (keepalive > 0 && !ev)
1521 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1523 return ev;
1526 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1528 pth_t accept_tid, tcp_accept_tid;
1529 guint n;
1530 sigset_t set;
1531 gint n_clients = 0;
1532 pth_attr_t attr;
1533 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1534 gint keepalive = get_key_file_integer("global", "keepalive");
1535 gpointer value;
1536 pth_status_t ev_status;
1538 pth_mutex_init(&cn_mutex);
1539 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1541 sigemptyset(&set);
1542 sigaddset(&set, SIGTERM);
1543 sigaddset(&set, SIGINT);
1544 sigaddset(&set, SIGUSR1);
1545 sigaddset(&set, SIGHUP);
1546 sigaddset(&set, SIGABRT);
1548 attr = pth_attr_new();
1549 pth_attr_init(attr);
1550 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1551 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1552 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1554 if (sockfd_r != -1)
1555 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1557 pth_attr_init(attr);
1558 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1559 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1562 * For the cache_timeout configuration parameter.
1564 timeout_ev = timeout_event_iterate(NULL, attr);
1565 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1566 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1568 do {
1569 gint sig = 0;
1571 pth_sigwait_ev(&set, &sig, timeout_ev);
1572 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1573 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1574 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1576 if (sig > 0) {
1577 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1579 /* Caught a signal. */
1580 switch (sig) {
1581 case SIGHUP:
1582 reload_rcfile();
1583 keepalive = get_key_file_integer("global", "keepalive");
1584 break;
1585 case SIGABRT:
1586 CACHE_LOCK(NULL);
1587 cache_clear(NULL, 2);
1588 CACHE_UNLOCK;
1589 #ifndef MEM_DEBUG
1590 xpanic();
1591 #endif
1592 exit(EXIT_FAILURE);
1593 case SIGUSR1:
1594 CACHE_LOCK(NULL);
1595 log_write(N_("clearing file cache"));
1596 cache_clear(NULL, 2);
1597 CACHE_UNLOCK;
1598 break;
1599 default:
1600 quit = 1;
1601 shutdown(sockfd, SHUT_RDWR);
1602 close(sockfd);
1604 if (sockfd_r != -1) {
1605 shutdown(sockfd_r, SHUT_RDWR);
1606 close(sockfd_r);
1608 break;
1611 } while (!quit);
1614 * We're out of the main server loop. This happens when a signal was sent
1615 * to terminate the daemon. We'll wait for all clients to disconnect
1616 * before exiting and ignore any following signals.
1618 pth_join(accept_tid, &value);
1620 if (sockfd_r != -1)
1621 pth_join(tcp_accept_tid, &value);
1623 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1624 unlink(*socketpath);
1625 g_free(*socketpath);
1626 *socketpath = NULL;
1628 if (n > 1)
1629 log_write(N_("waiting for all threads to terminate"));
1631 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1633 while (n > 1) {
1634 if (n != n_clients) {
1635 log_write(N_("%i threads remain"), n-1);
1636 n_clients = n;
1639 pth_wait(ev_quit);
1640 pth_event_isolate(ev_quit);
1641 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1642 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1643 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1644 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1647 pth_event_free(timeout_ev, PTH_FREE_THIS);
1648 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1649 pth_event_free(ev_quit, PTH_FREE_THIS);
1650 pth_attr_destroy(attr);
1654 * Called from pinentry_fork() in the child process.
1656 void free_client_list()
1658 gint i, t = g_slist_length(cn_thread_list);
1660 for (i = 0; i < t; i++) {
1661 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1663 free_client(cn->cl);
1666 memset(key_cache, 0, cache_size);
1669 int main(int argc, char *argv[])
1671 gint opt;
1672 struct sockaddr_un addr;
1673 struct sockaddr_in my_addr;
1674 struct passwd *pw = getpwuid(getuid());
1675 gchar buf[PATH_MAX];
1676 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1677 gchar *socketarg = NULL;
1678 gchar *datadir = NULL;
1679 gboolean n;
1680 gchar *p;
1681 gchar **cache_push = NULL;
1682 gint iter = 0;
1683 gchar *import = NULL;
1684 gint cmd_iterations = -1;
1685 gint default_timeout;
1686 gint rcfile_spec = 0;
1687 gint estatus = EXIT_FAILURE;
1688 gint sockfd, sockfd_r = -1;
1689 #ifndef MEM_DEBUG
1690 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1691 #endif
1692 gint do_unlink = 1;
1693 gboolean secure = FALSE;
1694 guint ptotal = 0;
1695 gint background = 1;
1696 sigset_t set;
1697 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1698 #if 0
1699 #ifndef DEBUG
1700 #ifdef HAVE_SETRLIMIT
1701 struct rlimit rl;
1703 rl.rlim_cur = rl.rlim_max = 0;
1705 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1706 err(EXIT_FAILURE, "setrlimit()");
1707 #endif
1708 #endif
1709 #endif
1711 #ifdef ENABLE_NLS
1712 setlocale(LC_ALL, "");
1713 bindtextdomain("pwmd", LOCALEDIR);
1714 textdomain("pwmd");
1715 #endif
1717 gpg_err_init();
1718 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1719 #ifndef MEM_DEBUG
1720 g_mem_set_vtable(&mtable);
1721 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1722 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1723 xmlInitMemory();
1724 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1725 xrealloc, xfree);
1726 #endif
1727 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1728 gnutls_global_init();
1729 gnutls_global_set_log_function(tls_log);
1730 gnutls_global_set_log_level(1);
1731 pth_init();
1732 assuan_set_io_hooks(&io_hooks);
1733 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1735 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1736 err(EXIT_FAILURE, "%s", buf);
1738 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1740 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1741 err(EXIT_FAILURE, "%s", buf);
1743 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1745 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1746 err(EXIT_FAILURE, "sysconf()");
1748 cache_size = page_size;
1750 while ((opt = getopt(argc, argv, "bnI:i:hvf:D")) != EOF) {
1751 switch (opt) {
1752 case 'b':
1753 /* Compatibility for version < 1.11 */
1754 break;
1755 case 'n':
1756 background = 0;
1757 break;
1758 case 'D':
1759 secure = TRUE;
1760 break;
1761 case 'I':
1762 import = optarg;
1763 break;
1764 case 'i':
1765 cmd_iterations = atoi(optarg);
1766 break;
1767 case 'f':
1768 g_free(rcfile);
1769 rcfile = g_strdup(optarg);
1770 rcfile_spec = 1;
1771 break;
1772 case 'v':
1773 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1774 exit(EXIT_SUCCESS);
1775 case 'h':
1776 default:
1777 usage(argv[0]);
1781 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1782 exit(EXIT_FAILURE);
1784 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1785 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1787 if (log_syslog == TRUE)
1788 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1790 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1791 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1792 errno = 0;
1794 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1795 warn("setpriority()");
1796 goto do_exit;
1800 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1801 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1803 #ifdef HAVE_MLOCKALL
1804 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1805 warn("mlockall()");
1806 goto do_exit;
1808 #endif
1810 setup_gcrypt();
1812 if (import) {
1813 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1814 g_key_file_free(keyfileh);
1815 g_free(rcfile);
1816 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1819 g_key_file_set_list_separator(keyfileh, ',');
1821 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1822 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1824 if (*p == '~') {
1825 p++;
1826 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1827 g_free(p);
1828 socketarg = g_strdup(buf);
1830 else
1831 socketarg = p;
1833 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1834 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1836 datadir = expand_homedir(p);
1837 g_free(p);
1839 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1840 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1841 disable_list_and_dump = n;
1843 else
1844 disable_list_and_dump = secure;
1846 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1847 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1848 else
1849 default_timeout = -1;
1851 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1852 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1854 if (cache_size < page_size || cache_size % page_size)
1855 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1858 setup_logging(keyfileh);
1860 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1861 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1863 if (argc != optind) {
1864 if (cache_push)
1865 ptotal = g_strv_length(cache_push);
1867 for (; optind < argc; optind++) {
1868 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1869 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1873 if (strchr(socketarg, '/') == NULL) {
1874 socketdir = g_get_current_dir();
1875 socketname = g_strdup(socketarg);
1876 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1878 else {
1879 socketname = g_strdup(strrchr(socketarg, '/'));
1880 socketname++;
1881 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1882 socketdir = g_strdup(socketarg);
1883 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1886 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1887 #ifdef MMAP_ANONYMOUS
1888 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1889 #else
1890 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1891 #endif
1892 err(EXIT_FAILURE, "mmap()");
1895 if (mlock(key_cache, cache_size) == -1)
1896 log_write("mlock(): %s", strerror(errno));
1898 memset(key_cache, 0, cache_size);
1900 if (chdir(datadir)) {
1901 warn("%s", datadir);
1902 unlink(socketpath);
1903 goto do_exit;
1906 if (parse_keyfile_key() == FALSE)
1907 goto do_exit;
1909 clear_errorfile_key();
1912 * Set the cache entry for a file. Prompts for the password.
1914 if (cache_push) {
1915 for (opt = 0; cache_push[opt]; opt++)
1916 do_cache_push(cache_push[opt], NULL);
1918 g_strfreev(cache_push);
1919 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1923 * bind() doesn't like the full pathname of the socket or any non alphanum
1924 * characters so change to the directory where the socket is wanted then
1925 * create it then change to datadir.
1927 if (chdir(socketdir)) {
1928 warn("%s", socketdir);
1929 goto do_exit;
1932 g_free(socketdir);
1934 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1935 warn("socket()");
1936 goto do_exit;
1939 addr.sun_family = AF_UNIX;
1940 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1942 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1943 warn("bind()");
1945 if (errno == EADDRINUSE)
1946 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1947 "stale socket. Please remove it manually."), socketpath);
1949 do_unlink = 0;
1950 goto do_exit;
1953 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1954 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1955 mode_t mode = strtol(t, NULL, 8);
1956 mode_t mask = umask(0);
1958 g_free(t);
1960 if (chmod(socketname, mode) == -1) {
1961 warn("%s", socketname);
1962 close(sockfd);
1963 unlink(socketpath);
1964 umask(mask);
1965 goto do_exit;
1968 umask(mask);
1971 g_free(--socketname);
1973 if (chdir(datadir)) {
1974 warn("%s", datadir);
1975 close(sockfd);
1976 unlink(socketpath);
1977 goto do_exit;
1980 g_free(datadir);
1981 pth_mutex_init(&cache_mutex);
1982 #ifdef WITH_PINENTRY
1983 pth_mutex_init(&pin_mutex);
1984 #endif
1986 if (listen(sockfd, 0) == -1) {
1987 warn("listen()");
1988 goto do_exit;
1991 if (get_key_file_boolean("global", "enable_tcp")) {
1992 gint ret;
1993 gchar *tmp, *tmp2;
1995 if ((sockfd_r = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
1996 warn("socket()");
1997 goto do_exit;
2000 my_addr.sin_family = PF_INET;
2001 my_addr.sin_port = htons(get_key_file_integer("global", "tcp_port"));
2002 my_addr.sin_addr.s_addr = INADDR_ANY;
2003 memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
2005 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &iter, sizeof(int)) == -1) {
2006 warn("setsockopt");
2007 goto do_exit;
2010 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2011 gchar *tmp = get_key_file_string("global", "tcp_interface");
2013 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1) == -1) {
2014 warn("setsockopt");
2015 goto do_exit;
2018 g_free(tmp);
2021 if (bind(sockfd_r, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) {
2022 warn("bind()");
2023 do_unlink = 1;
2024 goto do_exit;
2027 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2029 if (!tmp) {
2030 warnx("%s", strerror(ENOMEM));
2031 goto do_exit;
2034 tmp2 = expand_homedir("~/.pwmd/ca-key.pem");
2036 if (!tmp2) {
2037 g_free(tmp);
2038 warnx("%s", strerror(ENOMEM));
2039 goto do_exit;
2042 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2044 if (ret != GNUTLS_E_SUCCESS) {
2045 g_free(tmp);
2046 g_free(tmp2);
2047 warnx("%s", gnutls_strerror(ret));
2048 goto do_exit;
2051 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2052 GNUTLS_X509_FMT_PEM);
2054 if (ret < 0) {
2055 g_free(tmp);
2056 g_free(tmp2);
2057 warnx("%s", gnutls_strerror(ret));
2058 goto do_exit;
2061 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2062 GNUTLS_X509_FMT_PEM);
2063 g_free(tmp);
2064 g_free(tmp2);
2066 if (ret != GNUTLS_E_SUCCESS) {
2067 warnx("%s", gnutls_strerror(ret));
2068 goto do_exit;
2071 log_write("%s", N_("Generating random data ..."));
2072 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2074 if (ret) {
2075 warnx("%s", gpg_strerror(ret));
2076 goto do_exit;
2079 ret = gnutls_dh_params_init(&dh_params);
2081 if (ret != GNUTLS_E_SUCCESS) {
2082 warnx("%s", gnutls_strerror(ret));
2083 goto do_exit;
2086 ret = gnutls_dh_params_generate2(dh_params, 1024);
2088 if (ret != GNUTLS_E_SUCCESS) {
2089 warnx("%s", gnutls_strerror(ret));
2090 goto do_exit;
2093 gnutls_certificate_set_dh_params (x509_cred, dh_params);
2094 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2096 if (listen(sockfd_r, 0) == -1) {
2097 warn("listen()");
2098 goto do_exit;
2102 if (background) {
2103 switch (fork()) {
2104 case -1:
2105 warn("fork()");
2106 goto do_exit;
2107 case 0:
2108 close(0);
2109 close(1);
2110 close(2);
2111 setsid();
2112 break;
2113 default:
2114 exit(EXIT_SUCCESS);
2119 * These are the signals that we use in threads. libpth can catch signals
2120 * itself so ignore them everywhere else. Note that using
2121 * signal(N, SIG_IGN) doesn't work like you might think.
2123 sigemptyset(&set);
2125 /* Termination */
2126 sigaddset(&set, SIGTERM);
2127 sigaddset(&set, SIGINT);
2129 /* Configuration file reloading. */
2130 sigaddset(&set, SIGUSR1);
2132 /* Clears the file cache. */
2133 sigaddset(&set, SIGHUP);
2135 /* Caught in client_thread(). Sends a cache status message. */
2136 sigaddset(&set, SIGUSR2);
2138 /* Ignored everywhere. When a client disconnects abnormally this signal
2139 * gets raised. It isn't needed though because client_thread() will check
2140 * for rcs even after the client disconnects. */
2141 signal(SIGPIPE, SIG_IGN);
2142 pth_sigmask(SIG_BLOCK, &set, NULL);
2143 server_loop(sockfd, sockfd_r, &socketpath);
2144 estatus = EXIT_SUCCESS;
2146 do_exit:
2147 if (socketpath && do_unlink) {
2148 unlink(socketpath);
2149 g_free(socketpath);
2152 if (sockfd_r != -1) {
2153 gnutls_dh_params_deinit(dh_params);
2154 gnutls_certificate_free_credentials(x509_cred);
2155 gnutls_global_deinit();
2158 g_key_file_free(keyfileh);
2159 g_free(rcfile);
2160 xmlCleanupParser();
2162 if (key_cache) {
2163 cache_clear(NULL, 2);
2164 memset(key_cache, 0, cache_size);
2167 if (key_cache && munmap(key_cache, cache_size) == -1)
2168 log_write("munmap(): %s", strerror(errno));
2170 if (estatus == EXIT_SUCCESS)
2171 log_write(N_("pwmd exiting normally"));
2173 pth_kill();
2174 #if defined(DEBUG) && !defined(MEM_DEBUG)
2175 xdump();
2176 #endif
2177 exit(estatus);