Version 2.1.
[pwmd.git] / src / pwmd.c
blob3a45c7e5f02312211afe64751ae5794f27fbf933
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;
82 static void clear_rcfile_keys()
84 gsize n;
85 gchar **groups;
86 gchar **p;
88 groups = g_key_file_get_groups(keyfileh, &n);
90 for (p = groups; *p; p++) {
91 GError *rc = NULL;
93 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
94 g_key_file_set_string(keyfileh, *p, "key", "");
97 g_strfreev(groups);
100 static void *reload_rcfile_thread(void *arg)
102 gboolean b = disable_list_and_dump;
103 GKeyFile *k;
104 pth_attr_t attr = pth_attr_of(pth_self());
106 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
107 pth_attr_destroy(attr);
108 MUTEX_LOCK(&rcfile_mutex);
109 log_write(N_("reloading configuration file '%s'"), rcfile);
110 k = parse_rcfile(FALSE);
112 if (!k)
113 goto done;
115 g_key_file_free(keyfileh);
116 keyfileh = k;
117 parse_rcfile_keys();
118 clear_rcfile_keys();
119 disable_list_and_dump = b;
120 startStopKeepAlive(FALSE);
121 send_status_all(STATUS_CONFIG);
122 done:
123 MUTEX_UNLOCK(&rcfile_mutex);
124 return NULL;
127 static void reload_rcfile()
129 pth_t tid;
130 pth_attr_t attr = pth_attr_new();
131 gint n;
133 pth_attr_init(attr);
134 pth_attr_set(attr, PTH_ATTR_JOINABLE, 0);
135 tid = pth_spawn(attr, reload_rcfile_thread, NULL);
136 n = errno;
137 pth_attr_destroy(attr);
139 if (!tid)
140 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
141 _gpg_strerror(gpg_error_from_errno(n)));
144 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
146 gpg_error_t n = gpg_error_from_errno(e);
147 struct client_s *client = assuan_get_pointer(ctx);
149 client->last_rc = e;
150 return assuan_process_done(ctx, assuan_set_error(ctx, n, _gpg_strerror(n)));
153 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
155 gpg_err_code_t n = gpg_err_code(e);
156 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
157 struct client_s *client = assuan_get_pointer(ctx);
159 if (client)
160 client->last_rc = e;
162 if (!e)
163 return assuan_process_done(ctx, 0);
165 if (!ctx) {
166 log_write("%s", pwmd_strerror(e));
167 return e;
170 if (n == EPWMD_LIBXML_ERROR) {
171 xmlErrorPtr xe = client->xml_error;
173 if (!xe)
174 xe = xmlGetLastError();
176 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
177 log_write("%s", xe->message);
179 if (xe == client->xml_error)
180 xmlResetError(xe);
181 else
182 xmlResetLastError();
184 client->xml_error = NULL;
185 return e;
188 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
191 void log_write(const gchar *fmt, ...)
193 gchar *args, *line;
194 va_list ap;
195 struct tm *tm;
196 time_t now;
197 gchar tbuf[21];
198 gint fd = -1;
199 gchar *name;
200 gchar buf[255];
201 pth_t tid = pth_self();
202 pth_attr_t attr;
204 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
205 return;
207 if (!cmdline && logfile) {
208 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
209 warn("%s", logfile);
210 return;
214 va_start(ap, fmt);
216 if (g_vasprintf(&args, fmt, ap) == -1) {
217 if (logfile)
218 close(fd);
220 va_end(ap);
221 return;
224 va_end(ap);
226 if (cmdline) {
227 fprintf(stderr, "%s\n", args);
228 fflush(stderr);
229 g_free(args);
230 return;
233 attr = pth_attr_of(tid);
235 if (pth_attr_get(attr, PTH_ATTR_NAME, &name) == FALSE)
236 name = "unknown";
238 pth_attr_destroy(attr);
239 name = print_fmt(buf, sizeof(buf), "%s(%p): ", name, tid);
241 if (!cmdline && log_syslog == TRUE)
242 syslog(LOG_INFO, "%s%s", name, args);
244 time(&now);
245 tm = localtime(&now);
246 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
247 tbuf[sizeof(tbuf) - 1] = 0;
249 if (args[strlen(args)-1] == '\n')
250 args[strlen(args)-1] = 0;
252 line = g_strdup_printf("%s %i %s%s\n", tbuf, getpid(), name, args);
253 g_free(args);
255 if (!line) {
256 if (logfile)
257 close(fd);
259 return;
262 if (logfile) {
263 pth_write(fd, line, strlen(line));
264 fsync(fd);
265 close(fd);
268 if (isatty(STDERR_FILENO)) {
269 fprintf(stderr, "%s", line);
270 fflush(stderr);
273 g_free(line);
276 static void usage(gchar *pn, gint rc)
278 g_fprintf(rc == EXIT_FAILURE ? stderr : stdout, N_(
279 "Usage: %s [options] [file1] [...]\n"
280 " --no-fork/-n\n"
281 " run as a foreground process\n"
282 " --rcfile/-f <filename>\n"
283 " load the specified rcfile (~/.pwmd/config)\n"
284 " --convert/-C <filename>\n"
285 " convert a version 1 data file to version 2\n"
286 " --import/-I <filename>\n"
287 " import an XML file\n"
288 " --iterations/-i\n"
289 " encrypt with the specified number of iterations when importing\n"
290 " (default is in the rcfile \"global\" section)\n"
291 " --key-file/-k <filename>\n"
292 " obtain the key from the specified file when importing or converting\n"
293 " --outfile/-o <filename>\n"
294 " output file to use when importing or converting (- for stdout)\n"
295 " --disable-dump/-D\n"
296 " disable use of the LIST, XPATH and DUMP commands\n"
297 " --no-pinentry/-P\n"
298 " disable use of pinentry\n"
299 " --version\n"
300 " --help\n"
301 ), pn);
302 exit(rc);
305 static void setup_gcrypt()
307 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
309 if (!gcry_check_version(GCRYPT_VERSION))
310 errx(EXIT_FAILURE, N_("gcry_check_version(): Incompatible libgcrypt. Wanted %s, got %s."), GCRYPT_VERSION, gcry_check_version(NULL));
312 gcry_set_allocation_handler(xmalloc, xmalloc, NULL, xrealloc, xfree);
315 static gint new_connection(struct client_s *cl)
317 gpg_error_t rc;
318 gchar *ver;
320 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
322 if (rc)
323 goto fail;
325 assuan_set_pointer(cl->ctx, cl);
326 ver = g_strdup_printf("%s", PACKAGE_STRING);
327 assuan_set_hello_line(cl->ctx, ver);
328 g_free(ver);
329 rc = register_commands(cl->ctx);
331 if (rc)
332 goto fail;
334 rc = assuan_accept(cl->ctx);
336 if (rc)
337 goto fail;
340 gchar *str = get_key_file_string("global", "debug_file");
342 if (debugfp && str)
343 assuan_set_log_stream(cl->ctx, debugfp);
345 if (str)
346 g_free(str);
349 return 0;
351 fail:
352 log_write("%s", _gpg_strerror(rc));
353 close(cl->thd->fd);
354 cl->thd->fd = -1;
355 return 1;
358 static void xml_error_cb(void *data, xmlErrorPtr e)
360 struct client_s *client = data;
363 * Keep the first reported error as the one to show in the error
364 * description. Reset in send_error().
366 if (client->xml_error)
367 return;
369 xmlCopyError(e, client->xml_error);
372 void close_file_header(file_header_internal_t *fh)
374 if (!fh)
375 return;
377 if (fh->fd != -1 || (cmdline == TRUE && fh->fd != STDOUT_FILENO))
378 close(fh->fd);
380 if (fh->doc)
381 gcry_free(fh->doc);
383 g_free(fh);
386 void cleanup_crypto(struct client_crypto_s **c)
388 struct client_crypto_s *cr = *c;
390 if (!cr)
391 return;
393 if (cr->iv) {
394 gcry_free(cr->iv);
395 cr->iv = NULL;
398 if (cr->key) {
399 gcry_free(cr->key);
400 cr->key = NULL;
403 if (cr->tkey) {
404 gcry_free(cr->tkey);
405 cr->tkey = NULL;
408 if (cr->tkey2) {
409 gcry_free(cr->tkey2);
410 cr->tkey2 = NULL;
413 if (cr->inbuf) {
414 gcry_free(cr->inbuf);
415 cr->inbuf = NULL;
418 if (cr->outbuf) {
419 gcry_free(cr->outbuf);
420 cr->outbuf = NULL;
423 close_file_header(cr->fh);
424 cr->fh = NULL;
426 if (cr->gh)
427 gcry_cipher_close(cr->gh);
429 cr->gh = NULL;
430 g_free(cr);
431 *c = NULL;
435 * This is called after a child_thread terminates. Set with
436 * pth_cleanup_push().
438 static void cleanup_cb(void *arg)
440 struct client_thread_s *cn = arg;
441 struct client_s *cl = cn->cl;
443 MUTEX_LOCK(&cn_mutex);
444 cn_thread_list = g_slist_remove(cn_thread_list, cn);
445 MUTEX_UNLOCK(&cn_mutex);
447 if (cn->msg_tid) {
448 MUTEX_LOCK(&cn->mp_mutex);
449 pth_cancel(cn->msg_tid);
450 MUTEX_UNLOCK(&cn->mp_mutex);
453 if (cn->mp) {
454 while (pth_msgport_pending(cn->mp)) {
455 pth_message_t *msg = pth_msgport_get(cn->mp);
457 g_free(msg->m_data);
458 g_free(msg);
461 pth_msgport_destroy(cn->mp);
464 if (!cl) {
465 if (cn->fd != -1)
466 close(cn->fd);
468 goto done;
471 if (!cl->freed)
472 cleanup_client(cl);
474 if (cl->ctx)
475 assuan_deinit_server(cl->ctx);
476 else if (cl->thd && cl->thd->fd != -1)
477 close(cl->thd->fd);
479 #ifdef WITH_PINENTRY
480 if (cl->pinentry)
481 cleanup_pinentry(cl->pinentry);
482 #endif
484 if (cl->crypto)
485 cleanup_crypto(&cl->crypto);
487 g_free(cl);
488 done:
489 log_write(N_("exiting, fd=%i"), cn->fd);
490 g_free(cn);
491 send_status_all(STATUS_CLIENTS);
495 * Called every time a connection is made from init_new_connection(). This is
496 * the thread entry point.
498 static void *client_thread(void *data)
500 struct client_thread_s *thd = data;
501 struct client_s *cl = g_malloc0(sizeof(struct client_s));
502 gpg_error_t rc;
503 pth_attr_t attr;
504 gint n;
507 * Prevent a race condition with init_new_connection() if this thread
508 * fails (returns) for some reason before init_new_connection() releases
509 * the cn_mutex.
511 MUTEX_LOCK(&cn_mutex);
512 MUTEX_UNLOCK(&cn_mutex);
513 pth_cleanup_push(cleanup_cb, thd);
515 if (!cl) {
516 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
517 goto fail;
520 attr = pth_attr_of(pth_self());
521 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
522 pth_attr_destroy(attr);
523 thd->cl = cl;
524 cl->thd = thd;
526 if (new_connection(cl))
527 goto fail;
529 #ifdef WITH_PINENTRY
530 cl->pinentry = pinentry_init();
532 if (!cl->pinentry) {
533 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
534 goto fail;
536 #endif
538 #ifdef HAVE_MLOCKALL
539 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
540 log_write("mlockall(): %s", strerror(errno));
541 goto fail;
543 #endif
545 thd->mp = pth_msgport_create(NULL);
546 pth_mutex_init(&thd->mp_mutex);
547 thd->msg_tid = pth_spawn(NULL, client_msg_thread, thd);
548 n = errno;
550 if (!thd->msg_tid) {
551 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
552 _gpg_strerror(gpg_error_from_errno(n)));
553 goto fail;
556 pth_yield(thd->msg_tid);
557 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
559 if (rc) {
560 log_write("%s", _gpg_strerror(rc));
561 goto fail;
564 send_status_all(STATUS_CLIENTS);
565 xmlSetStructuredErrorFunc(cl, xml_error_cb);
567 for (;;) {
568 #ifdef WITH_PINENTRY
569 pth_event_t pev = NULL;
570 #endif
571 pth_status_t st, wst;
572 pth_event_t wev = NULL;
573 pth_event_t rev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE,
574 cl->thd->fd);
575 pth_event_t ev = rev;
577 #ifdef WITH_PINENTRY
578 if (cl->pinentry->status == PINENTRY_RUNNING) {
579 pev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, cl->pinentry->fd);
580 ev = pth_event_concat(ev, pev, NULL);
582 #endif
584 if (cl->inquire_status == INQUIRE_BUSY) {
585 wev = pth_event(PTH_EVENT_FD|PTH_UNTIL_FD_WRITEABLE, cl->thd->fd);
586 ev = pth_event_concat(ev, wev, NULL);
589 pth_cleanup_push(cleanup_ev_cb, ev);
590 pth_wait(ev);
591 st = pth_event_status(rev);
592 wst = pth_event_status(wev);
594 if (st == PTH_STATUS_OCCURRED || wst == PTH_STATUS_OCCURRED) {
595 rc = assuan_process_next(cl->ctx);
597 if (rc) {
598 cl->inquire_status = INQUIRE_INIT;
599 pth_cleanup_pop(1);
601 if (gpg_err_code(rc) == GPG_ERR_EOF)
602 goto done;
604 log_write("assuan_process_next(): %s", _gpg_strerror(rc));
605 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
607 if (rc) {
608 log_write("assuan_process_done(): %s", _gpg_strerror(rc));
609 goto done;
612 else {
613 #ifdef WITH_PINENTRY
614 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT)
615 cl->pinentry->status = PINENTRY_RUNNING;
616 #endif
618 switch (cl->inquire_status) {
619 case INQUIRE_BUSY:
620 case INQUIRE_INIT:
621 break;
622 case INQUIRE_DONE:
623 cl->inquire_status = INQUIRE_INIT;
624 rc = assuan_process_done(cl->ctx, 0);
625 break;
630 #ifdef WITH_PINENTRY
631 if (pev)
632 st = pth_event_status(pev);
634 rc = pinentry_iterate(cl,
635 pev && cl->pinentry->fd != -1 && st == PTH_STATUS_OCCURRED);
636 #endif
637 pth_cleanup_pop(1);
641 * Client cleanup (including XML data) is done in cleanup_cb().
643 done:
644 fail:
645 pth_exit(PTH_CANCELED);
646 return NULL;
649 static void setup_logging(GKeyFile *kf)
651 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
653 if (n == TRUE) {
654 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
656 if (*p == '~') {
657 gchar buf[PATH_MAX];
659 p++;
660 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
661 g_free(p);
663 if (logfile)
664 g_free(logfile);
666 logfile = g_strdup(buf);
668 else {
669 if (logfile)
670 g_free(logfile);
672 logfile = p;
676 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
680 * Make sure all settings are set to either the specified setting or a
681 * default.
683 static void set_rcfile_defaults(GKeyFile *kf)
685 gchar buf[PATH_MAX];
687 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
688 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
689 g_key_file_set_string(kf, "global", "socket_path", buf);
692 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
693 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
694 g_key_file_set_string(kf, "global", "data_directory", buf);
697 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
698 g_key_file_set_boolean(kf, "global", "backup", TRUE);
700 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
701 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
702 g_key_file_set_string(kf, "global", "log_path", buf);
705 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
706 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
708 #ifdef HAVE_MLOCKALL
709 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
710 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
711 #endif
713 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
714 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
716 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
717 g_key_file_get_double(kf, "global", "iterations", 0) < 0ULL)
718 g_key_file_set_double(kf, "global", "iterations", 1ULL);
720 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
721 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
723 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
724 g_key_file_set_double(kf, "global", "iteration_progress", 0ULL);
726 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
727 g_key_file_set_integer(kf, "global", "compression_level", 6);
729 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
730 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
732 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
733 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
735 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
737 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
738 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
740 #ifdef HAVE_MLOCKALL
741 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
742 #endif
744 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
745 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
747 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
748 g_key_file_set_integer(kf, "global", "keepalive", DEFAULT_KEEPALIVE_TO);
750 #ifdef WITH_PINENTRY
751 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
752 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
754 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
755 g_key_file_set_integer(kf, "global", "pinentry_timeout",
756 DEFAULT_PIN_TIMEOUT);
758 if (g_key_file_has_key(kf, "global", "pinentry_path", NULL) == FALSE)
759 g_key_file_set_string(kf, "global", "pinentry_path", PINENTRY_PATH);
760 #endif
762 if (g_key_file_has_key(kf, "global", "xfer_progress", NULL) == FALSE)
763 g_key_file_set_integer(kf, "global", "xfer_progress", 8196);
765 if (g_key_file_has_key(kf, "global", "cipher", NULL) == FALSE)
766 g_key_file_set_string(kf, "global", "cipher", "AES256");
768 if (g_key_file_has_key(kf, "global", "log_level", NULL) == FALSE)
769 g_key_file_set_integer(kf, "global", "log_level", 0);
771 setup_logging(kf);
774 static GKeyFile *parse_rcfile(gboolean specified)
776 GKeyFile *kf = g_key_file_new();
777 GError *rc = NULL;
779 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
780 log_write("%s: %s", rcfile, rc->message);
782 if (cmdline && specified) {
783 g_clear_error(&rc);
784 return NULL;
787 if (rc->code == G_FILE_ERROR_NOENT) {
788 g_clear_error(&rc);
789 set_rcfile_defaults(kf);
790 return kf;
793 g_clear_error(&rc);
794 return NULL;
797 set_rcfile_defaults(kf);
798 return kf;
801 static gchar *do_get_password(const gchar *prompt)
803 gchar buf[LINE_MAX] = {0}, *p;
804 struct termios told, tnew;
805 gchar *key;
807 if (tcgetattr(STDIN_FILENO, &told) == -1) {
808 log_write("tcgetattr(): %s", strerror(errno));
809 return NULL;
812 memcpy(&tnew, &told, sizeof(struct termios));
813 tnew.c_lflag &= ~(ECHO);
814 tnew.c_lflag |= ICANON|ECHONL;
816 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
817 log_write("tcsetattr(): %s", strerror(errno));
818 tcsetattr(STDIN_FILENO, TCSANOW, &told);
819 return NULL;
822 fprintf(stderr, "%s", prompt);
824 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
825 tcsetattr(STDIN_FILENO, TCSANOW, &told);
826 return NULL;
829 tcsetattr(STDIN_FILENO, TCSANOW, &told);
830 p[strlen(p) - 1] = 0;
832 if (!buf[0]) {
833 key = gcry_malloc(1);
834 key[0] = 0;
836 else {
837 key = gcry_malloc(strlen(p) + 1);
838 sprintf(key, "%s", p);
841 memset(&buf, 0, sizeof(buf));
842 return key;
845 /* Only used when "enable_pinentry" is "false" or -P. */
846 static gpg_error_t get_input(const gchar *filename,
847 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
849 gchar *prompt;
851 if (which == PINENTRY_SAVE) {
852 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
853 crypto->tkey = do_get_password(prompt);
854 g_free(prompt);
856 if (!crypto->tkey) {
857 log_write(N_("%s: Skipping file"), filename);
858 return GPG_ERR_BAD_PASSPHRASE;
861 prompt = g_strdup_printf(N_("Repeat passphrase: "));
862 crypto->tkey2 = do_get_password(prompt);
863 g_free(prompt);
865 if (!crypto->tkey2) {
866 log_write(N_("%s: Skipping file"), filename);
867 return GPG_ERR_BAD_PASSPHRASE;
870 if (strcmp(crypto->tkey, crypto->tkey2)) {
871 log_write(N_("%s: Passphrase mismatch"), filename);
872 return EPWMD_BADKEY;
875 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
876 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
877 return 0;
880 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
882 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
883 log_write(N_("%s: Skipping file"), filename);
884 g_free(prompt);
885 return GPG_ERR_BAD_PASSPHRASE;
888 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
889 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
890 g_free(prompt);
891 return 0;
895 * inbuf must have been allocated with gcry_malloc().
897 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
898 gpointer inbuf, gulong insize)
900 gpg_error_t rc;
901 gint level, zrc;
902 gulong outsize;
903 gpointer outbuf;
905 rc = update_save_flags(NULL, crypto);
907 if (rc)
908 return rc;
910 level = get_key_file_integer(filename, "compression_level");
912 if (level < 0)
913 level = 0;
915 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
916 == FALSE) {
917 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
920 crypto->inbuf = outbuf;
921 crypto->insize = outsize;
922 rc = do_xml_encrypt(NULL, crypto, filename);
923 return rc;
926 static gpg_error_t get_password(const gchar *filename,
927 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
928 pinentry_cmd_t which)
930 #ifdef WITH_PINENTRY
931 gpg_error_t rc = 0;
933 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
934 == FALSE) {
935 #endif
936 return get_input(filename, crypto, key, which);
937 #ifdef WITH_PINENTRY
939 else {
940 gchar *result = NULL;
941 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
943 pth_mutex_init(&pin->status_mutex);
944 set_pinentry_defaults(pin);
945 pin->which = which;
946 pin->filename = g_strdup(filename);
947 rc = pinentry_getpin(pin, &result);
949 if (rc) {
950 xfree(result);
951 goto done;
954 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, result ? strlen(result) : 1);
955 xfree(result);
956 cleanup_pinentry(pin);
959 done:
960 return rc;
961 #endif
964 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
966 FILE *fp;
967 gchar buf[LINE_MAX] = {0}, *p;
968 gchar *str = NULL;
969 gint len;
971 *rc = 0;
973 if ((fp = fopen(file, "r")) == NULL) {
974 *rc = gpg_error_from_syserror();
975 return FALSE;
978 p = fgets(buf, sizeof(buf), fp);
979 fclose(fp);
980 len = strlen(buf);
982 if (len && buf[len - 1] == '\n')
983 buf[--len] = 0;
985 str = gcry_malloc(len + 1);
987 if (!str) {
988 *rc = gpg_error_from_errno(ENOMEM);
989 return FALSE;
992 memcpy(str, buf, len ? len : 1);
993 str[len] = 0;
994 memset(&buf, 0, sizeof(buf));
995 *result = str;
996 return TRUE;
999 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
1000 gpg_error_t *rc)
1002 GError *rv = NULL;
1003 gchar *t, *file = NULL, *str;
1005 *rc = GPG_ERR_UNKNOWN_ERRNO;
1007 if (import == FALSE) {
1008 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1009 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1011 if (!file) {
1012 if (rv) {
1013 log_write("%s: key_file: %s", rcfile, rv->message);
1014 g_clear_error(&rv);
1017 return NULL;
1020 t = expand_homedir(file);
1022 if (!t) {
1023 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1024 *rc = gpg_error_from_errno(ENOMEM);
1025 return NULL;
1028 g_free(file);
1029 file = t;
1032 else {
1033 /* -I or -C. The filename is a key file. */
1034 file = g_strdup(filename);
1036 if (!file) {
1037 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1038 *rc = gpg_error_from_errno(ENOMEM);
1039 return NULL;
1043 if (rv) {
1044 log_write("%s: key_file: %s", rcfile, rv->message);
1045 g_clear_error(&rv);
1046 return NULL;
1049 if (!file)
1050 return NULL;
1052 if (_getline(file, &str, rc) == FALSE) {
1053 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1054 g_free(file);
1055 return NULL;
1058 g_free(file);
1059 *rc = 0;
1060 return str;
1063 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1064 const gchar *keyfile, guint64 iter)
1066 xmlDocPtr doc;
1067 gint fd;
1068 struct stat st;
1069 gint len;
1070 xmlChar *xmlbuf;
1071 xmlChar *xml;
1072 gpg_error_t rc;
1073 struct client_crypto_s *crypto;
1074 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1076 if (stat(filename, &st) == -1) {
1077 log_write("%s: %s", filename, strerror(errno));
1078 return FALSE;
1081 crypto = init_client_crypto();
1083 if (!crypto)
1084 return FALSE;
1086 crypto->key = gcry_malloc(hashlen);
1087 memset(crypto->key, 0, hashlen);
1089 if (!crypto->key) {
1090 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1091 goto fail;
1094 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1095 filename, outfile);
1097 if (iter && keyfile) {
1098 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1100 if (!crypto->tkey)
1101 goto fail;
1103 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1104 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1106 else if (iter) {
1107 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1109 if (rc)
1110 goto fail;
1113 if ((fd = open(filename, O_RDONLY)) == -1) {
1114 log_write("%s: %s", filename, strerror(errno));
1115 goto fail;
1118 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1119 close(fd);
1120 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1121 goto fail;
1124 if (pth_read(fd, xmlbuf, st.st_size) == -1) {
1125 rc = errno;
1126 close(fd);
1127 errno = rc;
1128 log_write("%s: %s", filename, strerror(errno));
1129 goto fail;
1132 close(fd);
1133 xmlbuf[st.st_size] = 0;
1136 * Make sure the document validates.
1138 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1139 log_write("xmlReadDoc() failed");
1140 gcry_free(xmlbuf);
1141 goto fail;
1144 gcry_free(xmlbuf);
1145 xmlDocDumpMemory(doc, &xml, &len);
1146 xmlFreeDoc(doc);
1148 if (!iter)
1149 memset(crypto->key, '!', hashlen);
1151 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1153 if (!crypto->fh) {
1154 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1155 goto fail;
1158 crypto->fh->ver.fh2.iter = iter;
1159 rc = export_common(outfile, crypto, xml, len);
1160 xmlFree(xml);
1162 if (rc) {
1163 send_error(NULL, rc);
1164 goto fail;
1167 cleanup_crypto(&crypto);
1168 return TRUE;
1170 fail:
1171 cleanup_crypto(&crypto);
1172 return FALSE;
1175 gchar *get_key_file_string(const gchar *section, const gchar *what)
1177 gchar *val = NULL;
1178 GError *grc = NULL;
1180 MUTEX_LOCK(&rcfile_mutex);
1182 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1183 val = g_key_file_get_string(keyfileh, section, what, &grc);
1185 if (grc) {
1186 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1187 g_clear_error(&grc);
1190 else {
1191 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1192 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1194 if (grc) {
1195 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1196 g_clear_error(&grc);
1201 MUTEX_UNLOCK(&rcfile_mutex);
1202 return val;
1205 gint get_key_file_integer(const gchar *section, const gchar *what)
1207 gint val = -1;
1208 GError *grc = NULL;
1210 MUTEX_LOCK(&rcfile_mutex);
1212 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1213 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1215 if (grc) {
1216 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1217 g_clear_error(&grc);
1220 else {
1221 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1222 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1224 if (grc) {
1225 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1226 g_clear_error(&grc);
1231 MUTEX_UNLOCK(&rcfile_mutex);
1232 return val;
1235 gdouble get_key_file_double(const gchar *section, const gchar *what)
1237 gdouble val = -1;
1238 GError *grc = NULL;
1240 MUTEX_LOCK(&rcfile_mutex);
1242 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1243 val = g_key_file_get_double(keyfileh, section ? section : "global", what, &grc);
1245 if (grc) {
1246 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1247 g_clear_error(&grc);
1250 else {
1251 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1252 val = g_key_file_get_double(keyfileh, "global", what, &grc);
1254 if (grc) {
1255 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1256 g_clear_error(&grc);
1261 MUTEX_UNLOCK(&rcfile_mutex);
1262 return val;
1265 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1267 gboolean val = FALSE;
1268 GError *grc = NULL;
1270 MUTEX_LOCK(&rcfile_mutex);
1272 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL)
1273 == TRUE) {
1274 val = g_key_file_get_boolean(keyfileh, section ? section : "global",
1275 what, &grc);
1277 if (grc) {
1278 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1279 g_clear_error(&grc);
1282 else {
1283 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1284 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1286 if (grc) {
1287 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1288 g_clear_error(&grc);
1293 MUTEX_UNLOCK(&rcfile_mutex);
1294 return val;
1297 static gboolean parse_rcfile_keys()
1299 gsize n;
1300 gchar **groups;
1301 gchar **p;
1302 gchar *str;
1304 groups = g_key_file_get_groups(keyfileh, &n);
1306 for (p = groups; *p; p++) {
1307 GError *rc = NULL;
1309 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1310 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1312 if (!str) {
1313 if (rc) {
1314 log_write("%s: key: %s", rcfile, rc->message);
1315 g_clear_error(&rc);
1317 continue;
1320 do_cache_push(*p, str);
1321 g_free(str);
1322 continue;
1325 if (rc) {
1326 log_write("%s: key: %s", rcfile, rc->message);
1327 g_clear_error(&rc);
1328 continue;
1331 gpg_error_t ret;
1332 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1334 if (!str)
1335 continue;
1337 do_cache_push(*p, str);
1338 gcry_free(str);
1341 g_strfreev(groups);
1342 return TRUE;
1345 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1347 guchar md5file[16];
1348 gint timeout;
1349 const gchar *p = filename;
1350 struct client_crypto_s *crypto;
1351 gpg_error_t rc;
1352 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1354 while (isspace(*p))
1355 p++;
1357 if (!*p)
1358 return FALSE;
1360 if (valid_filename(p) == FALSE) {
1361 log_write(N_("%s: Invalid characters in filename"), p);
1362 return FALSE;
1365 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1367 if (access(p, R_OK|W_OK) != 0) {
1368 log_write("%s: %s", p, strerror(errno));
1369 return FALSE;
1372 crypto = init_client_crypto();
1374 if (!crypto)
1375 return FALSE;
1377 crypto->fh = read_file_header(filename, FALSE, &rc);
1379 if (!crypto->fh) {
1380 log_write("%s: %s", p, pwmd_strerror(rc));
1381 cleanup_crypto(&crypto);
1382 return FALSE;
1385 crypto->key = gcry_malloc(hashlen);
1387 if (!crypto->key) {
1388 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1389 cleanup_crypto(&crypto);
1390 return FALSE;
1393 log_write(N_("Adding '%s' to the file cache ..."), filename);
1395 if (crypto->fh->ver.fh2.iter <= 0ULL) {
1396 memset(crypto->key, '!', hashlen);
1397 goto try_decrypt;
1400 if (!password) {
1401 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1403 if (rc) {
1404 send_error(NULL, rc);
1405 cleanup_crypto(&crypto);
1406 return FALSE;
1409 gcry_free(crypto->fh->doc);
1410 crypto->fh->doc = NULL;
1412 else
1413 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1414 strlen(password) ? strlen(password) : 1);
1416 rc = init_client_crypto2(filename, crypto);
1418 if (rc) {
1419 send_error(NULL, rc);
1420 cleanup_crypto(&crypto);
1421 return FALSE;
1424 try_decrypt:
1425 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1427 if (rc) {
1428 log_write("%s: %s", filename, pwmd_strerror(rc));
1429 cleanup_crypto(&crypto);
1430 return FALSE;
1433 if (cache_update_key(md5file, crypto->key) == FALSE) {
1434 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1435 cleanup_crypto(&crypto);
1436 return FALSE;
1439 timeout = get_key_file_integer(p, "cache_timeout");
1440 cache_set_timeout(md5file, timeout);
1441 log_write(N_("File '%s' now cached"), filename);
1442 cleanup_crypto(&crypto);
1443 return TRUE;
1446 static void init_new_connection(gint fd)
1448 pth_attr_t attr;
1449 struct client_thread_s *new;
1450 gint n;
1452 new = g_malloc0(sizeof(struct client_thread_s));
1454 if (!new) {
1455 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1456 close(fd);
1457 return;
1460 MUTEX_LOCK(&cn_mutex);
1461 new->fd = fd;
1462 attr = pth_attr_new();
1463 pth_attr_init(attr);
1464 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1465 new->tid = pth_spawn(attr, client_thread, new);
1466 n = errno;
1467 pth_attr_destroy(attr);
1469 if (!new->tid) {
1470 g_free(new);
1471 close(fd);
1472 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1473 _gpg_strerror(gpg_error_from_errno(n)));
1474 MUTEX_UNLOCK(&cn_mutex);
1475 return;
1478 cn_thread_list = g_slist_append(cn_thread_list, new);
1479 MUTEX_UNLOCK(&cn_mutex);
1480 log_write(N_("new connection: tid=%p, fd=%i"), new->tid, fd);
1483 static void *accept_thread(void *arg)
1485 gint sockfd = (gint)arg;
1486 pth_attr_t attr = pth_attr_of(pth_self());
1488 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1489 pth_attr_destroy(attr);
1491 for (;;) {
1492 socklen_t slen = sizeof(struct sockaddr_un);
1493 struct sockaddr_un raddr;
1494 gint fd = -1;
1496 fd = pth_accept(sockfd, (struct sockaddr *)&raddr, &slen);
1498 if (fd == -1) {
1499 if (errno != EAGAIN) {
1500 if (!quit) // probably EBADF
1501 log_write("accept(): %s", strerror(errno));
1503 break;
1506 continue;
1509 init_new_connection(fd);
1512 /* Just in case accept() failed for some reason other than EBADF */
1513 quit = 1;
1514 pth_exit(PTH_CANCELED);
1515 return NULL;
1518 static void *adjust_cache_timer_thread(void *arg)
1520 pth_attr_t attr = pth_attr_of(pth_self());
1522 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1523 pth_attr_destroy(attr);
1525 for (;;) {
1526 pth_sleep(1);
1527 CACHE_LOCK(NULL);
1528 cache_adjust_timer();
1529 CACHE_UNLOCK;
1532 return NULL;
1535 void cleanup_mutex_cb(void *arg)
1537 pth_mutex_t *m = arg;
1539 MUTEX_UNLOCK(m);
1542 void cleanup_ev_cb(void *arg)
1544 pth_event_t ev = arg;
1546 pth_event_free(ev, PTH_FREE_ALL);
1549 void cleanup_fd_cb(void *arg)
1551 gint fd = (gint)arg;
1553 close(fd);
1556 void cleanup_unlink_cb(void *arg)
1558 gchar *file = arg;
1560 unlink(file);
1563 void cleanup_cancel_cb(void *arg)
1565 pth_t tid = arg;
1567 pth_cancel(tid);
1570 static void *keepalive_thread(void *arg)
1572 gint to = (gint)arg;
1573 pth_attr_t attr = pth_attr_of(pth_self());
1575 pth_attr_set(attr, PTH_ATTR_NAME, __FUNCTION__);
1576 pth_attr_destroy(attr);
1578 for (;;) {
1579 pth_event_t ev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1581 pth_cleanup_push(cleanup_ev_cb, ev);
1582 pth_wait(ev);
1583 send_status_all(STATUS_KEEPALIVE);
1584 pth_cleanup_pop(1);
1587 return NULL;
1590 static void startStopKeepAlive(gboolean term)
1592 gint n = get_key_file_integer("global", "keepalive");
1594 if (keepalive_tid)
1595 pth_cancel(keepalive_tid);
1597 keepalive_tid = NULL;
1599 if (term)
1600 return;
1602 if (n > 0) {
1603 gint e;
1604 pth_attr_t attr = pth_attr_new();
1606 pth_attr_init(attr);
1607 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1608 keepalive_tid = pth_spawn(attr, keepalive_thread, (void *)n);
1609 e = errno;
1610 pth_attr_destroy(attr);
1612 if (!keepalive_tid) {
1613 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1614 _gpg_strerror(gpg_error_from_errno(e)));
1615 return;
1618 pth_yield(keepalive_tid);
1622 static gboolean waiting_for_exit()
1624 guint i, t;
1625 pth_event_t evs = NULL;
1627 MUTEX_LOCK(&cn_mutex);
1629 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
1630 struct client_thread_s *thd = g_slist_nth_data(cn_thread_list, i);
1631 pth_event_t ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, thd->tid);
1633 if (evs)
1634 evs = pth_event_concat(evs, ev, NULL);
1635 else
1636 evs = ev;
1639 MUTEX_UNLOCK(&cn_mutex);
1641 if (!evs)
1642 return FALSE;
1644 pth_wait(evs);
1645 MUTEX_LOCK(&cn_mutex);
1646 i = g_slist_length(cn_thread_list);
1647 MUTEX_UNLOCK(&cn_mutex);
1648 pth_event_free(evs, PTH_FREE_ALL);
1649 return i ? TRUE : FALSE;
1652 static void server_loop(gint sockfd, gchar **socketpath)
1654 pth_t accept_tid;
1655 guint n;
1656 sigset_t sigset;
1657 pth_attr_t attr;
1658 pth_t cache_timeout_tid;
1660 sigemptyset(&sigset);
1662 /* Termination */
1663 sigaddset(&sigset, SIGTERM);
1664 sigaddset(&sigset, SIGINT);
1666 /* Clears the file cache. */
1667 sigaddset(&sigset, SIGUSR1);
1669 /* Configuration file reloading. */
1670 sigaddset(&sigset, SIGHUP);
1672 /* Clears the cache and exits when something bad happens. */
1673 sigaddset(&sigset, SIGABRT);
1675 /* Ignored everywhere. When a client disconnects abnormally this signal
1676 * gets raised. It isn't needed though because client_thread() will check
1677 * for rcs even after the client disconnects. */
1678 signal(SIGPIPE, SIG_IGN);
1679 sigprocmask(SIG_BLOCK, &sigset, NULL);
1681 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1682 log_write(N_("Listening on %s"), *socketpath);
1683 attr = pth_attr_new();
1684 pth_attr_init(attr);
1685 accept_tid = pth_spawn(attr, accept_thread, (void *)sockfd);
1687 if (!accept_tid) {
1688 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1689 _gpg_strerror(gpg_error_from_errno(errno)));
1690 pth_attr_destroy(attr);
1691 goto done;
1694 pth_yield(accept_tid);
1695 startStopKeepAlive(FALSE);
1696 pth_attr_set(attr, PTH_ATTR_JOINABLE, FALSE);
1697 cache_timeout_tid = pth_spawn(attr, adjust_cache_timer_thread, NULL);
1699 if (!cache_timeout_tid) {
1700 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1701 _gpg_strerror(gpg_error_from_errno(errno)));
1702 pth_attr_destroy(attr);
1703 goto done;
1706 pth_yield(cache_timeout_tid);
1707 pth_attr_destroy(attr);
1710 gchar *str = get_key_file_string("global", "debug_file");
1712 if (str) {
1713 gchar *f = expand_homedir(str);
1715 g_free(str);
1716 debugfp = fopen(f, "w");
1718 if (!debugfp)
1719 log_write("%s: %s", f, pwmd_strerror(gpg_error_from_errno(errno)));
1720 else
1721 assuan_set_assuan_log_stream(debugfp);
1723 g_free(f);
1727 do {
1728 gint sig;
1730 pth_sigwait(&sigset, &sig);
1731 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1733 /* Caught a signal. */
1734 switch (sig) {
1735 case SIGHUP:
1736 reload_rcfile();
1737 break;
1738 case SIGABRT:
1739 cache_clear(NULL, 2);
1740 #ifndef MEM_DEBUG
1741 xpanic();
1742 #endif
1743 exit(EXIT_FAILURE);
1744 case SIGUSR1:
1745 CACHE_LOCK(NULL);
1746 log_write(N_("clearing file cache"));
1747 cache_clear(NULL, 2);
1748 CACHE_UNLOCK;
1749 break;
1750 default:
1751 quit = 1;
1752 break;
1754 } while (!quit);
1756 done:
1758 * We're out of the main server loop. This happens when a signal was sent
1759 * to terminate the daemon. We'll wait for all clients to disconnect
1760 * before exiting and ignore any following signals.
1762 shutdown(sockfd, SHUT_RDWR);
1763 close(sockfd);
1764 pth_cancel(accept_tid);
1765 pth_join(accept_tid, NULL);
1766 unlink(*socketpath);
1767 g_free(*socketpath);
1768 *socketpath = NULL;
1769 MUTEX_LOCK(&cn_mutex);
1770 n = g_slist_length(cn_thread_list);
1771 MUTEX_UNLOCK(&cn_mutex);
1773 if (n) {
1774 log_write(N_("waiting for all clients to disconnect"));
1776 do {
1777 MUTEX_LOCK(&cn_mutex);
1778 n = g_slist_length(cn_thread_list);
1779 MUTEX_UNLOCK(&cn_mutex);
1780 log_write(N_("%i clients remain"), n);
1781 } while (waiting_for_exit());
1784 startStopKeepAlive(TRUE);
1785 pth_cancel(cache_timeout_tid);
1786 cache_free();
1790 * Only called from pinentry_fork() in the child process.
1792 void free_client_list()
1794 gint i, t = g_slist_length(cn_thread_list);
1796 for (i = 0; i < t; i++) {
1797 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1799 free_client(cn->cl);
1802 cache_free();
1805 static guint pwmd_cipher_to_gcrypt(guint64 flags)
1807 if (flags & PWMD_CIPHER_AES128)
1808 return GCRY_CIPHER_AES128;
1809 else if (flags & PWMD_CIPHER_AES192)
1810 return GCRY_CIPHER_AES192;
1811 else if (flags & PWMD_CIPHER_AES256)
1812 return GCRY_CIPHER_AES256;
1813 else if (flags & PWMD_CIPHER_SERPENT128)
1814 return GCRY_CIPHER_SERPENT128;
1815 else if (flags & PWMD_CIPHER_SERPENT192)
1816 return GCRY_CIPHER_SERPENT192;
1817 else if (flags & PWMD_CIPHER_SERPENT256)
1818 return GCRY_CIPHER_SERPENT256;
1819 else if (flags & PWMD_CIPHER_CAMELLIA128)
1820 return GCRY_CIPHER_CAMELLIA128;
1821 else if (flags & PWMD_CIPHER_CAMELLIA192)
1822 return GCRY_CIPHER_CAMELLIA192;
1823 else if (flags & PWMD_CIPHER_CAMELLIA256)
1824 return GCRY_CIPHER_CAMELLIA256;
1825 else if (flags & PWMD_CIPHER_BLOWFISH)
1826 return GCRY_CIPHER_BLOWFISH;
1827 else if (flags & PWMD_CIPHER_3DES)
1828 return GCRY_CIPHER_3DES;
1829 else if (flags & PWMD_CIPHER_CAST5)
1830 return GCRY_CIPHER_CAST5;
1831 else if (flags & PWMD_CIPHER_TWOFISH)
1832 return GCRY_CIPHER_TWOFISH;
1833 else if (flags & PWMD_CIPHER_TWOFISH128)
1834 return GCRY_CIPHER_TWOFISH128;
1836 /* For backwards compatibility (no flags). */
1837 return GCRY_CIPHER_AES256;
1840 guint pwmd_cipher_str_to_cipher(const gchar *str)
1842 guint64 flags = 0;
1844 if (!g_strcasecmp(str, "aes128"))
1845 flags = PWMD_CIPHER_AES128;
1846 else if (!g_strcasecmp(str, "aes192"))
1847 flags = PWMD_CIPHER_AES192;
1848 else if (!g_strcasecmp(str, "aes256"))
1849 flags = PWMD_CIPHER_AES256;
1850 if (!g_strcasecmp(str, "serpent128"))
1851 flags = PWMD_CIPHER_SERPENT128;
1852 else if (!g_strcasecmp(str, "serpent192"))
1853 flags = PWMD_CIPHER_SERPENT192;
1854 else if (!g_strcasecmp(str, "serpent256"))
1855 flags = PWMD_CIPHER_SERPENT256;
1856 if (!g_strcasecmp(str, "camellia128"))
1857 flags = PWMD_CIPHER_CAMELLIA128;
1858 else if (!g_strcasecmp(str, "camellia192"))
1859 flags = PWMD_CIPHER_CAMELLIA192;
1860 else if (!g_strcasecmp(str, "camellia256"))
1861 flags = PWMD_CIPHER_CAMELLIA256;
1862 else if (!g_strcasecmp(str, "blowfish"))
1863 flags = PWMD_CIPHER_BLOWFISH;
1864 else if (!g_strcasecmp(str, "cast5"))
1865 flags = PWMD_CIPHER_CAST5;
1866 else if (!g_strcasecmp(str, "3des"))
1867 flags = PWMD_CIPHER_3DES;
1868 else if (!g_strcasecmp(str, "twofish256"))
1869 flags = PWMD_CIPHER_TWOFISH;
1870 else if (!g_strcasecmp(str, "twofish128"))
1871 flags = PWMD_CIPHER_TWOFISH128;
1873 return flags;
1876 /* To be called after read_file_header(). This sets the wanted algorithm from
1877 * .flags */
1878 gpg_error_t init_client_crypto2(const char *filename,
1879 struct client_crypto_s *crypto)
1881 gpg_error_t rc;
1882 guint algo;
1884 /* New file or conversion. */
1885 if (crypto->fh->v1)
1886 algo = pwmd_cipher_to_gcrypt(PWMD_CIPHER_AES256);
1887 else if (!crypto->fh->ver.fh2.flags) {
1888 gchar *tmp = get_key_file_string(filename ? filename : "global", "cipher");
1889 guint64 flags;
1891 flags = pwmd_cipher_str_to_cipher(tmp);
1892 g_free(tmp);
1893 algo = pwmd_cipher_to_gcrypt(flags);
1894 crypto->fh->ver.fh2.flags = flags;
1896 else
1897 algo = pwmd_cipher_to_gcrypt(crypto->fh->ver.fh2.flags);
1899 rc = gcry_cipher_algo_info(algo, GCRYCTL_TEST_ALGO, NULL, NULL);
1901 if (rc)
1902 return rc;
1904 rc = gcry_cipher_algo_info(algo, GCRYCTL_GET_KEYLEN, NULL,
1905 &crypto->keysize);
1907 if (rc)
1908 return rc;
1910 rc = gcry_cipher_algo_info(algo, GCRYCTL_GET_BLKLEN, NULL,
1911 &crypto->blocksize);
1913 if (rc)
1914 return rc;
1916 if (crypto->gh)
1917 gcry_cipher_close(crypto->gh);
1919 return gcry_cipher_open(&crypto->gh, algo, GCRY_CIPHER_MODE_CBC, 0);
1922 struct client_crypto_s *init_client_crypto()
1924 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1926 if (!new) {
1927 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1928 return NULL;
1931 return new;
1934 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1935 const gchar *outfile)
1937 gpg_error_t rc;
1938 guchar md5file[gcry_md_get_algo_dlen(GCRY_MD_MD5)];
1939 guint64 iter;
1940 struct client_crypto_s *crypto = init_client_crypto();
1941 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1943 if (!crypto)
1944 return GPG_ERR_ENOMEM;
1946 crypto->key = gcry_malloc(hashlen);
1948 if (!crypto->key) {
1949 cleanup_crypto(&crypto);
1950 return GPG_ERR_ENOMEM;
1953 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
1954 filename);
1955 crypto->fh = read_file_header(filename, TRUE, &rc);
1957 if (!crypto->fh)
1958 goto done;
1960 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
1962 /* The header in version 1 had a bug where the iterations were off-by-one.
1963 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
1964 * header.
1966 if (crypto->fh->ver.fh1.iter != -1) {
1967 if (keyfile) {
1968 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1970 if (!crypto->tkey)
1971 goto done;
1973 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1974 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1976 else {
1977 rc = get_password(filename, crypto, md5file, crypto->key,
1978 PINENTRY_OPEN);
1980 if (rc)
1981 goto done;
1985 rc = init_client_crypto2(NULL, crypto);
1987 if (rc)
1988 goto done;
1990 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
1991 &crypto->fh->len);
1993 if (rc)
1994 goto done;
1996 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
1998 if (rc) {
1999 log_write("%s: %s", filename, pwmd_strerror(rc));
2000 goto done;
2003 crypto->fh->v1 = FALSE;
2005 iter = crypto->fh->ver.fh1.iter+1;
2006 memset(&crypto->fh->ver.fh2, 0, sizeof(crypto->fh->ver.fh2));
2007 /* Keep the iterations and key from the original file. */
2008 crypto->fh->ver.fh2.iter = iter;
2009 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
2011 done:
2012 if (rc)
2013 send_error(NULL, rc);
2015 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
2016 cleanup_crypto(&crypto);
2017 return rc;
2020 int main(int argc, char *argv[])
2022 gint opt;
2023 struct sockaddr_un addr;
2024 gchar buf[PATH_MAX];
2025 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
2026 gchar *socketarg = NULL;
2027 gchar *datadir = NULL;
2028 gboolean n;
2029 gint x;
2030 gchar *p;
2031 gchar **cache_push = NULL;
2032 gchar *import = NULL, *keyfile = NULL;
2033 guint64 cmd_iterations = -1ULL;
2034 gint default_timeout;
2035 gboolean rcfile_spec = FALSE;
2036 gint estatus = EXIT_FAILURE;
2037 gint sockfd;
2038 gchar *outfile = NULL;
2039 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
2040 gint do_unlink = 1;
2041 gboolean secure = FALSE;
2042 gint background = 1;
2043 gchar *convert = NULL;
2044 gint show_version = 0;
2045 gint show_help = 0;
2046 #ifdef WITH_PINENTRY
2047 gboolean disable_pinentry = FALSE;
2048 #endif
2049 gint opt_index;
2050 const struct option long_opts[] = {
2051 #ifdef WITH_PINENTRY
2052 { "no-pinentry", 0, 0, 'P' },
2053 #endif
2054 { "outfile", 1, 0, 'o' },
2055 { "convert", 1, 0, 'C' },
2056 { "no-fork", 0, 0, 'n' },
2057 { "disable-dump", 0, 0, 'D' },
2058 { "import", 1, 0, 'I' },
2059 { "iterations", 1, 0, 'i' },
2060 { "key-file", 1, 0, 'k' },
2061 { "rcfile", 1, 0, 'f' },
2062 { "version", 0, &show_version, 1 },
2063 { "help", 0, &show_help, 1 },
2064 { 0, 0, 0, 0}
2066 #ifdef WITH_PINENTRY
2067 const gchar *optstring = "Po:C:nDI:i:k:f:";
2068 #else
2069 const gchar *optstring = "o:C:nDI:i:k:f:";
2070 #endif
2071 #ifndef DEBUG
2072 #ifdef HAVE_SETRLIMIT
2073 struct rlimit rl;
2075 rl.rlim_cur = rl.rlim_max = 0;
2077 if (setrlimit(RLIMIT_CORE, &rl) != 0)
2078 err(EXIT_FAILURE, "setrlimit()");
2079 #endif
2080 #endif
2082 #ifdef ENABLE_NLS
2083 setlocale(LC_ALL, "");
2084 bindtextdomain("pwmd", LOCALEDIR);
2085 textdomain("pwmd");
2086 #endif
2088 #ifndef MEM_DEBUG
2089 xmem_init();
2090 #endif
2091 setup_gcrypt();
2092 gpg_err_init();
2093 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
2094 g_mem_set_vtable(&mtable);
2095 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
2096 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
2097 xmlInitMemory();
2098 xmlInitGlobals();
2099 xmlInitParser();
2100 xmlXPathInit();
2101 g_snprintf(buf, sizeof(buf), "%s/.pwmd", g_get_home_dir());
2103 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2104 err(EXIT_FAILURE, "%s", buf);
2106 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", g_get_home_dir());
2108 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2109 err(EXIT_FAILURE, "%s", buf);
2111 cmdline = TRUE;
2113 while ((opt = getopt_long(argc, argv, optstring, long_opts, &opt_index)) != -1) {
2114 switch (opt) {
2115 case 0:
2116 if (show_help)
2117 usage(argv[0], EXIT_SUCCESS);
2119 if (show_version) {
2120 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,
2121 PACKAGE_BUGREPORT,
2122 #ifdef WITH_PINENTRY
2123 "+WITH_PINENTRY\n"
2124 #else
2125 "-WITH_PINENTRY\n"
2126 #endif
2127 #ifdef WITH_QUALITY
2128 "+WITH_QUALITY\n"
2129 #else
2130 "-WITH_QUALITY\n"
2131 #endif
2132 #ifdef WITH_LIBACL
2133 "+WITH_LIBACL\n"
2134 #else
2135 "-WITH_LIBACL\n"
2136 #endif
2137 #ifdef DEBUG
2138 "+DEBUG\n"
2139 #else
2140 "-DEBUG\n"
2141 #endif
2142 #ifdef MEM_DEBUG
2143 "+MEM_DEBUG\n"
2144 #else
2145 "-MEM_DEBUG\n"
2146 #endif
2148 exit(EXIT_SUCCESS);
2150 break;
2151 #ifdef WITH_PINENTRY
2152 case 'P':
2153 disable_pinentry = TRUE;
2154 break;
2155 #endif
2156 case 'o':
2157 outfile = optarg;
2158 break;
2159 case 'C':
2160 convert = optarg;
2161 break;
2162 case 'n':
2163 background = 0;
2164 break;
2165 case 'D':
2166 secure = TRUE;
2167 break;
2168 case 'I':
2169 import = optarg;
2170 break;
2171 case 'i':
2172 cmd_iterations = strtoll(optarg, NULL, 10);
2173 break;
2174 case 'k':
2175 keyfile = optarg;
2176 break;
2177 case 'f':
2178 rcfile = g_strdup(optarg);
2179 rcfile_spec = TRUE;
2180 break;
2181 default:
2182 usage(argv[0], EXIT_FAILURE);
2186 pth_mutex_init(&cn_mutex);
2187 pth_mutex_init(&cache_mutex);
2188 pth_mutex_init(&rcfile_mutex);
2189 #ifdef WITH_PINENTRY
2190 pth_mutex_init(&pin_mutex);
2191 #endif
2193 if (!rcfile)
2194 rcfile = g_strdup_printf("%s/.pwmd/config", g_get_home_dir());
2196 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2197 exit(EXIT_FAILURE);
2199 #ifdef WITH_PINENTRY
2200 if (disable_pinentry == TRUE)
2201 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2202 #endif
2204 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2205 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2207 if (log_syslog == TRUE)
2208 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2210 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2211 x = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2212 errno = 0;
2214 if (setpriority(PRIO_PROCESS, 0, x) == -1) {
2215 log_write("setpriority(): %s", strerror(errno));
2216 goto do_exit;
2220 #ifdef HAVE_MLOCKALL
2221 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2222 log_write("mlockall(): %s", strerror(errno));
2223 goto do_exit;
2225 #endif
2227 if (convert) {
2228 if (!outfile)
2229 usage(argv[0], EXIT_FAILURE);
2231 opt = convert_file(convert, keyfile, outfile);
2232 g_key_file_free(keyfileh);
2233 g_free(rcfile);
2234 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2237 if (import) {
2238 if (!outfile)
2239 usage(argv[0], EXIT_FAILURE);
2241 if (cmd_iterations == -1ULL)
2242 cmd_iterations = (guint64)get_key_file_double("global", "iterations");
2244 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2245 g_key_file_free(keyfileh);
2246 g_free(rcfile);
2247 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2250 g_key_file_set_list_separator(keyfileh, ',');
2252 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2253 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2255 socketarg = expand_homedir(p);
2256 g_free(p);
2258 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2259 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2261 datadir = expand_homedir(p);
2262 g_free(p);
2264 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2265 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2266 disable_list_and_dump = n;
2268 else
2269 disable_list_and_dump = secure;
2271 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2272 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2273 else
2274 default_timeout = -1;
2276 setup_logging(keyfileh);
2278 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2279 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2281 if (argc != optind) {
2282 for (; optind < argc; optind++) {
2283 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2284 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2288 if (strchr(socketarg, '/') == NULL) {
2289 socketdir = g_get_current_dir();
2290 socketname = g_strdup(socketarg);
2291 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2293 else {
2294 socketname = g_strdup(strrchr(socketarg, '/'));
2295 socketname++;
2296 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2297 socketdir = g_strdup(socketarg);
2298 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2301 if (chdir(datadir)) {
2302 log_write("%s: %s", datadir, strerror(errno));
2303 unlink(socketpath);
2304 goto do_exit;
2307 if (parse_rcfile_keys() == FALSE)
2308 goto do_exit;
2310 clear_rcfile_keys();
2313 * Set the cache entry for a file. Prompts for the password.
2315 if (cache_push) {
2316 for (opt = 0; cache_push[opt]; opt++)
2317 do_cache_push(cache_push[opt], NULL);
2319 g_strfreev(cache_push);
2320 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2324 * bind() doesn't like the full pathname of the socket or any non alphanum
2325 * characters so change to the directory where the socket is wanted then
2326 * create it then change to datadir.
2328 if (chdir(socketdir)) {
2329 log_write("%s: %s", socketdir, strerror(errno));
2330 goto do_exit;
2333 g_free(socketdir);
2335 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2336 log_write("socket(): %s", strerror(errno));
2337 goto do_exit;
2340 addr.sun_family = AF_UNIX;
2341 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2343 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2344 log_write("bind(): %s", strerror(errno));
2346 if (errno == EADDRINUSE)
2347 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2348 "stale socket. Please remove it manually."), socketpath);
2350 do_unlink = 0;
2351 goto do_exit;
2354 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2355 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2356 mode_t mode = strtol(t, NULL, 8);
2357 mode_t mask = umask(0);
2359 g_free(t);
2361 if (chmod(socketname, mode) == -1) {
2362 log_write("%s: %s", socketname, strerror(errno));
2363 close(sockfd);
2364 unlink(socketpath);
2365 umask(mask);
2366 goto do_exit;
2369 umask(mask);
2372 g_free(--socketname);
2374 if (chdir(datadir)) {
2375 log_write("%s: %s", datadir, strerror(errno));
2376 close(sockfd);
2377 unlink(socketpath);
2378 goto do_exit;
2381 g_free(datadir);
2383 if (listen(sockfd, 0) == -1) {
2384 log_write("listen(): %s", strerror(errno));
2385 goto do_exit;
2388 cmdline = FALSE;
2390 if (background) {
2391 switch (fork()) {
2392 case -1:
2393 log_write("fork(): %s", strerror(errno));
2394 goto do_exit;
2395 case 0:
2396 close(0);
2397 close(1);
2398 close(2);
2399 setsid();
2400 break;
2401 default:
2402 exit(EXIT_SUCCESS);
2406 server_loop(sockfd, &socketpath);
2407 estatus = EXIT_SUCCESS;
2409 do_exit:
2410 if (socketpath && do_unlink) {
2411 unlink(socketpath);
2412 g_free(socketpath);
2415 g_key_file_free(keyfileh);
2416 g_free(rcfile);
2417 xmlCleanupParser();
2418 xmlCleanupGlobals();
2420 if (estatus == EXIT_SUCCESS)
2421 log_write(N_("pwmd exiting normally"));
2423 #if defined(DEBUG) && !defined(MEM_DEBUG)
2424 xdump();
2425 #endif
2426 exit(estatus);