Fixed corruption of the connection list. Lock the cn_mutex in
[pwmd.git] / src / pwmd.c
blob913009ef0efe428331188bcd15fb123d90d0c628
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 02111-1307 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 #ifndef MEM_DEBUG
52 #include "mem.h"
53 #endif
55 #include "xml.h"
56 #include "common.h"
58 #ifdef WITH_PINENTRY
59 #include "pinentry.h"
60 #endif
62 #include "commands.h"
63 #include "pwmd_error.h"
64 #include "cache.h"
65 #include "pwmd.h"
67 static void clear_rcfile_key()
69 gsize n;
70 gchar **groups;
71 gchar **p;
73 groups = g_key_file_get_groups(keyfileh, &n);
75 for (p = groups; *p; p++) {
76 GError *error = NULL;
78 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE)
79 g_key_file_set_string(keyfileh, *p, "key", "");
82 g_strfreev(groups);
85 static void reload_rcfile()
87 log_write(N_("reloading configuration file '%s'"), rcfile);
88 g_key_file_free(keyfileh);
89 keyfileh = parse_rcfile(0);
90 clear_rcfile_key();
93 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
95 gpg_error_t n = gpg_error_from_errno(e);
97 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
100 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
102 gpg_err_code_t n = gpg_err_code(e);
103 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
105 if (!e)
106 return assuan_process_done(ctx, 0);
108 if (!ctx) {
109 log_write("%s\n", pwmd_strerror(e));
110 return e;
113 if (n == EPWMD_LIBXML_ERROR) {
114 xmlErrorPtr xml_error = xmlGetLastError();
115 return assuan_process_done(ctx, assuan_set_error(ctx, code, xml_error->message));
118 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
121 void log_write(const gchar *fmt, ...)
123 gchar *args, *line;
124 va_list ap;
125 struct tm *tm;
126 time_t now;
127 gchar tbuf[21];
128 gint fd = -1;
129 pth_attr_t attr;
130 gchar *name;
132 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
133 return;
135 if (logfile) {
136 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
137 warn(N_("logfile"));
138 return;
142 va_start(ap, fmt);
144 if (g_vasprintf(&args, fmt, ap) == -1) {
145 va_end(ap);
146 return;
149 attr = pth_attr_of(pth_self());
150 pth_attr_get(attr, PTH_ATTR_NAME, &name);
152 if (log_syslog == TRUE)
153 syslog(LOG_INFO, "%s: %s", name, args);
155 va_end(ap);
156 time(&now);
157 tm = localtime(&now);
158 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
159 tbuf[sizeof(tbuf) - 1] = 0;
160 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
162 if (!line) {
163 if (logfile)
164 close(fd);
166 g_free(args);
167 return;
170 if (logfile) {
171 write(fd, line, strlen(line));
172 fsync(fd);
173 close(fd);
176 if (isatty(STDERR_FILENO)) {
177 fprintf(stderr, "%s", line);
178 fflush(stderr);
181 g_free(line);
182 g_free(args);
185 static void usage(gchar *pn)
187 g_printf(N_(
188 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
189 " -b run as a background process\n"
190 " -f load the specified rcfile (~/.pwmd/config)\n"
191 " -I import an XML file and write the encrypted data to stdout\n"
192 " -D disable use of the LIST and DUMP commands\n"
193 " -v version\n"
194 " -h this help text\n"
195 ), pn);
196 exit(EXIT_SUCCESS);
199 #ifndef MEM_DEBUG
200 static int gcry_SecureCheck(const void *ptr)
202 return 1;
204 #endif
206 static void setup_gcrypt()
208 gcry_check_version(NULL);
210 #ifndef MEM_DEBUG
211 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
212 xfree);
213 #endif
215 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
216 NULL) != 0)
217 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
219 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
220 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
223 static assuan_context_t new_connection(gint fd)
225 gpg_error_t rc;
226 gchar ver[ASSUAN_LINELENGTH];
227 assuan_context_t ctx;
229 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
231 if (rc)
232 goto fail;
234 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
235 assuan_set_hello_line(ctx, ver);
236 assuan_register_post_cmd_notify(ctx, command_finalize);
237 rc = register_commands(ctx);
239 if (rc)
240 goto fail;
242 rc = assuan_accept(ctx);
244 if (rc)
245 goto fail;
247 return ctx;
249 fail:
250 assuan_deinit_server(ctx);
251 log_write("%s", gpg_strerror(rc));
252 return NULL;
255 void send_cache_status_all()
257 guint i, t;
259 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
261 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
262 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
264 if (cn->tid == pth_self()) {
265 send_cache_status(cn->cl->ctx);
266 continue;
269 pth_raise(cn->tid, SIGUSR2);
272 pth_mutex_release(&cn_mutex);
275 static void *keepalive_thread(void *arg)
277 struct client_thread_s *thd = arg;
279 for (;;) {
280 gpg_error_t error;
281 pth_event_t ev;
282 gint k = get_key_file_integer("global", "keepalive");
284 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k <= 0 ? 1 : k, 0));
285 pth_wait(ev);
286 pth_event_free(ev, PTH_FREE_THIS);
287 pth_cancel_point();
289 if (k <= 0)
290 continue;
292 error = assuan_write_status(thd->cl->ctx, "KEEPALIVE", NULL);
294 if (error) {
295 pth_raise(thd->tid, SIGQUIT);
296 break;
300 return NULL;
304 * Called every time a connection is made via pth_spawn(). This is the thread
305 * entry point.
307 static void *client_thread(void *data)
309 struct client_thread_s *thd = data;
310 gint fd = thd->fd;
311 pth_event_t ev;
312 #ifdef WITH_PINENTRY
313 pth_event_t pinentry_ev = NULL;
314 #endif
315 struct client_s *cl = g_malloc0(sizeof(struct client_s));
316 sigset_t set;
318 if (!cl) {
319 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
320 goto fail;
323 #ifdef WITH_PINENTRY
324 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
326 if (!cl->pinentry) {
327 g_free(cl);
328 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
329 goto fail;
332 set_pinentry_defaults(cl->pinentry);
333 #endif
334 thd->cl = cl;
335 cl->thd = thd;
338 * This is a "child" thread. Don't catch any signals. Let the master
339 * thread take care of signals in server_loop().
341 sigfillset(&set);
342 pth_sigmask(SIG_BLOCK, &set, NULL);
343 sigemptyset(&set);
344 /* Sends a cache status message to the client. */
345 sigaddset(&set, SIGUSR2);
346 /* Terminates this thread. Raised from keepalive_thread(). */
347 sigaddset(&set, SIGQUIT);
349 cl->ctx = new_connection(fd);
350 cl->fd = fd;
352 if (!cl->ctx)
353 goto fail;
355 assuan_set_pointer(cl->ctx, cl);
357 #ifdef HAVE_MLOCKALL
358 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
359 log_write("mlockall(): %s", strerror(errno));
360 goto fail;
362 #endif
364 send_cache_status(cl->ctx);
365 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
366 thd->keepalive_tid = pth_spawn(NULL, keepalive_thread, thd);
368 for (;;) {
369 gpg_error_t rc;
370 gint sig = 0;
372 pth_sigwait_ev(&set, &sig, ev);
374 if (sig > 0) {
375 switch (sig) {
376 case SIGUSR2:
377 send_cache_status(cl->ctx);
378 continue;
379 case SIGQUIT:
380 goto done;
381 default:
382 break;
386 pth_event_isolate(ev);
388 if (pth_event_occurred(ev)) {
389 rc = assuan_process_next(cl->ctx);
391 if (rc) {
392 cl->inquire_status = INQUIRE_INIT;
394 if (gpg_err_code(rc) == GPG_ERR_EOF)
395 goto done;
397 log_write("assuan_process_next(): %s", gpg_strerror(rc));
398 rc = assuan_process_done(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
400 if (rc) {
401 log_write("assuan_process_done(): %s", gpg_strerror(rc));
402 goto done;
405 else {
406 #ifdef WITH_PINENTRY
407 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
408 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
409 pth_event_concat(ev, pinentry_ev, NULL);
410 cl->pinentry->status = PINENTRY_RUNNING;
412 #endif
414 switch (cl->inquire_status) {
415 case INQUIRE_BUSY:
416 case INQUIRE_INIT:
417 break;
418 case INQUIRE_DONE:
419 cl->inquire_status = INQUIRE_INIT;
420 rc = assuan_process_done(cl->ctx, 0);
421 break;
426 #ifdef WITH_PINENTRY
427 if (cl->pinentry->status == PINENTRY_RUNNING) {
428 pth_event_isolate(pinentry_ev);
430 if (pth_event_occurred(pinentry_ev)) {
431 guchar shakey[gcrykeysize];
432 pinentry_key_s pk;
433 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
434 gint status;
436 pth_event_free(pinentry_ev, PTH_FREE_THIS);
437 pinentry_ev = NULL;
438 cl->pinentry->status = PINENTRY_NONE;
440 if (len == sizeof(pk)) {
441 if (pk.error)
442 rc = send_error(cl->ctx, pk.error);
443 else {
444 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, pk.key,
445 strlen(pk.key) == 0 ? 1 : strlen(pk.key));
446 rc = cl->pinentry->cb(cl->ctx, shakey, FALSE);
447 memset(shakey, 0, sizeof(shakey));
450 else if (len == -1)
451 log_write("%s", strerror(errno));
452 else if (len == 0)
453 log_write("pth_read(): EOF");
454 else
455 log_write(N_("pth_read(): short byte count"));
457 memset(&pk, 0, sizeof(pk));
458 pth_waitpid(cl->pinentry->pid, &status, 0);
459 close(cl->pinentry->fd);
460 cl->pinentry->fd = -1;
461 cl->pinentry->pid = 0;
462 unlock_file_mutex(cl);
465 pth_event_concat(ev, pinentry_ev, NULL);
467 #endif
471 * Client cleanup (including XML data) is done in remove_connection() from
472 * the cleanup thread.
474 done:
475 pth_event_free(ev, PTH_FREE_ALL);
477 fail:
478 log_write(N_("exiting, fd=%i"), thd->fd);
479 pth_exit(NULL);
480 return NULL;
484 * Make sure all settings are set to either the specified setting or a
485 * default.
487 static void set_rcfile_defaults(GKeyFile *kf)
489 gchar buf[PATH_MAX];
491 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
492 snprintf(buf, sizeof(buf), "~/.pwmd/socket");
493 g_key_file_set_string(kf, "global", "socket_path", buf);
496 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
497 snprintf(buf, sizeof(buf), "~/.pwmd/data");
498 g_key_file_set_string(kf, "global", "data_directory", buf);
501 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
502 snprintf(buf, sizeof(buf), "~/.pwmd/log");
503 g_key_file_set_string(kf, "global", "log_path", buf);
506 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
507 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
509 if (g_key_file_has_key(kf, "global", "cache_size", NULL) == FALSE)
510 g_key_file_set_integer(kf, "global", "cache_size", cache_size);
512 #ifdef HAVE_MLOCKALL
513 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
514 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
515 #endif
517 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
518 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
520 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE)
521 g_key_file_set_integer(kf, "global", "iterations", 0);
523 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
524 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
526 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
527 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
529 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
530 g_key_file_set_integer(kf, "global", "compression_level", 6);
532 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
533 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
535 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
536 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
538 zlib_bufsize = g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
540 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
541 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
543 #ifdef HAVE_MLOCKALL
544 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
545 #endif
547 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
548 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
550 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
551 g_key_file_set_integer(kf, "global", "keepalive", 5);
553 #ifdef WITH_PINENTRY
554 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
555 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
556 #endif
559 static GKeyFile *parse_rcfile(int cmdline)
561 GKeyFile *kf = g_key_file_new();
562 GError *error = NULL;
564 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &error) == FALSE) {
565 log_write("%s: %s", rcfile, error->message);
567 if (cmdline)
568 exit(EXIT_FAILURE);
570 if (error->code == G_FILE_ERROR_NOENT) {
571 g_clear_error(&error);
572 set_rcfile_defaults(kf);
573 return kf;
576 g_clear_error(&error);
577 return NULL;
579 else
580 set_rcfile_defaults(kf);
582 return kf;
585 static gchar *get_password(const gchar *prompt)
587 gchar buf[LINE_MAX] = {0}, *p;
588 struct termios told, tnew;
589 gchar *key;
591 if (tcgetattr(STDIN_FILENO, &told) == -1)
592 err(EXIT_FAILURE, "tcgetattr()");
594 memcpy(&tnew, &told, sizeof(struct termios));
595 tnew.c_lflag &= ~(ECHO);
596 tnew.c_lflag |= ICANON|ECHONL;
598 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
599 tcsetattr(STDIN_FILENO, TCSANOW, &told);
600 err(EXIT_FAILURE, "tcsetattr()");
603 fprintf(stderr, "%s", prompt);
605 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
606 tcsetattr(STDIN_FILENO, TCSANOW, &told);
607 return NULL;
610 tcsetattr(STDIN_FILENO, TCSANOW, &told);
611 p[strlen(p) - 1] = 0;
613 if (!buf[0]) {
614 key = gcry_malloc(1);
615 key[0] = 0;
617 else {
618 key = gcry_malloc(strlen(p) + 1);
619 sprintf(key, "%s", p);
622 memset(&buf, 0, sizeof(buf));
623 return key;
626 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
628 int fd;
629 struct stat st;
630 gpg_error_t error;
632 if ((fd = open_file(filename, &st)) == -1) {
633 warn("%s", filename);
634 return FALSE;
637 if (st.st_size == 0) {
638 warnx(N_("%s: skipping empty file"), filename);
639 close(fd);
640 return FALSE;
643 error = try_xml_decrypt(NULL, fd, st, key);
644 close(fd);
645 return error ? FALSE : TRUE;
648 static gboolean get_input(const gchar *filename, guchar *key)
650 gint try = 0;
651 gchar *password;
652 gchar *prompt;
654 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
656 again:
657 if ((password = get_password(prompt)) == NULL) {
658 warnx(N_("%s: skipping file"), filename);
659 g_free(prompt);
660 return FALSE;
663 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
664 gcry_free(password);
666 if (do_try_xml_decrypt(filename, key) == FALSE) {
667 if (try++ == 2) {
668 warnx(N_("%s: invalid password, skipping"), filename);
669 g_free(prompt);
670 return FALSE;
672 else {
673 warnx(N_("%s: invalid password"), filename);
674 goto again;
678 g_free(prompt);
679 return TRUE;
682 static gboolean xml_import(const gchar *filename, gint iter)
684 xmlDocPtr doc;
685 gint fd;
686 struct stat st;
687 gint len;
688 xmlChar *xmlbuf;
689 xmlChar *xml;
690 gchar *key = NULL;
691 gchar *key2 = NULL;
692 guchar shakey[gcrykeysize];
693 gcry_cipher_hd_t gh;
694 gpg_error_t error;
695 gint level;
696 glong outsize;
697 gpointer outbuf;
698 gint zerror;
700 if (stat(filename, &st) == -1) {
701 warn("%s", filename);
702 return FALSE;
705 if ((error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
706 send_error(NULL, error);
707 gcry_cipher_close(gh);
708 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
709 return FALSE;
712 if (iter == -1)
713 goto done;
715 if ((key = get_password(N_("New password: "))) == NULL) {
716 fprintf(stderr, "%s\n", N_("Invalid password."));
717 gcry_cipher_close(gh);
718 return FALSE;
721 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
722 fprintf(stderr, "%s\n", N_("Passwords do not match."));
723 gcry_free(key);
724 gcry_cipher_close(gh);
725 return FALSE;
728 if (g_utf8_collate(key, key2) != 0) {
729 fprintf(stderr, "%s\n", N_("Passwords do not match."));
730 gcry_free(key);
731 gcry_free(key2);
732 gcry_cipher_close(gh);
733 return FALSE;
736 gcry_free(key2);
738 done:
739 if ((fd = open(filename, O_RDONLY)) == -1) {
740 gcry_free(key);
741 warn("%s", filename);
742 gcry_cipher_close(gh);
743 return FALSE;
746 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
747 gcry_free(key);
748 close(fd);
749 log_write("%s", strerror(ENOMEM));
750 gcry_cipher_close(gh);
751 return FALSE;
754 if (read(fd, xmlbuf, st.st_size) == -1) {
755 error = errno;
756 close(fd);
757 gcry_free(key);
758 gcry_cipher_close(gh);
759 errno = error;
760 err(EXIT_FAILURE, "read()");
763 close(fd);
764 xmlbuf[st.st_size] = 0;
767 * Make sure the document validates.
769 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
770 log_write("xmlReadDoc()");
771 close(fd);
772 gcry_free(key);
773 gcry_free(xmlbuf);
774 gcry_cipher_close(gh);
775 return FALSE;
778 gcry_free(xmlbuf);
779 xmlDocDumpMemory(doc, &xml, &len);
780 xmlFreeDoc(doc);
782 level = get_key_file_integer(filename, "compression_level");
784 if (level < 0)
785 level = 0;
787 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zerror) == FALSE) {
788 memset(shakey, 0, sizeof(shakey));
789 gcry_free(xml);
791 if (zerror == Z_MEM_ERROR)
792 warnx("%s", strerror(ENOMEM));
793 else
794 warnx("do_compress() failed");
796 gcry_cipher_close(gh);
797 return FALSE;
799 else {
800 gcry_free(xml);
801 xml = outbuf;
802 len = outsize;
805 if (iter == -1)
806 memset(shakey, '!', sizeof(shakey));
807 else{
808 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key) ? strlen(key) : 1);
809 gcry_free(key);
812 error = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
813 gcry_cipher_close(gh);
815 if (error) {
816 memset(shakey, 0, sizeof(shakey));
817 warnx("%s", gpg_strerror(error));
818 return FALSE;
821 memset(shakey, 0, sizeof(shakey));
822 return TRUE;
825 gchar *get_key_file_string(const gchar *section, const gchar *what)
827 gchar *val = NULL;
828 GError *gerror = NULL;
830 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
831 val = g_key_file_get_string(keyfileh, section, what, &gerror);
833 if (gerror) {
834 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
835 g_clear_error(&gerror);
838 else {
839 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
840 val = g_key_file_get_string(keyfileh, "global", what, &gerror);
842 if (gerror) {
843 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
844 g_clear_error(&gerror);
849 return val;
852 gint get_key_file_integer(const gchar *section, const gchar *what)
854 gint val = -1;
855 GError *gerror = NULL;
857 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
858 val = g_key_file_get_integer(keyfileh, section, what, &gerror);
860 if (gerror) {
861 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
862 g_clear_error(&gerror);
865 else {
866 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
867 val = g_key_file_get_integer(keyfileh, "global", what, &gerror);
869 if (gerror) {
870 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
871 g_clear_error(&gerror);
876 return val;
879 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
881 gboolean val = FALSE;
882 GError *gerror = NULL;
884 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
885 val = g_key_file_get_boolean(keyfileh, section, what, &gerror);
887 if (gerror) {
888 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
889 g_clear_error(&gerror);
892 else {
893 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
894 val = g_key_file_get_boolean(keyfileh, "global", what, &gerror);
896 if (gerror) {
897 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
898 g_clear_error(&gerror);
903 return val;
906 gchar *expand_homedir(gchar *str)
908 gchar *p = str;
910 if (*p++ == '~')
911 return g_strdup_printf("%s%s", g_get_home_dir(), p);
913 return g_strdup(str);
916 static gboolean _getline(const gchar *file, gchar **result)
918 FILE *fp;
919 gchar buf[LINE_MAX] = {0}, *p;
920 gchar *str = NULL;
921 gint len;
923 if ((fp = fopen(file, "r")) == NULL) {
924 warn("%s", file);
925 return FALSE;
928 p = fgets(buf, sizeof(buf), fp);
929 fclose(fp);
930 len = strlen(buf);
932 if (len && buf[len - 1] == '\n')
933 buf[--len] = 0;
935 str = gcry_malloc(len + 1);
936 memcpy(str, buf, len ? len : 1);
937 str[len] = 0;
938 memset(&buf, 0, sizeof(buf));
939 *result = str;
940 return TRUE;
943 static gboolean parse_keyfile_key()
945 gsize n;
946 gchar **groups;
947 gchar **p;
948 gchar *str;
950 groups = g_key_file_get_groups(keyfileh, &n);
952 for (p = groups; *p; p++) {
953 GError *error = NULL;
955 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE) {
956 str = g_key_file_get_string(keyfileh, *p, "key", &error);
958 if (!str) {
959 if (error) {
960 warnx("%s", error->message);
961 g_clear_error(&error);
964 continue;
967 do_cache_push(*p, str);
968 g_free(str);
969 continue;
972 if (error) {
973 warnx("%s", error->message);
974 g_clear_error(&error);
975 continue;
978 if (g_key_file_has_key(keyfileh, *p, "key_file", &error) == TRUE) {
979 gchar *t;
980 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &error);
982 if (!file) {
983 if (error) {
984 warnx("%s", error->message);
985 g_clear_error(&error);
988 continue;
991 t = expand_homedir(file);
992 g_free(file);
993 file = t;
995 if (_getline(file, &str) == FALSE) {
996 g_free(file);
997 continue;
1000 g_free(file);
1001 do_cache_push(*p, str);
1002 gcry_free(str);
1003 continue;
1006 if (error) {
1007 warnx("%s", error->message);
1008 g_clear_error(&error);
1012 g_strfreev(groups);
1013 return TRUE;
1016 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1018 guchar *md5file;
1019 guchar *key;
1020 gint timeout;
1021 const gchar *p = filename;
1022 file_header_t file_header;
1023 gpg_error_t error;
1025 while (isspace(*p))
1026 p++;
1028 if (!*p)
1029 return FALSE;
1031 if (valid_filename(p) == FALSE) {
1032 warnx(N_("%s: invalid characters in filename"), p);
1033 return FALSE;
1036 md5file = gcry_malloc(16);
1037 key = gcry_malloc(gcrykeysize);
1038 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1040 if (cache_iscached(md5file) == TRUE) {
1041 warnx(N_("%s: file already cached, skipping"), p);
1042 gcry_free(md5file);
1043 gcry_free(key);
1044 return FALSE;
1047 if (access(p, R_OK|W_OK) != 0) {
1048 gcry_free(md5file);
1049 gcry_free(key);
1051 if (errno != ENOENT) {
1052 warn("%s", p);
1053 return FALSE;
1056 warn("%s", p);
1057 return TRUE;
1060 error = read_file_header(filename, &file_header);
1062 if (error) {
1063 gcry_free(md5file);
1064 gcry_free(key);
1065 warnx("%s", pwmd_strerror(error));
1066 return FALSE;
1069 if (file_header.iter == -1) {
1070 memset(key, '!', gcrykeysize);
1071 goto try_decrypt;
1074 if (!password) {
1075 #ifdef WITH_PINENTRY
1076 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL) == FALSE) {
1077 #endif
1078 if (get_input(p, key) == FALSE) {
1079 gcry_free(key);
1080 gcry_free(md5file);
1081 return FALSE;
1083 #ifdef WITH_PINENTRY
1085 else {
1086 gchar *result = NULL;
1087 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1088 gpg_error_t rc;
1089 gint try = 0;
1091 pin->which = PINENTRY_OPEN;
1092 pin->filename = g_strdup(filename);
1093 again:
1094 rc = pinentry_getpin(pin, &result);
1096 if (rc) {
1097 warnx("%s: %s", filename, gpg_strerror(rc));
1098 cleanup_pinentry(pin);
1099 gcry_free(key);
1100 gcry_free(md5file);
1101 xfree(result);
1102 return FALSE;
1105 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1106 xfree(result);
1108 if (do_try_xml_decrypt(filename, key) == FALSE) {
1109 if (try++ == 2) {
1110 cleanup_pinentry(pin);
1111 gcry_free(key);
1112 gcry_free(md5file);
1113 warnx(N_("%s: invalid password, skipping"), filename);
1114 return FALSE;
1116 else {
1117 g_free(pin->title);
1118 pin->title = g_strdup(N_("Incorrect password. Please try again."));
1119 goto again;
1123 cleanup_pinentry(pin);
1125 #endif
1127 else {
1128 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password) ? strlen(password) : 1);
1130 try_decrypt:
1131 if (do_try_xml_decrypt(filename, key) == FALSE) {
1132 warnx(N_("%s: invalid password, skipping"), filename);
1133 gcry_free(key);
1134 gcry_free(md5file);
1135 return FALSE;
1139 if (cache_add_file(md5file, key) == FALSE) {
1140 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1141 gcry_free(key);
1142 gcry_free(md5file);
1143 return FALSE;
1146 timeout = get_key_file_integer(p, "cache_timeout");
1147 cache_set_timeout(md5file, timeout);
1148 warnx(N_("%s: file added to the cache"), filename);
1149 gcry_free(key);
1150 gcry_free(md5file);
1151 return TRUE;
1154 static GSList *remove_connection(GSList *list, struct client_thread_s *cn)
1156 gpointer value;
1157 struct client_s *cl = cn->cl;
1159 if (cn->keepalive_tid) {
1160 pth_cancel(cn->keepalive_tid);
1161 pth_join(cn->keepalive_tid, &value);
1164 log_write("%p", cn->tid);
1165 pth_join(cn->tid, &value);
1166 close(cn->fd);
1168 if (cl->freed == FALSE)
1169 cleanup_assuan(cl->ctx);
1171 if (cl->ctx)
1172 assuan_deinit_server(cl->ctx);
1174 #ifdef WITH_PINENTRY
1175 if (cl->pinentry)
1176 cleanup_pinentry(cl->pinentry);
1177 #endif
1179 if (cl)
1180 g_free(cl);
1182 pth_event_isolate(cn->ev);
1183 pth_event_free(cn->ev, PTH_FREE_THIS);
1184 list = g_slist_remove(list, cn);
1185 g_free(cn);
1186 return list;
1190 * Can't pth_event_concat() to an empty event.
1192 static int event_ring_hack(void *data)
1194 return FALSE;
1198 * See if any thread has entered the DEAD queue and remove it.
1200 static GSList *cleanup_dead_queue(GSList *threads, pth_event_t tid_events)
1202 guint n, i;
1204 for (n = g_slist_length(threads), i = 0; i < n; i++) {
1205 struct client_thread_s *cn = g_slist_nth_data(threads, i);
1207 if (pth_event_occurred(cn->ev)) {
1208 threads = remove_connection(threads, cn);
1209 return cleanup_dead_queue(threads, tid_events);
1212 pth_event_concat(tid_events, cn->ev, NULL);
1215 return threads;
1218 static void *socket_thread(void *arg)
1220 gint sockfd = (gint)arg;
1222 for (;;) {
1223 socklen_t slen = sizeof(struct sockaddr_un);
1224 struct sockaddr_un raddr;
1225 gint fd = -1;
1226 pth_attr_t attr;
1228 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1229 if (errno != EAGAIN) {
1230 if (!quit) // probably EBADF
1231 log_write("accept(): %s", strerror(errno));
1233 break;
1237 if (fd >= 0) {
1238 pth_t tid;
1239 struct client_thread_s *new;
1240 gchar buf[41];
1242 new = g_malloc0(sizeof(struct client_thread_s));
1244 if (!new) {
1245 log_write("%s", strerror(ENOMEM));
1246 continue;
1250 * Thread priority is inherited from the calling thread. This
1251 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1252 * priority.
1254 attr = pth_attr_new();
1255 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1256 tid = pth_spawn(attr, client_thread, new);
1257 pth_attr_destroy(attr);
1259 if (!tid) {
1260 g_free(new);
1261 log_write(N_("pth_spawn() failed"));
1262 continue;
1265 snprintf(buf, sizeof(buf), "%p", tid);
1266 attr = pth_attr_of(tid);
1267 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1268 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1269 new->fd = fd;
1270 new->tid = tid;
1271 new->fd = fd;
1272 new->ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1273 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1274 pth_event_concat(cn_events, new->ev, NULL);
1275 cn_thread_list = g_slist_append(cn_thread_list, new);
1276 pth_mutex_release(&cn_mutex);
1280 /* Just in case pth_accept() failed for some reason other than EBADF */
1281 quit = 1;
1282 pth_exit(PTH_CANCELED);
1283 return NULL;
1287 * There needs to be a pth_timeout() here so pth_wait() can wait for new
1288 * cn_events which is updated from cleanup_dead_queue().
1290 static void *cleanup_thread(void *arg)
1292 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1294 for (;;) {
1295 if (pth_wait(cn_events) && pth_event_occurred(cn_events)) {
1296 pth_event_isolate(cn_events);
1297 pth_event_free(cn_events, PTH_FREE_THIS);
1298 pth_cancel_point();
1299 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1300 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1301 cn_thread_list = cleanup_dead_queue(cn_thread_list, cn_events);
1302 pth_mutex_release(&cn_mutex);
1306 pth_event_isolate(cn_events);
1307 pth_event_free(cn_events, PTH_FREE_THIS);
1308 return NULL;
1312 * This thread isn't joinable. For operations that block, these threads will
1313 * stack.
1315 static void *adjust_timer_thread(void *arg)
1317 CACHE_LOCK(NULL);
1318 cache_adjust_timer();
1319 CACHE_UNLOCK;
1320 return NULL;
1323 static void server_loop(int sockfd)
1325 pth_t socket_tid, cleanup_tid;
1326 guint n, i;
1327 sigset_t set;
1328 gint n_clients = 0;
1329 pth_attr_t attr;
1330 pth_event_t timeout_event;
1331 gpointer value;
1333 pth_mutex_init(&cn_mutex);
1334 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1336 sigemptyset(&set);
1337 sigaddset(&set, SIGTERM);
1338 sigaddset(&set, SIGINT);
1339 sigaddset(&set, SIGUSR1);
1340 sigaddset(&set, SIGHUP);
1341 sigaddset(&set, SIGABRT);
1343 attr = pth_attr_new();
1344 pth_attr_init(attr);
1345 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1346 pth_attr_set(attr, PTH_ATTR_NAME, "socket");
1347 socket_tid = pth_spawn(attr, socket_thread, (void *)sockfd);
1348 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1349 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ASYNCHRONOUS);
1350 pth_attr_set(attr, PTH_ATTR_NAME, "cleanup");
1351 cleanup_tid = pth_spawn(attr, cleanup_thread, NULL);
1354 * For the cache_timeout configuration parameter. This replaces the old
1355 * SIGALRM stuff and is safer.
1357 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1358 pth_attr_init(attr);
1359 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1360 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1362 do {
1363 gint sig = 0;
1365 pth_sigwait_ev(&set, &sig, timeout_event);
1367 if (pth_event_occurred(timeout_event)) {
1369 * The timer event has expired. Update the file cache. When the
1370 * cache mutex is locked and the timer expires again, the threads
1371 * will stack.
1373 pth_spawn(attr, adjust_timer_thread, NULL);
1374 pth_event_free(timeout_event, PTH_FREE_THIS);
1375 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1378 if (sig > 0) {
1379 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1381 /* Caught a signal. */
1382 switch (sig) {
1383 case SIGUSR1:
1384 reload_rcfile();
1385 break;
1386 case SIGABRT:
1387 CACHE_LOCK(NULL);
1388 cache_clear(NULL, 2);
1389 CACHE_UNLOCK;
1390 #ifndef MEM_DEBUG
1391 xpanic();
1392 #endif
1393 exit(EXIT_FAILURE);
1394 case SIGHUP:
1395 CACHE_LOCK(NULL);
1396 log_write(N_("clearing file cache"));
1397 cache_clear(NULL, 2);
1398 CACHE_UNLOCK;
1399 break;
1400 default:
1401 quit = 1;
1402 shutdown(sockfd, SHUT_RDWR);
1403 close(sockfd);
1404 break;
1407 } while (!quit);
1410 * We're out of the main server loop. This happens when a signal was sent
1411 * to terminate the daemon. We'll wait for all clients to disconnect
1412 * before exiting and ignore any following signals.
1414 pth_join(socket_tid, &value);
1415 pth_attr_destroy(attr);
1416 pth_event_free(timeout_event, PTH_FREE_THIS);
1418 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1420 /* 2 because the cleanup thread still exists, plus self. */
1421 if (n > 2)
1422 log_write(N_("waiting for all threads to terminate"));
1424 while (n > 2) {
1425 gint t;
1426 pth_event_t events;
1428 if (n != n_clients) {
1429 log_write(N_("%i threads remain"), n-2);
1430 n_clients = n;
1433 events = pth_event(PTH_EVENT_FUNC, event_ring_hack, NULL, pth_timeout(1, 0));
1434 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1436 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1437 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1439 pth_event_concat(events, cn->ev, NULL);
1442 if (!t)
1443 goto done;
1445 pth_mutex_release(&cn_mutex);
1446 pth_wait(events);
1447 pth_yield(cleanup_tid);
1448 done:
1449 pth_event_isolate(events);
1450 pth_event_free(events, PTH_FREE_THIS);
1451 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1454 pth_cancel(cleanup_tid);
1458 * Called from pinentry_fork() in the child process.
1460 void free_client_list()
1462 gint i, t = g_slist_length(cn_thread_list);
1464 for (i = 0; i < t; i++) {
1465 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1467 free_client(cn->cl);
1470 memset(key_cache, 0, cache_size);
1473 int main(int argc, char *argv[])
1475 gint opt;
1476 struct sockaddr_un addr;
1477 struct passwd *pw = getpwuid(getuid());
1478 gchar buf[PATH_MAX];
1479 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1480 gchar *socketarg = NULL;
1481 gchar *datadir = NULL;
1482 gboolean n;
1483 gchar *p;
1484 gchar **cache_push = NULL;
1485 gint iter = 0;
1486 gchar *import = NULL;
1487 gint default_timeout;
1488 gint rcfile_spec = 0;
1489 gint estatus = EXIT_FAILURE;
1490 gint sockfd;
1491 #ifndef MEM_DEBUG
1492 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1493 #endif
1494 gint do_unlink = 1;
1495 gboolean secure = FALSE;
1496 guint ptotal = 0;
1497 gint background = 0;
1498 sigset_t set;
1499 #ifndef DEBUG
1500 #ifdef HAVE_SETRLIMIT
1501 struct rlimit rl;
1503 rl.rlim_cur = rl.rlim_max = 0;
1505 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1506 err(EXIT_FAILURE, "setrlimit()");
1507 #endif
1508 #endif
1510 #ifdef ENABLE_NLS
1511 setlocale(LC_ALL, "");
1512 bindtextdomain("pwmd", LOCALEDIR);
1513 textdomain("pwmd");
1514 #endif
1516 gpg_err_init();
1517 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1518 #ifndef MEM_DEBUG
1519 g_mem_set_vtable(&mtable);
1520 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1521 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1522 xmlInitMemory();
1523 #endif
1524 pth_init();
1525 snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1527 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1528 err(EXIT_FAILURE, "%s", buf);
1530 snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1532 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1533 err(EXIT_FAILURE, "%s", buf);
1535 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1537 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1538 err(EXIT_FAILURE, "sysconf()");
1540 cache_size = page_size;
1542 while ((opt = getopt(argc, argv, "bI:hvf:D")) != EOF) {
1543 switch (opt) {
1544 case 'b':
1545 background = 1;
1546 break;
1547 case 'D':
1548 secure = TRUE;
1549 break;
1550 case 'I':
1551 import = optarg;
1552 break;
1553 case 'f':
1554 g_free(rcfile);
1555 rcfile = g_strdup(optarg);
1556 rcfile_spec = 1;
1557 break;
1558 case 'v':
1559 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1560 exit(EXIT_SUCCESS);
1561 case 'h':
1562 default:
1563 usage(argv[0]);
1567 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1568 exit(EXIT_FAILURE);
1570 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
1571 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
1573 if (log_syslog == TRUE)
1574 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1576 if (g_key_file_has_key(keyfileh, "global", "iterations", NULL) == TRUE)
1577 iter = g_key_file_get_integer(keyfileh, "global", "iterations", NULL);
1579 #ifdef HAVE_MLOCKALL
1580 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1581 warn("mlockall()");
1582 goto do_exit;
1584 #endif
1586 setup_gcrypt();
1588 if (import) {
1589 opt = xml_import(import, iter);
1590 g_key_file_free(keyfileh);
1591 g_free(rcfile);
1592 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1595 g_key_file_set_list_separator(keyfileh, ',');
1597 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
1598 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1600 if (*p == '~') {
1601 p++;
1602 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1603 g_free(p);
1604 socketarg = g_strdup(buf);
1606 else
1607 socketarg = p;
1609 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
1610 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1612 datadir = expand_homedir(p);
1613 g_free(p);
1615 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
1616 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
1617 disable_list_and_dump = n;
1619 else
1620 disable_list_and_dump = secure;
1622 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
1623 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
1624 else
1625 default_timeout = -1;
1627 if (g_key_file_has_key(keyfileh, "global", "cache_size", NULL) == TRUE) {
1628 cache_size = g_key_file_get_integer(keyfileh, "global", "cache_size", NULL);
1630 if (cache_size < page_size || cache_size % page_size)
1631 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1634 if (g_key_file_has_key(keyfileh, "global", "log_path", NULL) == TRUE) {
1635 if (g_key_file_has_key(keyfileh, "global", "enable_logging", NULL) == TRUE) {
1636 n = g_key_file_get_boolean(keyfileh, "global", "enable_logging", NULL);
1638 if (n == TRUE) {
1639 p = g_key_file_get_string(keyfileh, "global", "log_path", NULL);
1641 if (*p == '~') {
1642 p++;
1643 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1644 g_free(p);
1645 logfile = g_strdup(buf);
1647 else
1648 logfile = p;
1653 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
1654 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
1656 if (argc != optind) {
1657 if (cache_push)
1658 ptotal = g_strv_length(cache_push);
1660 for (; optind < argc; optind++) {
1661 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1662 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1666 if (strchr(socketarg, '/') == NULL) {
1667 socketdir = g_get_current_dir();
1668 socketname = g_strdup(socketarg);
1669 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1671 else {
1672 socketname = g_strdup(strrchr(socketarg, '/'));
1673 socketname++;
1674 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1675 socketdir = g_strdup(socketarg);
1676 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1679 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1680 #ifdef MMAP_ANONYMOUS
1681 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1682 #else
1683 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1684 #endif
1685 err(EXIT_FAILURE, "mmap()");
1688 if (mlock(key_cache, cache_size) == -1)
1689 log_write("mlock(): %s", strerror(errno));
1691 memset(key_cache, 0, cache_size);
1693 if (chdir(datadir)) {
1694 warn("%s", datadir);
1695 unlink(socketpath);
1696 goto do_exit;
1699 if (parse_keyfile_key() == FALSE)
1700 goto do_exit;
1702 clear_rcfile_key();
1705 * Set the cache entry for a file. Prompts for the password.
1707 if (cache_push) {
1708 for (opt = 0; cache_push[opt]; opt++)
1709 do_cache_push(cache_push[opt], NULL);
1711 g_strfreev(cache_push);
1712 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1716 * bind() doesn't like the full pathname of the socket or any non alphanum
1717 * characters so change to the directory where the socket is wanted then
1718 * create it then change to datadir.
1720 if (chdir(socketdir)) {
1721 warn("%s", socketdir);
1722 goto do_exit;
1725 g_free(socketdir);
1727 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1728 warn("socket()");
1729 goto do_exit;
1732 addr.sun_family = AF_UNIX;
1733 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1735 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1736 warn("bind()");
1738 if (errno == EADDRINUSE)
1739 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1740 "stale socket. Please remove it manually."), socketpath);
1742 do_unlink = 0;
1743 goto do_exit;
1746 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
1747 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
1748 mode_t mode = strtol(t, NULL, 8);
1749 mode_t mask = umask(0);
1751 g_free(t);
1753 if (chmod(socketname, mode) == -1) {
1754 warn("%s", socketname);
1755 close(sockfd);
1756 unlink(socketpath);
1757 umask(mask);
1758 goto do_exit;
1761 umask(mask);
1764 g_free(--socketname);
1766 if (chdir(datadir)) {
1767 warn("%s", datadir);
1768 close(sockfd);
1769 unlink(socketpath);
1770 goto do_exit;
1773 g_free(datadir);
1774 pth_mutex_init(&cache_mutex);
1776 if (listen(sockfd, 0) == -1) {
1777 warn("listen()");
1778 goto do_exit;
1781 if (background) {
1782 switch (fork()) {
1783 case -1:
1784 warn("fork()");
1785 goto do_exit;
1786 case 0:
1787 close(0);
1788 close(1);
1789 close(2);
1790 setsid();
1791 break;
1792 default:
1793 exit(EXIT_SUCCESS);
1798 * These are the signals that we use in threads. libpth can catch signals
1799 * itself so ignore them everywhere else. Note that using
1800 * signal(N, SIG_IGN) doesn't work like you might think.
1802 sigemptyset(&set);
1804 /* Termination */
1805 sigaddset(&set, SIGTERM);
1806 sigaddset(&set, SIGINT);
1808 /* Configuration file reloading. */
1809 sigaddset(&set, SIGUSR1);
1811 /* Clears the file cache. */
1812 sigaddset(&set, SIGHUP);
1814 /* Caught in client_thread(). Sends a cache status message. */
1815 sigaddset(&set, SIGUSR2);
1817 /* Caught in client_thread(). When keepalive_thread() fails, this signal
1818 * is raised to terminate the client. More of a failsafe than anything. */
1819 sigaddset(&set, SIGQUIT);
1821 /* Ignored everywhere. When a client disconnects abnormally this signal
1822 * gets raised. It isn't needed though because client_thread() will check
1823 * for errors even after the client disconnects. */
1824 signal(SIGPIPE, SIG_IGN);
1825 pth_sigmask(SIG_BLOCK, &set, NULL);
1826 server_loop(sockfd);
1827 estatus = EXIT_SUCCESS;
1829 do_exit:
1830 if (socketpath && do_unlink) {
1831 unlink(socketpath);
1832 g_free(socketpath);
1835 g_key_file_free(keyfileh);
1836 g_free(rcfile);
1838 if (key_cache) {
1839 cache_clear(NULL, 2);
1840 memset(key_cache, 0, cache_size);
1843 if (key_cache && munmap(key_cache, cache_size) == -1)
1844 log_write("munmap(): %s", strerror(errno));
1846 if (estatus == EXIT_SUCCESS)
1847 log_write(N_("pwmd exiting normally"));
1849 pth_kill();
1850 #if defined(DEBUG) && !defined(MEM_DEBUG)
1851 xdump();
1852 #endif
1853 xdump();
1854 exit(estatus);