Use thread-safe libgcrypt and libgpg-error functions. Only call the new
[pwmd.git] / src / pwmd.c
blobfd35c1031a9e9fc8f9f879a9e19d05f075616250
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/un.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <glib.h>
38 #include <glib/gprintf.h>
39 #include <sys/mman.h>
40 #include <termios.h>
41 #include <assert.h>
42 #include <syslog.h>
43 #include <zlib.h>
44 #include <gcrypt.h>
46 #ifdef HAVE_SETRLIMIT
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #endif
51 #ifdef TM_IN_SYS_TIME
52 #include <sys/time.h>
53 #else
54 #include <time.h>
55 #endif
57 #include "mem.h"
59 #include "xml.h"
60 #include "common.h"
62 #ifdef WITH_PINENTRY
63 #include "pinentry.h"
64 #endif
66 #include "commands.h"
67 #include "pwmd_error.h"
68 #include "cache.h"
69 #include "misc.h"
70 #include "pwmd.h"
72 GCRY_THREAD_OPTION_PTH_IMPL;
74 static void clear_keyfile_key()
76 gsize n;
77 gchar **groups;
78 gchar **p;
80 groups = g_key_file_get_groups(keyfileh, &n);
82 for (p = groups; *p; p++) {
83 GError *rc = NULL;
85 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
86 g_key_file_set_string(keyfileh, *p, "key", "");
89 g_strfreev(groups);
92 static void reload_rcfile()
94 gboolean b = disable_list_and_dump;
95 GKeyFile *k;
97 log_write(N_("reloading configuration file '%s'"), rcfile);
98 k = parse_rcfile(0);
100 if (!k)
101 return;
103 g_key_file_free(keyfileh);
104 keyfileh = k;
105 clear_keyfile_key();
106 disable_list_and_dump = b;
107 send_status_all(STATUS_CONFIG);
110 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
112 gpg_error_t n = gpg_error_from_errno(e);
114 return assuan_process_done(ctx, assuan_set_error(ctx, n, _gpg_strerror(n)));
117 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
119 gpg_err_code_t n = gpg_err_code(e);
120 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
121 struct client_s *client = assuan_get_pointer(ctx);
123 if (!e)
124 return assuan_process_done(ctx, 0);
126 if (!ctx) {
127 log_write("%s\n", pwmd_strerror(e));
128 return e;
131 if (n == EPWMD_LIBXML_ERROR) {
132 xmlErrorPtr xe = client->xml_error;
134 if (!xe)
135 xe = xmlGetLastError();
137 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
138 log_write("%s", xe->message);
140 if (xe == client->xml_error)
141 xmlResetError(xe);
142 else
143 xmlResetLastError();
145 client->xml_error = NULL;
146 return e;
149 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
152 void log_write(const gchar *fmt, ...)
154 gchar *args, *line;
155 va_list ap;
156 struct tm *tm;
157 time_t now;
158 gchar tbuf[21];
159 gint fd = -1;
160 pth_attr_t attr;
161 gchar *name;
162 pth_t tid = pth_self();
163 gchar tid_str[12], *p;
165 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
166 return;
168 if (logfile) {
169 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
170 warn(N_("logfile"));
171 return;
175 va_start(ap, fmt);
177 if (g_vasprintf(&args, fmt, ap) == -1) {
178 if (logfile)
179 close(fd);
181 va_end(ap);
182 return;
185 attr = pth_attr_of(tid);
187 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
188 name = "unknown";
190 pth_attr_destroy(attr);
191 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
192 p = tid_str;
194 if (strncmp(p+1, name, 9) == 0)
195 p = NULL;
197 if (log_syslog == TRUE)
198 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
200 va_end(ap);
201 time(&now);
202 tm = localtime(&now);
203 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
204 tbuf[sizeof(tbuf) - 1] = 0;
206 if (args[strlen(args)-1] == '\n')
207 args[strlen(args)-1] = 0;
209 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
210 p ? p : "", args);
211 g_free(args);
213 if (!line) {
214 if (logfile)
215 close(fd);
217 return;
220 if (logfile) {
221 write(fd, line, strlen(line));
222 fsync(fd);
223 close(fd);
226 if (isatty(STDERR_FILENO)) {
227 fprintf(stderr, "%s", line);
228 fflush(stderr);
231 g_free(line);
234 static void usage(gchar *pn)
236 g_printf(N_(
237 "Usage: %s [-hvDn] [-f <rcfile>] [-I <filename> [-i <iter>] [-k <keyfile>]]\n [file1] [...]\n"
238 " -n run as a foreground process\n"
239 " -f load the specified rcfile (~/.pwmd/config)\n"
240 " -I import an XML file and write the encrypted data to stdout\n"
241 " -i encrypt with the specified number of iterations when importing\n"
242 " (config default in the \"global\" section)\n"
243 " -k when importing, obtain the key from the specified file\n"
244 " -D disable use of the LIST and DUMP commands\n"
245 " -v version\n"
246 " -h this help text\n"
247 ), pn);
248 exit(EXIT_SUCCESS);
251 static int gcry_SecureCheck(const void *ptr)
253 return 1;
256 static void setup_gcrypt()
258 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
259 gcry_check_version(NULL);
261 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
262 xfree);
264 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
265 NULL) != 0)
266 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
268 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
269 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
272 static assuan_context_t new_connection(gint fd)
274 gpg_error_t rc;
275 gchar ver[ASSUAN_LINELENGTH];
276 assuan_context_t ctx;
278 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
280 if (rc)
281 goto fail;
283 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
284 assuan_set_hello_line(ctx, ver);
285 rc = register_commands(ctx);
287 if (rc)
288 goto fail;
290 rc = assuan_accept(ctx);
292 if (rc)
293 goto fail;
295 return ctx;
297 fail:
298 log_write("%s", _gpg_strerror(rc));
299 return NULL;
302 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
304 const gchar *line = NULL;
305 struct client_s *client = assuan_get_pointer(ctx);
306 gchar buf[ASSUAN_LINELENGTH];
307 gchar *status = NULL;
309 switch (which) {
310 case STATUS_CACHE:
311 CACHE_LOCK(client->ctx);
312 line = print_fmt(buf, sizeof(buf), "%i %i",
313 cache_file_count(),
314 (cache_size % sizeof(file_cache_t)) ?
315 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
316 (cache_size / sizeof(file_cache_t)) - cache_file_count());
317 CACHE_UNLOCK;
318 status = "CACHE";
319 break;
320 case STATUS_CLIENTS:
321 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
322 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
323 pth_mutex_release(&cn_mutex);
324 status = "CLIENTS";
325 break;
326 case STATUS_CONFIG:
327 status = "CONFIG";
328 break;
329 case STATUS_KEEPALIVE:
330 status = "KEEPALIVE";
331 break;
332 case STATUS_LOCKED:
333 status = "LOCKED";
334 line = N_("Waiting for lock");
335 break;
338 return assuan_write_status(ctx, status, line);
341 void send_status_all(status_msg_t which)
343 guint i, t;
345 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
347 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
348 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
349 pth_msgport_t m = pth_msgport_find(cn->msg_name);
351 if (m) {
352 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
354 msg->m_data = (status_msg_t *)which;
355 pth_msgport_put(m, msg);
359 pth_mutex_release(&cn_mutex);
362 static void xml_error_cb(void *data, xmlErrorPtr e)
364 struct client_s *client = data;
367 * Keep the first reported error as the one to show in the error
368 * description. Reset in send_error().
370 if (client->xml_error)
371 return;
373 xmlCopyError(e, client->xml_error);
377 * This is called after a child_thread terminates. Set with
378 * pth_cleanup_push().
380 static void cleanup_cb(void *arg)
382 struct client_thread_s *cn = arg;
383 gpointer value;
384 struct client_s *cl = cn->cl;
386 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
387 log_write(N_("exiting, fd=%i"), cn->fd);
389 if (cn->msg_tid) {
390 pth_cancel(cn->msg_tid);
391 pth_join(cn->msg_tid, &value);
392 pth_event_free(cn->msg_ev, PTH_FREE_THIS);
395 if (cn->msg_name)
396 g_free(cn->msg_name);
398 if (cn->msg) {
399 while (pth_msgport_pending(cn->msg) > 0) {
400 pth_message_t *m = pth_msgport_get(cn->msg);
402 g_free(m);
405 pth_msgport_destroy(cn->msg);
408 pth_join(cn->tid, &value);
410 if (cl && cl->freed == FALSE)
411 cleanup_assuan(cl->ctx);
413 if (cl && cl->ctx)
414 assuan_deinit_server(cl->ctx);
416 #ifdef WITH_PINENTRY
417 if (cl && cl->pinentry)
418 cleanup_pinentry(cl->pinentry);
419 #endif
421 g_free(cl);
422 cn_thread_list = g_slist_remove(cn_thread_list, cn);
423 g_free(cn);
424 pth_mutex_release(&cn_mutex);
425 send_status_all(STATUS_CLIENTS);
428 static void *client_msg_thread(void *data)
430 struct client_s *cl = data;
431 pth_status_t ev_status;
433 for (;;) {
434 pth_wait(cl->thd->msg_ev);
435 ev_status = pth_event_status(cl->thd->msg_ev);
437 if (ev_status == PTH_STATUS_FAILED) {
438 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
439 __FUNCTION__);
440 continue;
443 if (ev_status == PTH_STATUS_OCCURRED) {
444 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
446 while (pth_msgport_pending(cl->thd->msg) > 0) {
447 pth_message_t *m = pth_msgport_get(cl->thd->msg);
448 status_msg_t n = (status_msg_t)m->m_data;
449 gpg_error_t rc = send_status(cl->ctx, n);
451 g_free(m);
453 if (rc) {
454 pth_mutex_release(&cn_mutex);
455 log_write("%s", _gpg_strerror(rc));
456 break;
460 pth_mutex_release(&cn_mutex);
466 * Called every time a connection is made via pth_spawn(). This is the thread
467 * entry point.
469 static void *client_thread(void *data)
471 struct client_thread_s *thd = data;
472 gint fd = thd->fd;
473 pth_event_t ev;
474 struct client_s *cl = g_malloc0(sizeof(struct client_s));
475 gpg_error_t rc;
476 pth_attr_t attr;
479 * Prevent a race condition with accept_thread() if this thread fails
480 * (returns) for some reason before accept_thread() releases the cn_mutex.
482 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
483 pth_mutex_release(&cn_mutex);
485 if (!cl) {
486 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
487 goto fail;
490 #ifdef WITH_PINENTRY
491 cl->pinentry = pinentry_init();
493 if (!cl->pinentry) {
494 g_free(cl);
495 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
496 goto fail;
498 #endif
500 thd->cl = cl;
501 cl->thd = thd;
502 pth_cleanup_push(cleanup_cb, thd);
503 thd->msg_name = g_strdup_printf("%p", thd->tid);
505 if (!thd->msg_name) {
506 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
507 goto fail;
510 thd->msg = pth_msgport_create(thd->msg_name);
512 if (!thd->msg) {
513 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
514 goto fail;
517 thd->msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
518 attr = pth_attr_new();
519 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
520 thd->msg_tid = pth_spawn(attr, client_msg_thread, cl);
521 pth_attr_destroy(attr);
523 if (!thd->msg_tid) {
524 log_write(N_("pth_spawn() failed"));
525 goto fail;
529 * This is a "child" thread. Don't catch any signals. Let the master
530 * thread take care of signals in accept_thread().
532 cl->ctx = new_connection(fd);
533 cl->fd = fd;
535 if (!cl->ctx)
536 goto fail;
538 assuan_set_pointer(cl->ctx, cl);
540 #ifdef HAVE_MLOCKALL
541 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
542 log_write("mlockall(): %s", strerror(errno));
543 goto fail;
545 #endif
547 rc = send_status(cl->ctx, STATUS_CACHE);
549 if (rc) {
550 log_write("%s", _gpg_strerror(rc));
551 goto fail;
554 send_status_all(STATUS_CLIENTS);
555 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
556 xmlInitParser();
557 xmlXPathInit();
558 xmlSetStructuredErrorFunc(cl, xml_error_cb);
560 for (;;) {
561 pth_status_t ev_status;
563 pth_wait(ev);
564 ev_status = pth_event_status(ev);
566 if (ev_status == PTH_STATUS_FAILED) {
567 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
568 __FUNCTION__);
569 goto done;
571 else if (ev_status == PTH_STATUS_OCCURRED) {
572 rc = assuan_process_next(cl->ctx);
574 if (rc) {
575 cl->inquire_status = INQUIRE_INIT;
577 if (gpg_err_code(rc) == GPG_ERR_EOF)
578 goto done;
580 log_write("assuan_process_next(): %s", _gpg_strerror(rc));
581 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
583 if (rc) {
584 log_write("assuan_process_done(): %s", _gpg_strerror(rc));
585 goto done;
588 else {
589 #ifdef WITH_PINENTRY
590 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
591 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
592 pth_event_concat(ev, cl->pinentry->ev, NULL);
593 cl->pinentry->status = PINENTRY_RUNNING;
595 #endif
597 switch (cl->inquire_status) {
598 case INQUIRE_BUSY:
599 case INQUIRE_INIT:
600 break;
601 case INQUIRE_DONE:
602 cl->inquire_status = INQUIRE_INIT;
603 rc = assuan_process_done(cl->ctx, 0);
604 break;
609 #ifdef WITH_PINENTRY
610 ev = pinentry_iterate(cl, ev);
611 #endif
615 * Client cleanup (including XML data) is done in cleanup_cb() from
616 * the cleanup thread.
618 done:
619 pth_event_free(ev, PTH_FREE_ALL);
621 fail:
622 pth_exit(NULL);
623 return NULL;
626 static void setup_logging(GKeyFile *kf)
628 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
630 if (n == TRUE) {
631 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
633 if (*p == '~') {
634 gchar buf[PATH_MAX];
636 p++;
637 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
638 g_free(p);
640 if (logfile)
641 g_free(logfile);
643 logfile = g_strdup(buf);
645 else {
646 if (logfile)
647 g_free(logfile);
649 logfile = p;
653 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
657 * Make sure all settings are set to either the specified setting or a
658 * default.
660 static void set_rcfile_defaults(GKeyFile *kf)
662 gchar buf[PATH_MAX];
664 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
665 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
666 g_key_file_set_string(kf, "global", "socket_path", buf);
669 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
670 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
671 g_key_file_set_string(kf, "global", "data_directory", buf);
674 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
675 g_key_file_set_boolean(kf, "global", "backup", TRUE);
677 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
678 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
679 g_key_file_set_string(kf, "global", "log_path", buf);
682 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
683 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
685 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
686 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
688 #ifdef HAVE_MLOCKALL
689 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
690 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
691 #endif
693 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
694 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
696 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
697 g_key_file_set_integer(kf, "global", "iterations", 0);
699 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
700 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
702 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
703 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
705 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
706 g_key_file_set_integer(kf, "global", "compression_level", 6);
708 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
709 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
711 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
712 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
714 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
716 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
717 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
719 #ifdef HAVE_MLOCKALL
720 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
721 #endif
723 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
724 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
726 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
727 g_key_file_set_integer(kf, "global", "keepalive", 30);
729 #ifdef WITH_PINENTRY
730 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
731 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
733 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
734 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
735 #endif
737 setup_logging(kf);
740 static GKeyFile *parse_rcfile(int cmdline)
742 GKeyFile *kf = g_key_file_new();
743 GError *rc = NULL;
745 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
746 log_write("%s: %s", rcfile, rc->message);
747 g_clear_error(&rc);
749 if (cmdline)
750 exit(EXIT_FAILURE);
752 if (rc->code == G_FILE_ERROR_NOENT) {
753 set_rcfile_defaults(kf);
754 return kf;
757 return NULL;
760 set_rcfile_defaults(kf);
761 return kf;
764 static gchar *get_password(const gchar *prompt)
766 gchar buf[LINE_MAX] = {0}, *p;
767 struct termios told, tnew;
768 gchar *key;
770 if (tcgetattr(STDIN_FILENO, &told) == -1)
771 err(EXIT_FAILURE, "tcgetattr()");
773 memcpy(&tnew, &told, sizeof(struct termios));
774 tnew.c_lflag &= ~(ECHO);
775 tnew.c_lflag |= ICANON|ECHONL;
777 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
778 tcsetattr(STDIN_FILENO, TCSANOW, &told);
779 err(EXIT_FAILURE, "tcsetattr()");
782 fprintf(stderr, "%s", prompt);
784 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
785 tcsetattr(STDIN_FILENO, TCSANOW, &told);
786 return NULL;
789 tcsetattr(STDIN_FILENO, TCSANOW, &told);
790 p[strlen(p) - 1] = 0;
792 if (!buf[0]) {
793 key = gcry_malloc(1);
794 key[0] = 0;
796 else {
797 key = gcry_malloc(strlen(p) + 1);
798 sprintf(key, "%s", p);
801 memset(&buf, 0, sizeof(buf));
802 return key;
805 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
807 int fd;
808 struct stat st;
809 gpg_error_t rc;
810 gint iter;
812 if ((fd = open_file(filename, &st)) == -1) {
813 warn("%s", filename);
814 return FALSE;
817 if (st.st_size == 0) {
818 warnx(N_("%s: Skipping empty file"), filename);
819 close(fd);
820 return FALSE;
823 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
824 close(fd);
825 return rc ? FALSE : TRUE;
828 static gboolean get_input(const gchar *filename, guchar *key)
830 gint try = 0;
831 gchar *password;
832 gchar *prompt;
834 prompt = g_strdup_printf(N_("Passphrase for '%s': "), filename);
836 again:
837 if ((password = get_password(prompt)) == NULL) {
838 warnx(N_("%s: Skipping file"), filename);
839 g_free(prompt);
840 return FALSE;
843 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
844 gcry_free(password);
846 if (do_try_xml_decrypt(filename, key) == FALSE) {
847 if (try++ == 2) {
848 warnx(N_("%s: Invalid passphrase, skipping"), filename);
849 g_free(prompt);
850 return FALSE;
852 else {
853 warnx(N_("%s: Invalid passphrase"), filename);
854 goto again;
858 g_free(prompt);
859 return TRUE;
862 static gboolean _getline(const gchar *file, gchar **result)
864 FILE *fp;
865 gchar buf[LINE_MAX] = {0}, *p;
866 gchar *str = NULL;
867 gint len;
869 if ((fp = fopen(file, "r")) == NULL) {
870 warn("%s", file);
871 return FALSE;
874 p = fgets(buf, sizeof(buf), fp);
875 fclose(fp);
876 len = strlen(buf);
878 if (len && buf[len - 1] == '\n')
879 buf[--len] = 0;
881 str = gcry_malloc(len + 1);
882 memcpy(str, buf, len ? len : 1);
883 str[len] = 0;
884 memset(&buf, 0, sizeof(buf));
885 *result = str;
886 return TRUE;
889 static gchar *parse_keyfile(const gchar *filename, gboolean import)
891 gchar *key = NULL;
892 GError *rc = NULL;
893 gchar *t, *file;
895 if (import == FALSE &&
896 g_key_file_has_key(keyfileh, filename, "key_file", &rc) == TRUE) {
897 file = g_key_file_get_string(keyfileh, filename, "key_file", &rc);
899 if (!file) {
900 if (rc) {
901 warnx("%s", rc->message);
902 g_clear_error(&rc);
905 return NULL;
908 t = expand_homedir(file);
909 g_free(file);
910 file = t;
912 if (_getline(file, &key) == FALSE) {
913 g_free(file);
914 return NULL;
917 g_free(file);
919 else if (import == TRUE) {
920 t = g_strdup(filename);
921 file = expand_homedir(t);
922 g_free(t);
924 if (_getline(file, &key) == FALSE) {
925 g_free(file);
926 return NULL;
929 g_free(file);
932 if (rc) {
933 warnx("%s", rc->message);
934 g_clear_error(&rc);
937 return key;
940 static gboolean xml_import(const gchar *filename, const char *keyfile,
941 gint iter)
943 xmlDocPtr doc;
944 gint fd;
945 struct stat st;
946 gint len;
947 xmlChar *xmlbuf;
948 xmlChar *xml;
949 gchar *key = NULL;
950 gchar *key2 = NULL;
951 guchar shakey[gcrykeysize];
952 gcry_cipher_hd_t gh;
953 gpg_error_t rc;
954 gint level;
955 glong outsize;
956 gpointer outbuf;
957 gint zrc;
959 if (stat(filename, &st) == -1) {
960 warn("%s", filename);
961 return FALSE;
964 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
965 send_error(NULL, rc);
966 gcry_cipher_close(gh);
967 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
968 return FALSE;
971 if (iter == -1)
972 goto done;
974 if (!keyfile) {
975 if ((key = get_password(N_("New passphrase: "))) == NULL) {
976 fprintf(stderr, "%s\n", N_("Invalid passphrase"));
977 gcry_cipher_close(gh);
978 return FALSE;
981 if ((key2 = get_password(N_("Verify passphrase: "))) == NULL) {
982 fprintf(stderr, "%s\n", N_("Passphrases do not match"));
983 gcry_free(key);
984 gcry_cipher_close(gh);
985 return FALSE;
988 if (g_utf8_collate(key, key2) != 0) {
989 fprintf(stderr, "%s\n", N_("Passphrases do not match"));
990 gcry_free(key);
991 gcry_free(key2);
992 gcry_cipher_close(gh);
993 return FALSE;
996 gcry_free(key2);
998 else {
999 key = parse_keyfile(keyfile, TRUE);
1001 if (!key) {
1002 gcry_cipher_close(gh);
1003 return FALSE;
1007 done:
1008 if ((fd = open(filename, O_RDONLY)) == -1) {
1009 gcry_free(key);
1010 warn("%s", filename);
1011 gcry_cipher_close(gh);
1012 return FALSE;
1015 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1016 gcry_free(key);
1017 close(fd);
1018 log_write("%s", strerror(ENOMEM));
1019 gcry_cipher_close(gh);
1020 return FALSE;
1023 if (read(fd, xmlbuf, st.st_size) == -1) {
1024 rc = errno;
1025 close(fd);
1026 gcry_free(key);
1027 gcry_cipher_close(gh);
1028 errno = rc;
1029 err(EXIT_FAILURE, "read()");
1032 close(fd);
1033 xmlbuf[st.st_size] = 0;
1036 * Make sure the document validates.
1038 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1039 log_write("xmlReadDoc()");
1040 close(fd);
1041 gcry_free(key);
1042 gcry_free(xmlbuf);
1043 gcry_cipher_close(gh);
1044 return FALSE;
1047 gcry_free(xmlbuf);
1048 xmlDocDumpMemory(doc, &xml, &len);
1049 xmlFreeDoc(doc);
1051 level = get_key_file_integer(filename, "compression_level");
1053 if (level < 0)
1054 level = 0;
1056 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
1057 memset(shakey, 0, sizeof(shakey));
1058 gcry_free(xml);
1060 if (zrc == Z_MEM_ERROR)
1061 warnx("%s", strerror(ENOMEM));
1062 else
1063 warnx("do_compress() failed");
1065 gcry_cipher_close(gh);
1066 return FALSE;
1068 else {
1069 gcry_free(xml);
1070 xml = outbuf;
1071 len = outsize;
1074 if (iter == -1)
1075 memset(shakey, '!', sizeof(shakey));
1076 else{
1077 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
1078 gcry_free(key);
1081 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
1082 gcry_cipher_close(gh);
1084 if (rc) {
1085 memset(shakey, 0, sizeof(shakey));
1086 warnx("%s", _gpg_strerror(rc));
1087 return FALSE;
1090 memset(shakey, 0, sizeof(shakey));
1091 return TRUE;
1094 gchar *get_key_file_string(const gchar *section, const gchar *what)
1096 gchar *val = NULL;
1097 GError *grc = NULL;
1099 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1100 val = g_key_file_get_string(keyfileh, section, what, &grc);
1102 if (grc) {
1103 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1104 g_clear_error(&grc);
1107 else {
1108 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1109 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1111 if (grc) {
1112 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1113 g_clear_error(&grc);
1118 return val;
1121 gint get_key_file_integer(const gchar *section, const gchar *what)
1123 gint val = -1;
1124 GError *grc = NULL;
1126 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1127 val = g_key_file_get_integer(keyfileh, section, what, &grc);
1129 if (grc) {
1130 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1131 g_clear_error(&grc);
1134 else {
1135 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1136 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1138 if (grc) {
1139 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1140 g_clear_error(&grc);
1145 return val;
1148 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1150 gboolean val = FALSE;
1151 GError *grc = NULL;
1153 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1154 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1156 if (grc) {
1157 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1158 g_clear_error(&grc);
1161 else {
1162 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1163 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1165 if (grc) {
1166 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1167 g_clear_error(&grc);
1172 return val;
1175 static gboolean parse_keyfile_key()
1177 gsize n;
1178 gchar **groups;
1179 gchar **p;
1180 gchar *str;
1182 groups = g_key_file_get_groups(keyfileh, &n);
1184 for (p = groups; *p; p++) {
1185 GError *rc = NULL;
1187 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1188 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1190 if (!str) {
1191 if (rc) {
1192 warnx("%s", rc->message);
1193 g_clear_error(&rc);
1196 continue;
1199 do_cache_push(*p, str);
1200 g_free(str);
1201 continue;
1204 if (rc) {
1205 warnx("%s", rc->message);
1206 g_clear_error(&rc);
1207 continue;
1210 str = parse_keyfile(*p, FALSE);
1212 if (str) {
1213 do_cache_push(*p, str);
1214 g_free(str);
1218 g_strfreev(groups);
1219 return TRUE;
1222 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1224 guchar *md5file;
1225 guchar *key;
1226 gint timeout;
1227 const gchar *p = filename;
1228 file_header_t file_header;
1229 gpg_error_t rc;
1231 while (isspace(*p))
1232 p++;
1234 if (!*p)
1235 return FALSE;
1237 if (valid_filename(p) == FALSE) {
1238 warnx(N_("%s: invalid characters in filename"), p);
1239 return FALSE;
1242 md5file = gcry_malloc(16);
1243 key = gcry_malloc(gcrykeysize);
1244 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1246 if (cache_iscached(md5file) == TRUE) {
1247 warnx(N_("%s: file already cached, skipping"), p);
1248 gcry_free(md5file);
1249 gcry_free(key);
1250 return FALSE;
1253 if (access(p, R_OK|W_OK) != 0) {
1254 gcry_free(md5file);
1255 gcry_free(key);
1257 if (errno != ENOENT) {
1258 warn("%s", p);
1259 return FALSE;
1262 warn("%s", p);
1263 return TRUE;
1266 rc = read_file_header(filename, &file_header);
1268 if (rc) {
1269 gcry_free(md5file);
1270 gcry_free(key);
1271 warnx("%s", pwmd_strerror(rc));
1272 return FALSE;
1275 if (file_header.iter == -1) {
1276 memset(key, '!', gcrykeysize);
1277 goto try_decrypt;
1280 if (!password) {
1281 #ifdef WITH_PINENTRY
1282 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1283 #endif
1284 if (get_input(p, key) == FALSE) {
1285 gcry_free(key);
1286 gcry_free(md5file);
1287 return FALSE;
1289 #ifdef WITH_PINENTRY
1291 else {
1292 gchar *result = NULL;
1293 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1294 gint try = 0;
1296 set_pinentry_defaults(pin);
1297 pin->which = PINENTRY_OPEN;
1298 pin->filename = g_strdup(filename);
1299 again:
1300 rc = pinentry_getpin(pin, &result);
1302 if (rc) {
1303 warnx("%s: %s", filename, _gpg_strerror(rc));
1304 cleanup_pinentry(pin);
1305 gcry_free(key);
1306 gcry_free(md5file);
1307 xfree(result);
1308 return FALSE;
1311 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1312 xfree(result);
1314 if (do_try_xml_decrypt(filename, key) == FALSE) {
1315 if (try++ == 2) {
1316 cleanup_pinentry(pin);
1317 gcry_free(key);
1318 gcry_free(md5file);
1319 warnx(N_("%s: Invalid passphrase, skipping"), filename);
1320 return FALSE;
1322 else {
1323 g_free(pin->title);
1324 pin->title = g_strdup(N_("Incorrect passphrase, try again"));
1325 goto again;
1329 cleanup_pinentry(pin);
1331 #endif
1333 else {
1334 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1336 try_decrypt:
1337 if (do_try_xml_decrypt(filename, key) == FALSE) {
1338 warnx(N_("%s: Invalid passphrase, skipping"), filename);
1339 gcry_free(key);
1340 gcry_free(md5file);
1341 return FALSE;
1345 if (cache_add_file(md5file, key) == FALSE) {
1346 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1347 gcry_free(key);
1348 gcry_free(md5file);
1349 return FALSE;
1352 timeout = get_key_file_integer(p, "cache_timeout");
1353 cache_set_timeout(md5file, timeout);
1354 warnx(N_("%s: file added to the cache"), filename);
1355 gcry_free(key);
1356 gcry_free(md5file);
1357 return TRUE;
1360 static void *accept_thread(void *arg)
1362 gint sockfd = (gint)arg;
1364 for (;;) {
1365 socklen_t slen = sizeof(struct sockaddr_un);
1366 struct sockaddr_un raddr;
1367 gint fd = -1;
1368 pth_attr_t attr;
1370 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1371 if (errno != EAGAIN) {
1372 if (!quit) // probably EBADF
1373 log_write("accept(): %s", strerror(errno));
1375 break;
1379 if (fd >= 0) {
1380 pth_t tid;
1381 struct client_thread_s *new;
1382 gchar buf[41];
1384 new = g_malloc0(sizeof(struct client_thread_s));
1386 if (!new) {
1387 log_write("%s", strerror(ENOMEM));
1388 continue;
1392 * Thread priority is inherited from the calling thread. This
1393 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1394 * priority.
1396 new->fd = fd;
1397 attr = pth_attr_new();
1398 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1399 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1400 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1401 tid = pth_spawn(attr, client_thread, new);
1402 pth_attr_destroy(attr);
1404 if (!tid) {
1405 g_free(new);
1406 log_write(N_("pth_spawn() failed"));
1407 pth_mutex_release(&cn_mutex);
1408 continue;
1411 g_snprintf(buf, sizeof(buf), "%p", tid);
1412 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1413 attr = pth_attr_of(tid);
1414 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1415 pth_attr_destroy(attr);
1416 new->tid = tid;
1417 cn_thread_list = g_slist_append(cn_thread_list, new);
1418 pth_mutex_release(&cn_mutex);
1422 /* Just in case pth_accept() failed for some reason other than EBADF */
1423 quit = 1;
1424 pth_exit(PTH_CANCELED);
1425 return NULL;
1429 * This thread isn't joinable. For operations that block, these threads will
1430 * stack.
1432 static void *adjust_timer_thread(void *arg)
1434 CACHE_LOCK(NULL);
1435 cache_adjust_timer();
1436 CACHE_UNLOCK;
1437 return NULL;
1440 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1441 pth_attr_t attr)
1443 pth_status_t ev_status;
1445 if (timeout_ev) {
1446 pth_event_isolate(timeout_ev);
1447 ev_status = pth_event_status(timeout_ev);
1448 pth_event_free(timeout_ev, PTH_FREE_THIS);
1450 if (ev_status == PTH_STATUS_OCCURRED) {
1452 * The timer event has expired. Update the file cache. When the
1453 * cache mutex is locked and the timer expires again, the threads
1454 * will stack.
1456 pth_spawn(attr, adjust_timer_thread, NULL);
1460 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1463 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1464 gint keepalive)
1466 pth_event_t ev = NULL;
1467 pth_status_t ev_status;
1469 if (keepalive_ev) {
1470 pth_event_isolate(keepalive_ev);
1471 ev_status = pth_event_status(keepalive_ev);
1473 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1474 if (ev_status == PTH_STATUS_OCCURRED)
1475 send_status_all(STATUS_KEEPALIVE);
1477 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1479 else
1480 ev = keepalive_ev;
1483 if (keepalive > 0 && !ev)
1484 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1486 return ev;
1489 static void server_loop(gint sockfd, gchar **socketpath)
1491 pth_t accept_tid;
1492 guint n;
1493 sigset_t set;
1494 gint n_clients = 0;
1495 pth_attr_t attr;
1496 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1497 gint keepalive = get_key_file_integer("global", "keepalive");
1498 gpointer value;
1500 pth_mutex_init(&cn_mutex);
1501 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1503 sigemptyset(&set);
1504 sigaddset(&set, SIGTERM);
1505 sigaddset(&set, SIGINT);
1506 sigaddset(&set, SIGUSR1);
1507 sigaddset(&set, SIGHUP);
1508 sigaddset(&set, SIGABRT);
1510 attr = pth_attr_new();
1511 pth_attr_init(attr);
1512 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MIN);
1513 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1514 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1515 pth_attr_init(attr);
1516 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1517 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1520 * For the cache_timeout configuration parameter.
1522 timeout_ev = timeout_event_iterate(NULL, attr);
1523 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1524 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1526 do {
1527 gint sig = 0;
1529 pth_sigwait_ev(&set, &sig, timeout_ev);
1530 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1531 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1532 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1534 if (sig > 0) {
1535 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1537 /* Caught a signal. */
1538 switch (sig) {
1539 case SIGHUP:
1540 reload_rcfile();
1541 keepalive = get_key_file_integer("global", "keepalive");
1542 break;
1543 case SIGABRT:
1544 CACHE_LOCK(NULL);
1545 cache_clear(NULL, 2);
1546 CACHE_UNLOCK;
1547 xpanic();
1548 exit(EXIT_FAILURE);
1549 case SIGUSR1:
1550 CACHE_LOCK(NULL);
1551 log_write(N_("clearing file cache"));
1552 cache_clear(NULL, 2);
1553 CACHE_UNLOCK;
1554 break;
1555 default:
1556 quit = 1;
1557 shutdown(sockfd, SHUT_RDWR);
1558 close(sockfd);
1559 break;
1562 } while (!quit);
1565 * We're out of the main server loop. This happens when a signal was sent
1566 * to terminate the daemon. We'll wait for all clients to disconnect
1567 * before exiting and ignore any following signals.
1569 pth_join(accept_tid, &value);
1570 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1571 unlink(*socketpath);
1572 g_free(*socketpath);
1573 *socketpath = NULL;
1575 if (n > 1)
1576 log_write(N_("waiting for all threads to terminate"));
1578 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1580 while (n > 1) {
1581 if (n != n_clients) {
1582 log_write(N_("%i threads remain"), n-1);
1583 n_clients = n;
1586 pth_wait(ev_quit);
1587 pth_event_isolate(ev_quit);
1588 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1589 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1590 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1591 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1594 pth_event_free(timeout_ev, PTH_FREE_THIS);
1595 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1596 pth_event_free(ev_quit, PTH_FREE_THIS);
1597 pth_attr_destroy(attr);
1601 * Called from pinentry_fork() in the child process.
1603 void free_client_list()
1605 gint i, t = g_slist_length(cn_thread_list);
1607 for (i = 0; i < t; i++) {
1608 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1610 free_client(cn->cl);
1613 memset(key_cache, 0, cache_size);
1616 int main(int argc, char *argv[])
1618 gint opt;
1619 struct sockaddr_un addr;
1620 struct passwd *pw = getpwuid(getuid());
1621 gchar buf[PATH_MAX];
1622 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1623 gchar *socketarg = NULL;
1624 gchar *datadir = NULL;
1625 gboolean n;
1626 gchar *p;
1627 gchar **cache_push = NULL;
1628 gint iter = 0;
1629 gchar *import = NULL, *keyfile = NULL;
1630 gint cmd_iterations = -2;
1631 gint default_timeout;
1632 gint rcfile_spec = 0;
1633 gint estatus = EXIT_FAILURE;
1634 gint sockfd;
1635 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1636 gint do_unlink = 1;
1637 gboolean secure = FALSE;
1638 guint ptotal = 0;
1639 gint background = 1;
1640 sigset_t set;
1641 #ifndef DEBUG
1642 #ifdef HAVE_SETRLIMIT
1643 struct rlimit rl;
1645 rl.rlim_cur = rl.rlim_max = 0;
1647 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1648 err(EXIT_FAILURE, "setrlimit()");
1649 #endif
1650 #endif
1652 #ifdef ENABLE_NLS
1653 setlocale(LC_ALL, "");
1654 bindtextdomain("pwmd", LOCALEDIR);
1655 textdomain("pwmd");
1656 #endif
1658 xmem_init();
1659 gpg_err_init();
1660 setup_gcrypt();
1661 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1662 g_mem_set_vtable(&mtable);
1663 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1664 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1665 xmlInitMemory();
1666 pth_init();
1667 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1669 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1670 err(EXIT_FAILURE, "%s", buf);
1672 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1674 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1675 err(EXIT_FAILURE, "%s", buf);
1677 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1679 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1680 err(EXIT_FAILURE, "sysconf()");
1682 cache_size = page_size;
1684 while ((opt = getopt(argc, argv, "bnI:i:k:hvf:D")) != EOF) {
1685 switch (opt) {
1686 case 'b':
1687 /* Compatibility for version < 1.11 */
1688 break;
1689 case 'n':
1690 background = 0;
1691 break;
1692 case 'D':
1693 secure = TRUE;
1694 break;
1695 case 'k':
1696 keyfile = optarg;
1697 break;
1698 case 'I':
1699 import = optarg;
1700 break;
1701 case 'i':
1702 cmd_iterations = atoi(optarg);
1703 break;
1704 case 'f':
1705 g_free(rcfile);
1706 rcfile = g_strdup(optarg);
1707 rcfile_spec = 1;
1708 break;
1709 case 'v':
1710 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1711 exit(EXIT_SUCCESS);
1712 case 'h':
1713 default:
1714 usage(argv[0]);
1718 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1719 exit(EXIT_FAILURE);
1721 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1722 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1724 if (log_syslog == TRUE)
1725 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1727 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1728 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1729 errno = 0;
1731 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1732 warn("setpriority()");
1733 goto do_exit;
1737 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1738 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1740 #ifdef HAVE_MLOCKALL
1741 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1742 warn("mlockall()");
1743 goto do_exit;
1745 #endif
1747 if (import) {
1748 opt = xml_import(import, keyfile, cmd_iterations < -1 ? iter : cmd_iterations);
1749 g_key_file_free(keyfileh);
1750 g_free(rcfile);
1751 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1754 g_key_file_set_list_separator(keyfileh, ',');
1756 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1757 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1759 if (*p == '~') {
1760 p++;
1761 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1762 g_free(p);
1763 socketarg = g_strdup(buf);
1765 else
1766 socketarg = p;
1768 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1769 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1771 datadir = expand_homedir(p);
1772 g_free(p);
1774 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1775 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1776 disable_list_and_dump = n;
1778 else
1779 disable_list_and_dump = secure;
1781 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1782 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1783 else
1784 default_timeout = -1;
1786 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1787 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1789 if (cache_size < page_size || cache_size % page_size)
1790 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1793 setup_logging(keyfileh);
1795 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1796 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1798 if (argc != optind) {
1799 if (cache_push)
1800 ptotal = g_strv_length(cache_push);
1802 for (; optind < argc; optind++) {
1803 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1804 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1808 if (strchr(socketarg, '/') == NULL) {
1809 socketdir = g_get_current_dir();
1810 socketname = g_strdup(socketarg);
1811 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1813 else {
1814 socketname = g_strdup(strrchr(socketarg, '/'));
1815 socketname++;
1816 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1817 socketdir = g_strdup(socketarg);
1818 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1821 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1822 #ifdef MMAP_ANONYMOUS
1823 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1824 #else
1825 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1826 #endif
1827 err(EXIT_FAILURE, "mmap()");
1830 if (mlock(key_cache, cache_size) == -1)
1831 log_write("mlock(): %s", strerror(errno));
1833 memset(key_cache, 0, cache_size);
1835 if (chdir(datadir)) {
1836 warn("%s", datadir);
1837 unlink(socketpath);
1838 goto do_exit;
1841 if (parse_keyfile_key() == FALSE)
1842 goto do_exit;
1844 clear_keyfile_key();
1847 * Set the cache entry for a file. Prompts for the password.
1849 if (cache_push) {
1850 for (opt = 0; cache_push[opt]; opt++)
1851 do_cache_push(cache_push[opt], NULL);
1853 g_strfreev(cache_push);
1854 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1858 * bind() doesn't like the full pathname of the socket or any non alphanum
1859 * characters so change to the directory where the socket is wanted then
1860 * create it then change to datadir.
1862 if (chdir(socketdir)) {
1863 warn("%s", socketdir);
1864 goto do_exit;
1867 g_free(socketdir);
1869 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1870 warn("socket()");
1871 goto do_exit;
1874 addr.sun_family = AF_UNIX;
1875 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1877 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1878 warn("bind()");
1880 if (errno == EADDRINUSE)
1881 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1882 "stale socket. Please remove it manually."), socketpath);
1884 do_unlink = 0;
1885 goto do_exit;
1888 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1889 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1890 mode_t mode = strtol(t, NULL, 8);
1891 mode_t mask = umask(0);
1893 g_free(t);
1895 if (chmod(socketname, mode) == -1) {
1896 warn("%s", socketname);
1897 close(sockfd);
1898 unlink(socketpath);
1899 umask(mask);
1900 goto do_exit;
1903 umask(mask);
1906 g_free(--socketname);
1908 if (chdir(datadir)) {
1909 warn("%s", datadir);
1910 close(sockfd);
1911 unlink(socketpath);
1912 goto do_exit;
1915 g_free(datadir);
1916 pth_mutex_init(&cache_mutex);
1917 #ifdef WITH_PINENTRY
1918 pth_mutex_init(&pin_mutex);
1919 #endif
1921 if (listen(sockfd, 0) == -1) {
1922 warn("listen()");
1923 goto do_exit;
1926 if (background) {
1927 switch (fork()) {
1928 case -1:
1929 warn("fork()");
1930 goto do_exit;
1931 case 0:
1932 close(0);
1933 close(1);
1934 close(2);
1935 setsid();
1936 break;
1937 default:
1938 exit(EXIT_SUCCESS);
1943 * These are the signals that we use in threads. libpth can catch signals
1944 * itself so ignore them everywhere else. Note that using
1945 * signal(N, SIG_IGN) doesn't work like you might think.
1947 sigemptyset(&set);
1949 /* Termination */
1950 sigaddset(&set, SIGTERM);
1951 sigaddset(&set, SIGINT);
1953 /* Configuration file reloading. */
1954 sigaddset(&set, SIGUSR1);
1956 /* Clears the file cache. */
1957 sigaddset(&set, SIGHUP);
1959 /* Caught in client_thread(). Sends a cache status message. */
1960 sigaddset(&set, SIGUSR2);
1962 /* Ignored everywhere. When a client disconnects abnormally this signal
1963 * gets raised. It isn't needed though because client_thread() will check
1964 * for rcs even after the client disconnects. */
1965 signal(SIGPIPE, SIG_IGN);
1966 pth_sigmask(SIG_BLOCK, &set, NULL);
1967 server_loop(sockfd, &socketpath);
1968 estatus = EXIT_SUCCESS;
1970 do_exit:
1971 if (socketpath && do_unlink) {
1972 unlink(socketpath);
1973 g_free(socketpath);
1976 g_key_file_free(keyfileh);
1977 g_free(rcfile);
1978 xmlCleanupParser();
1980 if (key_cache) {
1981 cache_clear(NULL, 2);
1982 memset(key_cache, 0, cache_size);
1985 if (key_cache && munmap(key_cache, cache_size) == -1)
1986 log_write("munmap(): %s", strerror(errno));
1988 if (estatus == EXIT_SUCCESS)
1989 log_write(N_("pwmd exiting normally"));
1991 pth_kill();
1992 #if defined(DEBUG) && !defined(MEM_DEBUG)
1993 xdump();
1994 #endif
1995 exit(estatus);