Fixed a minor potential segfault.
[pwmd.git] / src / pwmd.c
blob0ac9b7603b6f80c102d079301a37f95600283444
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 #ifdef TM_IN_SYS_TIME
54 #include <sys/time.h>
55 #else
56 #include <time.h>
57 #endif
59 #ifndef MEM_DEBUG
60 #include "mem.h"
61 #endif
63 #include "xml.h"
64 #include "common.h"
66 #ifdef WITH_PINENTRY
67 #include "pinentry.h"
68 #endif
70 #ifdef WITH_GNUTLS
71 #include "tls.h"
72 #endif
73 #include "commands.h"
74 #include "pwmd_error.h"
75 #include "cache.h"
76 #include "misc.h"
77 #include "pwmd.h"
79 GCRY_THREAD_OPTION_PTH_IMPL;
81 static void clear_errorfile_key()
83 gsize n;
84 gchar **groups;
85 gchar **p;
87 groups = g_key_file_get_groups(keyfileh, &n);
89 for (p = groups; *p; p++) {
90 GError *rc = NULL;
92 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
93 g_key_file_set_string(keyfileh, *p, "key", "");
96 g_strfreev(groups);
99 static void reload_rcfile()
101 log_write(N_("reloading configuration file '%s'"), rcfile);
102 g_key_file_free(keyfileh);
103 keyfileh = parse_rcfile(0);
104 clear_errorfile_key();
105 send_status_all(STATUS_CONFIG);
108 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
110 gpg_error_t n = gpg_error_from_errno(e);
112 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
115 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
117 gpg_err_code_t n = gpg_err_code(e);
118 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
119 struct client_s *client = assuan_get_pointer(ctx);
121 if (!e)
122 return assuan_process_done(ctx, 0);
124 if (!ctx) {
125 log_write("%s\n", pwmd_strerror(e));
126 return e;
129 if (n == EPWMD_LIBXML_ERROR) {
130 xmlErrorPtr xe = client->xml_error;
132 if (!xe)
133 xe = xmlGetLastError();
135 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
136 log_write("%s", xe->message);
138 if (xe == client->xml_error)
139 xmlResetError(xe);
140 else
141 xmlResetLastError();
143 client->xml_error = NULL;
144 return e;
147 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
150 void log_write(const gchar *fmt, ...)
152 gchar *args, *line;
153 va_list ap;
154 struct tm *tm;
155 time_t now;
156 gchar tbuf[21];
157 gint fd = -1;
158 pth_attr_t attr;
159 gchar *name;
160 pth_t tid = pth_self();
161 gchar tid_str[12], *p;
163 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
164 return;
166 if (logfile) {
167 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
168 warn(N_("logfile"));
169 return;
173 va_start(ap, fmt);
175 if (g_vasprintf(&args, fmt, ap) == -1) {
176 if (logfile)
177 close(fd);
179 va_end(ap);
180 return;
183 attr = pth_attr_of(tid);
185 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
186 name = "unknown";
188 pth_attr_destroy(attr);
189 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
190 p = tid_str;
192 if (strncmp(p+1, name, 9) == 0)
193 p = NULL;
195 if (log_syslog == TRUE)
196 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
198 va_end(ap);
199 time(&now);
200 tm = localtime(&now);
201 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
202 tbuf[sizeof(tbuf) - 1] = 0;
204 if (args[strlen(args)-1] == '\n')
205 args[strlen(args)-1] = 0;
207 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
208 p ? p : "", args);
209 g_free(args);
211 if (!line) {
212 if (logfile)
213 close(fd);
215 return;
218 if (logfile) {
219 write(fd, line, strlen(line));
220 fsync(fd);
221 close(fd);
224 if (isatty(STDERR_FILENO)) {
225 fprintf(stderr, "%s", line);
226 fflush(stderr);
229 g_free(line);
232 static void usage(gchar *pn)
234 g_fprintf(stderr, N_(
235 "Usage: %s [-hvDn] [-f <rcfile>] [-C <filename> -o <outfile>]\n"
236 " [-I <filename> [-i <iter>] -o <outfile>] [file1] [...]\n"
237 " -n run as a foreground process\n"
238 " -f load the specified rcfile (~/.pwmd/config)\n"
239 " -I import an XML file and write the encrypted data to stdout\n"
240 " -i encrypt with the specified number of iterations when importing\n"
241 " (config default in the \"global\" section)\n"
242 " -D disable use of the LIST and DUMP commands\n"
243 " -C convert a version 1 data file to version 2\n"
244 " -v version\n"
245 " -h this help text\n"
246 ), pn);
247 exit(EXIT_FAILURE);
250 #ifndef MEM_DEBUG
251 static int gcry_SecureCheck(const void *ptr)
253 return 1;
255 #endif
257 static void setup_gcrypt()
259 gcry_check_version(NULL);
261 #ifndef MEM_DEBUG
262 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
263 xfree);
264 #endif
266 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
267 NULL) != 0)
268 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
270 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
271 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
274 static gint new_connection(struct client_s *cl)
276 gpg_error_t rc;
277 gchar ver[ASSUAN_LINELENGTH];
279 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
281 if (rc)
282 goto fail;
284 assuan_set_pointer(cl->ctx, cl);
285 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
286 assuan_set_hello_line(cl->ctx, ver);
287 rc = register_commands(cl->ctx);
289 if (rc)
290 goto fail;
292 rc = assuan_accept(cl->ctx);
294 if (rc)
295 goto fail;
297 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
298 return 0;
300 fail:
301 assuan_deinit_server(cl->ctx);
302 log_write("%s", gpg_strerror(rc));
303 return 1;
306 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
308 gchar *line = NULL;
309 struct client_s *client = assuan_get_pointer(ctx);
310 gchar buf[ASSUAN_LINELENGTH];
311 gchar *status = NULL;
313 switch (which) {
314 case STATUS_CACHE:
315 CACHE_LOCK(client->ctx);
316 line = print_fmt(buf, sizeof(buf), "%i %i",
317 cache_file_count(),
318 (cache_size % sizeof(file_cache_t)) ?
319 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
320 (cache_size / sizeof(file_cache_t)) - cache_file_count());
321 CACHE_UNLOCK;
322 status = "CACHE";
323 break;
324 case STATUS_CLIENTS:
325 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
326 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
327 pth_mutex_release(&cn_mutex);
328 status = "CLIENTS";
329 break;
330 case STATUS_CONFIG:
331 status = "CONFIG";
332 break;
333 case STATUS_KEEPALIVE:
334 status = "KEEPALIVE";
335 break;
336 case STATUS_LOCKED:
337 status = "LOCKED";
338 line = N_("Waiting for lock");
339 break;
342 return assuan_write_status(ctx, status, line);
345 void send_status_all(status_msg_t which)
347 guint i, t;
349 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
351 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
352 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
353 pth_msgport_t m = pth_msgport_find(cn->msg_name);
355 if (m) {
356 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
358 msg->m_data = (status_msg_t *)which;
359 pth_msgport_put(m, msg);
363 pth_mutex_release(&cn_mutex);
366 static void xml_error_cb(void *data, xmlErrorPtr e)
368 struct client_s *client = data;
371 * Keep the first reported error as the one to show in the error
372 * description. Reset in send_error().
374 if (client->xml_error)
375 return;
377 xmlCopyError(e, client->xml_error);
381 * This is called after a child_thread terminates. Set with
382 * pth_cleanup_push().
384 static void cleanup_cb(void *arg)
386 struct client_thread_s *cn = arg;
387 gpointer value;
388 struct client_s *cl = cn->cl;
390 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
391 log_write(N_("exiting, fd=%i"), cn->fd);
392 pth_join(cn->tid, &value);
394 if (cl && cl->freed == FALSE)
395 cleanup_assuan(cl->ctx);
397 if (cl && cl->ctx)
398 assuan_deinit_server(cl->ctx);
400 #ifdef WITH_PINENTRY
401 if (cl && cl->pinentry)
402 cleanup_pinentry(cl->pinentry);
403 #endif
405 #ifdef WITH_GNUTLS
406 if (cn->tls) {
407 gnutls_deinit(cn->tls->ses);
408 g_free(cn->tls);
410 #endif
412 g_free(cl);
414 if (cn->msg_name)
415 g_free(cn->msg_name);
417 if (cn->msg) {
418 while (pth_msgport_pending(cn->msg) > 0) {
419 pth_message_t *m = pth_msgport_get(cn->msg);
421 g_free(m);
424 pth_msgport_destroy(cn->msg);
427 cn_thread_list = g_slist_remove(cn_thread_list, cn);
428 g_free(cn);
429 pth_mutex_release(&cn_mutex);
430 send_status_all(STATUS_CLIENTS);
433 #ifdef WITH_GNUTLS
434 static int read_hook(assuan_context_t ctx, assuan_fd_t fd, void *data,
435 size_t len, ssize_t *ret)
437 struct client_s *cl = assuan_get_pointer(ctx);
439 if (!cl || !cl->thd->remote)
440 *ret = pth_read((int)fd, data, len);
441 else {
442 do {
443 *ret = gnutls_record_recv(cl->thd->tls->ses, data, len);
445 if (*ret == GNUTLS_E_REHANDSHAKE) {
446 *ret = gnutls_rehandshake(cl->thd->tls->ses);
448 if (*ret == GNUTLS_E_WARNING_ALERT_RECEIVED ||
449 *ret == GNUTLS_A_NO_RENEGOTIATION) {
450 log_write("%s", gnutls_strerror(*ret));
451 continue;
454 if (*ret != GNUTLS_E_SUCCESS) {
455 log_write("%s", gnutls_strerror(*ret));
456 *ret = 0;
457 break;
460 *ret = gnutls_handshake(cl->thd->tls->ses);
462 if (*ret != GNUTLS_E_SUCCESS) {
463 log_write("%s", gnutls_strerror(*ret));
464 *ret = 0;
465 break;
468 continue;
470 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
473 return *ret <= 0 ? 0 : 1;
476 static int write_hook(assuan_context_t ctx, assuan_fd_t fd, const void *data,
477 size_t len, ssize_t *ret)
479 struct client_s *cl = assuan_get_pointer(ctx);
481 if (!cl || !cl->thd->remote)
482 *ret = pth_write((int)fd, data, len);
483 else {
484 do {
485 *ret = gnutls_record_send(cl->thd->tls->ses, data, len);
486 } while (*ret == GNUTLS_E_INTERRUPTED || *ret == GNUTLS_E_AGAIN);
489 return *ret <= 0 ? 0 : 1;
491 #endif
494 * Called every time a connection is made via pth_spawn(). This is the thread
495 * entry point.
497 static void *client_thread(void *data)
499 struct client_thread_s *thd = data;
500 pth_event_t ev, msg_ev;
501 struct client_s *cl = g_malloc0(sizeof(struct client_s));
502 gpg_error_t rc;
505 * Prevent a race condition with init_new_connection() if this thread
506 * fails (returns) for some reason before init_new_connection() releases
507 * the cn_mutex.
509 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
510 pth_mutex_release(&cn_mutex);
512 if (!cl) {
513 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
514 goto fail;
517 thd->cl = cl;
518 cl->thd = thd;
519 pth_cleanup_push(cleanup_cb, thd);
521 #ifdef WITH_GNUTLS
523 * Do the TLS handshake before anything else.
525 if (thd->remote) {
526 thd->tls = tls_init(thd->fd);
528 if (!thd->tls) {
529 close(thd->fd);
530 goto fail;
533 #endif
536 * This is a "child" thread. Don't catch any signals. Let the master
537 * thread take care of signals in server_loop().
539 if (new_connection(cl))
540 goto fail;
542 #ifdef WITH_PINENTRY
543 cl->pinentry = pinentry_init();
545 if (!cl->pinentry) {
546 g_free(cl);
547 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
548 goto fail;
550 #endif
552 thd->msg_name = g_strdup_printf("%p", thd->tid);
554 if (!thd->msg_name) {
555 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
556 goto fail;
559 thd->msg = pth_msgport_create(thd->msg_name);
561 if (!thd->msg) {
562 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
563 goto fail;
566 #ifdef HAVE_MLOCKALL
567 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
568 log_write("mlockall(): %s", strerror(errno));
569 goto fail;
571 #endif
573 rc = send_status(cl->ctx, STATUS_CACHE);
575 if (rc) {
576 log_write("%s", gpg_strerror(rc));
577 goto fail;
580 send_status_all(STATUS_CLIENTS);
581 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->thd->fd);
582 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
583 pth_event_concat(ev, msg_ev, NULL);
584 xmlInitParser();
585 xmlXPathInit();
586 xmlSetStructuredErrorFunc(cl, xml_error_cb);
588 for (;;) {
589 pth_status_t ev_status;
591 pth_wait(ev);
592 pth_event_isolate(ev);
593 pth_event_isolate(msg_ev);
594 ev_status = pth_event_status(msg_ev);
596 if (ev_status == PTH_STATUS_FAILED)
597 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
598 __FUNCTION__);
599 else if (ev_status == PTH_STATUS_OCCURRED) {
600 while (pth_msgport_pending(thd->msg) > 0) {
601 pth_message_t *m = pth_msgport_get(thd->msg);
602 status_msg_t n = (status_msg_t)m->m_data;
604 rc = send_status(cl->ctx, n);
605 g_free(m);
607 if (rc) {
608 log_write("%s", gpg_strerror(rc));
609 goto done;
614 ev_status = pth_event_status(ev);
615 pth_event_concat(ev, msg_ev, NULL);
617 if (ev_status == PTH_STATUS_FAILED) {
618 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
619 __FUNCTION__);
620 goto done;
622 else if (ev_status == PTH_STATUS_OCCURRED) {
623 rc = assuan_process_next(cl->ctx);
625 if (rc) {
626 cl->inquire_status = INQUIRE_INIT;
628 if (gpg_err_code(rc) == GPG_ERR_EOF)
629 goto done;
631 log_write("assuan_process_next(): %s", gpg_strerror(rc));
632 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
634 if (rc) {
635 log_write("assuan_process_done(): %s", gpg_strerror(rc));
636 goto done;
639 else {
640 #ifdef WITH_PINENTRY
641 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
642 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
643 pth_event_concat(ev, cl->pinentry->ev, NULL);
644 cl->pinentry->status = PINENTRY_RUNNING;
646 #endif
648 switch (cl->inquire_status) {
649 case INQUIRE_BUSY:
650 case INQUIRE_INIT:
651 break;
652 case INQUIRE_DONE:
653 cl->inquire_status = INQUIRE_INIT;
654 rc = assuan_process_done(cl->ctx, 0);
655 break;
660 #ifdef WITH_PINENTRY
661 ev = pinentry_iterate(cl, ev);
662 #endif
666 * Client cleanup (including XML data) is done in cleanup_cb() from
667 * the cleanup thread.
669 done:
670 pth_event_free(ev, PTH_FREE_ALL);
672 fail:
673 pth_exit(NULL);
674 return NULL;
677 static void setup_logging(GKeyFile *kf)
679 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
681 if (n == TRUE) {
682 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
684 if (*p == '~') {
685 gchar buf[PATH_MAX];
687 p++;
688 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
689 g_free(p);
691 if (logfile)
692 g_free(logfile);
694 logfile = g_strdup(buf);
696 else {
697 if (logfile)
698 g_free(logfile);
700 logfile = p;
704 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
708 * Make sure all settings are set to either the specified setting or a
709 * default.
711 static void set_rcfile_defaults(GKeyFile *kf)
713 gchar buf[PATH_MAX];
715 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
716 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
717 g_key_file_set_string(kf, "global", "socket_path", buf);
720 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
721 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
722 g_key_file_set_string(kf, "global", "data_directory", buf);
725 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
726 g_key_file_set_boolean(kf, "global", "backup", TRUE);
728 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
729 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
730 g_key_file_set_string(kf, "global", "log_path", buf);
733 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
734 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
736 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
737 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
739 #ifdef HAVE_MLOCKALL
740 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
741 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
742 #endif
744 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
745 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
747 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
748 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
749 g_key_file_set_integer(kf, "global", "iterations", 0);
751 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
752 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
754 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
755 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
757 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
758 g_key_file_set_integer(kf, "global", "compression_level", 6);
760 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
761 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
763 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
764 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
766 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
768 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
769 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
771 #ifdef HAVE_MLOCKALL
772 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
773 #endif
775 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
776 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
778 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
779 g_key_file_set_integer(kf, "global", "keepalive", 30);
781 #ifdef WITH_PINENTRY
782 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
783 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
785 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
786 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
787 #endif
789 #ifdef WITH_GNUTLS
790 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
791 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
793 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
794 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
795 #endif
797 setup_logging(kf);
800 static GKeyFile *parse_rcfile(int cmdline)
802 GKeyFile *kf = g_key_file_new();
803 GError *rc = NULL;
805 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
806 log_write("%s: %s", rcfile, rc->message);
808 if (cmdline)
809 exit(EXIT_FAILURE);
811 if (rc->code == G_FILE_ERROR_NOENT) {
812 g_clear_error(&rc);
813 set_rcfile_defaults(kf);
814 return kf;
817 g_clear_error(&rc);
818 return NULL;
820 else
821 set_rcfile_defaults(kf);
823 return kf;
826 static gchar *do_get_password(const gchar *prompt)
828 gchar buf[LINE_MAX] = {0}, *p;
829 struct termios told, tnew;
830 gchar *key;
832 if (tcgetattr(STDIN_FILENO, &told) == -1) {
833 warn("tcgetattr()");
834 return NULL;
837 memcpy(&tnew, &told, sizeof(struct termios));
838 tnew.c_lflag &= ~(ECHO);
839 tnew.c_lflag |= ICANON|ECHONL;
841 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
842 warn("tcsetattr()");
843 tcsetattr(STDIN_FILENO, TCSANOW, &told);
844 return NULL;
847 fprintf(stderr, "%s", prompt);
849 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
850 tcsetattr(STDIN_FILENO, TCSANOW, &told);
851 return NULL;
854 tcsetattr(STDIN_FILENO, TCSANOW, &told);
855 p[strlen(p) - 1] = 0;
857 if (!buf[0]) {
858 key = gcry_malloc(1);
859 key[0] = 0;
861 else {
862 key = gcry_malloc(strlen(p) + 1);
863 sprintf(key, "%s", p);
866 memset(&buf, 0, sizeof(buf));
867 return key;
870 /* Only used when "enable_pinentry" is "false". */
871 static gboolean get_input(const gchar *filename, file_header_internal_t *fh,
872 guchar *key, pinentry_cmd_t which)
874 gint try = 0;
875 gchar *password;
876 gchar *prompt;
878 if (which == PINENTRY_SAVE) {
879 gchar *key1, *key2;
881 prompt = g_strdup_printf(N_("New passphrase for %s: "), filename);
882 key1 = do_get_password(prompt);
883 g_free(prompt);
885 if (!key1) {
886 warnx(N_("%s: skipping file"), filename);
887 return FALSE;
890 prompt = g_strdup_printf(N_("Repeat passphrase: "));
891 key2 = do_get_password(prompt);
892 g_free(prompt);
894 if (!key2) {
895 gcry_free(key1);
896 warnx(N_("%s: skipping file"), filename);
897 return FALSE;
900 if (strcmp(key1, key2)) {
901 gcry_free(key1);
902 gcry_free(key2);
903 warnx("passphrase mismatch");
904 return FALSE;
907 gcry_md_hash_buffer(GCRY_MD_SHA256, key, key1,
908 strlen(key1) ? strlen(key1) : 1);
909 gcry_free(key1);
910 gcry_free(key2);
911 return TRUE;
914 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
916 do {
917 gpg_error_t rc;
919 if ((password = do_get_password(prompt)) == NULL) {
920 warnx(N_("%s: skipping file"), filename);
921 g_free(prompt);
922 return FALSE;
925 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
926 gcry_free(password);
928 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
930 if (!rc)
931 break;
933 fprintf(stderr, N_("%s: Invalid passphrase"), filename);
934 } while (try++ < 2);
936 g_free(prompt);
938 if (try == 3) {
939 fprintf(stderr, N_("%s: Invalid passphrase, skipping"), filename);
940 return FALSE;
943 return TRUE;
947 * inbuf must have been allocated with gcry_malloc().
949 gpg_error_t export_common(const gchar *filename, file_header_internal_t *fh,
950 guchar *shakey, gpointer inbuf, gulong insize)
952 gcry_cipher_hd_t gh;
953 gpg_error_t rc;
954 gint level, zrc;
955 glong outsize;
956 gpointer outbuf;
958 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
960 if (rc)
961 return rc;
963 level = get_key_file_integer(filename, "compression_level");
965 if (level < 0)
966 level = 0;
968 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
969 == FALSE) {
970 gcry_cipher_close(gh);
971 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
973 else {
974 gcry_free(inbuf);
975 inbuf = outbuf;
976 insize = outsize;
979 rc = do_xml_encrypt(NULL, gh, filename, inbuf, insize, shakey, fh->fh2.iter);
980 gcry_cipher_close(gh);
981 return rc;
984 static gboolean get_password(const gchar *filename, file_header_internal_t *fh,
985 guchar *md5file, guchar *key, pinentry_cmd_t which)
987 #ifdef WITH_PINENTRY
988 gpg_error_t rc = 0;
990 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
991 == FALSE) {
992 #endif
993 return get_input(filename, fh, key, which);
994 #ifdef WITH_PINENTRY
996 else {
997 gchar *result = NULL;
998 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
999 gint try = 0;
1001 set_pinentry_defaults(pin);
1002 pin->which = which;
1003 pin->filename = g_strdup(filename);
1004 again:
1005 rc = pinentry_getpin(pin, &result);
1007 if (rc) {
1008 warnx("%s", gpg_strerror(rc));
1009 xfree(result);
1010 goto done;
1013 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1014 xfree(result);
1016 if (which == PINENTRY_SAVE) {
1017 cleanup_pinentry(pin);
1018 goto done;
1021 rc = try_xml_decrypt(NULL, key, fh, &fh->doc, &fh->len);
1023 if (rc == EPWMD_BADKEY) {
1024 if (try++ == 2)
1025 warnx("%s: %s", filename, pwmd_strerror(rc));
1026 else {
1027 g_free(pin->title);
1028 pin->title = g_strdup(N_("Incorrect passphrase. Please try again."));
1029 goto again;
1032 else if (rc)
1033 warnx("%s", pwmd_strerror(rc));
1035 cleanup_pinentry(pin);
1038 done:
1039 return rc ? FALSE : TRUE;
1040 #endif
1043 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1044 gulong iter)
1046 xmlDocPtr doc;
1047 gint fd;
1048 struct stat st;
1049 gint len;
1050 xmlChar *xmlbuf;
1051 xmlChar *xml;
1052 guchar shakey[gcrykeysize];
1053 gpg_error_t rc;
1054 file_header_internal_t fh;
1056 if (stat(filename, &st) == -1) {
1057 warn("%s", filename);
1058 return FALSE;
1061 if (iter && get_password(filename, NULL, NULL, shakey, PINENTRY_SAVE)
1062 == FALSE)
1063 return FALSE;
1065 if ((fd = open(filename, O_RDONLY)) == -1) {
1066 memset(shakey, 0, sizeof(shakey));
1067 warn("%s", filename);
1068 return FALSE;
1071 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1072 close(fd);
1073 memset(shakey, 0, sizeof(shakey));
1074 log_write("%s", strerror(ENOMEM));
1075 return FALSE;
1078 if (read(fd, xmlbuf, st.st_size) == -1) {
1079 memset(shakey, 0, sizeof(shakey));
1080 rc = errno;
1081 close(fd);
1082 errno = rc;
1083 err(EXIT_FAILURE, "read()");
1086 close(fd);
1087 xmlbuf[st.st_size] = 0;
1090 * Make sure the document validates.
1092 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1093 log_write("xmlReadDoc()");
1094 close(fd);
1095 gcry_free(xmlbuf);
1096 memset(shakey, 0, sizeof(shakey));
1097 return FALSE;
1100 gcry_free(xmlbuf);
1101 xmlDocDumpMemory(doc, &xml, &len);
1102 xmlFreeDoc(doc);
1104 if (!iter)
1105 memset(shakey, '!', sizeof(shakey));
1107 memset(&fh, 0, sizeof(fh));
1108 fh.fh2.iter = iter;
1109 rc = export_common(outfile, &fh, shakey, xml, len);
1110 memset(shakey, 0, sizeof(shakey));
1112 if (rc)
1113 send_error(NULL, rc);
1115 return rc ? FALSE : TRUE;
1118 gchar *get_key_file_string(const gchar *section, const gchar *what)
1120 gchar *val = NULL;
1121 GError *grc = NULL;
1123 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1124 val = g_key_file_get_string(keyfileh, section, what, &grc);
1126 if (grc) {
1127 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1128 g_clear_error(&grc);
1131 else {
1132 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1133 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1135 if (grc) {
1136 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1137 g_clear_error(&grc);
1142 return val;
1145 gint get_key_file_integer(const gchar *section, const gchar *what)
1147 gint val = -1;
1148 GError *grc = NULL;
1150 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1151 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1153 if (grc) {
1154 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1155 g_clear_error(&grc);
1158 else {
1159 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1160 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1162 if (grc) {
1163 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1164 g_clear_error(&grc);
1169 return val;
1172 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1174 gboolean val = FALSE;
1175 GError *grc = NULL;
1177 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1178 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1180 if (grc) {
1181 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1182 g_clear_error(&grc);
1185 else {
1186 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1187 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1189 if (grc) {
1190 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1191 g_clear_error(&grc);
1196 return val;
1199 static gboolean _getline(const gchar *file, gchar **result)
1201 FILE *fp;
1202 gchar buf[LINE_MAX] = {0}, *p;
1203 gchar *str = NULL;
1204 gint len;
1206 if ((fp = fopen(file, "r")) == NULL) {
1207 warn("%s", file);
1208 return FALSE;
1211 p = fgets(buf, sizeof(buf), fp);
1212 fclose(fp);
1213 len = strlen(buf);
1215 if (len && buf[len - 1] == '\n')
1216 buf[--len] = 0;
1218 str = gcry_malloc(len + 1);
1219 memcpy(str, buf, len ? len : 1);
1220 str[len] = 0;
1221 memset(&buf, 0, sizeof(buf));
1222 *result = str;
1223 return TRUE;
1226 static gboolean parse_keyfile_key()
1228 gsize n;
1229 gchar **groups;
1230 gchar **p;
1231 gchar *str;
1233 groups = g_key_file_get_groups(keyfileh, &n);
1235 for (p = groups; *p; p++) {
1236 GError *rc = NULL;
1238 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1239 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1241 if (!str) {
1242 if (rc) {
1243 warnx("%s", rc->message);
1244 g_clear_error(&rc);
1247 continue;
1250 do_cache_push(*p, str);
1251 g_free(str);
1252 continue;
1255 if (rc) {
1256 warnx("%s", rc->message);
1257 g_clear_error(&rc);
1258 continue;
1261 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1262 gchar *t;
1263 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1265 if (!file) {
1266 if (rc) {
1267 warnx("%s", rc->message);
1268 g_clear_error(&rc);
1271 continue;
1274 t = expand_homedir(file);
1275 g_free(file);
1276 file = t;
1278 if (_getline(file, &str) == FALSE) {
1279 g_free(file);
1280 continue;
1283 g_free(file);
1284 do_cache_push(*p, str);
1285 gcry_free(str);
1286 continue;
1289 if (rc) {
1290 warnx("%s", rc->message);
1291 g_clear_error(&rc);
1295 g_strfreev(groups);
1296 return TRUE;
1299 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1301 guchar *md5file;
1302 guchar *key;
1303 gint timeout;
1304 const gchar *p = filename;
1305 file_header_internal_t *fh;
1306 gpg_error_t rc;
1308 while (isspace(*p))
1309 p++;
1311 if (!*p)
1312 return FALSE;
1314 if (valid_filename(p) == FALSE) {
1315 warnx(N_("%s: invalid characters in filename"), p);
1316 return FALSE;
1319 md5file = gcry_malloc(16);
1320 key = gcry_malloc(gcrykeysize);
1321 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1323 if (cache_iscached(md5file) == TRUE) {
1324 warnx(N_("%s: file already cached, skipping"), p);
1325 gcry_free(md5file);
1326 gcry_free(key);
1327 return FALSE;
1330 if (access(p, R_OK|W_OK) != 0) {
1331 gcry_free(md5file);
1332 gcry_free(key);
1334 if (errno != ENOENT) {
1335 warn("%s", p);
1336 return FALSE;
1339 warn("%s", p);
1340 return TRUE;
1343 fh = read_file_header(filename, FALSE, &rc);
1345 if (!fh) {
1346 gcry_free(md5file);
1347 gcry_free(key);
1348 warnx("%s", pwmd_strerror(rc));
1349 return FALSE;
1352 if (fh->fh2.iter <= 0) {
1353 memset(key, '!', gcrykeysize);
1354 goto try_decrypt;
1357 if (!password) {
1358 if (!get_password(p, fh, md5file, key, PINENTRY_OPEN)) {
1359 g_free(fh);
1360 return FALSE;
1363 else
1364 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password,
1365 strlen(password) ? strlen(password) : 1);
1367 try_decrypt:
1368 rc = try_xml_decrypt(NULL, key, fh, NULL, NULL);
1370 if (rc) {
1371 warnx("%s: %s", filename, pwmd_strerror(rc));
1372 gcry_free(key);
1373 gcry_free(md5file);
1374 g_free(fh);
1375 return FALSE;
1378 if (cache_add_file(md5file, key) == FALSE) {
1379 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1380 gcry_free(key);
1381 gcry_free(md5file);
1382 g_free(fh);
1383 return FALSE;
1386 timeout = get_key_file_integer(p, "cache_timeout");
1387 cache_set_timeout(md5file, timeout);
1388 warnx(N_("%s: file added to the cache"), filename);
1389 gcry_free(key);
1390 gcry_free(md5file);
1391 g_free(fh);
1392 return TRUE;
1395 static void init_new_connection(gint fd, gchar *addr)
1397 pth_t tid;
1398 pth_attr_t attr;
1399 struct client_thread_s *new;
1400 gchar buf[41];
1402 new = g_malloc0(sizeof(struct client_thread_s));
1404 if (!new) {
1405 log_write("%s", strerror(ENOMEM));
1406 return;
1410 * Thread priority is inherited from the calling thread. This
1411 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1412 * priority.
1414 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1415 new->fd = fd;
1417 if (addr)
1418 new->remote = TRUE;
1420 attr = pth_attr_new();
1421 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1422 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1423 tid = pth_spawn(attr, client_thread, new);
1424 pth_attr_destroy(attr);
1426 if (!tid) {
1427 g_free(new);
1428 log_write(N_("pth_spawn() failed"));
1429 pth_mutex_release(&cn_mutex);
1430 return;
1433 g_snprintf(buf, sizeof(buf), "%p", tid);
1435 if (addr)
1436 log_write(N_("new tid=%s, fd=%i, addr=%s"), buf, fd, addr);
1437 else
1438 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1440 attr = pth_attr_of(tid);
1441 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1442 pth_attr_destroy(attr);
1443 new->tid = tid;
1444 cn_thread_list = g_slist_append(cn_thread_list, new);
1445 pth_mutex_release(&cn_mutex);
1448 #ifdef WITH_GNUTLS
1449 static void *tcp_accept_thread(void *arg)
1451 gint sockfd = (gint)arg;
1453 for (;;) {
1454 struct sockaddr_in raddr;
1455 socklen_t slen = sizeof(raddr);
1456 gint fd = -1;
1458 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1459 if (errno != EAGAIN) {
1460 if (!quit) // probably EBADF
1461 log_write("accept(): %s", strerror(errno));
1463 break;
1467 if (quit)
1468 break;
1470 if (fd >= 0)
1471 init_new_connection(fd, inet_ntoa(raddr.sin_addr));
1474 /* Just in case pth_accept() failed for some reason other than EBADF */
1475 quit = 1;
1476 pth_exit(PTH_CANCELED);
1477 return NULL;
1479 #endif
1481 static void *accept_thread(void *arg)
1483 gint sockfd = (gint)arg;
1485 for (;;) {
1486 socklen_t slen = sizeof(struct sockaddr_un);
1487 struct sockaddr_un raddr;
1488 gint fd = -1;
1490 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1491 if (errno != EAGAIN) {
1492 if (!quit) // probably EBADF
1493 log_write("accept(): %s", strerror(errno));
1495 break;
1499 if (fd >= 0)
1500 init_new_connection(fd, NULL);
1503 /* Just in case pth_accept() failed for some reason other than EBADF */
1504 quit = 1;
1505 pth_exit(PTH_CANCELED);
1506 return NULL;
1510 * This thread isn't joinable. For operations that block, these threads will
1511 * stack.
1513 static void *adjust_timer_thread(void *arg)
1515 CACHE_LOCK(NULL);
1516 cache_adjust_timer();
1517 CACHE_UNLOCK;
1518 return NULL;
1521 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1522 pth_attr_t attr)
1524 pth_status_t ev_status;
1526 if (timeout_ev) {
1527 pth_event_isolate(timeout_ev);
1528 ev_status = pth_event_status(timeout_ev);
1529 pth_event_free(timeout_ev, PTH_FREE_THIS);
1531 if (ev_status == PTH_STATUS_OCCURRED) {
1533 * The timer event has expired. Update the file cache. When the
1534 * cache mutex is locked and the timer expires again, the threads
1535 * will stack.
1537 pth_spawn(attr, adjust_timer_thread, NULL);
1541 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1544 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1545 gint keepalive)
1547 pth_event_t ev = NULL;
1548 pth_status_t ev_status;
1550 if (keepalive_ev) {
1551 pth_event_isolate(keepalive_ev);
1552 ev_status = pth_event_status(keepalive_ev);
1554 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1555 if (ev_status == PTH_STATUS_OCCURRED)
1556 send_status_all(STATUS_KEEPALIVE);
1558 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1560 else
1561 ev = keepalive_ev;
1564 if (keepalive > 0 && !ev)
1565 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1567 return ev;
1570 static void server_loop(gint sockfd, gint sockfd_r, gchar **socketpath)
1572 pth_t accept_tid;
1573 #ifdef WITH_GNUTLS
1574 pth_t tcp_accept_tid;
1575 #endif
1576 guint n;
1577 sigset_t set;
1578 gint n_clients = 0;
1579 pth_attr_t attr;
1580 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1581 gint keepalive = get_key_file_integer("global", "keepalive");
1582 gpointer value;
1584 pth_mutex_init(&cn_mutex);
1585 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1586 sigemptyset(&set);
1587 sigaddset(&set, SIGTERM);
1588 sigaddset(&set, SIGINT);
1589 sigaddset(&set, SIGUSR1);
1590 sigaddset(&set, SIGHUP);
1591 sigaddset(&set, SIGABRT);
1593 attr = pth_attr_new();
1594 pth_attr_init(attr);
1595 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1596 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1597 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1599 #ifdef WITH_GNUTLS
1600 if (sockfd_r != -1) {
1601 pth_attr_set(attr, PTH_ATTR_NAME, "tcp_accept");
1602 tcp_accept_tid = pth_spawn(attr, tcp_accept_thread, (void *)sockfd_r);
1604 #endif
1606 pth_attr_init(attr);
1607 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1608 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1611 * For the cache_timeout configuration parameter.
1613 timeout_ev = timeout_event_iterate(NULL, attr);
1614 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1615 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1617 do {
1618 gint sig = 0;
1620 pth_sigwait_ev(&set, &sig, timeout_ev);
1621 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1622 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1623 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1625 if (sig > 0) {
1626 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1628 /* Caught a signal. */
1629 switch (sig) {
1630 case SIGHUP:
1631 reload_rcfile();
1632 keepalive = get_key_file_integer("global", "keepalive");
1633 break;
1634 case SIGABRT:
1635 CACHE_LOCK(NULL);
1636 cache_clear(NULL, 2);
1637 CACHE_UNLOCK;
1638 #ifndef MEM_DEBUG
1639 xpanic();
1640 #endif
1641 exit(EXIT_FAILURE);
1642 case SIGUSR1:
1643 CACHE_LOCK(NULL);
1644 log_write(N_("clearing file cache"));
1645 cache_clear(NULL, 2);
1646 CACHE_UNLOCK;
1647 break;
1648 default:
1649 quit = 1;
1650 shutdown(sockfd, SHUT_RDWR);
1651 close(sockfd);
1653 if (sockfd_r != -1) {
1654 shutdown(sockfd_r, SHUT_RDWR);
1655 close(sockfd_r);
1657 break;
1660 } while (!quit);
1663 * We're out of the main server loop. This happens when a signal was sent
1664 * to terminate the daemon. We'll wait for all clients to disconnect
1665 * before exiting and ignore any following signals.
1667 pth_join(accept_tid, &value);
1669 #ifdef WITH_GNUTLS
1670 if (sockfd_r != -1) {
1671 pth_cancel(tcp_accept_tid);
1672 pth_join(tcp_accept_tid, &value);
1674 #endif
1676 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1677 unlink(*socketpath);
1678 g_free(*socketpath);
1679 *socketpath = NULL;
1681 if (n > 1)
1682 log_write(N_("waiting for all threads to terminate"));
1684 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1686 while (n > 1) {
1687 if (n != n_clients) {
1688 log_write(N_("%i threads remain"), n-1);
1689 n_clients = n;
1692 pth_wait(ev_quit);
1693 pth_event_isolate(ev_quit);
1694 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1695 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1696 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1697 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1700 pth_event_free(timeout_ev, PTH_FREE_THIS);
1701 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1702 pth_event_free(ev_quit, PTH_FREE_THIS);
1703 pth_attr_destroy(attr);
1707 * Called from pinentry_fork() in the child process.
1709 void free_client_list()
1711 gint i, t = g_slist_length(cn_thread_list);
1713 for (i = 0; i < t; i++) {
1714 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1716 free_client(cn->cl);
1719 memset(key_cache, 0, cache_size);
1722 static gpg_error_t convert_file(const gchar *filename, const gchar *outfile)
1724 file_header_internal_t *fh;
1725 gpg_error_t rc;
1726 guchar *md5file;
1727 guchar *shakey;
1728 guint iter;
1730 md5file = gcry_malloc(16);
1731 if (!md5file)
1732 return GPG_ERR_ENOMEM;
1734 shakey = gcry_malloc(gcrykeysize);
1735 if (!shakey) {
1736 gcry_free(md5file);
1737 return GPG_ERR_ENOMEM;
1740 fh = read_file_header(filename, TRUE, &rc);
1742 if (!fh)
1743 goto done;
1745 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1747 /* The header in version 1 had a bug where the iterations were off-by-one.
1748 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1749 * header.
1751 if (fh->fh1.iter >= 0) {
1752 if (get_password(filename, fh, md5file, shakey, PINENTRY_OPEN)
1753 == FALSE) {
1754 rc = GPG_ERR_UNKNOWN_ERRNO;
1755 close(fh->fd);
1756 goto done;
1759 else
1760 rc = try_xml_decrypt(NULL, shakey, fh, &fh->doc, &fh->len);
1762 close(fh->fd);
1764 if (rc)
1765 goto done;
1767 fh->v1 = FALSE;
1768 iter = fh->fh1.iter;
1769 memset(&fh->fh2, 0, sizeof(fh->fh2));
1770 /* Keep the iterations and key from the original file. */
1771 fh->fh2.iter = iter+1;
1772 rc = export_common(outfile, fh, shakey, fh->doc, fh->len);
1774 if (rc)
1775 send_error(NULL, rc);
1777 done:
1778 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
1779 gcry_free(shakey);
1780 gcry_free(md5file);
1781 g_free(fh);
1782 return rc;
1785 int main(int argc, char *argv[])
1787 gint opt;
1788 struct sockaddr_un addr;
1789 struct passwd *pw = getpwuid(getuid());
1790 gchar buf[PATH_MAX];
1791 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1792 gchar *socketarg = NULL;
1793 gchar *datadir = NULL;
1794 gboolean n;
1795 gchar *p;
1796 gchar **cache_push = NULL;
1797 gint iter = 0;
1798 gchar *import = NULL;
1799 gulong cmd_iterations = -1;
1800 gint default_timeout;
1801 gint rcfile_spec = 0;
1802 gint estatus = EXIT_FAILURE;
1803 gint sockfd, sockfd_r = -1;
1804 gchar *outfile = NULL;
1805 #ifndef MEM_DEBUG
1806 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1807 #endif
1808 gint do_unlink = 1;
1809 gboolean secure = FALSE;
1810 guint ptotal = 0;
1811 gint background = 1;
1812 sigset_t set;
1813 gchar *convert = NULL;
1814 #ifdef WITH_GNUTLS
1815 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
1816 gint ret;
1817 struct sockaddr_in my_addr;
1818 #endif
1819 #if 0
1820 #ifndef DEBUG
1821 #ifdef HAVE_SETRLIMIT
1822 struct rlimit rl;
1824 rl.rlim_cur = rl.rlim_max = 0;
1826 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1827 err(EXIT_FAILURE, "setrlimit()");
1828 #endif
1829 #endif
1830 #endif
1832 #ifdef ENABLE_NLS
1833 setlocale(LC_ALL, "");
1834 bindtextdomain("pwmd", LOCALEDIR);
1835 textdomain("pwmd");
1836 #endif
1838 gpg_err_init();
1839 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1840 #ifndef MEM_DEBUG
1841 g_mem_set_vtable(&mtable);
1842 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1843 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1844 xmlInitMemory();
1845 #ifdef WITH_GNUTLS
1846 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
1847 xrealloc, xfree);
1848 #endif
1849 #endif
1850 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
1851 #ifdef WITH_GNUTLS
1852 gnutls_global_init();
1853 gnutls_global_set_log_function(tls_log);
1854 gnutls_global_set_log_level(1);
1855 assuan_set_io_hooks(&io_hooks);
1856 #endif
1857 pth_init();
1858 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1860 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1861 err(EXIT_FAILURE, "%s", buf);
1863 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1865 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1866 err(EXIT_FAILURE, "%s", buf);
1868 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1870 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1871 err(EXIT_FAILURE, "sysconf()");
1873 cache_size = page_size;
1875 while ((opt = getopt(argc, argv, "o:C:bnI:i:hvf:D")) != EOF) {
1876 switch (opt) {
1877 case 'o':
1878 outfile = optarg;
1879 break;
1880 case 'C':
1881 convert = optarg;
1882 break;
1883 case 'b':
1884 /* Compatibility for version < 1.11 */
1885 break;
1886 case 'n':
1887 background = 0;
1888 break;
1889 case 'D':
1890 secure = TRUE;
1891 break;
1892 case 'I':
1893 import = optarg;
1894 break;
1895 case 'i':
1896 cmd_iterations = strtol(optarg, NULL, 10);
1897 break;
1898 case 'f':
1899 g_free(rcfile);
1900 rcfile = g_strdup(optarg);
1901 rcfile_spec = 1;
1902 break;
1903 case 'v':
1904 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1905 exit(EXIT_SUCCESS);
1906 case 'h':
1907 default:
1908 usage(argv[0]);
1912 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1913 exit(EXIT_FAILURE);
1915 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1916 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1918 if (log_syslog == TRUE)
1919 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1921 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1922 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1923 errno = 0;
1925 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1926 warn("setpriority()");
1927 goto do_exit;
1931 #ifdef HAVE_MLOCKALL
1932 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1933 warn("mlockall()");
1934 goto do_exit;
1936 #endif
1938 setup_gcrypt();
1940 if (convert) {
1941 if (!outfile)
1942 usage(argv[0]);
1944 opt = convert_file(convert, outfile);
1945 g_key_file_free(keyfileh);
1946 g_free(rcfile);
1947 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1950 if (import) {
1951 if (!outfile)
1952 usage(argv[0]);
1954 if (cmd_iterations == -1)
1955 cmd_iterations = get_key_file_integer("global", "iterations");
1957 opt = xml_import(import, outfile, cmd_iterations);
1958 g_key_file_free(keyfileh);
1959 g_free(rcfile);
1960 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1963 g_key_file_set_list_separator(keyfileh, ',');
1965 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1966 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1968 if (*p == '~') {
1969 p++;
1970 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1971 g_free(p);
1972 socketarg = g_strdup(buf);
1974 else
1975 socketarg = p;
1977 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1978 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1980 datadir = expand_homedir(p);
1981 g_free(p);
1983 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1984 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1985 disable_list_and_dump = n;
1987 else
1988 disable_list_and_dump = secure;
1990 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1991 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1992 else
1993 default_timeout = -1;
1995 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1996 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1998 if (cache_size < page_size || cache_size % page_size)
1999 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
2002 setup_logging(keyfileh);
2004 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2005 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2007 if (argc != optind) {
2008 if (cache_push)
2009 ptotal = g_strv_length(cache_push);
2011 for (; optind < argc; optind++) {
2012 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2013 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2017 if (strchr(socketarg, '/') == NULL) {
2018 socketdir = g_get_current_dir();
2019 socketname = g_strdup(socketarg);
2020 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2022 else {
2023 socketname = g_strdup(strrchr(socketarg, '/'));
2024 socketname++;
2025 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2026 socketdir = g_strdup(socketarg);
2027 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2030 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
2031 #ifdef MMAP_ANONYMOUS
2032 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
2033 #else
2034 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
2035 #endif
2036 err(EXIT_FAILURE, "mmap()");
2039 if (mlock(key_cache, cache_size) == -1)
2040 log_write("mlock(): %s", strerror(errno));
2042 memset(key_cache, 0, cache_size);
2044 if (chdir(datadir)) {
2045 warn("%s", datadir);
2046 unlink(socketpath);
2047 goto do_exit;
2050 if (parse_keyfile_key() == FALSE)
2051 goto do_exit;
2053 clear_errorfile_key();
2056 * Set the cache entry for a file. Prompts for the password.
2058 if (cache_push) {
2059 for (opt = 0; cache_push[opt]; opt++)
2060 do_cache_push(cache_push[opt], NULL);
2062 g_strfreev(cache_push);
2063 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2067 * bind() doesn't like the full pathname of the socket or any non alphanum
2068 * characters so change to the directory where the socket is wanted then
2069 * create it then change to datadir.
2071 if (chdir(socketdir)) {
2072 warn("%s", socketdir);
2073 goto do_exit;
2076 g_free(socketdir);
2078 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2079 warn("socket()");
2080 goto do_exit;
2083 addr.sun_family = AF_UNIX;
2084 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2086 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2087 warn("bind()");
2089 if (errno == EADDRINUSE)
2090 warnx(N_("Either there is another pwmd running or '%s' is a \n"
2091 "stale socket. Please remove it manually."), socketpath);
2093 do_unlink = 0;
2094 goto do_exit;
2097 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2098 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2099 mode_t mode = strtol(t, NULL, 8);
2100 mode_t mask = umask(0);
2102 g_free(t);
2104 if (chmod(socketname, mode) == -1) {
2105 warn("%s", socketname);
2106 close(sockfd);
2107 unlink(socketpath);
2108 umask(mask);
2109 goto do_exit;
2112 umask(mask);
2115 g_free(--socketname);
2117 if (chdir(datadir)) {
2118 warn("%s", datadir);
2119 close(sockfd);
2120 unlink(socketpath);
2121 goto do_exit;
2124 g_free(datadir);
2125 pth_mutex_init(&cache_mutex);
2126 #ifdef WITH_PINENTRY
2127 pth_mutex_init(&pin_mutex);
2128 #endif
2130 if (listen(sockfd, 0) == -1) {
2131 warn("listen()");
2132 goto do_exit;
2135 #ifdef WITH_GNUTLS
2136 if (get_key_file_boolean("global", "enable_tcp")) {
2137 gchar *tmp, *tmp2;
2139 if ((sockfd_r = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
2140 warn("socket()");
2141 goto do_exit;
2144 my_addr.sin_family = PF_INET;
2145 my_addr.sin_port = htons(get_key_file_integer("global", "tcp_port"));
2146 my_addr.sin_addr.s_addr = INADDR_ANY;
2147 memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
2149 if (setsockopt(sockfd_r, SOL_SOCKET, SO_REUSEADDR, &iter, sizeof(int)) == -1) {
2150 warn("setsockopt");
2151 goto do_exit;
2154 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2155 gchar *tmp = get_key_file_string("global", "tcp_interface");
2157 if (setsockopt(sockfd_r, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1) == -1) {
2158 warn("setsockopt");
2159 goto do_exit;
2162 g_free(tmp);
2165 if (bind(sockfd_r, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) {
2166 warn("bind()");
2167 do_unlink = 1;
2168 goto do_exit;
2171 ret = gnutls_certificate_allocate_credentials(&x509_cred);
2173 if (ret != GNUTLS_E_SUCCESS) {
2174 warnx("%s", gnutls_strerror(ret));
2175 goto do_exit;
2178 tmp = expand_homedir("~/.pwmd/ca-cert.pem");
2180 if (!tmp) {
2181 warnx("%s", strerror(ENOMEM));
2182 goto do_exit;
2185 ret = gnutls_certificate_set_x509_trust_file(x509_cred, tmp,
2186 GNUTLS_X509_FMT_PEM);
2187 g_free(tmp);
2189 if (ret < 0) {
2190 warnx("%s", gnutls_strerror(ret));
2191 goto do_exit;
2194 tmp = expand_homedir("~/.pwmd/server-cert.pem");
2196 if (!tmp) {
2197 warnx("%s", strerror(ENOMEM));
2198 goto do_exit;
2201 tmp2 = expand_homedir("~/.pwmd/server-key.pem");
2203 if (!tmp2) {
2204 xfree(tmp);
2205 warnx("%s", strerror(ENOMEM));
2206 goto do_exit;
2209 ret = gnutls_certificate_set_x509_key_file (x509_cred, tmp, tmp2,
2210 GNUTLS_X509_FMT_PEM);
2211 g_free(tmp);
2212 g_free(tmp2);
2214 if (ret != GNUTLS_E_SUCCESS) {
2215 warnx("%s", gnutls_strerror(ret));
2216 goto do_exit;
2219 #endif
2221 if (background) {
2222 switch (fork()) {
2223 case -1:
2224 warn("fork()");
2225 goto do_exit;
2226 case 0:
2227 close(0);
2228 close(1);
2229 close(2);
2230 setsid();
2231 break;
2232 default:
2233 exit(EXIT_SUCCESS);
2237 #ifdef WITH_GNUTLS
2238 if (get_key_file_boolean("global", "enable_tcp")) {
2239 log_write("%s", N_("Generating key exchange parameters..."));
2240 ret = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
2242 if (ret) {
2243 warnx("%s", gpg_strerror(ret));
2244 goto do_exit;
2247 ret = gnutls_dh_params_init(&dh_params);
2249 if (ret != GNUTLS_E_SUCCESS) {
2250 warnx("%s", gnutls_strerror(ret));
2251 goto do_exit;
2254 ret = gnutls_dh_params_generate2(dh_params, 1024);
2256 if (ret != GNUTLS_E_SUCCESS) {
2257 warnx("%s", gnutls_strerror(ret));
2258 goto do_exit;
2261 gnutls_certificate_set_dh_params (x509_cred, dh_params);
2262 gnutls_certificate_set_params_function(x509_cred, tls_get_params);
2264 if (listen(sockfd_r, 0) == -1) {
2265 warn("listen()");
2266 goto do_exit;
2269 #endif
2272 * These are the signals that we use in threads. libpth can catch signals
2273 * itself so ignore them everywhere else. Note that using
2274 * signal(N, SIG_IGN) doesn't work like you might think.
2276 sigemptyset(&set);
2278 /* Termination */
2279 sigaddset(&set, SIGTERM);
2280 sigaddset(&set, SIGINT);
2282 /* Configuration file reloading. */
2283 sigaddset(&set, SIGUSR1);
2285 /* Clears the file cache. */
2286 sigaddset(&set, SIGHUP);
2288 /* Caught in client_thread(). Sends a cache status message. */
2289 sigaddset(&set, SIGUSR2);
2291 /* Ignored everywhere. When a client disconnects abnormally this signal
2292 * gets raised. It isn't needed though because client_thread() will check
2293 * for rcs even after the client disconnects. */
2294 signal(SIGPIPE, SIG_IGN);
2295 pth_sigmask(SIG_BLOCK, &set, NULL);
2296 server_loop(sockfd, sockfd_r, &socketpath);
2297 estatus = EXIT_SUCCESS;
2299 do_exit:
2300 if (socketpath && do_unlink) {
2301 unlink(socketpath);
2302 g_free(socketpath);
2305 #ifdef WITH_GNUTLS
2306 if (sockfd_r != -1) {
2307 gnutls_dh_params_deinit(dh_params);
2309 if (x509_cred)
2310 gnutls_certificate_free_credentials(x509_cred);
2312 gnutls_global_deinit();
2314 #endif
2316 g_key_file_free(keyfileh);
2317 g_free(rcfile);
2318 xmlCleanupParser();
2320 if (key_cache) {
2321 cache_clear(NULL, 2);
2322 memset(key_cache, 0, cache_size);
2325 if (key_cache && munmap(key_cache, cache_size) == -1)
2326 log_write("munmap(): %s", strerror(errno));
2328 if (estatus == EXIT_SUCCESS)
2329 log_write(N_("pwmd exiting normally"));
2331 pth_kill();
2332 #if defined(DEBUG) && !defined(MEM_DEBUG)
2333 xdump();
2334 #endif
2335 exit(estatus);