Ported to libassuan 2.0. This version supports building a DSO so no
[pwmd.git] / src / pwmd.c
blobb3e2300ecdad2bf396e5aa9f440ea2d1f4090764
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <sys/un.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <sys/wait.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <glib.h>
38 #include <glib/gprintf.h>
39 #include <sys/mman.h>
40 #include <termios.h>
41 #include <assert.h>
42 #include <syslog.h>
43 #include <zlib.h>
44 #include <gcrypt.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <sys/time.h>
49 #include <sys/resource.h>
51 #ifdef HAVE_GETOPT_LONG
52 #ifdef HAVE_GETOPT_H
53 #include <getopt.h>
54 #endif
55 #else
56 #include "getopt_long.h"
57 #endif
59 #ifdef TM_IN_SYS_TIME
60 #include <sys/time.h>
61 #else
62 #include <time.h>
63 #endif
65 #include "mem.h"
66 #include "xml.h"
67 #include "common.h"
69 #ifdef WITH_PINENTRY
70 #include "pinentry.h"
71 #endif
73 #include "commands.h"
74 #include "pwmd_error.h"
75 #include "cache.h"
76 #include "misc.h"
77 #include "pwmd.h"
78 #include "lock.h"
80 GCRY_THREAD_OPTION_PTH_IMPL;
81 ASSUAN_SYSTEM_PTH_IMPL;
83 static void clear_rcfile_keys()
85 gsize n;
86 gchar **groups;
87 gchar **p;
89 groups = g_key_file_get_groups(keyfileh, &n);
91 for (p = groups; *p; p++) {
92 GError *rc = NULL;
94 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
95 g_key_file_set_string(keyfileh, *p, "key", "");
98 g_strfreev(groups);
101 static void *reload_rcfile_thread(void *arg)
103 gboolean b = disable_list_and_dump;
104 GKeyFile *k;
105 pth_attr_t attr = pth_attr_of(pth_self());
107 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
108 pth_attr_destroy(attr);
109 MUTEX_LOCK(&rcfile_mutex);
110 log_write(N_("reloading configuration file '%s'"), rcfile);
111 k = parse_rcfile(FALSE);
113 if (!k)
114 goto done;
116 g_key_file_free(keyfileh);
117 keyfileh = k;
118 parse_rcfile_keys();
119 clear_rcfile_keys();
120 disable_list_and_dump = b;
121 startStopKeepAlive(FALSE);
122 send_status_all(STATUS_CONFIG);
123 done:
124 MUTEX_UNLOCK(&rcfile_mutex);
125 return NULL;
128 static void reload_rcfile()
130 pth_t tid;
131 pth_attr_t attr = pth_attr_new();
132 gint n;
134 pth_attr_init(attr);
135 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
136 tid = pth_spawn(attr, reload_rcfile_thread, NULL);
137 n = errno;
138 pth_attr_destroy(attr);
140 if (!tid)
141 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
142 _gpg_strerror(gpg_error_from_errno(n)));
145 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
147 gpg_error_t n = gpg_error_from_errno(e);
148 struct client_s *client = assuan_get_pointer(ctx);
150 client->last_rc = e;
151 return assuan_process_done(ctx, assuan_set_error(ctx, n, _gpg_strerror(n)));
154 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
156 gpg_err_code_t n = gpg_err_code(e);
157 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
158 struct client_s *client = assuan_get_pointer(ctx);
160 if (client)
161 client->last_rc = e;
163 if (!e)
164 return assuan_process_done(ctx, 0);
166 if (!ctx) {
167 log_write("%s", pwmd_strerror(e));
168 return e;
171 if (n == EPWMD_LIBXML_ERROR) {
172 xmlErrorPtr xe = client->xml_error;
174 if (!xe)
175 xe = xmlGetLastError();
177 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
178 log_write("%s", xe->message);
180 if (xe == client->xml_error)
181 xmlResetError(xe);
182 else
183 xmlResetLastError();
185 client->xml_error = NULL;
186 return e;
189 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
192 void log_write(const gchar *fmt, ...)
194 gchar *args, *line;
195 va_list ap;
196 struct tm *tm;
197 time_t now;
198 gchar tbuf[21];
199 gint fd = -1;
200 gchar *name;
201 gchar buf[255];
202 pth_t tid = pth_self();
203 pth_attr_t attr;
205 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
206 return;
208 if (!cmdline && logfile) {
209 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
210 warn("%s", logfile);
211 return;
215 va_start(ap, fmt);
217 if (g_vasprintf(&args, fmt, ap) == -1) {
218 if (logfile)
219 close(fd);
221 va_end(ap);
222 return;
225 va_end(ap);
227 if (cmdline) {
228 fprintf(stderr, "%s\n", args);
229 fflush(stderr);
230 g_free(args);
231 return;
234 attr = pth_attr_of(tid);
236 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
237 name = "unknown";
239 pth_attr_destroy(attr);
240 name = print_fmt(buf, sizeof(buf), "%s(%p): ", name, tid);
242 if (!cmdline && log_syslog == TRUE)
243 syslog(LOG_INFO, "%s%s", name, args);
245 time(&now);
246 tm = localtime(&now);
247 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
248 tbuf[sizeof(tbuf) - 1] = 0;
250 if (args[strlen(args)-1] == '\n')
251 args[strlen(args)-1] = 0;
253 line = g_strdup_printf("%s %i %s%s\n", tbuf, getpid(), name, args);
254 g_free(args);
256 if (!line) {
257 if (logfile)
258 close(fd);
260 return;
263 if (logfile) {
264 pth_write(fd, line, strlen(line));
265 fsync(fd);
266 close(fd);
269 if (isatty(STDERR_FILENO)) {
270 fprintf(stderr, "%s", line);
271 fflush(stderr);
274 g_free(line);
277 static void usage(gchar *pn, gint rc)
279 g_fprintf(rc == EXIT_FAILURE ? stderr : stdout, N_(
280 "Usage: %s [options] [file1] [...]\n"
281 " --no-fork/-n\n"
282 " run as a foreground process\n"
283 " --rcfile/-f <filename>\n"
284 " load the specified rcfile (~/.pwmd/config)\n"
285 " --convert/-C <filename>\n"
286 " convert a version 1 data file to version 2\n"
287 " --import/-I <filename>\n"
288 " import an XML file\n"
289 " --iterations/-i\n"
290 " encrypt with the specified number of iterations when importing\n"
291 " (default is in the rcfile \"global\" section)\n"
292 " --key-file/-k <filename>\n"
293 " obtain the key from the specified file when importing or converting\n"
294 " --outfile/-o <filename>\n"
295 " output file to use when importing or converting (- for stdout)\n"
296 " --disable-dump/-D\n"
297 " disable use of the LIST, XPATH and DUMP commands\n"
298 " --no-pinentry/-P\n"
299 " disable use of pinentry\n"
300 " --version\n"
301 " --help\n"
302 ), pn);
303 exit(rc);
306 static void setup_gcrypt()
308 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
310 if (!gcry_check_version(GCRYPT_VERSION))
311 errx(EXIT_FAILURE, N_("gcry_check_version(): Incompatible libgcrypt. Wanted %s, got %s."), GCRYPT_VERSION, gcry_check_version(NULL));
313 gcry_set_allocation_handler(xmalloc, xmalloc, NULL, xrealloc, xfree);
316 static gint new_connection(struct client_s *cl)
318 gpg_error_t rc;
319 gchar *ver;
321 rc = assuan_new(&cl->ctx);
323 if (rc)
324 goto fail;
326 rc = assuan_init_socket_server(cl->ctx, cl->thd->fd,
327 ASSUAN_SOCKET_SERVER_ACCEPTED);
329 if (rc)
330 goto fail;
332 assuan_set_pointer(cl->ctx, cl);
333 ver = g_strdup_printf("%s", PACKAGE_STRING);
334 assuan_set_hello_line(cl->ctx, ver);
335 g_free(ver);
336 rc = register_commands(cl->ctx);
338 if (rc)
339 goto fail;
341 rc = assuan_accept(cl->ctx);
343 if (rc)
344 goto fail;
347 gchar *str = get_key_file_string("global", "debug_file");
349 if (debugfp && str)
350 assuan_set_log_stream(cl->ctx, debugfp);
352 if (str)
353 g_free(str);
356 return 0;
358 fail:
359 log_write("%s", _gpg_strerror(rc));
360 close(cl->thd->fd);
361 cl->thd->fd = -1;
362 return 1;
365 static void xml_error_cb(void *data, xmlErrorPtr e)
367 struct client_s *client = data;
370 * Keep the first reported error as the one to show in the error
371 * description. Reset in send_error().
373 if (client->xml_error)
374 return;
376 xmlCopyError(e, client->xml_error);
379 void close_file_header(file_header_internal_t *fh)
381 if (!fh)
382 return;
384 if (fh->fd != -1 || (cmdline == TRUE && fh->fd != STDOUT_FILENO))
385 close(fh->fd);
387 if (fh->doc)
388 gcry_free(fh->doc);
390 g_free(fh);
393 void cleanup_crypto(struct client_crypto_s **c)
395 struct client_crypto_s *cr = *c;
397 if (!cr)
398 return;
400 if (cr->iv) {
401 gcry_free(cr->iv);
402 cr->iv = NULL;
405 if (cr->key) {
406 gcry_free(cr->key);
407 cr->key = NULL;
410 if (cr->tkey) {
411 gcry_free(cr->tkey);
412 cr->tkey = NULL;
415 if (cr->tkey2) {
416 gcry_free(cr->tkey2);
417 cr->tkey2 = NULL;
420 if (cr->inbuf) {
421 gcry_free(cr->inbuf);
422 cr->inbuf = NULL;
425 if (cr->outbuf) {
426 gcry_free(cr->outbuf);
427 cr->outbuf = NULL;
430 close_file_header(cr->fh);
431 cr->fh = NULL;
433 if (cr->gh)
434 gcry_cipher_close(cr->gh);
436 cr->gh = NULL;
437 g_free(cr);
438 *c = NULL;
442 * This is called after a child_thread terminates. Set with
443 * pth_cleanup_push().
445 static void cleanup_cb(void *arg)
447 struct client_thread_s *cn = arg;
448 struct client_s *cl = cn->cl;
450 MUTEX_LOCK(&cn_mutex);
451 cn_thread_list = g_slist_remove(cn_thread_list, cn);
452 MUTEX_UNLOCK(&cn_mutex);
454 if (cn->msg_tid) {
455 MUTEX_LOCK(&cn->mp_mutex);
456 pth_cancel(cn->msg_tid);
457 MUTEX_UNLOCK(&cn->mp_mutex);
460 if (cn->mp) {
461 while (pth_msgport_pending(cn->mp)) {
462 pth_message_t *msg = pth_msgport_get(cn->mp);
464 g_free(msg->m_data);
465 g_free(msg);
468 pth_msgport_destroy(cn->mp);
471 if (!cl) {
472 if (cn->fd != -1)
473 close(cn->fd);
475 goto done;
478 if (!cl->freed)
479 cleanup_client(cl);
481 if (cl->ctx)
482 assuan_release(cl->ctx);
483 else if (cl->thd && cl->thd->fd != -1)
484 close(cl->thd->fd);
486 #ifdef WITH_PINENTRY
487 if (cl->pinentry)
488 cleanup_pinentry(cl->pinentry);
489 #endif
491 if (cl->crypto)
492 cleanup_crypto(&cl->crypto);
494 g_free(cl);
495 done:
496 log_write(N_("exiting, fd=%i"), cn->fd);
497 g_free(cn);
498 send_status_all(STATUS_CLIENTS);
502 * Called every time a connection is made from init_new_connection(). This is
503 * the thread entry point.
505 static void *client_thread(void *data)
507 struct client_thread_s *thd = data;
508 struct client_s *cl = g_malloc0(sizeof(struct client_s));
509 gpg_error_t rc;
510 pth_attr_t attr;
511 gint n;
514 * Prevent a race condition with init_new_connection() if this thread
515 * fails (returns) for some reason before init_new_connection() releases
516 * the cn_mutex.
518 MUTEX_LOCK(&cn_mutex);
519 MUTEX_UNLOCK(&cn_mutex);
520 pth_cleanup_push(cleanup_cb, thd);
522 if (!cl) {
523 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
524 goto fail;
527 attr = pth_attr_of(pth_self());
528 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
529 pth_attr_destroy(attr);
530 thd->cl = cl;
531 cl->thd = thd;
533 if (new_connection(cl))
534 goto fail;
536 #ifdef WITH_PINENTRY
537 cl->pinentry = pinentry_init();
539 if (!cl->pinentry) {
540 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
541 goto fail;
543 #endif
545 #ifdef HAVE_MLOCKALL
546 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
547 log_write("mlockall(): %s", strerror(errno));
548 goto fail;
550 #endif
552 thd->mp = pth_msgport_create(NULL);
553 pth_mutex_init(&thd->mp_mutex);
554 thd->msg_tid = pth_spawn(NULL, client_msg_thread, thd);
555 n = errno;
557 if (!thd->msg_tid) {
558 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
559 _gpg_strerror(gpg_error_from_errno(n)));
560 goto fail;
563 pth_yield(thd->msg_tid);
564 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
566 if (rc) {
567 log_write("%s", _gpg_strerror(rc));
568 goto fail;
571 send_status_all(STATUS_CLIENTS);
572 xmlSetStructuredErrorFunc(cl, xml_error_cb);
574 for (;;) {
575 #ifdef WITH_PINENTRY
576 pth_event_t pev = NULL;
577 #endif
578 pth_status_t st, wst;
579 pth_event_t wev = NULL;
580 pth_event_t rev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE,
581 cl->thd->fd);
582 pth_event_t ev = rev;
584 #ifdef WITH_PINENTRY
585 if (cl->pinentry->status == PINENTRY_RUNNING) {
586 pev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
587 ev = pth_event_concat(ev, pev, NULL);
589 #endif
591 if (cl->inquire_status == INQUIRE_BUSY) {
592 wev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_WRITEABLE, cl->thd->fd);
593 ev = pth_event_concat(ev, wev, NULL);
596 pth_cleanup_push(cleanup_ev_cb, ev);
597 pth_wait(ev);
598 st = pth_event_status(rev);
599 wst = pth_event_status(wev);
601 if (st == PTH_STATUS_OCCURRED || wst == PTH_STATUS_OCCURRED) {
602 int ended;
604 rc = assuan_process_next(cl->ctx, &ended);
606 if (ended)
607 goto done;
609 if (rc) {
610 cl->inquire_status = INQUIRE_INIT;
611 pth_cleanup_pop(1);
613 if (gpg_err_code(rc) == GPG_ERR_EOF)
614 goto done;
616 log_write("assuan_process_next(): %s", _gpg_strerror(rc));
617 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
619 if (rc) {
620 log_write("assuan_process_done(): %s", _gpg_strerror(rc));
621 goto done;
624 else {
625 #ifdef WITH_PINENTRY
626 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT)
627 cl->pinentry->status = PINENTRY_RUNNING;
628 #endif
630 switch (cl->inquire_status) {
631 case INQUIRE_BUSY:
632 case INQUIRE_INIT:
633 break;
634 case INQUIRE_DONE:
635 cl->inquire_status = INQUIRE_INIT;
636 rc = assuan_process_done(cl->ctx, 0);
637 break;
642 #ifdef WITH_PINENTRY
643 if (pev)
644 st = pth_event_status(pev);
646 rc = pinentry_iterate(cl,
647 pev && cl->pinentry->fd != -1 && st == PTH_STATUS_OCCURRED);
648 #endif
649 pth_cleanup_pop(1);
653 * Client cleanup (including XML data) is done in cleanup_cb().
655 done:
656 fail:
657 pth_exit(PTH_CANCELED);
658 return NULL;
661 static void setup_logging(GKeyFile *kf)
663 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
665 if (n == TRUE) {
666 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
668 if (*p == '~') {
669 gchar buf[PATH_MAX];
671 p++;
672 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
673 g_free(p);
675 if (logfile)
676 g_free(logfile);
678 logfile = g_strdup(buf);
680 else {
681 if (logfile)
682 g_free(logfile);
684 logfile = p;
688 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
692 * Make sure all settings are set to either the specified setting or a
693 * default.
695 static void set_rcfile_defaults(GKeyFile *kf)
697 gchar buf[PATH_MAX];
699 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
700 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
701 g_key_file_set_string(kf, "global", "socket_path", buf);
704 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
705 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
706 g_key_file_set_string(kf, "global", "data_directory", buf);
709 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
710 g_key_file_set_boolean(kf, "global", "backup", TRUE);
712 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
713 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
714 g_key_file_set_string(kf, "global", "log_path", buf);
717 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
718 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
720 #ifdef HAVE_MLOCKALL
721 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
722 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
723 #endif
725 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
726 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
728 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
729 g_key_file_get_double(kf, "global", "iterations", 0) < 0ULL)
730 g_key_file_set_double(kf, "global", "iterations", 1ULL);
732 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
733 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
735 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
736 g_key_file_set_double(kf, "global", "iteration_progress", 0ULL);
738 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
739 g_key_file_set_integer(kf, "global", "compression_level", 6);
741 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
742 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
744 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
745 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
747 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
749 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
750 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
752 #ifdef HAVE_MLOCKALL
753 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
754 #endif
756 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
757 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
759 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
760 g_key_file_set_integer(kf, "global", "keepalive", DEFAULT_KEEPALIVE_TO);
762 #ifdef WITH_PINENTRY
763 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
764 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
766 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
767 g_key_file_set_integer(kf, "global", "pinentry_timeout",
768 DEFAULT_PIN_TIMEOUT);
770 if (g_key_file_has_key(kf, "global", "pinentry_path", NULL) == FALSE)
771 g_key_file_set_string(kf, "global", "pinentry_path", PINENTRY_PATH);
772 #endif
774 if (g_key_file_has_key(kf, "global", "xfer_progress", NULL) == FALSE)
775 g_key_file_set_integer(kf, "global", "xfer_progress", 8196);
777 if (g_key_file_has_key(kf, "global", "cipher", NULL) == FALSE)
778 g_key_file_set_string(kf, "global", "cipher", "AES256");
780 if (g_key_file_has_key(kf, "global", "log_level", NULL) == FALSE)
781 g_key_file_set_integer(kf, "global", "log_level", 0);
783 setup_logging(kf);
786 static GKeyFile *parse_rcfile(gboolean specified)
788 GKeyFile *kf = g_key_file_new();
789 GError *rc = NULL;
791 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
792 log_write("%s: %s", rcfile, rc->message);
794 if (cmdline && specified) {
795 g_clear_error(&rc);
796 return NULL;
799 if (rc->code == G_FILE_ERROR_NOENT) {
800 g_clear_error(&rc);
801 set_rcfile_defaults(kf);
802 return kf;
805 g_clear_error(&rc);
806 return NULL;
809 set_rcfile_defaults(kf);
810 return kf;
813 static gchar *do_get_password(const gchar *prompt)
815 gchar buf[LINE_MAX] = {0}, *p;
816 struct termios told, tnew;
817 gchar *key;
819 if (tcgetattr(STDIN_FILENO, &told) == -1) {
820 log_write("tcgetattr(): %s", strerror(errno));
821 return NULL;
824 memcpy(&tnew, &told, sizeof(struct termios));
825 tnew.c_lflag &= ~(ECHO);
826 tnew.c_lflag |= ICANON|ECHONL;
828 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
829 log_write("tcsetattr(): %s", strerror(errno));
830 tcsetattr(STDIN_FILENO, TCSANOW, &told);
831 return NULL;
834 fprintf(stderr, "%s", prompt);
836 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
837 tcsetattr(STDIN_FILENO, TCSANOW, &told);
838 return NULL;
841 tcsetattr(STDIN_FILENO, TCSANOW, &told);
842 p[strlen(p) - 1] = 0;
844 if (!buf[0]) {
845 key = gcry_malloc(1);
846 key[0] = 0;
848 else {
849 key = gcry_malloc(strlen(p) + 1);
850 sprintf(key, "%s", p);
853 memset(&buf, 0, sizeof(buf));
854 return key;
857 /* Only used when "enable_pinentry" is "false" or -P. */
858 static gpg_error_t get_input(const gchar *filename,
859 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
861 gchar *prompt;
863 if (which == PINENTRY_SAVE) {
864 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
865 crypto->tkey = do_get_password(prompt);
866 g_free(prompt);
868 if (!crypto->tkey) {
869 log_write(N_("%s: Skipping file"), filename);
870 return GPG_ERR_BAD_PASSPHRASE;
873 prompt = g_strdup_printf(N_("Repeat passphrase: "));
874 crypto->tkey2 = do_get_password(prompt);
875 g_free(prompt);
877 if (!crypto->tkey2) {
878 log_write(N_("%s: Skipping file"), filename);
879 return GPG_ERR_BAD_PASSPHRASE;
882 if (strcmp(crypto->tkey, crypto->tkey2)) {
883 log_write(N_("%s: Passphrase mismatch"), filename);
884 return EPWMD_BADKEY;
887 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
888 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
889 return 0;
892 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
894 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
895 log_write(N_("%s: Skipping file"), filename);
896 g_free(prompt);
897 return GPG_ERR_BAD_PASSPHRASE;
900 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
901 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
902 g_free(prompt);
903 return 0;
907 * inbuf must have been allocated with gcry_malloc().
909 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
910 gpointer inbuf, gulong insize)
912 gpg_error_t rc;
913 gint level, zrc;
914 gulong outsize;
915 gpointer outbuf;
917 rc = update_save_flags(NULL, crypto);
919 if (rc)
920 return rc;
922 level = get_key_file_integer(filename, "compression_level");
924 if (level < 0)
925 level = 0;
927 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
928 == FALSE) {
929 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
932 crypto->inbuf = outbuf;
933 crypto->insize = outsize;
934 rc = do_xml_encrypt(NULL, crypto, filename);
935 return rc;
938 static gpg_error_t get_password(const gchar *filename,
939 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
940 pinentry_cmd_t which)
942 #ifdef WITH_PINENTRY
943 gpg_error_t rc = 0;
945 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
946 == FALSE) {
947 #endif
948 return get_input(filename, crypto, key, which);
949 #ifdef WITH_PINENTRY
951 else {
952 gchar *result = NULL;
953 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
955 pth_mutex_init(&pin->status_mutex);
956 set_pinentry_defaults(pin);
957 pin->which = which;
958 pin->filename = g_strdup(filename);
959 rc = pinentry_getpin(pin, &result);
961 if (rc) {
962 xfree(result);
963 goto done;
966 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, result ? strlen(result) : 1);
967 xfree(result);
968 cleanup_pinentry(pin);
971 done:
972 return rc;
973 #endif
976 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
978 FILE *fp;
979 gchar buf[LINE_MAX] = {0}, *p;
980 gchar *str = NULL;
981 gint len;
983 *rc = 0;
985 if ((fp = fopen(file, "r")) == NULL) {
986 *rc = gpg_error_from_syserror();
987 return FALSE;
990 p = fgets(buf, sizeof(buf), fp);
991 fclose(fp);
992 len = strlen(buf);
994 if (len && buf[len - 1] == '\n')
995 buf[--len] = 0;
997 str = gcry_malloc(len + 1);
999 if (!str) {
1000 *rc = gpg_error_from_errno(ENOMEM);
1001 return FALSE;
1004 memcpy(str, buf, len ? len : 1);
1005 str[len] = 0;
1006 memset(&buf, 0, sizeof(buf));
1007 *result = str;
1008 return TRUE;
1011 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
1012 gpg_error_t *rc)
1014 GError *rv = NULL;
1015 gchar *t, *file = NULL, *str;
1017 *rc = GPG_ERR_UNKNOWN_ERRNO;
1019 if (import == FALSE) {
1020 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1021 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1023 if (!file) {
1024 if (rv) {
1025 log_write("%s: key_file: %s", rcfile, rv->message);
1026 g_clear_error(&rv);
1029 return NULL;
1032 t = expand_homedir(file);
1034 if (!t) {
1035 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1036 *rc = gpg_error_from_errno(ENOMEM);
1037 return NULL;
1040 g_free(file);
1041 file = t;
1044 else {
1045 /* -I or -C. The filename is a key file. */
1046 file = g_strdup(filename);
1048 if (!file) {
1049 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1050 *rc = gpg_error_from_errno(ENOMEM);
1051 return NULL;
1055 if (rv) {
1056 log_write("%s: key_file: %s", rcfile, rv->message);
1057 g_clear_error(&rv);
1058 return NULL;
1061 if (!file)
1062 return NULL;
1064 if (_getline(file, &str, rc) == FALSE) {
1065 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1066 g_free(file);
1067 return NULL;
1070 g_free(file);
1071 *rc = 0;
1072 return str;
1075 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1076 const gchar *keyfile, guint64 iter)
1078 xmlDocPtr doc;
1079 gint fd;
1080 struct stat st;
1081 gint len;
1082 xmlChar *xmlbuf;
1083 xmlChar *xml;
1084 gpg_error_t rc;
1085 struct client_crypto_s *crypto;
1086 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1088 if (stat(filename, &st) == -1) {
1089 log_write("%s: %s", filename, strerror(errno));
1090 return FALSE;
1093 crypto = init_client_crypto();
1095 if (!crypto)
1096 return FALSE;
1098 crypto->key = gcry_malloc(hashlen);
1099 memset(crypto->key, 0, hashlen);
1101 if (!crypto->key) {
1102 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1103 goto fail;
1106 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1107 filename, outfile);
1109 if (iter && keyfile) {
1110 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1112 if (!crypto->tkey)
1113 goto fail;
1115 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1116 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1118 else if (iter) {
1119 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1121 if (rc)
1122 goto fail;
1125 if ((fd = open(filename, O_RDONLY)) == -1) {
1126 log_write("%s: %s", filename, strerror(errno));
1127 goto fail;
1130 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1131 close(fd);
1132 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1133 goto fail;
1136 if (pth_read(fd, xmlbuf, st.st_size) == -1) {
1137 rc = errno;
1138 close(fd);
1139 errno = rc;
1140 log_write("%s: %s", filename, strerror(errno));
1141 goto fail;
1144 close(fd);
1145 xmlbuf[st.st_size] = 0;
1148 * Make sure the document validates.
1150 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1151 log_write("xmlReadDoc() failed");
1152 gcry_free(xmlbuf);
1153 goto fail;
1156 gcry_free(xmlbuf);
1157 xmlDocDumpMemory(doc, &xml, &len);
1158 xmlFreeDoc(doc);
1160 if (!iter)
1161 memset(crypto->key, '!', hashlen);
1163 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1165 if (!crypto->fh) {
1166 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1167 goto fail;
1170 crypto->fh->ver.fh2.iter = iter;
1171 rc = export_common(outfile, crypto, xml, len);
1172 xmlFree(xml);
1174 if (rc) {
1175 send_error(NULL, rc);
1176 goto fail;
1179 cleanup_crypto(&crypto);
1180 return TRUE;
1182 fail:
1183 cleanup_crypto(&crypto);
1184 return FALSE;
1187 gchar *get_key_file_string(const gchar *section, const gchar *what)
1189 gchar *val = NULL;
1190 GError *grc = NULL;
1192 MUTEX_LOCK(&rcfile_mutex);
1194 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1195 val = g_key_file_get_string(keyfileh, section, what, &grc);
1197 if (grc) {
1198 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1199 g_clear_error(&grc);
1202 else {
1203 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1204 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1206 if (grc) {
1207 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1208 g_clear_error(&grc);
1213 MUTEX_UNLOCK(&rcfile_mutex);
1214 return val;
1217 gint get_key_file_integer(const gchar *section, const gchar *what)
1219 gint val = -1;
1220 GError *grc = NULL;
1222 MUTEX_LOCK(&rcfile_mutex);
1224 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1225 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1227 if (grc) {
1228 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1229 g_clear_error(&grc);
1232 else {
1233 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1234 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1236 if (grc) {
1237 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1238 g_clear_error(&grc);
1243 MUTEX_UNLOCK(&rcfile_mutex);
1244 return val;
1247 gdouble get_key_file_double(const gchar *section, const gchar *what)
1249 gdouble val = -1;
1250 GError *grc = NULL;
1252 MUTEX_LOCK(&rcfile_mutex);
1254 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1255 val = g_key_file_get_double(keyfileh, section ? section : "global", what, &grc);
1257 if (grc) {
1258 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1259 g_clear_error(&grc);
1262 else {
1263 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1264 val = g_key_file_get_double(keyfileh, "global", what, &grc);
1266 if (grc) {
1267 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1268 g_clear_error(&grc);
1273 MUTEX_UNLOCK(&rcfile_mutex);
1274 return val;
1277 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1279 gboolean val = FALSE;
1280 GError *grc = NULL;
1282 MUTEX_LOCK(&rcfile_mutex);
1284 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL)
1285 == TRUE) {
1286 val = g_key_file_get_boolean(keyfileh, section ? section : "global",
1287 what, &grc);
1289 if (grc) {
1290 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1291 g_clear_error(&grc);
1294 else {
1295 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1296 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1298 if (grc) {
1299 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1300 g_clear_error(&grc);
1305 MUTEX_UNLOCK(&rcfile_mutex);
1306 return val;
1309 static gboolean parse_rcfile_keys()
1311 gsize n;
1312 gchar **groups;
1313 gchar **p;
1314 gchar *str;
1316 groups = g_key_file_get_groups(keyfileh, &n);
1318 for (p = groups; *p; p++) {
1319 GError *rc = NULL;
1321 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1322 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1324 if (!str) {
1325 if (rc) {
1326 log_write("%s: key: %s", rcfile, rc->message);
1327 g_clear_error(&rc);
1329 continue;
1332 do_cache_push(*p, str);
1333 g_free(str);
1334 continue;
1337 if (rc) {
1338 log_write("%s: key: %s", rcfile, rc->message);
1339 g_clear_error(&rc);
1340 continue;
1343 gpg_error_t ret;
1344 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1346 if (!str)
1347 continue;
1349 do_cache_push(*p, str);
1350 gcry_free(str);
1353 g_strfreev(groups);
1354 return TRUE;
1357 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1359 guchar md5file[16];
1360 gint timeout;
1361 const gchar *p = filename;
1362 struct client_crypto_s *crypto;
1363 gpg_error_t rc;
1364 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1366 while (isspace(*p))
1367 p++;
1369 if (!*p)
1370 return FALSE;
1372 if (valid_filename(p) == FALSE) {
1373 log_write(N_("%s: Invalid characters in filename"), p);
1374 return FALSE;
1377 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1379 if (access(p, R_OK|W_OK) != 0) {
1380 log_write("%s: %s", p, strerror(errno));
1381 return FALSE;
1384 crypto = init_client_crypto();
1386 if (!crypto)
1387 return FALSE;
1389 crypto->fh = read_file_header(filename, FALSE, &rc);
1391 if (!crypto->fh) {
1392 log_write("%s: %s", p, pwmd_strerror(rc));
1393 cleanup_crypto(&crypto);
1394 return FALSE;
1397 crypto->key = gcry_malloc(hashlen);
1399 if (!crypto->key) {
1400 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1401 cleanup_crypto(&crypto);
1402 return FALSE;
1405 log_write(N_("Adding '%s' to the file cache ..."), filename);
1407 if (crypto->fh->ver.fh2.iter <= 0ULL) {
1408 memset(crypto->key, '!', hashlen);
1409 goto try_decrypt;
1412 if (!password) {
1413 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1415 if (rc) {
1416 send_error(NULL, rc);
1417 cleanup_crypto(&crypto);
1418 return FALSE;
1421 gcry_free(crypto->fh->doc);
1422 crypto->fh->doc = NULL;
1424 else
1425 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1426 strlen(password) ? strlen(password) : 1);
1428 try_decrypt:
1429 rc = init_client_crypto2(filename, crypto);
1431 if (rc) {
1432 send_error(NULL, rc);
1433 cleanup_crypto(&crypto);
1434 return FALSE;
1437 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1439 if (rc) {
1440 log_write("%s: %s", filename, pwmd_strerror(rc));
1441 cleanup_crypto(&crypto);
1442 return FALSE;
1445 if (cache_update_key(md5file, crypto->key) == FALSE) {
1446 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1447 cleanup_crypto(&crypto);
1448 return FALSE;
1451 timeout = get_key_file_integer(p, "cache_timeout");
1452 cache_set_timeout(md5file, timeout);
1453 log_write(N_("File '%s' now cached"), filename);
1454 cleanup_crypto(&crypto);
1455 return TRUE;
1458 static void init_new_connection(gint fd)
1460 pth_attr_t attr;
1461 struct client_thread_s *new;
1462 gint n;
1464 new = g_malloc0(sizeof(struct client_thread_s));
1466 if (!new) {
1467 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1468 close(fd);
1469 return;
1472 MUTEX_LOCK(&cn_mutex);
1473 new->fd = fd;
1474 attr = pth_attr_new();
1475 pth_attr_init(attr);
1476 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1477 new->tid = pth_spawn(attr, client_thread, new);
1478 n = errno;
1479 pth_attr_destroy(attr);
1481 if (!new->tid) {
1482 g_free(new);
1483 close(fd);
1484 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1485 _gpg_strerror(gpg_error_from_errno(n)));
1486 MUTEX_UNLOCK(&cn_mutex);
1487 return;
1490 cn_thread_list = g_slist_append(cn_thread_list, new);
1491 MUTEX_UNLOCK(&cn_mutex);
1492 log_write(N_("new connection: tid=%p, fd=%i"), new->tid, fd);
1495 static void *accept_thread(void *arg)
1497 gint sockfd = (gint)arg;
1498 pth_attr_t attr = pth_attr_of(pth_self());
1500 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1501 pth_attr_destroy(attr);
1503 for (;;) {
1504 socklen_t slen = sizeof(struct sockaddr_un);
1505 struct sockaddr_un raddr;
1506 gint fd = -1;
1508 fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen);
1510 if (fd == -1) {
1511 if (errno != EAGAIN) {
1512 if (!quit) // probably EBADF
1513 log_write("accept(): %s", strerror(errno));
1515 break;
1518 continue;
1521 init_new_connection(fd);
1524 /* Just in case accept() failed for some reason other than EBADF */
1525 quit = 1;
1526 pth_exit(PTH_CANCELED);
1527 return NULL;
1530 static void *adjust_cache_timer_thread(void *arg)
1532 pth_attr_t attr = pth_attr_of(pth_self());
1534 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1535 pth_attr_destroy(attr);
1537 for (;;) {
1538 pth_sleep(1);
1539 CACHE_LOCK(NULL);
1540 cache_adjust_timer();
1541 CACHE_UNLOCK;
1544 return NULL;
1547 void cleanup_mutex_cb(void *arg)
1549 pth_mutex_t *m = arg;
1551 MUTEX_UNLOCK(m);
1554 void cleanup_ev_cb(void *arg)
1556 pth_event_t ev = arg;
1558 pth_event_free(ev, PTH_FREE_ALL);
1561 void cleanup_fd_cb(void *arg)
1563 gint fd = (gint)arg;
1565 close(fd);
1568 void cleanup_unlink_cb(void *arg)
1570 gchar *file = arg;
1572 unlink(file);
1575 void cleanup_cancel_cb(void *arg)
1577 pth_t tid = arg;
1578 pth_attr_t attr;
1579 gint join;
1581 attr = pth_attr_of(tid);
1582 pth_attr_get(attr, PTH_ATTR_JOINABLE, &join);
1583 pth_cancel(tid);
1585 if (join) {
1586 gpg_error_t rc;
1587 pth_join(tid, (void **)&rc);
1591 static void *keepalive_thread(void *arg)
1593 gint to = (gint)arg;
1594 pth_attr_t attr = pth_attr_of(pth_self());
1596 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1597 pth_attr_destroy(attr);
1599 for (;;) {
1600 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1602 pth_cleanup_push(cleanup_ev_cb, ev);
1603 pth_wait(ev);
1604 send_status_all(STATUS_KEEPALIVE);
1605 pth_cleanup_pop(1);
1608 return NULL;
1611 static void startStopKeepAlive(gboolean term)
1613 gint n = get_key_file_integer("global", "keepalive");
1615 if (keepalive_tid)
1616 pth_cancel(keepalive_tid);
1618 keepalive_tid = NULL;
1620 if (term)
1621 return;
1623 if (n > 0) {
1624 gint e;
1625 pth_attr_t attr = pth_attr_new();
1627 pth_attr_init(attr);
1628 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1629 keepalive_tid = pth_spawn(attr, keepalive_thread, (void *)n);
1630 e = errno;
1631 pth_attr_destroy(attr);
1633 if (!keepalive_tid) {
1634 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1635 _gpg_strerror(gpg_error_from_errno(e)));
1636 return;
1639 pth_yield(keepalive_tid);
1643 static gboolean waiting_for_exit()
1645 guint i, t;
1646 pth_event_t evs = NULL;
1648 MUTEX_LOCK(&cn_mutex);
1650 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1651 struct client_thread_s *thd = g_slist_nth_data(cn_thread_list, i);
1652 pth_event_t ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, thd->tid);
1654 if (evs)
1655 evs = pth_event_concat(evs, ev, NULL);
1656 else
1657 evs = ev;
1660 MUTEX_UNLOCK(&cn_mutex);
1662 if (!evs)
1663 return FALSE;
1665 pth_wait(evs);
1666 MUTEX_LOCK(&cn_mutex);
1667 i = g_slist_length(cn_thread_list);
1668 MUTEX_UNLOCK(&cn_mutex);
1669 pth_event_free(evs, PTH_FREE_ALL);
1670 return i ? TRUE : FALSE;
1673 static void server_loop(gint sockfd, gchar **socketpath)
1675 pth_t accept_tid;
1676 guint n;
1677 sigset_t sigset;
1678 pth_attr_t attr;
1679 pth_t cache_timeout_tid;
1681 sigemptyset(&sigset);
1683 /* Termination */
1684 sigaddset(&sigset, SIGTERM);
1685 sigaddset(&sigset, SIGINT);
1687 /* Clears the file cache. */
1688 sigaddset(&sigset, SIGUSR1);
1690 /* Configuration file reloading. */
1691 sigaddset(&sigset, SIGHUP);
1693 /* Clears the cache and exits when something bad happens. */
1694 sigaddset(&sigset, SIGABRT);
1696 /* Ignored everywhere. When a client disconnects abnormally this signal
1697 * gets raised. It isn't needed though because client_thread() will check
1698 * for rcs even after the client disconnects. */
1699 signal(SIGPIPE, SIG_IGN);
1700 sigprocmask(SIG_BLOCK, &sigset, NULL);
1702 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1703 log_write(N_("Listening on %s"), *socketpath);
1704 attr = pth_attr_new();
1705 pth_attr_init(attr);
1706 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1708 if (!accept_tid) {
1709 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1710 _gpg_strerror(gpg_error_from_errno(errno)));
1711 pth_attr_destroy(attr);
1712 goto done;
1715 pth_yield(accept_tid);
1716 startStopKeepAlive(FALSE);
1717 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1718 cache_timeout_tid = pth_spawn(attr, adjust_cache_timer_thread, NULL);
1720 if (!cache_timeout_tid) {
1721 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1722 _gpg_strerror(gpg_error_from_errno(errno)));
1723 pth_attr_destroy(attr);
1724 goto done;
1727 pth_yield(cache_timeout_tid);
1728 pth_attr_destroy(attr);
1731 gchar *str = get_key_file_string("global", "debug_file");
1733 if (str) {
1734 gchar *f = expand_homedir(str);
1736 g_free(str);
1737 debugfp = fopen(f, "w");
1739 if (!debugfp)
1740 log_write("%s: %s", f, pwmd_strerror(gpg_error_from_errno(errno)));
1741 else
1742 assuan_set_assuan_log_stream(debugfp);
1744 g_free(f);
1748 do {
1749 gint sig;
1751 pth_sigwait(&sigset, &sig);
1752 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1754 /* Caught a signal. */
1755 switch (sig) {
1756 case SIGHUP:
1757 reload_rcfile();
1758 break;
1759 case SIGABRT:
1760 cache_clear(NULL, 2);
1761 #ifndef MEM_DEBUG
1762 xpanic();
1763 #endif
1764 exit(EXIT_FAILURE);
1765 case SIGUSR1:
1766 CACHE_LOCK(NULL);
1767 log_write(N_("clearing file cache"));
1768 cache_clear(NULL, 2);
1769 CACHE_UNLOCK;
1770 break;
1771 default:
1772 quit = 1;
1773 break;
1775 } while (!quit);
1777 done:
1779 * We're out of the main server loop. This happens when a signal was sent
1780 * to terminate the daemon. We'll wait for all clients to disconnect
1781 * before exiting and ignore any following signals.
1783 shutdown(sockfd, SHUT_RDWR);
1784 close(sockfd);
1785 pth_cancel(accept_tid);
1786 pth_join(accept_tid, NULL);
1787 unlink(*socketpath);
1788 g_free(*socketpath);
1789 *socketpath = NULL;
1790 MUTEX_LOCK(&cn_mutex);
1791 n = g_slist_length(cn_thread_list);
1792 MUTEX_UNLOCK(&cn_mutex);
1794 if (n) {
1795 log_write(N_("waiting for all clients to disconnect"));
1797 do {
1798 MUTEX_LOCK(&cn_mutex);
1799 n = g_slist_length(cn_thread_list);
1800 MUTEX_UNLOCK(&cn_mutex);
1801 log_write(N_("%i clients remain"), n);
1802 } while (waiting_for_exit());
1805 startStopKeepAlive(TRUE);
1806 pth_cancel(cache_timeout_tid);
1807 cache_free();
1811 * Only called from pinentry_fork() in the child process.
1813 void free_client_list()
1815 gint i, t = g_slist_length(cn_thread_list);
1817 for (i = 0; i < t; i++) {
1818 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1820 free_client(cn->cl);
1823 cache_free();
1826 static guint pwmd_cipher_to_gcrypt(guint64 flags)
1828 if (flags & PWMD_CIPHER_AES128)
1829 return GCRY_CIPHER_AES128;
1830 else if (flags & PWMD_CIPHER_AES192)
1831 return GCRY_CIPHER_AES192;
1832 else if (flags & PWMD_CIPHER_AES256)
1833 return GCRY_CIPHER_AES256;
1834 else if (flags & PWMD_CIPHER_SERPENT128)
1835 return GCRY_CIPHER_SERPENT128;
1836 else if (flags & PWMD_CIPHER_SERPENT192)
1837 return GCRY_CIPHER_SERPENT192;
1838 else if (flags & PWMD_CIPHER_SERPENT256)
1839 return GCRY_CIPHER_SERPENT256;
1840 else if (flags & PWMD_CIPHER_CAMELLIA128)
1841 return GCRY_CIPHER_CAMELLIA128;
1842 else if (flags & PWMD_CIPHER_CAMELLIA192)
1843 return GCRY_CIPHER_CAMELLIA192;
1844 else if (flags & PWMD_CIPHER_CAMELLIA256)
1845 return GCRY_CIPHER_CAMELLIA256;
1846 else if (flags & PWMD_CIPHER_BLOWFISH)
1847 return GCRY_CIPHER_BLOWFISH;
1848 else if (flags & PWMD_CIPHER_3DES)
1849 return GCRY_CIPHER_3DES;
1850 else if (flags & PWMD_CIPHER_CAST5)
1851 return GCRY_CIPHER_CAST5;
1852 else if (flags & PWMD_CIPHER_TWOFISH)
1853 return GCRY_CIPHER_TWOFISH;
1854 else if (flags & PWMD_CIPHER_TWOFISH128)
1855 return GCRY_CIPHER_TWOFISH128;
1857 /* For backwards compatibility (no flags). */
1858 return GCRY_CIPHER_AES256;
1861 guint pwmd_cipher_str_to_cipher(const gchar *str)
1863 guint64 flags = 0;
1865 if (!g_strcasecmp(str, "aes128"))
1866 flags = PWMD_CIPHER_AES128;
1867 else if (!g_strcasecmp(str, "aes192"))
1868 flags = PWMD_CIPHER_AES192;
1869 else if (!g_strcasecmp(str, "aes256"))
1870 flags = PWMD_CIPHER_AES256;
1871 if (!g_strcasecmp(str, "serpent128"))
1872 flags = PWMD_CIPHER_SERPENT128;
1873 else if (!g_strcasecmp(str, "serpent192"))
1874 flags = PWMD_CIPHER_SERPENT192;
1875 else if (!g_strcasecmp(str, "serpent256"))
1876 flags = PWMD_CIPHER_SERPENT256;
1877 if (!g_strcasecmp(str, "camellia128"))
1878 flags = PWMD_CIPHER_CAMELLIA128;
1879 else if (!g_strcasecmp(str, "camellia192"))
1880 flags = PWMD_CIPHER_CAMELLIA192;
1881 else if (!g_strcasecmp(str, "camellia256"))
1882 flags = PWMD_CIPHER_CAMELLIA256;
1883 else if (!g_strcasecmp(str, "blowfish"))
1884 flags = PWMD_CIPHER_BLOWFISH;
1885 else if (!g_strcasecmp(str, "cast5"))
1886 flags = PWMD_CIPHER_CAST5;
1887 else if (!g_strcasecmp(str, "3des"))
1888 flags = PWMD_CIPHER_3DES;
1889 else if (!g_strcasecmp(str, "twofish256"))
1890 flags = PWMD_CIPHER_TWOFISH;
1891 else if (!g_strcasecmp(str, "twofish128"))
1892 flags = PWMD_CIPHER_TWOFISH128;
1894 return flags;
1897 /* To be called after read_file_header(). This sets the wanted algorithm from
1898 * .flags */
1899 gpg_error_t init_client_crypto2(const char *filename,
1900 struct client_crypto_s *crypto)
1902 gpg_error_t rc;
1903 guint algo;
1905 /* New file or conversion. */
1906 if (crypto->fh->v1)
1907 algo = pwmd_cipher_to_gcrypt(PWMD_CIPHER_AES256);
1908 else if (!crypto->fh->ver.fh2.flags) {
1909 gchar *tmp = get_key_file_string(filename ? filename : "global", "cipher");
1910 guint64 flags;
1912 flags = pwmd_cipher_str_to_cipher(tmp);
1913 g_free(tmp);
1914 algo = pwmd_cipher_to_gcrypt(flags);
1915 crypto->fh->ver.fh2.flags = flags;
1917 else
1918 algo = pwmd_cipher_to_gcrypt(crypto->fh->ver.fh2.flags);
1920 rc = gcry_cipher_algo_info(algo, GCRYCTL_TEST_ALGO, NULL, NULL);
1922 if (rc)
1923 return rc;
1925 rc = gcry_cipher_algo_info(algo, GCRYCTL_GET_KEYLEN, NULL,
1926 &crypto->keysize);
1928 if (rc)
1929 return rc;
1931 rc = gcry_cipher_algo_info(algo, GCRYCTL_GET_BLKLEN, NULL,
1932 &crypto->blocksize);
1934 if (rc)
1935 return rc;
1937 if (crypto->gh)
1938 gcry_cipher_close(crypto->gh);
1940 return gcry_cipher_open(&crypto->gh, algo, GCRY_CIPHER_MODE_CBC, 0);
1943 struct client_crypto_s *init_client_crypto()
1945 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1947 if (!new) {
1948 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1949 return NULL;
1952 return new;
1955 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1956 const gchar *outfile)
1958 gpg_error_t rc;
1959 guchar md5file[gcry_md_get_algo_dlen(GCRY_MD_MD5)];
1960 guint64 iter;
1961 struct client_crypto_s *crypto = init_client_crypto();
1962 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1964 if (!crypto)
1965 return GPG_ERR_ENOMEM;
1967 crypto->key = gcry_malloc(hashlen);
1969 if (!crypto->key) {
1970 cleanup_crypto(&crypto);
1971 return GPG_ERR_ENOMEM;
1974 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1975 filename);
1976 crypto->fh = read_file_header(filename, TRUE, &rc);
1978 if (!crypto->fh)
1979 goto done;
1981 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1983 /* The header in version 1 had a bug where the iterations were off-by-one.
1984 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1985 * header.
1987 if (crypto->fh->ver.fh1.iter != -1) {
1988 if (keyfile) {
1989 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1991 if (!crypto->tkey)
1992 goto done;
1994 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1995 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1997 else {
1998 rc = get_password(filename, crypto, md5file, crypto->key,
1999 PINENTRY_OPEN);
2001 if (rc)
2002 goto done;
2006 rc = init_client_crypto2(NULL, crypto);
2008 if (rc)
2009 goto done;
2011 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
2012 &crypto->fh->len);
2014 if (rc)
2015 goto done;
2017 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
2019 if (rc) {
2020 log_write("%s: %s", filename, pwmd_strerror(rc));
2021 goto done;
2024 crypto->fh->v1 = FALSE;
2026 iter = crypto->fh->ver.fh1.iter+1;
2027 memset(&crypto->fh->ver.fh2, 0, sizeof(crypto->fh->ver.fh2));
2028 /* Keep the iterations and key from the original file. */
2029 crypto->fh->ver.fh2.iter = iter;
2030 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
2032 done:
2033 if (rc)
2034 send_error(NULL, rc);
2036 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
2037 cleanup_crypto(&crypto);
2038 return rc;
2041 int main(int argc, char *argv[])
2043 gint opt;
2044 struct sockaddr_un addr;
2045 gchar buf[PATH_MAX];
2046 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
2047 gchar *socketarg = NULL;
2048 gchar *datadir = NULL;
2049 gboolean n;
2050 gint x;
2051 gchar *p;
2052 gchar **cache_push = NULL;
2053 gchar *import = NULL, *keyfile = NULL;
2054 guint64 cmd_iterations = -1ULL;
2055 gint default_timeout;
2056 gboolean rcfile_spec = FALSE;
2057 gint estatus = EXIT_FAILURE;
2058 gint sockfd;
2059 gchar *outfile = NULL;
2060 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
2061 gint do_unlink = 1;
2062 gboolean secure = FALSE;
2063 gint background = 1;
2064 gchar *convert = NULL;
2065 gint show_version = 0;
2066 gint show_help = 0;
2067 #ifdef WITH_PINENTRY
2068 gboolean disable_pinentry = FALSE;
2069 #endif
2070 gint opt_index;
2071 const struct option long_opts[] = {
2072 #ifdef WITH_PINENTRY
2073 { "no-pinentry", 0, 0, 'P' },
2074 #endif
2075 { "outfile", 1, 0, 'o' },
2076 { "convert", 1, 0, 'C' },
2077 { "no-fork", 0, 0, 'n' },
2078 { "disable-dump", 0, 0, 'D' },
2079 { "import", 1, 0, 'I' },
2080 { "iterations", 1, 0, 'i' },
2081 { "key-file", 1, 0, 'k' },
2082 { "rcfile", 1, 0, 'f' },
2083 { "version", 0, &show_version, 1 },
2084 { "help", 0, &show_help, 1 },
2085 { 0, 0, 0, 0}
2087 #ifdef WITH_PINENTRY
2088 const gchar *optstring = "Po:C:nDI:i:k:f:";
2089 #else
2090 const gchar *optstring = "o:C:nDI:i:k:f:";
2091 #endif
2092 #ifndef DEBUG
2093 #ifdef HAVE_SETRLIMIT
2094 struct rlimit rl;
2096 rl.rlim_cur = rl.rlim_max = 0;
2098 if (setrlimit(RLIMIT_CORE, &rl) != 0)
2099 err(EXIT_FAILURE, "setrlimit()");
2100 #endif
2101 #endif
2103 #ifdef ENABLE_NLS
2104 setlocale(LC_ALL, "");
2105 bindtextdomain("pwmd", LOCALEDIR);
2106 textdomain("pwmd");
2107 #endif
2109 #ifndef MEM_DEBUG
2110 xmem_init();
2111 #endif
2112 setup_gcrypt();
2113 gpg_err_init();
2114 assuan_set_gpg_err_source(GPG_ERR_SOURCE_DEFAULT);
2115 g_mem_set_vtable(&mtable);
2116 struct assuan_malloc_hooks mhooks = {
2117 xmalloc, xrealloc, xfree
2119 assuan_set_system_hooks(ASSUAN_SYSTEM_PTH);
2120 assuan_set_malloc_hooks(&mhooks);
2121 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
2122 xmlInitMemory();
2123 xmlInitGlobals();
2124 xmlInitParser();
2125 xmlXPathInit();
2126 g_snprintf(buf, sizeof(buf), "%s/.pwmd", g_get_home_dir());
2128 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2129 err(EXIT_FAILURE, "%s", buf);
2131 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", g_get_home_dir());
2133 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2134 err(EXIT_FAILURE, "%s", buf);
2136 cmdline = TRUE;
2138 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
2139 switch (opt) {
2140 case 0:
2141 if (show_help)
2142 usage(argv[0], EXIT_SUCCESS);
2144 if (show_version) {
2145 printf(N_("%s\nCopyright (c) %s\nReleased under the terms of the GPL v2. Use at your own risk.\n\nCompile time features:\n%s"), PACKAGE_STRING,
2146 PACKAGE_BUGREPORT,
2147 #ifdef WITH_PINENTRY
2148 "+WITH_PINENTRY\n"
2149 #else
2150 "-WITH_PINENTRY\n"
2151 #endif
2152 #ifdef WITH_QUALITY
2153 "+WITH_QUALITY\n"
2154 #else
2155 "-WITH_QUALITY\n"
2156 #endif
2157 #ifdef WITH_LIBACL
2158 "+WITH_LIBACL\n"
2159 #else
2160 "-WITH_LIBACL\n"
2161 #endif
2162 #ifdef DEBUG
2163 "+DEBUG\n"
2164 #else
2165 "-DEBUG\n"
2166 #endif
2167 #ifdef MEM_DEBUG
2168 "+MEM_DEBUG\n"
2169 #else
2170 "-MEM_DEBUG\n"
2171 #endif
2173 exit(EXIT_SUCCESS);
2175 break;
2176 #ifdef WITH_PINENTRY
2177 case 'P':
2178 disable_pinentry = TRUE;
2179 break;
2180 #endif
2181 case 'o':
2182 outfile = optarg;
2183 break;
2184 case 'C':
2185 convert = optarg;
2186 break;
2187 case 'n':
2188 background = 0;
2189 break;
2190 case 'D':
2191 secure = TRUE;
2192 break;
2193 case 'I':
2194 import = optarg;
2195 break;
2196 case 'i':
2197 cmd_iterations = strtoll(optarg, NULL, 10);
2198 break;
2199 case 'k':
2200 keyfile = optarg;
2201 break;
2202 case 'f':
2203 rcfile = g_strdup(optarg);
2204 rcfile_spec = TRUE;
2205 break;
2206 default:
2207 usage(argv[0], EXIT_FAILURE);
2211 pth_mutex_init(&cn_mutex);
2212 pth_mutex_init(&cache_mutex);
2213 pth_mutex_init(&rcfile_mutex);
2214 #ifdef WITH_PINENTRY
2215 pth_mutex_init(&pin_mutex);
2216 #endif
2218 if (!rcfile)
2219 rcfile = g_strdup_printf("%s/.pwmd/config", g_get_home_dir());
2221 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2222 exit(EXIT_FAILURE);
2224 #ifdef WITH_PINENTRY
2225 if (disable_pinentry == TRUE)
2226 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2227 #endif
2229 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2230 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2232 if (log_syslog == TRUE)
2233 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2235 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2236 x = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2237 errno = 0;
2239 if (setpriority(PRIO_PROCESS, 0, x) == -1) {
2240 log_write("setpriority(): %s", strerror(errno));
2241 goto do_exit;
2245 #ifdef HAVE_MLOCKALL
2246 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2247 log_write("mlockall(): %s", strerror(errno));
2248 goto do_exit;
2250 #endif
2252 if (convert) {
2253 if (!outfile)
2254 usage(argv[0], EXIT_FAILURE);
2256 opt = convert_file(convert, keyfile, outfile);
2257 g_key_file_free(keyfileh);
2258 g_free(rcfile);
2259 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2262 if (import) {
2263 if (!outfile)
2264 usage(argv[0], EXIT_FAILURE);
2266 if (cmd_iterations == -1ULL)
2267 cmd_iterations = (guint64)get_key_file_double("global", "iterations");
2269 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2270 g_key_file_free(keyfileh);
2271 g_free(rcfile);
2272 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2275 g_key_file_set_list_separator(keyfileh, ',');
2277 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2278 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2280 socketarg = expand_homedir(p);
2281 g_free(p);
2283 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2284 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2286 datadir = expand_homedir(p);
2287 g_free(p);
2289 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2290 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2291 disable_list_and_dump = n;
2293 else
2294 disable_list_and_dump = secure;
2296 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2297 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2298 else
2299 default_timeout = -1;
2301 setup_logging(keyfileh);
2303 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2304 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2306 if (argc != optind) {
2307 for (; optind < argc; optind++) {
2308 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2309 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2313 if (strchr(socketarg, '/') == NULL) {
2314 socketdir = g_get_current_dir();
2315 socketname = g_strdup(socketarg);
2316 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2318 else {
2319 socketname = g_strdup(strrchr(socketarg, '/'));
2320 socketname++;
2321 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2322 socketdir = g_strdup(socketarg);
2323 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2326 if (chdir(datadir)) {
2327 log_write("%s: %s", datadir, strerror(errno));
2328 unlink(socketpath);
2329 goto do_exit;
2332 if (parse_rcfile_keys() == FALSE)
2333 goto do_exit;
2335 clear_rcfile_keys();
2338 * Set the cache entry for a file. Prompts for the password.
2340 if (cache_push) {
2341 for (opt = 0; cache_push[opt]; opt++)
2342 do_cache_push(cache_push[opt], NULL);
2344 g_strfreev(cache_push);
2345 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2349 * bind() doesn't like the full pathname of the socket or any non alphanum
2350 * characters so change to the directory where the socket is wanted then
2351 * create it then change to datadir.
2353 if (chdir(socketdir)) {
2354 log_write("%s: %s", socketdir, strerror(errno));
2355 goto do_exit;
2358 g_free(socketdir);
2360 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2361 log_write("socket(): %s", strerror(errno));
2362 goto do_exit;
2365 addr.sun_family = AF_UNIX;
2366 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2368 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2369 log_write("bind(): %s", strerror(errno));
2371 if (errno == EADDRINUSE)
2372 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2373 "stale socket. Please remove it manually."), socketpath);
2375 do_unlink = 0;
2376 goto do_exit;
2379 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2380 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2381 mode_t mode = strtol(t, NULL, 8);
2382 mode_t mask = umask(0);
2384 g_free(t);
2386 if (chmod(socketname, mode) == -1) {
2387 log_write("%s: %s", socketname, strerror(errno));
2388 close(sockfd);
2389 unlink(socketpath);
2390 umask(mask);
2391 goto do_exit;
2394 umask(mask);
2397 g_free(--socketname);
2399 if (chdir(datadir)) {
2400 log_write("%s: %s", datadir, strerror(errno));
2401 close(sockfd);
2402 unlink(socketpath);
2403 goto do_exit;
2406 g_free(datadir);
2408 if (listen(sockfd, 0) == -1) {
2409 log_write("listen(): %s", strerror(errno));
2410 goto do_exit;
2413 cmdline = FALSE;
2414 unsetenv("DISPLAY");
2415 unsetenv("TERM");
2417 if (background) {
2418 switch (fork()) {
2419 case -1:
2420 log_write("fork(): %s", strerror(errno));
2421 goto do_exit;
2422 case 0:
2423 close(0);
2424 close(1);
2425 close(2);
2426 setsid();
2427 break;
2428 default:
2429 exit(EXIT_SUCCESS);
2433 server_loop(sockfd, &socketpath);
2434 estatus = EXIT_SUCCESS;
2436 do_exit:
2437 if (socketpath && do_unlink) {
2438 unlink(socketpath);
2439 g_free(socketpath);
2442 g_key_file_free(keyfileh);
2443 g_free(rcfile);
2444 xmlCleanupParser();
2445 xmlCleanupGlobals();
2447 if (estatus == EXIT_SUCCESS)
2448 log_write(N_("pwmd exiting normally"));
2450 #if defined(DEBUG) && !defined(MEM_DEBUG)
2451 xdump();
2452 #endif
2453 exit(estatus);