Make sure client->pinentry->filename is set in save_command() before
[pwmd.git] / src / pwmd.c
blobbeb3f7e9eafcfba45d9aaf441f0ac2653ea05f69
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 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"
57 #include "pinentry.h"
58 #include "commands.h"
59 #include "pwmd_error.h"
60 #include "cache.h"
61 #include "pwmd.h"
63 static void clear_rcfile_key()
65 gsize n;
66 gchar **groups;
67 gchar **p;
69 groups = g_key_file_get_groups(keyfileh, &n);
71 for (p = groups; *p; p++) {
72 GError *error = NULL;
74 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE)
75 g_key_file_set_string(keyfileh, *p, "key", "");
78 g_strfreev(groups);
81 static void reload_rcfile()
83 log_write(N_("reloading configuration file '%s'"), rcfile);
84 g_key_file_free(keyfileh);
85 keyfileh = parse_rcfile(0);
86 clear_rcfile_key();
89 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
91 gpg_error_t n = gpg_error_from_errno(e);
93 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
96 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
98 gpg_err_code_t n = gpg_err_code(e);
99 gpg_error_t code = gpg_err_make(GPG_ERR_SOURCE_USER_1, n);
101 if (!e)
102 return assuan_process_done(ctx, 0);
104 if (!ctx) {
105 log_write("%s\n", pwmd_strerror(e));
106 return e;
109 if (n == EPWMD_LIBXML_ERROR) {
110 xmlErrorPtr xml_error = xmlGetLastError();
111 return assuan_process_done(ctx, assuan_set_error(ctx, code, xml_error->message));
114 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
117 void log_write(const gchar *fmt, ...)
119 gchar *args, *line;
120 va_list ap;
121 struct tm *tm;
122 time_t now;
123 gchar tbuf[21];
124 gint fd = -1;
125 pth_attr_t attr;
126 gchar *name;
128 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
129 return;
131 if (logfile) {
132 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
133 warn(N_("logfile"));
134 return;
138 va_start(ap, fmt);
140 if (g_vasprintf(&args, fmt, ap) == -1) {
141 va_end(ap);
142 return;
145 attr = pth_attr_of(pth_self());
146 pth_attr_get(attr, PTH_ATTR_NAME, &name);
148 if (log_syslog == TRUE)
149 syslog(LOG_INFO, "%s: %s", name, args);
151 va_end(ap);
152 time(&now);
153 tm = localtime(&now);
154 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
155 tbuf[sizeof(tbuf) - 1] = 0;
156 line = g_strdup_printf("%s %i %s: %s\n", tbuf, getpid(), name, args);
158 if (!line) {
159 if (logfile)
160 close(fd);
162 g_free(args);
163 return;
166 if (logfile) {
167 write(fd, line, strlen(line));
168 fsync(fd);
169 close(fd);
172 if (isatty(STDERR_FILENO)) {
173 fprintf(stderr, "%s", line);
174 fflush(stderr);
177 g_free(line);
178 g_free(args);
181 static void usage(gchar *pn)
183 g_printf(N_(
184 "Usage: %s [-hvDb] [-f <rcfile>] [-I <filename>] [file1] [...]\n"
185 " -b run as a background process\n"
186 " -f load the specified rcfile (~/.pwmd/config)\n"
187 " -I import an XML file and write the encrypted data to stdout\n"
188 " -D disable use of the LIST and DUMP commands\n"
189 " -v version\n"
190 " -h this help text\n"
191 ), pn);
192 exit(EXIT_SUCCESS);
195 #ifndef MEM_DEBUG
196 static int gcry_SecureCheck(const void *ptr)
198 return 1;
200 #endif
202 static void setup_gcrypt()
204 gcry_check_version(NULL);
206 #ifndef MEM_DEBUG
207 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
208 xfree);
209 #endif
211 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
212 NULL) != 0)
213 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
215 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
216 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
219 static assuan_context_t new_connection(gint fd)
221 gpg_error_t rc;
222 gchar ver[ASSUAN_LINELENGTH];
223 assuan_context_t ctx;
225 rc = assuan_init_socket_server_ext(&ctx, fd, 2);
227 if (rc)
228 goto fail;
230 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
231 assuan_set_hello_line(ctx, ver);
232 assuan_register_post_cmd_notify(ctx, command_finalize);
233 rc = register_commands(ctx);
235 if (rc)
236 goto fail;
238 rc = assuan_accept(ctx);
240 if (rc)
241 goto fail;
243 return ctx;
245 fail:
246 assuan_deinit_server(ctx);
247 log_write("%s", gpg_strerror(rc));
248 return NULL;
251 void send_cache_status_all()
253 guint i, t;
255 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
256 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
258 if (cn->tid == pth_self()) {
259 send_cache_status(cn->cl->ctx);
260 continue;
263 pth_raise(cn->tid, SIGUSR2);
267 static void *keepalive_thread(void *arg)
269 struct client_thread_s *thd = arg;
270 pth_event_t ev;
271 sigset_t set;
273 sigemptyset(&set);
274 sigaddset(&set, SIGALRM);
276 for (;;) {
277 gint sig = 0;
278 gpg_error_t error;
279 gint k = get_key_file_integer("default", "keepalive");
281 ev = pth_event(PTH_EVENT_TIME, pth_timeout(k <= 0 ? 1 : k, 0));
282 pth_sigwait_ev(&set, &sig, ev);
283 pth_event_free(ev, PTH_FREE_THIS);
285 if (sig)
286 break;
288 if (k <= 0)
289 continue;
291 error = assuan_write_status(thd->cl->ctx, "KEEPALIVE", NULL);
293 if (error) {
294 pth_raise(thd->tid, SIGQUIT);
295 break;
299 return NULL;
303 * Called every time a connection is made via pth_spawn(). This is the thread
304 * entry point.
306 static void *client_thread(void *data)
308 struct client_thread_s *thd = data;
309 gint fd = thd->fd;
310 pth_event_t ev;
311 #ifdef WITH_PINENTRY
312 pth_event_t pinentry_ev = NULL;
313 #endif
314 struct client_s *cl = g_malloc0(sizeof(struct client_s));
315 sigset_t set;
317 if (!cl) {
318 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
319 goto fail;
322 #ifdef WITH_PINENTRY
323 cl->pinentry = g_malloc0(sizeof(struct pinentry_s));
325 if (!cl->pinentry) {
326 g_free(cl);
327 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
328 goto fail;
331 set_pinentry_defaults(cl->pinentry);
332 #endif
333 thd->cl = cl;
334 cl->thd = thd;
337 * This is a "child" thread. Don't catch any signals. Let the master
338 * thread take care of signals in server_loop().
340 sigfillset(&set);
341 pth_sigmask(SIG_BLOCK, &set, NULL);
342 sigemptyset(&set);
343 /* Sends a cache status message to the client. */
344 sigaddset(&set, SIGUSR2);
345 /* Terminates this thread. Raised from keepalive_thread(). */
346 sigaddset(&set, SIGQUIT);
348 cl->ctx = new_connection(fd);
349 cl->fd = fd;
351 if (!cl->ctx)
352 goto fail;
354 assuan_set_pointer(cl->ctx, cl);
356 #ifdef HAVE_MLOCKALL
357 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
358 log_write("mlockall(): %s", strerror(errno));
359 goto fail;
361 #endif
363 send_cache_status(cl->ctx);
364 ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->fd);
365 thd->keepalive_tid = pth_spawn(NULL, keepalive_thread, thd);
367 for (;;) {
368 gpg_error_t rc;
369 gint sig = 0;
371 pth_sigwait_ev(&set, &sig, ev);
373 if (sig > 0) {
374 switch (sig) {
375 case SIGUSR2:
376 send_cache_status(cl->ctx);
377 continue;
378 case SIGQUIT:
379 goto done;
380 default:
381 break;
385 pth_event_isolate(ev);
387 if (pth_event_occurred(ev)) {
388 rc = assuan_process_next(cl->ctx);
390 if (rc) {
391 cl->inquire_status = INQUIRE_INIT;
393 if (gpg_err_code(rc) == GPG_ERR_EOF)
394 goto done;
396 log_write("assuan_process_next(): %s", gpg_strerror(rc));
397 rc = assuan_process_done(cl->ctx, gpg_err_make(GPG_ERR_SOURCE_USER_1, rc));
399 if (rc) {
400 log_write("assuan_process_done(): %s", gpg_strerror(rc));
401 goto done;
404 else {
405 #ifdef WITH_PINENTRY
406 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT) {
407 pinentry_ev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
408 pth_event_concat(ev, pinentry_ev, NULL);
409 cl->pinentry->status = PINENTRY_RUNNING;
411 #endif
413 switch (cl->inquire_status) {
414 case INQUIRE_BUSY:
415 case INQUIRE_INIT:
416 break;
417 case INQUIRE_DONE:
418 cl->inquire_status = INQUIRE_INIT;
419 rc = assuan_process_done(cl->ctx, 0);
420 break;
425 #ifdef WITH_PINENTRY
426 if (cl->pinentry->status == PINENTRY_RUNNING) {
427 pth_event_isolate(pinentry_ev);
429 if (pth_event_occurred(pinentry_ev)) {
430 guchar shakey[gcrykeysize];
431 pinentry_key_s pk;
432 gsize len = pth_read(cl->pinentry->fd, &pk, sizeof(pk));
433 gint status;
435 pth_event_free(pinentry_ev, PTH_FREE_THIS);
436 pinentry_ev = NULL;
437 cl->pinentry->status = PINENTRY_NONE;
439 if (len == sizeof(pk)) {
440 if (pk.error)
441 rc = assuan_process_done(cl->ctx, gpg_err_make(GPG_ERR_SOURCE_USER_1,
442 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, WNOHANG);
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, "default", "socket_path", NULL) == FALSE) {
492 snprintf(buf, sizeof(buf), "~/.pwmd/socket");
493 g_key_file_set_string(kf, "default", "socket_path", buf);
496 if (g_key_file_has_key(kf, "default", "data_directory", NULL) == FALSE) {
497 snprintf(buf, sizeof(buf), "~/.pwmd/data");
498 g_key_file_set_string(kf, "default", "data_directory", buf);
501 if (g_key_file_has_key(kf, "default", "log_path", NULL) == FALSE) {
502 snprintf(buf, sizeof(buf), "~/.pwmd/log");
503 g_key_file_set_string(kf, "default", "log_path", buf);
506 if (g_key_file_has_key(kf, "default", "enable_logging", NULL) == FALSE)
507 g_key_file_set_boolean(kf, "default", "enable_logging", FALSE);
509 if (g_key_file_has_key(kf, "default", "cache_size", NULL) == FALSE)
510 g_key_file_set_integer(kf, "default", "cache_size", cache_size);
512 #ifdef HAVE_MLOCKALL
513 if (g_key_file_has_key(kf, "default", "disable_mlockall", NULL) == FALSE)
514 g_key_file_set_boolean(kf, "default", "disable_mlockall", TRUE);
515 #endif
517 if (g_key_file_has_key(kf, "default", "cache_timeout", NULL) == FALSE)
518 g_key_file_set_integer(kf, "default", "cache_timeout", -1);
520 if (g_key_file_has_key(kf, "default", "iterations", NULL) == FALSE)
521 g_key_file_set_integer(kf, "default", "iterations", 0);
523 if (g_key_file_has_key(kf, "default", "disable_list_and_dump", NULL) == FALSE)
524 g_key_file_set_boolean(kf, "default", "disable_list_and_dump", FALSE);
526 if (g_key_file_has_key(kf, "default", "iteration_progress", NULL) == FALSE)
527 g_key_file_set_integer(kf, "default", "iteration_progress", 0);
529 if (g_key_file_has_key(kf, "default", "compression_level", NULL) == FALSE)
530 g_key_file_set_integer(kf, "default", "compression_level", 6);
532 if (g_key_file_has_key(kf, "default", "recursion_depth", NULL) == FALSE)
533 g_key_file_set_integer(kf, "default", "recursion_depth", DEFAULT_RECURSION_DEPTH);
535 if (g_key_file_has_key(kf, "default", "zlib_bufsize", NULL) == FALSE)
536 g_key_file_set_integer(kf, "default", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
538 zlib_bufsize = g_key_file_get_integer(kf, "default", "zlib_bufsize", NULL);
540 max_recursion_depth = g_key_file_get_integer(kf, "default", "recursion_depth", NULL);
541 disable_list_and_dump = g_key_file_get_boolean(kf, "default", "disable_list_and_dump", NULL);
543 #ifdef HAVE_MLOCKALL
544 disable_mlock = g_key_file_get_boolean(kf, "default", "disable_mlockall", NULL);
545 #endif
547 if (g_key_file_has_key(kf, "default", "syslog", NULL) == FALSE)
548 g_key_file_set_boolean(kf, "default", "syslog", FALSE);
550 if (g_key_file_has_key(kf, "default", "keepalive", NULL) == FALSE)
551 g_key_file_set_integer(kf, "default", "keepalive", 5);
553 #ifdef WITH_PINENTRY
554 if (g_key_file_has_key(kf, "default", "enable_pinentry", NULL) == FALSE)
555 g_key_file_set_boolean(kf, "default", "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], *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 (!p || !*p)
614 return NULL;
616 key = gcry_malloc(strlen(p) + 1);
617 sprintf(key, "%s", p);
618 memset(&buf, 0, sizeof(buf));
619 return key;
622 static gboolean do_try_xml_decrypt(const gchar *filename, guchar *key)
624 int fd;
625 struct stat st;
626 gpg_error_t error;
628 if ((fd = open_file(filename, &st)) == -1) {
629 warn("%s", filename);
630 return FALSE;
633 if (st.st_size == 0) {
634 warnx(N_("%s: skipping empty file"), filename);
635 close(fd);
636 return FALSE;
639 error = try_xml_decrypt(NULL, fd, st, key);
640 close(fd);
641 return error ? FALSE : TRUE;
644 static gboolean get_input(const gchar *filename, guchar *key)
646 gint try = 0;
647 gchar *password;
648 gchar *prompt;
650 prompt = g_strdup_printf(N_("Password for '%s': "), filename);
652 again:
653 if ((password = get_password(prompt)) == NULL) {
654 warnx(N_("%s: skipping file"), filename);
655 g_free(prompt);
656 return FALSE;
659 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password));
660 gcry_free(password);
662 if (do_try_xml_decrypt(filename, key) == FALSE) {
663 if (try++ == 2) {
664 warnx(N_("%s: invalid password, skipping"), filename);
665 g_free(prompt);
666 return FALSE;
668 else {
669 warnx(N_("%s: invalid password"), filename);
670 goto again;
674 g_free(prompt);
675 return TRUE;
678 static gboolean xml_import(const gchar *filename, gint iter)
680 xmlDocPtr doc;
681 gint fd;
682 struct stat st;
683 gint len;
684 xmlChar *xmlbuf;
685 xmlChar *xml;
686 gchar *key = NULL;
687 gchar *key2 = NULL;
688 guchar shakey[gcrykeysize];
689 gcry_cipher_hd_t gh;
690 gpg_error_t error;
691 gint level;
692 glong outsize;
693 gpointer outbuf;
694 gint zerror;
696 if (stat(filename, &st) == -1) {
697 warn("%s", filename);
698 return FALSE;
701 if ((error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
702 send_error(NULL, error);
703 gcry_cipher_close(gh);
704 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
705 return FALSE;
708 if ((key = get_password(N_("New password: "))) == NULL) {
709 fprintf(stderr, "%s\n", N_("Invalid password."));
710 gcry_cipher_close(gh);
711 return FALSE;
714 if ((key2 = get_password(N_("Verify password: "))) == NULL) {
715 fprintf(stderr, "%s\n", N_("Passwords do not match."));
716 gcry_free(key);
717 gcry_cipher_close(gh);
718 return FALSE;
721 if (g_utf8_collate(key, key2) != 0) {
722 fprintf(stderr, "%s\n", N_("Passwords do not match."));
723 gcry_free(key);
724 gcry_free(key2);
725 gcry_cipher_close(gh);
726 return FALSE;
729 gcry_free(key2);
731 if ((fd = open(filename, O_RDONLY)) == -1) {
732 gcry_free(key);
733 warn("%s", filename);
734 gcry_cipher_close(gh);
735 return FALSE;
738 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
739 gcry_free(key);
740 close(fd);
741 log_write("%s", strerror(ENOMEM));
742 gcry_cipher_close(gh);
743 return FALSE;
746 if (read(fd, xmlbuf, st.st_size) == -1) {
747 error = errno;
748 close(fd);
749 gcry_free(key);
750 gcry_cipher_close(gh);
751 errno = error;
752 err(EXIT_FAILURE, "read()");
755 close(fd);
756 xmlbuf[st.st_size] = 0;
759 * Make sure the document validates.
761 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
762 log_write("xmlReadDoc()");
763 close(fd);
764 gcry_free(key);
765 gcry_free(xmlbuf);
766 gcry_cipher_close(gh);
767 return FALSE;
770 gcry_free(xmlbuf);
771 xmlDocDumpMemory(doc, &xml, &len);
772 xmlFreeDoc(doc);
774 level = get_key_file_integer(filename, "compression_level");
776 if (level < 0)
777 level = 0;
779 if (do_compress(NULL, level, xml, len, &outbuf, &outsize, &zerror) == FALSE) {
780 memset(shakey, 0, sizeof(shakey));
781 gcry_free(xml);
783 if (zerror == Z_MEM_ERROR)
784 warnx("%s", strerror(ENOMEM));
785 else
786 warnx("do_compress() failed");
788 gcry_cipher_close(gh);
789 return FALSE;
791 else {
792 gcry_free(xml);
793 xml = outbuf;
794 len = outsize;
797 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key));
798 gcry_free(key);
799 error = do_xml_encrypt(NULL, gh, NULL, xml, len, shakey, iter);
800 gcry_cipher_close(gh);
802 if (error) {
803 memset(shakey, 0, sizeof(shakey));
804 warnx("%s", gpg_strerror(error));
805 return FALSE;
808 memset(shakey, 0, sizeof(shakey));
809 return TRUE;
812 gchar *get_key_file_string(const gchar *section, const gchar *what)
814 gchar *val = NULL;
815 GError *gerror = NULL;
817 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
818 val = g_key_file_get_string(keyfileh, section, what, &gerror);
820 if (gerror) {
821 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
822 g_clear_error(&gerror);
825 else {
826 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
827 val = g_key_file_get_string(keyfileh, "default", what, &gerror);
829 if (gerror) {
830 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
831 g_clear_error(&gerror);
836 return val;
839 gint get_key_file_integer(const gchar *section, const gchar *what)
841 gint val = -1;
842 GError *gerror = NULL;
844 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
845 val = g_key_file_get_integer(keyfileh, section, what, &gerror);
847 if (gerror) {
848 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
849 g_clear_error(&gerror);
852 else {
853 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
854 val = g_key_file_get_integer(keyfileh, "default", what, &gerror);
856 if (gerror) {
857 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
858 g_clear_error(&gerror);
863 return val;
866 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
868 gboolean val = FALSE;
869 GError *gerror = NULL;
871 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
872 val = g_key_file_get_boolean(keyfileh, section, what, &gerror);
874 if (gerror) {
875 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
876 g_clear_error(&gerror);
879 else {
880 if (g_key_file_has_key(keyfileh, "default", what, NULL) == TRUE) {
881 val = g_key_file_get_boolean(keyfileh, "default", what, &gerror);
883 if (gerror) {
884 log_write("%s(%i): %s", __FILE__, __LINE__, gerror->message);
885 g_clear_error(&gerror);
890 return val;
893 gchar *expand_homedir(gchar *str)
895 gchar *p = str;
897 if (*p++ == '~')
898 return g_strdup_printf("%s%s", g_get_home_dir(), p);
900 return g_strdup(str);
903 static gchar *_getline(const gchar *file)
905 FILE *fp;
906 gchar buf[LINE_MAX], *p;
907 gchar *str = NULL;
909 if ((fp = fopen(file, "r")) == NULL) {
910 warn("%s", file);
911 return NULL;
914 if ((p = fgets(buf, sizeof(buf), fp)) == NULL) {
915 warnx(N_("%s: empty file?"), file);
916 return NULL;
919 fclose(fp);
921 if (buf[strlen(buf) - 1] == '\n')
922 buf[strlen(buf) - 1] = 0;
924 str = gcry_malloc(strlen(p) + 1);
925 memcpy(str, p, strlen(p));
926 str[strlen(p)] = 0;
927 memset(&buf, 0, sizeof(buf));
928 return str;
931 static gboolean parse_keyfile_key()
933 gsize n;
934 gchar **groups;
935 gchar **p;
936 gchar *str;
938 groups = g_key_file_get_groups(keyfileh, &n);
940 for (p = groups; *p; p++) {
941 GError *error = NULL;
943 if (g_key_file_has_key(keyfileh, *p, "key", &error) == TRUE) {
944 str = g_key_file_get_string(keyfileh, *p, "key", &error);
946 if (!str) {
947 if (error) {
948 warnx("%s", error->message);
949 g_clear_error(&error);
952 continue;
955 do_cache_push(*p, str);
956 g_free(str);
957 continue;
960 if (error) {
961 warnx("%s", error->message);
962 g_clear_error(&error);
963 continue;
966 if (g_key_file_has_key(keyfileh, *p, "key_file", &error) == TRUE) {
967 gchar *t;
968 gchar *file = g_key_file_get_string(keyfileh, *p, "key_file", &error);
970 if (!file) {
971 if (error) {
972 warnx("%s", error->message);
973 g_clear_error(&error);
976 continue;
979 t = expand_homedir(file);
980 g_free(file);
981 file = t;
983 if ((str = _getline(file)) == NULL) {
984 g_free(file);
985 continue;
988 g_free(file);
989 do_cache_push(*p, str);
990 gcry_free(str);
991 continue;
994 if (error) {
995 warnx("%s", error->message);
996 g_clear_error(&error);
1000 g_strfreev(groups);
1001 return TRUE;
1004 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1006 guchar *md5file;
1007 guchar *key;
1008 gint timeout;
1009 const gchar *p = filename;
1011 while (isspace(*p))
1012 p++;
1014 if (!*p)
1015 return FALSE;
1017 if (valid_filename(p) == FALSE) {
1018 warnx(N_("%s: invalid characters in filename"), p);
1019 return FALSE;
1022 md5file = gcry_malloc(16);
1023 key = gcry_malloc(gcrykeysize);
1024 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1026 if (cache_iscached(md5file) == TRUE) {
1027 warnx(N_("%s: file already cached, skipping"), p);
1028 gcry_free(md5file);
1029 gcry_free(key);
1030 return FALSE;
1033 if (access(p, R_OK|W_OK) != 0) {
1034 gcry_free(md5file);
1035 gcry_free(key);
1037 if (errno != ENOENT) {
1038 warn("%s", p);
1039 return FALSE;
1042 warn("%s", p);
1043 return TRUE;
1046 if (!password) {
1047 if (get_input(p, key) == FALSE) {
1048 gcry_free(key);
1049 gcry_free(md5file);
1050 return FALSE;
1053 else {
1054 gcry_md_hash_buffer(GCRY_MD_SHA256, key, password, strlen(password));
1056 if (do_try_xml_decrypt(filename, key) == FALSE) {
1057 warnx(N_("%s: invalid password, skipping"), filename);
1058 gcry_free(key);
1059 gcry_free(md5file);
1060 return FALSE;
1064 if (cache_add_file(md5file, key) == FALSE) {
1065 warnx("%s: %s", p, pwmd_strerror(EPWMD_MAX_SLOTS));
1066 gcry_free(key);
1067 gcry_free(md5file);
1068 return FALSE;
1071 timeout = get_key_file_integer(p, "cache_timeout");
1072 cache_set_timeout(md5file, timeout);
1073 warnx(N_("%s: file added to the cache"), filename);
1074 gcry_free(key);
1075 gcry_free(md5file);
1076 return TRUE;
1079 static GSList *remove_connection(GSList *list, struct client_thread_s *cn)
1081 gpointer value;
1082 struct client_s *cl = cn->cl;
1084 if (cn->keepalive_tid) {
1085 pth_raise(cn->keepalive_tid, SIGALRM);
1086 pth_join(cn->keepalive_tid, &value);
1089 log_write("%p", cn->tid);
1090 pth_join(cn->tid, &value);
1091 close(cn->fd);
1093 if (cl->freed == FALSE)
1094 cleanup_assuan(cl->ctx);
1096 if (cl->ctx)
1097 assuan_deinit_server(cl->ctx);
1099 if (cl->pinentry)
1100 cleanup_pinentry(cl->pinentry);
1102 if (cl)
1103 g_free(cl);
1105 pth_event_isolate(cn->ev);
1106 pth_event_free(cn->ev, PTH_FREE_THIS);
1107 list = g_slist_remove(list, cn);
1108 g_free(cn);
1109 return list;
1113 * Can't pth_event_concat() to an empty event.
1115 static int event_ring_hack(void *data)
1117 return FALSE;
1121 * See if any thread has entered the DEAD queue and remove it.
1123 static GSList *cleanup_dead_queue(GSList *threads, pth_event_t tid_events)
1125 guint n, i;
1127 for (n = g_slist_length(threads), i = 0; i < n; i++) {
1128 struct client_thread_s *cn = g_slist_nth_data(threads, i);
1130 if (pth_event_occurred(cn->ev)) {
1131 threads = remove_connection(threads, cn);
1132 return cleanup_dead_queue(threads, tid_events);
1135 pth_event_concat(tid_events, cn->ev, NULL);
1138 return threads;
1141 static void *socket_thread(void *arg)
1143 gint sockfd = (gint)arg;
1145 for (;;) {
1146 socklen_t slen = sizeof(struct sockaddr_un);
1147 struct sockaddr_un raddr;
1148 gint fd = -1;
1149 pth_attr_t attr;
1151 if ((fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen)) == -1) {
1152 if (errno != EAGAIN) {
1153 if (!quit) // probably EBADF
1154 log_write("accept(): %s", strerror(errno));
1156 break;
1160 if (fd >= 0) {
1161 pth_t tid;
1162 struct client_thread_s *new;
1163 gchar buf[41];
1165 new = g_malloc0(sizeof(struct client_thread_s));
1167 if (!new) {
1168 log_write("%s", strerror(ENOMEM));
1169 continue;
1173 * Thread priority is inherited from the calling thread. This
1174 * thread is PTH_PRIO_MAX. Keep the "child" threads at standard
1175 * priority.
1177 attr = pth_attr_new();
1178 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_STD);
1179 tid = pth_spawn(attr, client_thread, new);
1180 pth_attr_destroy(attr);
1182 if (!tid) {
1183 g_free(new);
1184 log_write(N_("pth_spawn() failed"));
1185 continue;
1188 snprintf(buf, sizeof(buf), "%p", tid);
1189 attr = pth_attr_of(tid);
1190 pth_attr_set(attr, PTH_ATTR_NAME, buf);
1191 log_write(N_("new tid=%s, fd=%i"), buf, fd);
1192 new->fd = fd;
1193 new->tid = tid;
1194 new->fd = fd;
1195 new->ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1196 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1197 pth_event_concat(cn_events, new->ev, NULL);
1198 cn_thread_list = g_slist_append(cn_thread_list, new);
1199 pth_mutex_release(&cn_mutex);
1203 /* Just in case pth_accept() failed for some reason other than EBADF */
1204 quit = 1;
1205 pth_exit(PTH_CANCELED);
1206 return NULL;
1209 static void *cleanup_thread(void *arg)
1211 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1213 for (;;) {
1214 if (pth_wait(cn_events) && pth_event_occurred(cn_events)) {
1215 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1216 pth_event_isolate(cn_events);
1217 pth_event_free(cn_events, PTH_FREE_THIS);
1218 cn_events = pth_event(PTH_EVENT_TIME, pth_timeout(0, 500000));
1219 cn_thread_list = cleanup_dead_queue(cn_thread_list, cn_events);
1220 pth_mutex_release(&cn_mutex);
1224 pth_event_isolate(cn_events);
1225 pth_event_free(cn_events, PTH_FREE_THIS);
1226 return NULL;
1229 static void *adjust_cache_time_thread(void *arg)
1231 CACHE_LOCK(NULL);
1232 cache_adjust_timer();
1233 CACHE_UNLOCK;
1234 return NULL;
1237 static void server_loop(int sockfd)
1239 pth_t socket_tid, cleanup_tid;
1240 guint n, i;
1241 sigset_t set;
1242 gint n_clients = 0;
1243 pth_attr_t attr;
1244 pth_event_t timeout_event;
1245 gpointer value;
1247 pth_mutex_init(&cn_mutex);
1248 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1250 sigemptyset(&set);
1251 sigaddset(&set, SIGTERM);
1252 sigaddset(&set, SIGINT);
1253 sigaddset(&set, SIGUSR1);
1254 sigaddset(&set, SIGHUP);
1255 sigaddset(&set, SIGABRT);
1257 attr = pth_attr_new();
1258 pth_attr_init(attr);
1259 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1260 pth_attr_set(attr, PTH_ATTR_NAME, "socket");
1261 socket_tid = pth_spawn(attr, socket_thread, (void *)sockfd);
1262 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1263 pth_attr_set(attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ASYNCHRONOUS);
1264 pth_attr_set(attr, PTH_ATTR_NAME, "cleanup");
1265 cleanup_tid = pth_spawn(attr, cleanup_thread, NULL);
1268 * For the cache_timeout configuration parameter. This replaces the old
1269 * SIGALRM stuff and is safer.
1271 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1272 pth_attr_init(attr);
1273 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1274 pth_attr_set(attr, PTH_ATTR_PRIO, PTH_PRIO_MAX);
1276 do {
1277 gint sig = 0;
1279 pth_sigwait_ev(&set, &sig, timeout_event);
1281 if (pth_event_occurred(timeout_event)) {
1283 * The timer event has expired. Update the file cache. When the
1284 * cache mutex is locked and the timer expires again, the threads
1285 * will stack.
1287 pth_spawn(attr, adjust_cache_time_thread, NULL);
1288 pth_event_free(timeout_event, PTH_FREE_THIS);
1289 timeout_event = pth_event(PTH_EVENT_TIME, pth_timeout(1, 0));
1292 if (sig > 0) {
1293 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1295 /* Caught a signal. */
1296 switch (sig) {
1297 case SIGUSR1:
1298 reload_rcfile();
1299 break;
1300 case SIGABRT:
1301 CACHE_LOCK(NULL);
1302 cache_clear(NULL, 2);
1303 CACHE_UNLOCK;
1304 #ifndef MEM_DEBUG
1305 xpanic();
1306 #endif
1307 exit(EXIT_FAILURE);
1308 case SIGHUP:
1309 CACHE_LOCK(NULL);
1310 log_write(N_("clearing file cache"));
1311 cache_clear(NULL, 2);
1312 CACHE_UNLOCK;
1313 break;
1314 default:
1315 quit = 1;
1316 shutdown(sockfd, SHUT_RDWR);
1317 close(sockfd);
1318 break;
1321 } while (!quit);
1324 * We're out of the main server loop. This happens when a signal was sent
1325 * to terminate the daemon. We'll wait for all clients to disconnect
1326 * before exiting and ignore any following signals.
1328 pth_join(socket_tid, &value);
1329 pth_attr_destroy(attr);
1330 pth_event_free(timeout_event, PTH_FREE_THIS);
1332 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1334 /* 2 because the cleanup thread still exists, plus self. */
1335 if (n > 2)
1336 log_write(N_("waiting for all threads to terminate"));
1338 while (n > 2) {
1339 gint t;
1340 pth_event_t events;
1342 if (n != n_clients) {
1343 log_write(N_("%i threads remain"), n-2);
1344 n_clients = n;
1347 events = pth_event(PTH_EVENT_FUNC, event_ring_hack, NULL, pth_timeout(1, 0));
1348 pth_mutex_acquire(&cn_mutex, FALSE, NULL);
1350 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1351 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1353 pth_event_concat(events, cn->ev, NULL);
1356 if (!t)
1357 goto done;
1359 pth_mutex_release(&cn_mutex);
1360 pth_wait(events);
1361 pth_yield(cleanup_tid);
1362 done:
1363 pth_event_isolate(events);
1364 pth_event_free(events, PTH_FREE_THIS);
1365 n = pth_ctrl(PTH_CTRL_GETTHREADS);
1368 pth_cancel(cleanup_tid);
1371 int main(int argc, char *argv[])
1373 gint opt;
1374 struct sockaddr_un addr;
1375 struct passwd *pw = getpwuid(getuid());
1376 gchar buf[PATH_MAX];
1377 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
1378 gchar *socketarg = NULL;
1379 gchar *datadir = NULL;
1380 gboolean n;
1381 gchar *p;
1382 gchar **cache_push = NULL;
1383 gint iter = 0;
1384 gchar *import = NULL;
1385 gint default_timeout;
1386 gint rcfile_spec = 0;
1387 gint estatus = EXIT_FAILURE;
1388 gint sockfd;
1389 #ifndef MEM_DEBUG
1390 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
1391 #endif
1392 gint do_unlink = 1;
1393 gboolean secure = FALSE;
1394 guint ptotal = 0;
1395 gint background = 0;
1396 sigset_t set;
1397 #ifndef DEBUG
1398 #ifdef HAVE_SETRLIMIT
1399 struct rlimit rl;
1401 rl.rlim_cur = rl.rlim_max = 0;
1403 if (setrlimit(RLIMIT_CORE, &rl) != 0)
1404 err(EXIT_FAILURE, "setrlimit()");
1405 #endif
1406 #endif
1408 #ifdef ENABLE_NLS
1409 setlocale(LC_ALL, "");
1410 bindtextdomain("pwmd", LOCALEDIR);
1411 textdomain("pwmd");
1412 #endif
1414 gpg_err_init();
1415 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
1416 #ifndef MEM_DEBUG
1417 g_mem_set_vtable(&mtable);
1418 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
1419 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
1420 xmlInitMemory();
1421 #endif
1422 pth_init();
1423 snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
1425 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1426 err(EXIT_FAILURE, "%s", buf);
1428 snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
1430 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
1431 err(EXIT_FAILURE, "%s", buf);
1433 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
1435 if ((page_size = sysconf(_SC_PAGESIZE)) == -1)
1436 err(EXIT_FAILURE, "sysconf()");
1438 cache_size = page_size;
1440 while ((opt = getopt(argc, argv, "bI:hvf:D")) != EOF) {
1441 switch (opt) {
1442 case 'b':
1443 background = 1;
1444 break;
1445 case 'D':
1446 secure = TRUE;
1447 break;
1448 case 'I':
1449 import = optarg;
1450 break;
1451 case 'f':
1452 g_free(rcfile);
1453 rcfile = g_strdup(optarg);
1454 rcfile_spec = 1;
1455 break;
1456 case 'v':
1457 printf("%s\n%s\n", PACKAGE_STRING, PACKAGE_BUGREPORT);
1458 exit(EXIT_SUCCESS);
1459 case 'h':
1460 default:
1461 usage(argv[0]);
1465 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
1466 exit(EXIT_FAILURE);
1468 if (g_key_file_has_key(keyfileh, "default", "syslog", NULL) == TRUE)
1469 log_syslog = g_key_file_get_boolean(keyfileh, "default", "syslog", NULL);
1471 if (log_syslog == TRUE)
1472 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
1474 if (g_key_file_has_key(keyfileh, "default", "iterations", NULL) == TRUE)
1475 iter = g_key_file_get_integer(keyfileh, "default", "iterations", NULL);
1477 #ifdef HAVE_MLOCKALL
1478 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
1479 warn("mlockall()");
1480 goto do_exit;
1482 #endif
1484 setup_gcrypt();
1486 if (import) {
1487 opt = xml_import(import, iter);
1488 g_key_file_free(keyfileh);
1489 g_free(rcfile);
1490 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
1493 g_key_file_set_list_separator(keyfileh, ',');
1495 if ((p = g_key_file_get_string(keyfileh, "default", "socket_path", NULL)) == NULL)
1496 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
1498 if (*p == '~') {
1499 p++;
1500 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1501 g_free(p);
1502 socketarg = g_strdup(buf);
1504 else
1505 socketarg = p;
1507 if ((p = g_key_file_get_string(keyfileh, "default", "data_directory", NULL)) == NULL)
1508 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
1510 datadir = expand_homedir(p);
1511 g_free(p);
1513 if (secure == FALSE && g_key_file_has_key(keyfileh, "default", "disable_list_and_dump", NULL) == TRUE) {
1514 n = g_key_file_get_boolean(keyfileh, "default", "disable_list_and_dump", NULL);
1515 disable_list_and_dump = n;
1517 else
1518 disable_list_and_dump = secure;
1520 if (g_key_file_has_key(keyfileh, "default", "cache_timeout", NULL) == TRUE)
1521 default_timeout = g_key_file_get_integer(keyfileh, "default", "cache_timeout", NULL);
1522 else
1523 default_timeout = -1;
1525 if (g_key_file_has_key(keyfileh, "default", "cache_size", NULL) == TRUE) {
1526 cache_size = g_key_file_get_integer(keyfileh, "default", "cache_size", NULL);
1528 if (cache_size < page_size || cache_size % page_size)
1529 errx(EXIT_FAILURE, N_("cache size must be in multiples of %li"), page_size);
1532 if (g_key_file_has_key(keyfileh, "default", "log_path", NULL) == TRUE) {
1533 if (g_key_file_has_key(keyfileh, "default", "enable_logging", NULL) == TRUE) {
1534 n = g_key_file_get_boolean(keyfileh, "default", "enable_logging", NULL);
1536 if (n == TRUE) {
1537 p = g_key_file_get_string(keyfileh, "default", "log_path", NULL);
1539 if (*p == '~') {
1540 p++;
1541 snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
1542 g_free(p);
1543 logfile = g_strdup(buf);
1545 else
1546 logfile = p;
1551 if (g_key_file_has_key(keyfileh, "default", "cache_push", NULL) == TRUE)
1552 cache_push = g_key_file_get_string_list(keyfileh, "default", "cache_push", NULL, NULL);
1554 if (argc != optind) {
1555 if (cache_push)
1556 ptotal = g_strv_length(cache_push);
1558 for (; optind < argc; optind++) {
1559 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
1560 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
1564 if (strchr(socketarg, '/') == NULL) {
1565 socketdir = g_get_current_dir();
1566 socketname = g_strdup(socketarg);
1567 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1569 else {
1570 socketname = g_strdup(strrchr(socketarg, '/'));
1571 socketname++;
1572 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
1573 socketdir = g_strdup(socketarg);
1574 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
1577 if ((key_cache = mmap(NULL, cache_size, PROT_READ|PROT_WRITE,
1578 #ifdef MMAP_ANONYMOUS
1579 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
1580 #else
1581 MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED) {
1582 #endif
1583 err(EXIT_FAILURE, "mmap()");
1586 if (mlock(key_cache, cache_size) == -1)
1587 log_write("mlock(): %s", strerror(errno));
1589 memset(key_cache, 0, cache_size);
1591 if (chdir(datadir)) {
1592 warn("%s", datadir);
1593 unlink(socketpath);
1594 goto do_exit;
1597 if (parse_keyfile_key() == FALSE)
1598 goto do_exit;
1600 clear_rcfile_key();
1603 * Set the cache entry for a file. Prompts for the password.
1605 if (cache_push) {
1606 for (opt = 0; cache_push[opt]; opt++)
1607 do_cache_push(cache_push[opt], NULL);
1609 g_strfreev(cache_push);
1610 warnx(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
1614 * bind() doesn't like the full pathname of the socket or any non alphanum
1615 * characters so change to the directory where the socket is wanted then
1616 * create it then change to datadir.
1618 if (chdir(socketdir)) {
1619 warn("%s", socketdir);
1620 goto do_exit;
1623 g_free(socketdir);
1625 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
1626 warn("socket()");
1627 goto do_exit;
1630 addr.sun_family = AF_UNIX;
1631 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
1633 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
1634 warn("bind()");
1636 if (errno == EADDRINUSE)
1637 warnx(N_("Either there is another pwmd running or '%s' is a \n"
1638 "stale socket. Please remove it manually."), socketpath);
1640 do_unlink = 0;
1641 goto do_exit;
1644 if (g_key_file_has_key(keyfileh, "default", "socket_perms", NULL) == TRUE) {
1645 gchar *t = g_key_file_get_string(keyfileh, "default", "socket_perms", NULL);
1646 mode_t mode = strtol(t, NULL, 8);
1647 mode_t mask = umask(0);
1649 g_free(t);
1651 if (chmod(socketname, mode) == -1) {
1652 warn("%s", socketname);
1653 close(sockfd);
1654 unlink(socketpath);
1655 umask(mask);
1656 goto do_exit;
1659 umask(mask);
1662 g_free(--socketname);
1664 if (chdir(datadir)) {
1665 warn("%s", datadir);
1666 close(sockfd);
1667 unlink(socketpath);
1668 goto do_exit;
1671 g_free(datadir);
1672 pth_mutex_init(&cache_mutex);
1674 if (listen(sockfd, 0) == -1) {
1675 warn("listen()");
1676 goto do_exit;
1679 if (background) {
1680 switch (fork()) {
1681 case -1:
1682 warn("fork()");
1683 goto do_exit;
1684 case 0:
1685 close(0);
1686 close(1);
1687 close(2);
1688 setsid();
1689 break;
1690 default:
1691 exit(EXIT_SUCCESS);
1696 * These are the signals that we use in threads. libpth can catch signals
1697 * itself so ignore them everywhere else. Note that using
1698 * signal(N, SIG_IGN) doesn't work like you might think.
1700 sigemptyset(&set);
1702 /* Termination */
1703 sigaddset(&set, SIGTERM);
1704 sigaddset(&set, SIGINT);
1706 /* Configuration file reloading. */
1707 sigaddset(&set, SIGUSR1);
1709 /* Clears the file cache. */
1710 sigaddset(&set, SIGHUP);
1712 /* Caught in client_thread(). Sends a cache status message. */
1713 sigaddset(&set, SIGUSR2);
1715 /* Caught in client_thread(). When keepalive_thread() fails, this signal
1716 * is raised to terminate the client. More of a failsafe than anything. */
1717 sigaddset(&set, SIGQUIT);
1719 /* Ignored everywhere. When a client disconnects abnormally this signal
1720 * gets raised. It isn't needed though because client_thread() will check
1721 * for errors even after the client disconnects. */
1722 signal(SIGPIPE, SIG_IGN);
1723 pth_sigmask(SIG_BLOCK, &set, NULL);
1724 server_loop(sockfd);
1725 estatus = EXIT_SUCCESS;
1727 do_exit:
1728 if (socketpath && do_unlink) {
1729 unlink(socketpath);
1730 g_free(socketpath);
1733 g_key_file_free(keyfileh);
1734 g_free(rcfile);
1736 if (key_cache) {
1737 cache_clear(NULL, 2);
1738 memset(key_cache, 0, cache_size);
1741 if (key_cache && munmap(key_cache, cache_size) == -1)
1742 log_write("munmap(): %s", strerror(errno));
1744 if (estatus == EXIT_SUCCESS)
1745 log_write(N_("pwmd exiting normally"));
1747 pth_kill();
1748 #if defined(DEBUG) && !defined(MEM_DEBUG)
1749 xdump();
1750 #endif
1751 exit(estatus);