Fixed an showing an invalid number of cache slots available in the
[pwmd.git] / src / pwmd.c
blobdc1291ce9414ad5feb6426cdf84729b52e6f78d3
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>
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 #ifndef MEM_DEBUG
58 #include "mem.h"
59 #endif
61 #include "xml.h"
62 #include "common.h"
64 #ifdef WITH_PINENTRY
65 #include "pinentry.h"
66 #endif
68 #include "commands.h"
69 #include "pwmd_error.h"
70 #include "cache.h"
71 #include "misc.h"
72 #include "pwmd.h"
74 static void clear_errorfile_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 log_write(N_("reloading configuration file '%s'"), rcfile);
95 g_key_file_free(keyfileh);
96 keyfileh = parse_rcfile(0);
97 clear_errorfile_key();
98 send_status_all(STATUS_CONFIG);
101 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
103 gpg_error_t n = gpg_error_from_errno(e);
105 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
108 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
110 gpg_err_code_t n = gpg_err_code(e);
111 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
112 struct client_s *client = assuan_get_pointer(ctx);
114 if (!e)
115 return assuan_process_done(ctx, 0);
117 if (!ctx) {
118 log_write("%s\n", pwmd_strerror(e));
119 return e;
122 if (n == EPWMD_LIBXML_ERROR) {
123 xmlErrorPtr xe = client->xml_error;
125 if (!xe)
126 xe = xmlGetLastError();
128 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
129 log_write("%s", xe->message);
131 if (xe == client->xml_error)
132 xmlResetError(xe);
133 else
134 xmlResetLastError();
136 client->xml_error = NULL;
137 return e;
140 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
143 void log_write(const gchar *fmt, ...)
145 gchar *args, *line;
146 va_list ap;
147 struct tm *tm;
148 time_t now;
149 gchar tbuf[21];
150 gint fd = -1;
151 pth_attr_t attr;
152 gchar *name;
153 pth_t tid = pth_self();
154 gchar tid_str[12], *p;
156 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
157 return;
159 if (logfile) {
160 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
161 warn(N_("logfile"));
162 return;
166 va_start(ap, fmt);
168 if (g_vasprintf(&args, fmt, ap) == -1) {
169 if (logfile)
170 close(fd);
172 va_end(ap);
173 return;
176 attr = pth_attr_of(tid);
178 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
179 name = "unknown";
181 pth_attr_destroy(attr);
182 g_snprintf(tid_str, sizeof(tid_str), "(%p)", tid);
183 p = tid_str;
185 if (strncmp(p+1, name, 9) == 0)
186 p = NULL;
188 if (log_syslog == TRUE)
189 syslog(LOG_INFO, "%s%s: %s", name, p ? p : "", args);
191 va_end(ap);
192 time(&now);
193 tm = localtime(&now);
194 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
195 tbuf[sizeof(tbuf) - 1] = 0;
197 if (args[strlen(args)-1] == '\n')
198 args[strlen(args)-1] = 0;
200 line = g_strdup_printf("%s %i %s%s: %s\n", tbuf, getpid(), name,
201 p ? p : "", args);
202 g_free(args);
204 if (!line) {
205 if (logfile)
206 close(fd);
208 return;
211 if (logfile) {
212 write(fd, line, strlen(line));
213 fsync(fd);
214 close(fd);
217 if (isatty(STDERR_FILENO)) {
218 fprintf(stderr, "%s", line);
219 fflush(stderr);
222 g_free(line);
225 static void usage(gchar *pn)
227 g_printf(N_(
228 "Usage: %s [-hvDn] [-f <rcfile>] [-I <filename> [-i <iter>]] [file1] [...]\n"
229 " -n run as a foreground process\n"
230 " -f load the specified rcfile (~/.pwmd/config)\n"
231 " -I import an XML file and write the encrypted data to stdout\n"
232 " -i encrypt with the specified number of iterations when importing\n"
233 " (config default in the \"global\" section)\n"
234 " -D disable use of the LIST and DUMP commands\n"
235 " -v version\n"
236 " -h this help text\n"
237 ), pn);
238 exit(EXIT_SUCCESS);
241 #ifndef MEM_DEBUG
242 static int gcry_SecureCheck(const void *ptr)
244 return 1;
246 #endif
248 static void setup_gcrypt()
250 gcry_check_version(NULL);
252 #ifndef MEM_DEBUG
253 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
254 xfree);
255 #endif
257 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
258 NULL) != 0)
259 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
261 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
262 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
265 static assuan_context_t new_connection(gint fd)
267 gpg_error_t rc;
268 gchar ver[ASSUAN_LINELENGTH];
269 assuan_context_t ctx;
271 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
273 if (rc)
274 goto fail;
276 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
277 assuan_set_hello_line(ctx, ver);
278 rc = register_commands(ctx);
280 if (rc)
281 goto fail;
283 rc = assuan_accept(ctx);
285 if (rc)
286 goto fail;
288 return ctx;
290 fail:
291 assuan_deinit_server(ctx);
292 log_write("%s", gpg_strerror(rc));
293 return NULL;
296 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which)
298 gchar *line = NULL;
299 struct client_s *client = assuan_get_pointer(ctx);
300 gchar buf[ASSUAN_LINELENGTH];
301 gchar *status = NULL;
303 switch (which) {
304 case STATUS_CACHE:
305 CACHE_LOCK(client->ctx);
306 line = print_fmt(buf, sizeof(buf), "%i %i",
307 cache_file_count(),
308 (cache_size % sizeof(file_cache_t)) ?
309 (cache_size / sizeof(file_cache_t)) - cache_file_count()-1 :
310 (cache_size / sizeof(file_cache_t)) - cache_file_count());
311 CACHE_UNLOCK;
312 status = "CACHE";
313 break;
314 case STATUS_CLIENTS:
315 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
316 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
317 pth_mutex_release(&cn_mutex);
318 status = "CLIENTS";
319 break;
320 case STATUS_CONFIG:
321 status = "CONFIG";
322 break;
323 case STATUS_KEEPALIVE:
324 status = "KEEPALIVE";
325 break;
326 case STATUS_LOCKED:
327 status = "LOCKED";
328 line = N_("Waiting for lock");
329 break;
332 return assuan_write_status(ctx, status, line);
335 void send_status_all(status_msg_t which)
337 guint i, t;
339 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
341 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
342 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
343 pth_msgport_t m = pth_msgport_find(cn->msg_name);
345 if (m) {
346 pth_message_t *msg = g_malloc0(sizeof(pth_message_t));
348 msg->m_data = (status_msg_t *)which;
349 pth_msgport_put(m, msg);
353 pth_mutex_release(&cn_mutex);
356 static void xml_error_cb(void *data, xmlErrorPtr e)
358 struct client_s *client = data;
361 * Keep the first reported error as the one to show in the error
362 * description. Reset in send_error().
364 if (client->xml_error)
365 return;
367 xmlCopyError(e, client->xml_error);
371 * This is called after a child_thread terminates. Set with
372 * pth_cleanup_push().
374 static void cleanup_cb(void *arg)
376 struct client_thread_s *cn = arg;
377 gpointer value;
378 struct client_s *cl = cn->cl;
380 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
381 log_write(N_("exiting, fd=%i"), cn->fd);
382 pth_join(cn->tid, &value);
384 if (cl && cl->freed == FALSE)
385 cleanup_assuan(cl->ctx);
387 if (cl && cl->ctx)
388 assuan_deinit_server(cl->ctx);
390 #ifdef WITH_PINENTRY
391 if (cl && cl->pinentry)
392 cleanup_pinentry(cl->pinentry);
393 #endif
395 g_free(cl);
397 if (cn->msg_name)
398 g_free(cn->msg_name);
400 if (cn->msg) {
401 while (pth_msgport_pending(cn->msg) > 0) {
402 pth_message_t *m = pth_msgport_get(cn->msg);
404 g_free(m);
407 pth_msgport_destroy(cn->msg);
410 cn_thread_list = g_slist_remove(cn_thread_list, cn);
411 g_free(cn);
412 pth_mutex_release(&cn_mutex);
413 send_status_all(STATUS_CLIENTS);
417 * Called every time a connection is made via pth_spawn(). This is the thread
418 * entry point.
420 static void *client_thread(void *data)
422 struct client_thread_s *thd = data;
423 gint fd = thd->fd;
424 pth_event_t ev, msg_ev;
425 struct client_s *cl = g_malloc0(sizeof(struct client_s));
426 gpg_error_t rc;
428 if (!cl) {
429 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
430 goto fail;
433 #ifdef WITH_PINENTRY
434 cl->pinentry = pinentry_init();
436 if (!cl->pinentry) {
437 g_free(cl);
438 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
439 goto fail;
441 #endif
443 thd->cl = cl;
444 cl->thd = thd;
445 pth_cleanup_push(cleanup_cb, thd);
446 thd->msg_name = g_strdup_printf("%p", thd->tid);
448 if (!thd->msg_name) {
449 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
450 goto fail;
453 thd->msg = pth_msgport_create(thd->msg_name);
455 if (!thd->msg) {
456 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
457 goto fail;
461 * This is a "child" thread. Don't catch any signals. Let the master
462 * thread take care of signals in accept_thread().
464 cl->ctx = new_connection(fd);
465 cl->fd = fd;
467 if (!cl->ctx)
468 goto fail;
470 assuan_set_pointer(cl->ctx, cl);
472 #ifdef HAVE_MLOCKALL
473 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
474 log_write("mlockall(): %s", strerror(errno));
475 goto fail;
477 #endif
479 rc = send_status(cl->ctx, STATUS_CACHE);
481 if (rc) {
482 log_write("%s", gpg_strerror(rc));
483 goto fail;
486 send_status_all(STATUS_CLIENTS);
487 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
488 msg_ev = pth_event(PTH_EVENT_MSG, thd->msg);
489 pth_event_concat(ev, msg_ev, NULL);
490 xmlInitParser();
491 xmlXPathInit();
492 xmlSetStructuredErrorFunc(cl, xml_error_cb);
494 for (;;) {
495 pth_status_t ev_status;
497 pth_wait(ev);
498 pth_event_isolate(ev);
499 pth_event_isolate(msg_ev);
500 ev_status = pth_event_status(msg_ev);
502 if (ev_status == PTH_STATUS_FAILED)
503 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
504 __FUNCTION__);
505 else if (ev_status == PTH_STATUS_OCCURRED) {
506 while (pth_msgport_pending(thd->msg) > 0) {
507 pth_message_t *m = pth_msgport_get(thd->msg);
508 status_msg_t n = (status_msg_t)m->m_data;
510 rc = send_status(cl->ctx, n);
511 g_free(m);
513 if (rc) {
514 log_write("%s", gpg_strerror(rc));
515 goto done;
520 ev_status = pth_event_status(ev);
521 pth_event_concat(ev, msg_ev, NULL);
523 if (ev_status == PTH_STATUS_FAILED) {
524 log_write("%s(%i): %s: PTH_STATUS_FAILED", __FILE__, __LINE__,
525 __FUNCTION__);
526 goto done;
528 else if (ev_status == PTH_STATUS_OCCURRED) {
529 rc = assuan_process_next(cl->ctx);
531 if (rc) {
532 cl->inquire_status = INQUIRE_INIT;
534 if (gpg_err_code(rc) == GPG_ERR_EOF)
535 goto done;
537 log_write("assuan_process_next(): %s", gpg_strerror(rc));
538 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
540 if (rc) {
541 log_write("assuan_process_done(): %s", gpg_strerror(rc));
542 goto done;
545 else {
546 #ifdef WITH_PINENTRY
547 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
548 cl->pinentry->ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
549 pth_event_concat(ev, cl->pinentry->ev, NULL);
550 cl->pinentry->status = PINENTRY_RUNNING;
552 #endif
554 switch (cl->inquire_status) {
555 case INQUIRE_BUSY:
556 case INQUIRE_INIT:
557 break;
558 case INQUIRE_DONE:
559 cl->inquire_status = INQUIRE_INIT;
560 rc = assuan_process_done(cl->ctx, 0);
561 break;
566 #ifdef WITH_PINENTRY
567 ev = pinentry_iterate(cl, ev);
568 #endif
572 * Client cleanup (including XML data) is done in cleanup_cb() from
573 * the cleanup thread.
575 done:
576 pth_event_free(ev, PTH_FREE_ALL);
578 fail:
579 pth_exit(NULL);
580 return NULL;
583 static void setup_logging(GKeyFile *kf)
585 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
587 if (n == TRUE) {
588 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
590 if (*p == '~') {
591 gchar buf[PATH_MAX];
593 p++;
594 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
595 g_free(p);
597 if (logfile)
598 g_free(logfile);
600 logfile = g_strdup(buf);
602 else {
603 if (logfile)
604 g_free(logfile);
606 logfile = p;
610 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
614 * Make sure all settings are set to either the specified setting or a
615 * default.
617 static void set_rcfile_defaults(GKeyFile *kf)
619 gchar buf[PATH_MAX];
621 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
622 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
623 g_key_file_set_string(kf, "global", "socket_path", buf);
626 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
627 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
628 g_key_file_set_string(kf, "global", "data_directory", buf);
631 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
632 g_key_file_set_boolean(kf, "global", "backup", TRUE);
634 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
635 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
636 g_key_file_set_string(kf, "global", "log_path", buf);
639 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
640 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
642 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
643 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
645 #ifdef HAVE_MLOCKALL
646 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
647 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
648 #endif
650 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
651 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
653 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
654 g_key_file_set_integer(kf, "global", "iterations", 0);
656 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
657 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
659 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
660 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
662 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
663 g_key_file_set_integer(kf, "global", "compression_level", 6);
665 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
666 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
668 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
669 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
671 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
673 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
674 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
676 #ifdef HAVE_MLOCKALL
677 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
678 #endif
680 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
681 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
683 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
684 g_key_file_set_integer(kf, "global", "keepalive", 30);
686 #ifdef WITH_PINENTRY
687 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
688 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
690 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
691 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
692 #endif
694 setup_logging(kf);
697 static GKeyFile *parse_rcfile(int cmdline)
699 GKeyFile *kf = g_key_file_new();
700 GError *rc = NULL;
702 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
703 log_write("%s: %s", rcfile, rc->message);
705 if (cmdline)
706 exit(EXIT_FAILURE);
708 if (rc->code == G_FILE_ERROR_NOENT) {
709 g_clear_error(&rc);
710 set_rcfile_defaults(kf);
711 return kf;
714 g_clear_error(&rc);
715 return NULL;
717 else
718 set_rcfile_defaults(kf);
720 return kf;
723 static gchar *get_password(const gchar *prompt)
725 gchar buf[LINE_MAX] = {0}, *p;
726 struct termios told, tnew;
727 gchar *key;
729 if (tcgetattr(STDIN_FILENO, &told) == -1)
730 err(EXIT_FAILURE, "tcgetattr()");
732 memcpy(&tnew, &told, sizeof(struct termios));
733 tnew.c_lflag &= ~(ECHO);
734 tnew.c_lflag |= ICANON|ECHONL;
736 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
737 tcsetattr(STDIN_FILENO, TCSANOW, &told);
738 err(EXIT_FAILURE, "tcsetattr()");
741 fprintf(stderr, "%s", prompt);
743 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
744 tcsetattr(STDIN_FILENO, TCSANOW, &told);
745 return NULL;
748 tcsetattr(STDIN_FILENO, TCSANOW, &told);
749 p[strlen(p) - 1] = 0;
751 if (!buf[0]) {
752 key = gcry_malloc(1);
753 key[0] = 0;
755 else {
756 key = gcry_malloc(strlen(p) + 1);
757 sprintf(key, "%s", p);
760 memset(&buf, 0, sizeof(buf));
761 return key;
764 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
766 int fd;
767 struct stat st;
768 gpg_error_t rc;
769 gint iter;
771 if ((fd = open_file(filename, &st)) == -1) {
772 warn("%s", filename);
773 return FALSE;
776 if (st.st_size == 0) {
777 warnx(N_("%s: skipping empty file"), filename);
778 close(fd);
779 return FALSE;
782 rc = try_xml_decrypt(NULL, fd, st, key, &iter);
783 close(fd);
784 return rc ? FALSE : TRUE;
787 static gboolean get_input(const gchar *filename, guchar *key)
789 gint try = 0;
790 gchar *password;
791 gchar *prompt;
793 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
795 again:
796 if ((password = get_password(prompt)) == NULL) {
797 warnx(N_("%s: skipping file"), filename);
798 g_free(prompt);
799 return FALSE;
802 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
803 gcry_free(password);
805 if (do_try_xml_decrypt(filename, key) == FALSE) {
806 if (try++ == 2) {
807 warnx(N_("%s: invalid password, skipping"), filename);
808 g_free(prompt);
809 return FALSE;
811 else {
812 warnx(N_("%s: invalid password"), filename);
813 goto again;
817 g_free(prompt);
818 return TRUE;
821 static gboolean xml_import(const gchar *filename, gint iter)
823 xmlDocPtr doc;
824 gint fd;
825 struct stat st;
826 gint len;
827 xmlChar *xmlbuf;
828 xmlChar *xml;
829 gchar *key = NULL;
830 gchar *key2 = NULL;
831 guchar shakey[gcrykeysize];
832 gcry_cipher_hd_t gh;
833 gpg_error_t rc;
834 gint level;
835 glong outsize;
836 gpointer outbuf;
837 gint zrc;
839 if (stat(filename, &st) == -1) {
840 warn("%s", filename);
841 return FALSE;
844 if ((rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
845 send_error(NULL, rc);
846 gcry_cipher_close(gh);
847 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
848 return FALSE;
851 if (iter == -1)
852 goto done;
854 if ((key = get_password(N_("New password: "))) == NULL) {
855 fprintf(stderr, "%s\n", N_("Invalid password."));
856 gcry_cipher_close(gh);
857 return FALSE;
860 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
861 fprintf(stderr, "%s\n", N_("Passwords do not match."));
862 gcry_free(key);
863 gcry_cipher_close(gh);
864 return FALSE;
867 if (g_utf8_collate(key, key2) != 0) {
868 fprintf(stderr, "%s\n", N_("Passwords do not match."));
869 gcry_free(key);
870 gcry_free(key2);
871 gcry_cipher_close(gh);
872 return FALSE;
875 gcry_free(key2);
877 done:
878 if ((fd = open(filename, O_RDONLY)) == -1) {
879 gcry_free(key);
880 warn("%s", filename);
881 gcry_cipher_close(gh);
882 return FALSE;
885 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
886 gcry_free(key);
887 close(fd);
888 log_write("%s", strerror(ENOMEM));
889 gcry_cipher_close(gh);
890 return FALSE;
893 if (read(fd, xmlbuf, st.st_size) == -1) {
894 rc = errno;
895 close(fd);
896 gcry_free(key);
897 gcry_cipher_close(gh);
898 errno = rc;
899 err(EXIT_FAILURE, "read()");
902 close(fd);
903 xmlbuf[st.st_size] = 0;
906 * Make sure the document validates.
908 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
909 log_write("xmlReadDoc()");
910 close(fd);
911 gcry_free(key);
912 gcry_free(xmlbuf);
913 gcry_cipher_close(gh);
914 return FALSE;
917 gcry_free(xmlbuf);
918 xmlDocDumpMemory(doc, &xml, &len);
919 xmlFreeDoc(doc);
921 level = get_key_file_integer(filename, "compression_level");
923 if (level < 0)
924 level = 0;
926 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zrc) == FALSE) {
927 memset(shakey, 0, sizeof(shakey));
928 gcry_free(xml);
930 if (zrc == Z_MEM_ERROR)
931 warnx("%s", strerror(ENOMEM));
932 else
933 warnx("do_compress() failed");
935 gcry_cipher_close(gh);
936 return FALSE;
938 else {
939 gcry_free(xml);
940 xml = outbuf;
941 len = outsize;
944 if (iter == -1)
945 memset(shakey, '!', sizeof(shakey));
946 else{
947 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
948 gcry_free(key);
951 rc = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
952 gcry_cipher_close(gh);
954 if (rc) {
955 memset(shakey, 0, sizeof(shakey));
956 warnx("%s", gpg_strerror(rc));
957 return FALSE;
960 memset(shakey, 0, sizeof(shakey));
961 return TRUE;
964 gchar *get_key_file_string(const gchar *section, const gchar *what)
966 gchar *val = NULL;
967 GError *grc = NULL;
969 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
970 val = g_key_file_get_string(keyfileh, section, what, &grc);
972 if (grc) {
973 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
974 g_clear_error(&grc);
977 else {
978 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
979 val = g_key_file_get_string(keyfileh, "global", what, &grc);
981 if (grc) {
982 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
983 g_clear_error(&grc);
988 return val;
991 gint get_key_file_integer(const gchar *section, const gchar *what)
993 gint val = -1;
994 GError *grc = NULL;
996 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
997 val = g_key_file_get_integer(keyfileh, section, what, &grc);
999 if (grc) {
1000 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1001 g_clear_error(&grc);
1004 else {
1005 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1006 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1008 if (grc) {
1009 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1010 g_clear_error(&grc);
1015 return val;
1018 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1020 gboolean val = FALSE;
1021 GError *grc = NULL;
1023 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1024 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1026 if (grc) {
1027 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1028 g_clear_error(&grc);
1031 else {
1032 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1033 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1035 if (grc) {
1036 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1037 g_clear_error(&grc);
1042 return val;
1045 static gboolean _getline(const gchar *file, gchar **result)
1047 FILE *fp;
1048 gchar buf[LINE_MAX] = {0}, *p;
1049 gchar *str = NULL;
1050 gint len;
1052 if ((fp = fopen(file, "r")) == NULL) {
1053 warn("%s", file);
1054 return FALSE;
1057 p = fgets(buf, sizeof(buf), fp);
1058 fclose(fp);
1059 len = strlen(buf);
1061 if (len && buf[len - 1] == '\n')
1062 buf[--len] = 0;
1064 str = gcry_malloc(len + 1);
1065 memcpy(str, buf, len ? len : 1);
1066 str[len] = 0;
1067 memset(&buf, 0, sizeof(buf));
1068 *result = str;
1069 return TRUE;
1072 static gboolean parse_keyfile_key()
1074 gsize n;
1075 gchar **groups;
1076 gchar **p;
1077 gchar *str;
1079 groups = g_key_file_get_groups(keyfileh, &n);
1081 for (p = groups; *p; p++) {
1082 GError *rc = NULL;
1084 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1085 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1087 if (!str) {
1088 if (rc) {
1089 warnx("%s", rc->message);
1090 g_clear_error(&rc);
1093 continue;
1096 do_cache_push(*p, str);
1097 g_free(str);
1098 continue;
1101 if (rc) {
1102 warnx("%s", rc->message);
1103 g_clear_error(&rc);
1104 continue;
1107 if (g_key_file_has_key(keyfileh, *p, "key_file", &rc) == TRUE) {
1108 gchar *t;
1109 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &rc);
1111 if (!file) {
1112 if (rc) {
1113 warnx("%s", rc->message);
1114 g_clear_error(&rc);
1117 continue;
1120 t = expand_homedir(file);
1121 g_free(file);
1122 file = t;
1124 if (_getline(file, &str) == FALSE) {
1125 g_free(file);
1126 continue;
1129 g_free(file);
1130 do_cache_push(*p, str);
1131 gcry_free(str);
1132 continue;
1135 if (rc) {
1136 warnx("%s", rc->message);
1137 g_clear_error(&rc);
1141 g_strfreev(groups);
1142 return TRUE;
1145 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1147 guchar *md5file;
1148 guchar *key;
1149 gint timeout;
1150 const gchar *p = filename;
1151 file_header_t file_header;
1152 gpg_error_t rc;
1154 while (isspace(*p))
1155 p++;
1157 if (!*p)
1158 return FALSE;
1160 if (valid_filename(p) == FALSE) {
1161 warnx(N_("%s: invalid characters in filename"), p);
1162 return FALSE;
1165 md5file = gcry_malloc(16);
1166 key = gcry_malloc(gcrykeysize);
1167 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1169 if (cache_iscached(md5file) == TRUE) {
1170 warnx(N_("%s: file already cached, skipping"), p);
1171 gcry_free(md5file);
1172 gcry_free(key);
1173 return FALSE;
1176 if (access(p, R_OK|W_OK) != 0) {
1177 gcry_free(md5file);
1178 gcry_free(key);
1180 if (errno != ENOENT) {
1181 warn("%s", p);
1182 return FALSE;
1185 warn("%s", p);
1186 return TRUE;
1189 rc = read_file_header(filename, &file_header);
1191 if (rc) {
1192 gcry_free(md5file);
1193 gcry_free(key);
1194 warnx("%s", pwmd_strerror(rc));
1195 return FALSE;
1198 if (file_header.iter == -1) {
1199 memset(key, '!', gcrykeysize);
1200 goto try_decrypt;
1203 if (!password) {
1204 #ifdef WITH_PINENTRY
1205 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1206 #endif
1207 if (get_input(p, key) == FALSE) {
1208 gcry_free(key);
1209 gcry_free(md5file);
1210 return FALSE;
1212 #ifdef WITH_PINENTRY
1214 else {
1215 gchar *result = NULL;
1216 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1217 gint try = 0;
1219 set_pinentry_defaults(pin);
1220 pin->which = PINENTRY_OPEN;
1221 pin->filename = g_strdup(filename);
1222 again:
1223 rc = pinentry_getpin(pin, &result);
1225 if (rc) {
1226 warnx("%s: %s", filename, gpg_strerror(rc));
1227 cleanup_pinentry(pin);
1228 gcry_free(key);
1229 gcry_free(md5file);
1230 xfree(result);
1231 return FALSE;
1234 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1235 xfree(result);
1237 if (do_try_xml_decrypt(filename, key) == FALSE) {
1238 if (try++ == 2) {
1239 cleanup_pinentry(pin);
1240 gcry_free(key);
1241 gcry_free(md5file);
1242 warnx(N_("%s: invalid password, skipping"), filename);
1243 return FALSE;
1245 else {
1246 g_free(pin->title);
1247 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1248 goto again;
1252 cleanup_pinentry(pin);
1254 #endif
1256 else {
1257 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1259 try_decrypt:
1260 if (do_try_xml_decrypt(filename, key) == FALSE) {
1261 warnx(N_("%s: invalid password, skipping"), filename);
1262 gcry_free(key);
1263 gcry_free(md5file);
1264 return FALSE;
1268 if (cache_add_file(md5file, key) == FALSE) {
1269 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1270 gcry_free(key);
1271 gcry_free(md5file);
1272 return FALSE;
1275 timeout = get_key_file_integer(p, "cache_timeout");
1276 cache_set_timeout(md5file, timeout);
1277 warnx(N_("%s: file added to the cache"), filename);
1278 gcry_free(key);
1279 gcry_free(md5file);
1280 return TRUE;
1283 static void *accept_thread(void *arg)
1285 gint sockfd = (gint)arg;
1287 for (;;) {
1288 socklen_t slen = sizeof(struct sockaddr_un);
1289 struct sockaddr_un raddr;
1290 gint fd = -1;
1291 pth_attr_t attr;
1293 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1294 if (errno != EAGAIN) {
1295 if (!quit) // probably EBADF
1296 log_write("accept(): %s", strerror(errno));
1298 break;
1302 if (fd >= 0) {
1303 pth_t tid;
1304 struct client_thread_s *new;
1305 gchar buf[41];
1307 new = g_malloc0(sizeof(struct client_thread_s));
1309 if (!new) {
1310 log_write("%s", strerror(ENOMEM));
1311 continue;
1315 * Thread priority is inherited from the calling thread. This
1316 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1317 * priority.
1319 new->fd = fd;
1320 attr = pth_attr_new();
1321 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1322 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1323 tid = pth_spawn(attr, client_thread, new);
1324 pth_attr_destroy(attr);
1326 if (!tid) {
1327 g_free(new);
1328 log_write(N_("pth_spawn() failed"));
1329 continue;
1332 g_snprintf(buf, sizeof(buf), "%p", tid);
1333 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1334 attr = pth_attr_of(tid);
1335 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1336 pth_attr_destroy(attr);
1337 new->tid = tid;
1338 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1339 cn_thread_list = g_slist_append(cn_thread_list, new);
1340 pth_mutex_release(&cn_mutex);
1344 /* Just in case pth_accept() failed for some reason other than EBADF */
1345 quit = 1;
1346 pth_exit(PTH_CANCELED);
1347 return NULL;
1351 * This thread isn't joinable. For operations that block, these threads will
1352 * stack.
1354 static void *adjust_timer_thread(void *arg)
1356 CACHE_LOCK(NULL);
1357 cache_adjust_timer();
1358 CACHE_UNLOCK;
1359 return NULL;
1362 static pth_event_t timeout_event_iterate(pth_event_t timeout_ev,
1363 pth_attr_t attr)
1365 pth_status_t ev_status;
1367 if (timeout_ev) {
1368 pth_event_isolate(timeout_ev);
1369 ev_status = pth_event_status(timeout_ev);
1370 pth_event_free(timeout_ev, PTH_FREE_THIS);
1372 if (ev_status == PTH_STATUS_OCCURRED) {
1374 * The timer event has expired. Update the file cache. When the
1375 * cache mutex is locked and the timer expires again, the threads
1376 * will stack.
1378 pth_spawn(attr, adjust_timer_thread, NULL);
1382 return pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1385 static pth_event_t keepalive_event_iterate(pth_event_t keepalive_ev,
1386 gint keepalive)
1388 pth_event_t ev = NULL;
1389 pth_status_t ev_status;
1391 if (keepalive_ev) {
1392 pth_event_isolate(keepalive_ev);
1393 ev_status = pth_event_status(keepalive_ev);
1395 if (ev_status == PTH_STATUS_OCCURRED || ev_status == PTH_STATUS_FAILED) {
1396 if (ev_status == PTH_STATUS_OCCURRED)
1397 send_status_all(STATUS_KEEPALIVE);
1399 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1401 else
1402 ev = keepalive_ev;
1405 if (keepalive > 0 && !ev)
1406 ev = pth_event(PTH_EVENT_TIME, pth_timeout(keepalive, 0));
1408 return ev;
1411 static void server_loop(gint sockfd, gchar **socketpath)
1413 pth_t accept_tid;
1414 guint n;
1415 sigset_t set;
1416 gint n_clients = 0;
1417 pth_attr_t attr;
1418 pth_event_t timeout_ev, keepalive_ev = NULL, ev_quit;
1419 gint keepalive = get_key_file_integer("global", "keepalive");
1420 gpointer value;
1422 pth_mutex_init(&cn_mutex);
1423 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1425 sigemptyset(&set);
1426 sigaddset(&set, SIGTERM);
1427 sigaddset(&set, SIGINT);
1428 sigaddset(&set, SIGUSR1);
1429 sigaddset(&set, SIGHUP);
1430 sigaddset(&set, SIGABRT);
1432 attr = pth_attr_new();
1433 pth_attr_init(attr);
1434 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1435 pth_attr_set(attr, PTH_ATTR_NAME, "accept");
1436 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1437 pth_attr_init(attr);
1438 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1439 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1442 * For the cache_timeout configuration parameter.
1444 timeout_ev = timeout_event_iterate(NULL, attr);
1445 keepalive_ev = keepalive_event_iterate(NULL, keepalive);
1446 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1448 do {
1449 gint sig = 0;
1451 pth_sigwait_ev(&set, &sig, timeout_ev);
1452 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1453 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1454 timeout_ev = pth_event_concat(timeout_ev, keepalive_ev, NULL);
1456 if (sig > 0) {
1457 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1459 /* Caught a signal. */
1460 switch (sig) {
1461 case SIGHUP:
1462 reload_rcfile();
1463 keepalive = get_key_file_integer("global", "keepalive");
1464 break;
1465 case SIGABRT:
1466 CACHE_LOCK(NULL);
1467 cache_clear(NULL, 2);
1468 CACHE_UNLOCK;
1469 #ifndef MEM_DEBUG
1470 xpanic();
1471 #endif
1472 exit(EXIT_FAILURE);
1473 case SIGUSR1:
1474 CACHE_LOCK(NULL);
1475 log_write(N_("clearing file cache"));
1476 cache_clear(NULL, 2);
1477 CACHE_UNLOCK;
1478 break;
1479 default:
1480 quit = 1;
1481 shutdown(sockfd, SHUT_RDWR);
1482 close(sockfd);
1483 break;
1486 } while (!quit);
1489 * We're out of the main server loop. This happens when a signal was sent
1490 * to terminate the daemon. We'll wait for all clients to disconnect
1491 * before exiting and ignore any following signals.
1493 pth_join(accept_tid, &value);
1494 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1495 unlink(*socketpath);
1496 g_free(*socketpath);
1497 *socketpath = NULL;
1499 if (n > 1)
1500 log_write(N_("waiting for all threads to terminate"));
1502 ev_quit = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1504 while (n > 1) {
1505 if (n != n_clients) {
1506 log_write(N_("%i threads remain"), n-1);
1507 n_clients = n;
1510 pth_wait(ev_quit);
1511 pth_event_isolate(ev_quit);
1512 timeout_ev = timeout_event_iterate(timeout_ev, attr);
1513 keepalive_ev = keepalive_event_iterate(keepalive_ev, keepalive);
1514 ev_quit = pth_event_concat(ev_quit, timeout_ev, keepalive_ev, NULL);
1515 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1518 pth_event_free(timeout_ev, PTH_FREE_THIS);
1519 pth_event_free(keepalive_ev, PTH_FREE_THIS);
1520 pth_event_free(ev_quit, PTH_FREE_THIS);
1521 pth_attr_destroy(attr);
1525 * Called from pinentry_fork() in the child process.
1527 void free_client_list()
1529 gint i, t = g_slist_length(cn_thread_list);
1531 for (i = 0; i < t; i++) {
1532 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1534 free_client(cn->cl);
1537 memset(key_cache, 0, cache_size);
1540 int main(int argc, char *argv[])
1542 gint opt;
1543 struct sockaddr_un addr;
1544 struct passwd *pw = getpwuid(getuid());
1545 gchar buf[PATH_MAX];
1546 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1547 gchar *socketarg = NULL;
1548 gchar *datadir = NULL;
1549 gboolean n;
1550 gchar *p;
1551 gchar **cache_push = NULL;
1552 gint iter = 0;
1553 gchar *import = NULL;
1554 gint cmd_iterations = -1;
1555 gint default_timeout;
1556 gint rcfile_spec = 0;
1557 gint estatus = EXIT_FAILURE;
1558 gint sockfd;
1559 #ifndef MEM_DEBUG
1560 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1561 #endif
1562 gint do_unlink = 1;
1563 gboolean secure = FALSE;
1564 guint ptotal = 0;
1565 gint background = 1;
1566 sigset_t set;
1567 #ifndef DEBUG
1568 #ifdef HAVE_SETRLIMIT
1569 struct rlimit rl;
1571 rl.rlim_cur = rl.rlim_max = 0;
1573 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1574 err(EXIT_FAILURE, "setrlimit()");
1575 #endif
1576 #endif
1578 #ifdef ENABLE_NLS
1579 setlocale(LC_ALL, "");
1580 bindtextdomain("pwmd", LOCALEDIR);
1581 textdomain("pwmd");
1582 #endif
1584 gpg_err_init();
1585 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1586 #ifndef MEM_DEBUG
1587 g_mem_set_vtable(&mtable);
1588 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1589 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1590 xmlInitMemory();
1591 #endif
1592 pth_init();
1593 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1595 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1596 err(EXIT_FAILURE, "%s", buf);
1598 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1600 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1601 err(EXIT_FAILURE, "%s", buf);
1603 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1605 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1606 err(EXIT_FAILURE, "sysconf()");
1608 cache_size = page_size;
1610 while ((opt = getopt(argc, argv, "bnI:i:hvf:D")) != EOF) {
1611 switch (opt) {
1612 case 'b':
1613 /* Compatibility for version < 1.11 */
1614 break;
1615 case 'n':
1616 background = 0;
1617 break;
1618 case 'D':
1619 secure = TRUE;
1620 break;
1621 case 'I':
1622 import = optarg;
1623 break;
1624 case 'i':
1625 cmd_iterations = atoi(optarg);
1626 break;
1627 case 'f':
1628 g_free(rcfile);
1629 rcfile = g_strdup(optarg);
1630 rcfile_spec = 1;
1631 break;
1632 case 'v':
1633 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1634 exit(EXIT_SUCCESS);
1635 case 'h':
1636 default:
1637 usage(argv[0]);
1641 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1642 exit(EXIT_FAILURE);
1644 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1645 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1647 if (log_syslog == TRUE)
1648 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1650 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
1651 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
1652 errno = 0;
1654 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
1655 warn("setpriority()");
1656 goto do_exit;
1660 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1661 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1663 #ifdef HAVE_MLOCKALL
1664 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1665 warn("mlockall()");
1666 goto do_exit;
1668 #endif
1670 setup_gcrypt();
1672 if (import) {
1673 opt = xml_import(import, cmd_iterations < -1 ? iter : cmd_iterations);
1674 g_key_file_free(keyfileh);
1675 g_free(rcfile);
1676 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1679 g_key_file_set_list_separator(keyfileh, ',');
1681 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1682 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1684 if (*p == '~') {
1685 p++;
1686 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1687 g_free(p);
1688 socketarg = g_strdup(buf);
1690 else
1691 socketarg = p;
1693 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1694 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1696 datadir = expand_homedir(p);
1697 g_free(p);
1699 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1700 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1701 disable_list_and_dump = n;
1703 else
1704 disable_list_and_dump = secure;
1706 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1707 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1708 else
1709 default_timeout = -1;
1711 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1712 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1714 if (cache_size < page_size || cache_size % page_size)
1715 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1718 setup_logging(keyfileh);
1720 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1721 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1723 if (argc != optind) {
1724 if (cache_push)
1725 ptotal = g_strv_length(cache_push);
1727 for (; optind < argc; optind++) {
1728 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1729 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1733 if (strchr(socketarg, '/') == NULL) {
1734 socketdir = g_get_current_dir();
1735 socketname = g_strdup(socketarg);
1736 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1738 else {
1739 socketname = g_strdup(strrchr(socketarg, '/'));
1740 socketname++;
1741 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1742 socketdir = g_strdup(socketarg);
1743 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1746 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1747 #ifdef MMAP_ANONYMOUS
1748 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1749 #else
1750 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1751 #endif
1752 err(EXIT_FAILURE, "mmap()");
1755 if (mlock(key_cache, cache_size) == -1)
1756 log_write("mlock(): %s", strerror(errno));
1758 memset(key_cache, 0, cache_size);
1760 if (chdir(datadir)) {
1761 warn("%s", datadir);
1762 unlink(socketpath);
1763 goto do_exit;
1766 if (parse_keyfile_key() == FALSE)
1767 goto do_exit;
1769 clear_errorfile_key();
1772 * Set the cache entry for a file. Prompts for the password.
1774 if (cache_push) {
1775 for (opt = 0; cache_push[opt]; opt++)
1776 do_cache_push(cache_push[opt], NULL);
1778 g_strfreev(cache_push);
1779 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1783 * bind() doesn't like the full pathname of the socket or any non alphanum
1784 * characters so change to the directory where the socket is wanted then
1785 * create it then change to datadir.
1787 if (chdir(socketdir)) {
1788 warn("%s", socketdir);
1789 goto do_exit;
1792 g_free(socketdir);
1794 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1795 warn("socket()");
1796 goto do_exit;
1799 addr.sun_family = AF_UNIX;
1800 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1802 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1803 warn("bind()");
1805 if (errno == EADDRINUSE)
1806 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1807 "stale socket. Please remove it manually."), socketpath);
1809 do_unlink = 0;
1810 goto do_exit;
1813 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1814 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1815 mode_t mode = strtol(t, NULL, 8);
1816 mode_t mask = umask(0);
1818 g_free(t);
1820 if (chmod(socketname, mode) == -1) {
1821 warn("%s", socketname);
1822 close(sockfd);
1823 unlink(socketpath);
1824 umask(mask);
1825 goto do_exit;
1828 umask(mask);
1831 g_free(--socketname);
1833 if (chdir(datadir)) {
1834 warn("%s", datadir);
1835 close(sockfd);
1836 unlink(socketpath);
1837 goto do_exit;
1840 g_free(datadir);
1841 pth_mutex_init(&cache_mutex);
1842 #ifdef WITH_PINENTRY
1843 pth_mutex_init(&pin_mutex);
1844 #endif
1846 if (listen(sockfd, 0) == -1) {
1847 warn("listen()");
1848 goto do_exit;
1851 if (background) {
1852 switch (fork()) {
1853 case -1:
1854 warn("fork()");
1855 goto do_exit;
1856 case 0:
1857 close(0);
1858 close(1);
1859 close(2);
1860 setsid();
1861 break;
1862 default:
1863 exit(EXIT_SUCCESS);
1868 * These are the signals that we use in threads. libpth can catch signals
1869 * itself so ignore them everywhere else. Note that using
1870 * signal(N, SIG_IGN) doesn't work like you might think.
1872 sigemptyset(&set);
1874 /* Termination */
1875 sigaddset(&set, SIGTERM);
1876 sigaddset(&set, SIGINT);
1878 /* Configuration file reloading. */
1879 sigaddset(&set, SIGUSR1);
1881 /* Clears the file cache. */
1882 sigaddset(&set, SIGHUP);
1884 /* Caught in client_thread(). Sends a cache status message. */
1885 sigaddset(&set, SIGUSR2);
1887 /* Ignored everywhere. When a client disconnects abnormally this signal
1888 * gets raised. It isn't needed though because client_thread() will check
1889 * for rcs even after the client disconnects. */
1890 signal(SIGPIPE, SIG_IGN);
1891 pth_sigmask(SIG_BLOCK, &set, NULL);
1892 server_loop(sockfd, &socketpath);
1893 estatus = EXIT_SUCCESS;
1895 do_exit:
1896 if (socketpath && do_unlink) {
1897 unlink(socketpath);
1898 g_free(socketpath);
1901 g_key_file_free(keyfileh);
1902 g_free(rcfile);
1903 xmlCleanupParser();
1905 if (key_cache) {
1906 cache_clear(NULL, 2);
1907 memset(key_cache, 0, cache_size);
1910 if (key_cache && munmap(key_cache, cache_size) == -1)
1911 log_write("munmap(): %s", strerror(errno));
1913 if (estatus == EXIT_SUCCESS)
1914 log_write(N_("pwmd exiting normally"));
1916 pth_kill();
1917 #if defined(DEBUG) && !defined(MEM_DEBUG)
1918 xdump();
1919 #endif
1920 exit(estatus);