More thread cancelation tests and handlers.
[pwmd.git] / src / pwmd.c
blob4de47997d1e79a0b1d071c18a268f85b6b72d4c0
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 TM_IN_SYS_TIME
52 #include <sys/time.h>
53 #else
54 #include <time.h>
55 #endif
57 #include "mem.h"
58 #include "xml.h"
59 #include "common.h"
61 #ifdef WITH_PINENTRY
62 #include "pinentry.h"
63 #endif
65 #ifdef WITH_GNUTLS
66 #include "tls.h"
67 #endif
68 #include "commands.h"
69 #include "pwmd_error.h"
70 #include "cache.h"
71 #include "misc.h"
72 #include "pwmd.h"
73 #include "lock.h"
75 GCRY_THREAD_OPTION_PTHREAD_IMPL;
77 static void clear_rcfile_keys()
79 gsize n;
80 gchar **groups;
81 gchar **p;
83 groups = g_key_file_get_groups(keyfileh, &n);
85 for (p = groups; *p; p++) {
86 GError *rc = NULL;
88 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE)
89 g_key_file_set_string(keyfileh, *p, "key", "");
92 g_strfreev(groups);
95 static void *reload_rcfile_thread(void *arg)
97 gboolean b = disable_list_and_dump;
98 GKeyFile *k;
100 pthread_mutex_lock(&reload_rcfile_mutex);
101 log_write(N_("reloading configuration file '%s'"), rcfile);
102 k = parse_rcfile(FALSE);
104 if (!k)
105 goto done;
107 g_key_file_free(keyfileh);
108 keyfileh = k;
109 parse_rcfile_keys();
110 clear_rcfile_keys();
111 disable_list_and_dump = b;
112 #ifdef WITH_GNUTLS
113 startStopTcp(FALSE);
114 #endif
115 startStopKeepAlive(FALSE);
116 send_status_all(STATUS_CONFIG);
117 done:
118 pthread_mutex_unlock(&reload_rcfile_mutex);
119 return NULL;
122 static void reload_rcfile()
124 pthread_t tid;
125 pthread_attr_t attr;
127 pthread_attr_init(&attr);
128 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
129 pthread_create(&tid, &attr, reload_rcfile_thread, NULL);
130 pthread_attr_destroy(&attr);
133 gpg_error_t send_syserror(assuan_context_t ctx, gint e)
135 gpg_error_t n = gpg_error_from_errno(e);
137 pthread_testcancel();
138 return assuan_process_done(ctx, assuan_set_error(ctx, n, gpg_strerror(n)));
141 gpg_error_t send_error(assuan_context_t ctx, gpg_error_t e)
143 gpg_err_code_t n = gpg_err_code(e);
144 gpg_error_t code = gpg_err_make(PWMD_ERR_SOURCE, n);
145 struct client_s *client = assuan_get_pointer(ctx);
147 pthread_testcancel();
149 if (!e)
150 return assuan_process_done(ctx, 0);
152 if (!ctx) {
153 log_write("%s", pwmd_strerror(e));
154 return e;
157 if (n == EPWMD_LIBXML_ERROR) {
158 xmlErrorPtr xe = client->xml_error;
160 if (!xe)
161 xe = xmlGetLastError();
163 e = assuan_process_done(ctx, assuan_set_error(ctx, code, xe->message));
164 log_write("%s", xe->message);
166 if (xe == client->xml_error)
167 xmlResetError(xe);
168 else
169 xmlResetLastError();
171 client->xml_error = NULL;
172 return e;
175 return assuan_process_done(ctx, assuan_set_error(ctx, code, pwmd_strerror(e)));
178 static struct client_thread_s *find_cn(pthread_t tid)
180 guint t, i;
182 if (!cn_thread_list)
183 return NULL;
185 pthread_mutex_lock(&cn_mutex);
187 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
188 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
190 if (cn->tid == tid) {
191 pthread_mutex_unlock(&cn_mutex);
192 return cn;
196 pthread_mutex_unlock(&cn_mutex);
197 return NULL;
200 void log_write(const gchar *fmt, ...)
202 gchar *args, *line;
203 va_list ap;
204 struct tm *tm;
205 time_t now;
206 gchar tbuf[21];
207 gint fd = -1;
208 struct client_thread_s *cn;
209 gchar *name = "";
210 gchar buf[255];
212 if ((!logfile && !isatty(STDERR_FILENO) && log_syslog == FALSE) || !fmt)
213 return;
215 if (!cmdline && logfile) {
216 if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0600)) == -1) {
217 warn("%s", logfile);
218 return;
222 va_start(ap, fmt);
224 if (g_vasprintf(&args, fmt, ap) == -1) {
225 if (logfile)
226 close(fd);
228 va_end(ap);
229 return;
232 va_end(ap);
234 if (cmdline) {
235 fprintf(stderr, "%s\n", args);
236 fflush(stderr);
237 g_free(args);
238 return;
241 cn = find_cn(pthread_self());
243 if (cn) {
244 if (!cn->name)
245 name = print_fmt(buf, sizeof(buf), "%i: ", cn->fd);
246 else
247 name = print_fmt(buf, sizeof(buf), "%s(%i): ", cn->name, cn->fd);
250 if (!cmdline && log_syslog == TRUE)
251 syslog(LOG_INFO, "%s%s", name, args);
253 time(&now);
254 tm = localtime(&now);
255 strftime(tbuf, sizeof(tbuf), "%b %d %Y %H:%M:%S ", tm);
256 tbuf[sizeof(tbuf) - 1] = 0;
258 if (args[strlen(args)-1] == '\n')
259 args[strlen(args)-1] = 0;
261 line = g_strdup_printf("%s %i %s%s\n", tbuf, getpid(), name, args);
262 g_free(args);
264 if (!line) {
265 if (logfile)
266 close(fd);
268 return;
271 if (logfile) {
272 write(fd, line, strlen(line));
273 fsync(fd);
274 close(fd);
277 if (isatty(STDERR_FILENO)) {
278 fprintf(stderr, "%s", line);
279 fflush(stderr);
282 g_free(line);
285 static void usage(gchar *pn)
287 g_fprintf(stderr, N_(
288 "Usage: %s [-hvDnP] [-f <rcfile>] [-C <filename>] "
289 "[-I <filename> [-i <iter>]]\n "
290 "[-k <keyfile>] [-o <outfile>] [file1] [...]\n"
291 " -n run as a foreground process\n"
292 " -f load the specified rcfile (~/.pwmd/config)\n"
293 " -C convert a version 1 data file to version 2\n"
294 " -I import an XML file\n"
295 " -i encrypt with the specified number of iterations when importing\n"
296 " (config default in the \"global\" section)\n"
297 " -k obtain the key from the specified file\n"
298 " -o output file for use with the -C and -I options\n"
299 " -D disable use of the LIST and DUMP commands\n"
300 " -P disable pinentry\n"
301 " -v version\n"
302 " -h this help text\n"
303 ), pn);
304 exit(EXIT_FAILURE);
307 static int gcry_SecureCheck(const void *ptr)
309 return 1;
312 static void setup_gcrypt()
314 gcry_check_version(NULL);
316 gcry_set_allocation_handler(xmalloc, xmalloc, gcry_SecureCheck, xrealloc,
317 xfree);
319 if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, NULL,
320 NULL) != 0)
321 errx(EXIT_FAILURE, N_("Required AES cipher not supported by libgcrypt."));
323 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_KEYLEN, NULL, &gcrykeysize);
324 gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_GET_BLKLEN, NULL, &gcryblocksize);
327 static gint new_connection(struct client_s *cl)
329 gpg_error_t rc;
330 gchar ver[ASSUAN_LINELENGTH];
332 rc = assuan_init_socket_server_ext(&cl->ctx, cl->thd->fd, 2);
334 if (rc)
335 goto fail;
337 assuan_set_pointer(cl->ctx, cl);
338 g_snprintf(ver, sizeof(ver), "%s", PACKAGE_STRING);
339 assuan_set_hello_line(cl->ctx, ver);
340 rc = register_commands(cl->ctx);
342 if (rc)
343 goto fail;
345 rc = assuan_accept(cl->ctx);
347 if (rc)
348 goto fail;
350 return 0;
352 fail:
353 log_write("%s", gpg_strerror(rc));
354 return 1;
357 gpg_error_t send_status(assuan_context_t ctx, status_msg_t which,
358 const gchar *fmt, ...)
360 gchar *line = NULL;
361 struct client_s *client = assuan_get_pointer(ctx);
362 gchar buf[ASSUAN_LINELENGTH];
363 gchar *status = NULL;
364 va_list ap;
366 if (fmt) {
367 va_start(ap, fmt);
368 g_vsnprintf(buf, sizeof(buf), fmt, ap);
369 va_end(ap);
370 line = buf;
373 switch (which) {
374 case STATUS_CACHE:
375 CACHE_LOCK(client->ctx);
376 line = print_fmt(buf, sizeof(buf), "%i", cache_file_count());
377 CACHE_UNLOCK;
378 status = "CACHE";
379 break;
380 case STATUS_CLIENTS:
381 MUTEX_LOCK(&cn_mutex);
382 line = print_fmt(buf, sizeof(buf), "%i", g_slist_length(cn_thread_list));
383 MUTEX_UNLOCK(&cn_mutex);
384 status = "CLIENTS";
385 break;
386 case STATUS_CONFIG:
387 status = "CONFIG";
388 break;
389 case STATUS_KEEPALIVE:
390 status = "KEEPALIVE";
391 break;
392 case STATUS_LOCKED:
393 status = "LOCKED";
394 line = N_("Waiting for lock");
395 break;
396 case STATUS_ENCRYPT:
397 status = "ENCRYPT";
398 break;
399 case STATUS_DECRYPT:
400 status = "DECRYPT";
401 break;
402 case STATUS_DECOMPRESS:
403 status = "DECOMPRESS";
404 break;
405 case STATUS_COMPRESS:
406 status = "COMPRESS";
407 break;
410 if (!ctx) {
411 log_write("%s %s", status, line);
412 return 0;
415 return assuan_write_status(ctx, status, line);
418 /* This is needed for FreeBSD systems (and maybe others). I'm guessing here,
419 * but I think it lets the scheduler let other threads do their work. If we
420 * were to do the write() in send_status_all() then write() would return
421 * before the signal was actually sent to client_msg_thread(). This is only
422 * called from send_status_all().
424 static void *write_status_msg(void *arg)
426 struct client_thread_s *cn =arg;
427 size_t len;
429 pthread_cond_signal(&cn->msg_cond);
430 len = write(cn->msg_fd[1], &cn->msg, sizeof(status_msg_t));
432 if (len != sizeof(status_msg_t))
433 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
435 return NULL;
438 void send_status_all(status_msg_t which)
440 guint i, t;
442 MUTEX_LOCK(&cn_mutex);
444 for (t = g_slist_length(cn_thread_list), i = 0; i < t; i++) {
445 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
446 pthread_t tid;
448 cn->msg = which;
449 pthread_create(&tid, NULL, write_status_msg, cn);
450 pthread_join(tid, NULL);
453 MUTEX_UNLOCK(&cn_mutex);
456 static void xml_error_cb(void *data, xmlErrorPtr e)
458 struct client_s *client = data;
461 * Keep the first reported error as the one to show in the error
462 * description. Reset in send_error().
464 if (client->xml_error)
465 return;
467 xmlCopyError(e, client->xml_error);
470 static void cleanup_crypto_handler(void *arg)
472 struct client_crypto_s **a = (struct client_crypto_s **)arg;
473 struct client_crypto_s *cr = *a;
475 if (cr->fh) {
476 if (cr->fh->fd != -1 ||
477 (cmdline == TRUE && cr->fh->fd != STDOUT_FILENO))
478 close(cr->fh->fd);
480 if (cr->fh->doc)
481 gcry_free(cr->fh->doc);
483 g_free(cr->fh);
486 if (cr->gh)
487 gcry_cipher_close(cr->gh);
489 g_free(cr);
490 *a = NULL;
493 void cleanup_crypto(struct client_crypto_s **c)
495 struct client_crypto_s *cr = *c;
497 if (!cr)
498 return;
500 if (cr->iv)
501 gcry_free(cr->iv);
503 if (cr->key)
504 gcry_free(cr->key);
506 if (cr->tkey)
507 gcry_free(cr->tkey);
509 if (cr->tkey2)
510 gcry_free(cr->tkey2);
512 if (cr->inbuf)
513 gcry_free(cr->inbuf);
515 if (cr->outbuf)
516 gcry_free(cr->outbuf);
518 pthread_cleanup_push(cleanup_crypto_handler, c);
519 pthread_testcancel();
520 pthread_cleanup_pop(1);
524 * This is called after a child_thread terminates. Set with
525 * pthread_cleanup_push().
527 static void cleanup_cb(void *arg)
529 struct client_thread_s *cn = arg;
530 struct client_s *cl = cn->cl;
532 MUTEX_LOCK(&cn_mutex);
533 log_write(N_("exiting, fd=%i"), cn->fd);
535 if (cl->thd) {
536 pthread_cancel(cn->msg_tid);
537 pthread_join(cn->msg_tid, NULL);
538 pthread_cancel(cn->msg_sender_tid);
539 pthread_join(cn->msg_sender_tid, NULL);
540 close(cl->thd->msg_fd[0]);
541 close(cl->thd->msg_fd[1]);
544 pthread_join(cn->tid, NULL);
546 if (pthread_mutex_trylock(&cn->msg_mutex) == EBUSY) {
547 MUTEX_UNLOCK(&cn->msg_mutex);
549 else
550 pthread_mutex_unlock(&cn->msg_mutex);
552 pthread_mutex_destroy(&cn->msg_mutex);
553 pthread_cond_destroy(&cn->msg_cond);
555 if (pthread_mutex_trylock(&cn->msg_sender_mutex) == EBUSY) {
556 MUTEX_UNLOCK(&cn->msg_sender_mutex);
558 else
559 pthread_mutex_unlock(&cn->msg_sender_mutex);
561 pthread_mutex_destroy(&cn->msg_sender_mutex);
562 pthread_cond_destroy(&cn->msg_sender_cond);
564 for (;;) {
565 struct status_msg_s *m = g_slist_nth_data(cn->msg_queue, 0);
567 if (!m)
568 break;
570 cn->msg_queue = g_slist_remove(cn->msg_queue, m);
571 g_free(m);
574 if (cl && cl->freed == FALSE)
575 cleanup_client(cl);
577 #ifdef WITH_GNUTLS
578 if (cn->tls) {
579 gnutls_deinit(cn->tls->ses);
581 if (cn->tls->fp)
582 g_free(cn->tls->fp);
584 g_free(cn->tls);
586 #endif
588 if (cl && cl->ctx)
589 assuan_deinit_server(cl->ctx);
591 #ifdef WITH_PINENTRY
592 if (cl && cl->pinentry)
593 cleanup_pinentry(cl->pinentry);
594 #endif
596 if (cl->crypto)
597 cleanup_crypto(&cl->crypto);
599 g_free(cl);
601 if (cn->name)
602 g_free(cn->name);
604 cn_thread_list = g_slist_remove(cn_thread_list, cn);
605 g_free(cn);
606 MUTEX_UNLOCK(&cn_mutex);
607 send_status_all(STATUS_CLIENTS);
610 static void *client_msg_sender_thread(void *arg)
612 struct client_thread_s *thd = arg;
614 MUTEX_LOCK(&thd->msg_sender_mutex);
616 for (;;) {
617 struct status_msg_s *msg;
618 gpg_error_t rc;
620 pthread_cond_wait(&thd->msg_sender_cond, &thd->msg_sender_mutex);
621 pthread_testcancel();
623 /* The messages may have been stacked while waiting for send_status()
624 * to return. Send what's in the queue. */
625 for (;;) {
626 msg = g_slist_nth_data(thd->msg_queue, 0);
628 if (!msg)
629 break;
631 /* Unlock to prevent blocking in client_msg_thread(). */
632 MUTEX_UNLOCK(&thd->msg_sender_mutex);
633 rc = send_status(thd->cl->ctx, msg->msg, NULL);
634 MUTEX_LOCK(&thd->msg_sender_mutex);
635 thd->msg_queue = g_slist_remove(thd->msg_queue, msg);
636 g_free(msg);
637 pthread_testcancel();
639 if (rc) {
640 log_write(N_("msg for %i failed: %s"), thd->fd,
641 pwmd_strerror(rc));
642 pthread_cancel(thd->tid);
647 return NULL;
651 * This function waits for a signal from send_status_all() then appends a
652 * message read from a pipe to the clients message queue. The actual sending
653 * of the message is done in client_msg_sender_thread() which waits for a
654 * signal from this function. This prevents blocking in assuan_send_status()
655 * when sending to remote clients. This also avoids duplicate status messages.
656 * If an existing status message in the message queue has the same type as the
657 * current message the the current one will be skipped. This avoids flooding
658 * the client with old status messages.
660 static void *client_msg_thread(void *arg)
662 struct client_thread_s *thd = arg;
664 MUTEX_LOCK(&thd->msg_mutex);
666 for (;;) {
667 fd_set rfds;
668 int n;
669 status_msg_t m;
670 size_t len;
671 struct status_msg_s *msg;
673 pthread_cond_wait(&thd->msg_cond, &thd->msg_mutex);
674 pthread_testcancel();
675 FD_ZERO(&rfds);
676 FD_SET(thd->msg_fd[0], &rfds);
677 n = select(thd->msg_fd[0]+1, &rfds, NULL, NULL, NULL);
679 if (n <= 0 || !FD_ISSET(thd->msg_fd[0], &rfds))
680 continue;
682 len = read(thd->msg_fd[0], &m, sizeof(status_msg_t));
683 pthread_testcancel();
685 if (len != sizeof(status_msg_t)) {
686 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
687 continue;
690 MUTEX_LOCK(&thd->msg_sender_mutex);
692 for (n = 0; n < g_slist_length(thd->msg_queue); n++) {
693 msg = g_slist_nth_data(thd->msg_queue, n);
695 if (msg->msg == m)
696 goto done;
699 msg = g_malloc(sizeof(struct status_msg_s));
701 if (!msg) {
702 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
703 MUTEX_UNLOCK(&thd->msg_sender_mutex);
704 continue;
707 msg->msg = m;
708 thd->msg_queue = g_slist_append(thd->msg_queue, msg);
709 done:
710 MUTEX_UNLOCK(&thd->msg_sender_mutex);
711 pthread_cond_signal(&thd->msg_sender_cond);
714 return NULL;
718 * Called every time a connection is made from init_new_connection(). This is
719 * the thread entry point.
721 static void *client_thread(void *data)
723 struct client_thread_s *thd = data;
724 struct client_s *cl = g_malloc0(sizeof(struct client_s));
725 gpg_error_t rc;
726 pthread_attr_t attr;
729 * Prevent a race condition with init_new_connection() if this thread
730 * fails (returns) for some reason before init_new_connection() releases
731 * the cn_mutex.
733 MUTEX_LOCK(&cn_mutex);
734 MUTEX_UNLOCK(&cn_mutex);
735 pthread_cleanup_push(cleanup_cb, thd);
737 if (!cl) {
738 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
739 goto fail;
742 thd->cl = cl;
744 #ifdef WITH_GNUTLS
746 * Do the TLS handshake before anything else.
748 if (thd->remote) {
749 gchar *prio = get_key_file_string("global", "cipher_suite");
751 thd->tls = tls_init(thd->fd, prio);
752 g_free(prio);
754 if (!thd->tls) {
755 close(thd->fd);
756 goto fail;
759 #endif
761 cl->thd = thd;
763 if (new_connection(cl))
764 goto fail;
766 #ifdef WITH_PINENTRY
767 cl->pinentry = pinentry_init();
769 if (!cl->pinentry) {
770 g_free(cl);
771 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
772 goto fail;
775 #ifdef WITH_GNUTLS
776 /* Require the client to explicity set OPTION PINENTRY since the DISPLAY
777 * might be automatically set from the client. Connections to the X11
778 * server usually aren't encrypted and the client might unintentionally
779 * send the passphrase in the clear.
781 if (thd->remote)
782 cl->pinentry->enable = FALSE;
783 #endif
784 #endif
786 #ifdef HAVE_MLOCKALL
787 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
788 log_write("mlockall(): %s", strerror(errno));
789 goto fail;
791 #endif
793 if (pipe(thd->msg_fd) == -1) {
794 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
795 goto fail;
798 pthread_cond_init(&thd->msg_cond, NULL);
799 pthread_mutex_init(&thd->msg_mutex, NULL);
800 pthread_attr_init(&attr);
801 pthread_create(&thd->msg_tid, &attr, client_msg_thread, thd);
803 pthread_cond_init(&thd->msg_sender_cond, NULL);
804 pthread_mutex_init(&thd->msg_sender_mutex, NULL);
805 pthread_create(&thd->msg_sender_tid, &attr, client_msg_sender_thread, thd);
806 pthread_attr_destroy(&attr);
807 rc = send_status(cl->ctx, STATUS_CACHE, NULL);
809 if (rc) {
810 log_write("%s", gpg_strerror(rc));
811 goto fail;
814 send_status_all(STATUS_CLIENTS);
815 xmlSetStructuredErrorFunc(cl, xml_error_cb);
817 for (;;) {
818 fd_set rfds;
819 int n;
821 FD_ZERO(&rfds);
822 FD_SET(cl->thd->fd, &rfds);
824 #ifdef WITH_PINENTRY
825 if (cl->pinentry->status == PINENTRY_RUNNING)
826 FD_SET(cl->pinentry->fd, &rfds);
828 n = cl->thd->fd > cl->pinentry->fd ? cl->thd->fd : cl->pinentry->fd;
829 #else
830 n = cl->thd->fd;
831 #endif
832 n = select(n+1, &rfds, NULL, NULL, NULL);
833 pthread_testcancel();
835 if (n <= 0)
836 continue;
838 if (FD_ISSET(cl->thd->fd, &rfds)) {
839 rc = assuan_process_next(cl->ctx);
840 pthread_testcancel();
842 if (rc) {
843 cl->inquire_status = INQUIRE_INIT;
845 if (gpg_err_code(rc) == GPG_ERR_EOF)
846 goto done;
848 log_write("assuan_process_next(): %s", gpg_strerror(rc));
849 rc = send_error(cl->ctx, gpg_err_make(PWMD_ERR_SOURCE, rc));
851 if (rc) {
852 log_write("assuan_process_done(): %s", gpg_strerror(rc));
853 goto done;
856 else {
857 #ifdef WITH_PINENTRY
858 if (cl->pinentry->pid && cl->pinentry->status == PINENTRY_INIT)
859 cl->pinentry->status = PINENTRY_RUNNING;
860 #endif
862 switch (cl->inquire_status) {
863 case INQUIRE_BUSY:
864 case INQUIRE_INIT:
865 break;
866 case INQUIRE_DONE:
867 cl->inquire_status = INQUIRE_INIT;
868 pthread_testcancel();
869 rc = assuan_process_done(cl->ctx, 0);
870 break;
875 #ifdef WITH_PINENTRY
876 pinentry_iterate(cl,
877 cl->pinentry->fd != -1 && FD_ISSET(cl->pinentry->fd, &rfds));
878 #endif
882 * Client cleanup (including XML data) is done in cleanup_cb() from
883 * the cleanup thread.
885 done:
886 fail:
887 if (1) {} // Fixes compile time error with pthread_cleanup_push().
888 pthread_cleanup_pop(1);
889 pthread_exit(PTHREAD_CANCELED);
890 return NULL;
893 static void setup_logging(GKeyFile *kf)
895 gboolean n = g_key_file_get_boolean(kf, "global", "enable_logging", NULL);
897 if (n == TRUE) {
898 gchar *p = g_key_file_get_string(kf, "global", "log_path", NULL);
900 if (*p == '~') {
901 gchar buf[PATH_MAX];
903 p++;
904 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
905 g_free(p);
907 if (logfile)
908 g_free(logfile);
910 logfile = g_strdup(buf);
912 else {
913 if (logfile)
914 g_free(logfile);
916 logfile = p;
920 log_syslog = g_key_file_get_boolean(kf, "global", "syslog", NULL);
924 * Make sure all settings are set to either the specified setting or a
925 * default.
927 static void set_rcfile_defaults(GKeyFile *kf)
929 gchar buf[PATH_MAX];
931 if (g_key_file_has_key(kf, "global", "socket_path", NULL) == FALSE) {
932 g_snprintf(buf, sizeof(buf), "~/.pwmd/socket");
933 g_key_file_set_string(kf, "global", "socket_path", buf);
936 if (g_key_file_has_key(kf, "global", "data_directory", NULL) == FALSE) {
937 g_snprintf(buf, sizeof(buf), "~/.pwmd/data");
938 g_key_file_set_string(kf, "global", "data_directory", buf);
941 if (g_key_file_has_key(kf, "global", "backup", NULL) == FALSE)
942 g_key_file_set_boolean(kf, "global", "backup", TRUE);
944 if (g_key_file_has_key(kf, "global", "log_path", NULL) == FALSE) {
945 g_snprintf(buf, sizeof(buf), "~/.pwmd/log");
946 g_key_file_set_string(kf, "global", "log_path", buf);
949 if (g_key_file_has_key(kf, "global", "enable_logging", NULL) == FALSE)
950 g_key_file_set_boolean(kf, "global", "enable_logging", FALSE);
952 #ifdef HAVE_MLOCKALL
953 if (g_key_file_has_key(kf, "global", "disable_mlockall", NULL) == FALSE)
954 g_key_file_set_boolean(kf, "global", "disable_mlockall", TRUE);
955 #endif
957 if (g_key_file_has_key(kf, "global", "cache_timeout", NULL) == FALSE)
958 g_key_file_set_integer(kf, "global", "cache_timeout", -1);
960 if (g_key_file_has_key(kf, "global", "iterations", NULL) == FALSE ||
961 g_key_file_get_integer(kf, "global", "iterations", 0) < 0)
962 g_key_file_set_integer(kf, "global", "iterations", 1);
964 if (g_key_file_has_key(kf, "global", "disable_list_and_dump", NULL) == FALSE)
965 g_key_file_set_boolean(kf, "global", "disable_list_and_dump", FALSE);
967 if (g_key_file_has_key(kf, "global", "iteration_progress", NULL) == FALSE)
968 g_key_file_set_integer(kf, "global", "iteration_progress", 0);
970 if (g_key_file_has_key(kf, "global", "compression_level", NULL) == FALSE)
971 g_key_file_set_integer(kf, "global", "compression_level", 6);
973 if (g_key_file_has_key(kf, "global", "recursion_depth", NULL) == FALSE)
974 g_key_file_set_integer(kf, "global", "recursion_depth", DEFAULT_RECURSION_DEPTH);
976 if (g_key_file_has_key(kf, "global", "zlib_bufsize", NULL) == FALSE)
977 g_key_file_set_integer(kf, "global", "zlib_bufsize", DEFAULT_ZLIB_BUFSIZE);
979 zlib_bufsize = (uInt)g_key_file_get_integer(kf, "global", "zlib_bufsize", NULL);
981 max_recursion_depth = g_key_file_get_integer(kf, "global", "recursion_depth", NULL);
982 disable_list_and_dump = g_key_file_get_boolean(kf, "global", "disable_list_and_dump", NULL);
984 #ifdef HAVE_MLOCKALL
985 disable_mlock = g_key_file_get_boolean(kf, "global", "disable_mlockall", NULL);
986 #endif
988 if (g_key_file_has_key(kf, "global", "syslog", NULL) == FALSE)
989 g_key_file_set_boolean(kf, "global", "syslog", FALSE);
991 if (g_key_file_has_key(kf, "global", "keepalive", NULL) == FALSE)
992 g_key_file_set_integer(kf, "global", "keepalive", 30);
994 #ifdef WITH_PINENTRY
995 if (g_key_file_has_key(kf, "global", "enable_pinentry", NULL) == FALSE)
996 g_key_file_set_boolean(kf, "global", "enable_pinentry", TRUE);
998 if (g_key_file_has_key(kf, "global", "pinentry_timeout", NULL) == FALSE)
999 g_key_file_set_integer(kf, "global", "pinentry_timeout", 20);
1000 #endif
1002 #ifdef WITH_GNUTLS
1003 if (g_key_file_has_key(kf, "global", "tcp_port", NULL) == FALSE)
1004 g_key_file_set_integer(kf, "global", "tcp_port", 6466);
1006 if (g_key_file_has_key(kf, "global", "enable_tcp", NULL) == FALSE)
1007 g_key_file_set_boolean(kf, "global", "enable_tcp", FALSE);
1009 if (g_key_file_has_key(kf, "global", "tcp_require_key", NULL) == FALSE)
1010 g_key_file_set_boolean(kf, "global", "tcp_require_key", FALSE);
1012 if (g_key_file_has_key(kf, "global", "tcp_wait", NULL) == FALSE)
1013 g_key_file_set_boolean(kf, "global", "tcp_wait", 3);
1015 if (g_key_file_has_key(kf, "global", "cipher_suite", NULL) == FALSE)
1016 g_key_file_set_string(kf, "global", "cipher_suite", "SECURE256");
1018 if (g_key_file_has_key(kf, "global", "tcp_use_crl", NULL) == FALSE)
1019 g_key_file_set_boolean(kf, "global", "tcp_use_crl", FALSE);
1020 #endif
1022 setup_logging(kf);
1025 static GKeyFile *parse_rcfile(gboolean specified)
1027 GKeyFile *kf = g_key_file_new();
1028 GError *rc = NULL;
1030 if (g_key_file_load_from_file(kf, rcfile, G_KEY_FILE_NONE, &rc) == FALSE) {
1031 log_write("%s: %s", rcfile, rc->message);
1033 if (cmdline && specified) {
1034 g_clear_error(&rc);
1035 return NULL;
1038 if (rc->code == G_FILE_ERROR_NOENT) {
1039 g_clear_error(&rc);
1040 set_rcfile_defaults(kf);
1041 return kf;
1044 g_clear_error(&rc);
1045 return NULL;
1048 set_rcfile_defaults(kf);
1049 return kf;
1052 static gchar *do_get_password(const gchar *prompt)
1054 gchar buf[LINE_MAX] = {0}, *p;
1055 struct termios told, tnew;
1056 gchar *key;
1058 if (tcgetattr(STDIN_FILENO, &told) == -1) {
1059 log_write("tcgetattr(): %s", strerror(errno));
1060 return NULL;
1063 memcpy(&tnew, &told, sizeof(struct termios));
1064 tnew.c_lflag &= ~(ECHO);
1065 tnew.c_lflag |= ICANON|ECHONL;
1067 if (tcsetattr(STDIN_FILENO, TCSANOW, &tnew) == -1) {
1068 log_write("tcsetattr(): %s", strerror(errno));
1069 tcsetattr(STDIN_FILENO, TCSANOW, &told);
1070 return NULL;
1073 fprintf(stderr, "%s", prompt);
1075 if ((p = fgets(buf, sizeof(buf), stdin)) == NULL) {
1076 tcsetattr(STDIN_FILENO, TCSANOW, &told);
1077 return NULL;
1080 tcsetattr(STDIN_FILENO, TCSANOW, &told);
1081 p[strlen(p) - 1] = 0;
1083 if (!buf[0]) {
1084 key = gcry_malloc(1);
1085 key[0] = 0;
1087 else {
1088 key = gcry_malloc(strlen(p) + 1);
1089 sprintf(key, "%s", p);
1092 memset(&buf, 0, sizeof(buf));
1093 return key;
1096 /* Only used when "enable_pinentry" is "false" or -P. */
1097 static gpg_error_t get_input(const gchar *filename,
1098 struct client_crypto_s *crypto, guchar *key, pinentry_cmd_t which)
1100 gchar *prompt;
1102 if (which == PINENTRY_SAVE) {
1103 prompt = g_strdup_printf(N_("New passphrase for file %s: "), filename);
1104 crypto->tkey = do_get_password(prompt);
1105 g_free(prompt);
1107 if (!crypto->tkey) {
1108 log_write(N_("%s: Skipping file"), filename);
1109 return GPG_ERR_BAD_PASSPHRASE;
1112 prompt = g_strdup_printf(N_("Repeat passphrase: "));
1113 crypto->tkey2 = do_get_password(prompt);
1114 g_free(prompt);
1116 if (!crypto->tkey2) {
1117 log_write(N_("%s: Skipping file"), filename);
1118 return GPG_ERR_BAD_PASSPHRASE;
1121 if (strcmp(crypto->tkey, crypto->tkey2)) {
1122 log_write(N_("%s: Passphrase mismatch"), filename);
1123 return EPWMD_BADKEY;
1126 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
1127 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1128 return 0;
1131 prompt = g_strdup_printf(N_("Passphrase required for %s: "), filename);
1133 if ((crypto->tkey = do_get_password(prompt)) == NULL) {
1134 log_write(N_("%s: Skipping file"), filename);
1135 g_free(prompt);
1136 return GPG_ERR_BAD_PASSPHRASE;
1139 gcry_md_hash_buffer(GCRY_MD_SHA256, key, crypto->tkey,
1140 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1141 g_free(prompt);
1142 return 0;
1146 * inbuf must have been allocated with gcry_malloc().
1148 gpg_error_t export_common(const gchar *filename, struct client_crypto_s *crypto,
1149 gpointer inbuf, gulong insize)
1151 gpg_error_t rc;
1152 gint level, zrc;
1153 gulong outsize;
1154 gpointer outbuf;
1156 level = get_key_file_integer(filename, "compression_level");
1158 if (level < 0)
1159 level = 0;
1161 if (do_compress(NULL, level, inbuf, insize, &outbuf, &outsize, &zrc)
1162 == FALSE) {
1163 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
1166 crypto->inbuf = outbuf;
1167 crypto->insize = outsize;
1168 rc = do_xml_encrypt(NULL, crypto, filename);
1169 return rc;
1172 static gpg_error_t get_password(const gchar *filename,
1173 struct client_crypto_s *crypto, guchar *md5file, guchar *key,
1174 pinentry_cmd_t which)
1176 #ifdef WITH_PINENTRY
1177 gpg_error_t rc = 0;
1179 if (g_key_file_get_boolean(keyfileh, "global", "enable_pinentry", NULL)
1180 == FALSE) {
1181 #endif
1182 return get_input(filename, crypto, key, which);
1183 #ifdef WITH_PINENTRY
1185 else {
1186 gchar *result = NULL;
1187 struct pinentry_s *pin = g_malloc0(sizeof(struct pinentry_s));
1189 set_pinentry_defaults(pin);
1190 pin->which = which;
1191 pin->filename = g_strdup(filename);
1192 rc = pinentry_getpin(pin, &result);
1194 if (rc) {
1195 xfree(result);
1196 goto done;
1199 gcry_md_hash_buffer(GCRY_MD_SHA256, key, result, strlen(result) ? strlen(result) : 1);
1200 xfree(result);
1201 cleanup_pinentry(pin);
1204 done:
1205 return rc;
1206 #endif
1209 static gboolean _getline(const gchar *file, gchar **result, gpg_error_t *rc)
1211 FILE *fp;
1212 gchar buf[LINE_MAX] = {0}, *p;
1213 gchar *str = NULL;
1214 gint len;
1216 *rc = 0;
1218 if ((fp = fopen(file, "r")) == NULL) {
1219 *rc = gpg_error_from_syserror();
1220 return FALSE;
1223 p = fgets(buf, sizeof(buf), fp);
1224 fclose(fp);
1225 len = strlen(buf);
1227 if (len && buf[len - 1] == '\n')
1228 buf[--len] = 0;
1230 str = gcry_malloc(len + 1);
1232 if (!str) {
1233 *rc = gpg_error_from_errno(ENOMEM);
1234 return FALSE;
1237 memcpy(str, buf, len ? len : 1);
1238 str[len] = 0;
1239 memset(&buf, 0, sizeof(buf));
1240 *result = str;
1241 return TRUE;
1244 static gchar *parse_rcfile_keyfile(const gchar *filename, gboolean import,
1245 gpg_error_t *rc)
1247 GError *rv = NULL;
1248 gchar *t, *file = NULL, *str;
1250 *rc = GPG_ERR_UNKNOWN_ERRNO;
1252 if (import == FALSE) {
1253 if (g_key_file_has_key(keyfileh, filename, "key_file", &rv) == TRUE) {
1254 file = g_key_file_get_string(keyfileh, filename, "key_file", &rv);
1256 if (!file) {
1257 if (rv) {
1258 log_write("%s: key_file: %s", rcfile, rv->message);
1259 g_clear_error(&rv);
1262 return NULL;
1265 t = expand_homedir(file);
1267 if (!t) {
1268 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1269 *rc = gpg_error_from_errno(ENOMEM);
1270 return NULL;
1273 g_free(file);
1274 file = t;
1277 else {
1278 /* -I or -C. The filename is a key file. */
1279 file = g_strdup(filename);
1281 if (!file) {
1282 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1283 *rc = gpg_error_from_errno(ENOMEM);
1284 return NULL;
1288 if (rv) {
1289 log_write("%s: key_file: %s", rcfile, rv->message);
1290 g_clear_error(&rv);
1291 return NULL;
1294 if (!file)
1295 return NULL;
1297 if (_getline(file, &str, rc) == FALSE) {
1298 log_write("%s: %s: %s", filename, file, pwmd_strerror(*rc));
1299 g_free(file);
1300 return NULL;
1303 g_free(file);
1304 *rc = 0;
1305 return str;
1308 static gboolean xml_import(const gchar *filename, const gchar *outfile,
1309 const gchar *keyfile, gulong iter)
1311 xmlDocPtr doc;
1312 gint fd;
1313 struct stat st;
1314 gint len;
1315 xmlChar *xmlbuf;
1316 xmlChar *xml;
1317 gpg_error_t rc;
1318 struct client_crypto_s *crypto;
1320 if (stat(filename, &st) == -1) {
1321 log_write("%s: %s", filename, strerror(errno));
1322 return FALSE;
1325 crypto = init_client_crypto();
1327 if (!crypto)
1328 return FALSE;
1330 crypto->key = gcry_malloc(gcrykeysize);
1331 memset(crypto->key, 0, gcrykeysize);
1333 if (!crypto->key) {
1334 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1335 goto fail;
1338 log_write(N_("Importing XML from '%s'. Output will be written to '%s' ..."),
1339 filename, outfile);
1341 if (iter && keyfile) {
1342 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
1344 if (!crypto->tkey)
1345 goto fail;
1347 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
1348 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
1350 else if (iter) {
1351 rc = get_password(outfile, crypto, NULL, crypto->key, PINENTRY_SAVE);
1353 if (rc)
1354 goto fail;
1357 if ((fd = open(filename, O_RDONLY)) == -1) {
1358 log_write("%s: %s", filename, strerror(errno));
1359 goto fail;
1362 if ((xmlbuf = gcry_malloc(st.st_size+1)) == NULL) {
1363 close(fd);
1364 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1365 goto fail;
1368 if (read(fd, xmlbuf, st.st_size) == -1) {
1369 rc = errno;
1370 close(fd);
1371 errno = rc;
1372 log_write("%s: %s", filename, strerror(errno));
1373 goto fail;
1376 close(fd);
1377 xmlbuf[st.st_size] = 0;
1380 * Make sure the document validates.
1382 if ((doc = xmlReadDoc(xmlbuf, NULL, "UTF-8", XML_PARSE_NOBLANKS)) == NULL) {
1383 log_write("xmlReadDoc() failed");
1384 gcry_free(xmlbuf);
1385 goto fail;
1388 gcry_free(xmlbuf);
1389 xmlDocDumpMemory(doc, &xml, &len);
1390 xmlFreeDoc(doc);
1392 if (!iter)
1393 memset(crypto->key, '!', gcrykeysize);
1395 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1397 if (!crypto->fh) {
1398 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1399 goto fail;
1402 crypto->fh->fh2.iter = iter;
1403 rc = export_common(outfile, crypto, xml, len);
1404 xmlFree(xml);
1406 if (rc) {
1407 send_error(NULL, rc);
1408 goto fail;
1411 cleanup_crypto(&crypto);
1412 return TRUE;
1414 fail:
1415 cleanup_crypto(&crypto);
1416 return FALSE;
1419 gchar *get_key_file_string(const gchar *section, const gchar *what)
1421 gchar *val = NULL;
1422 GError *grc = NULL;
1424 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1425 val = g_key_file_get_string(keyfileh, section, what, &grc);
1427 if (grc) {
1428 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1429 g_clear_error(&grc);
1432 else {
1433 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1434 val = g_key_file_get_string(keyfileh, "global", what, &grc);
1436 if (grc) {
1437 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1438 g_clear_error(&grc);
1443 return val;
1446 gint get_key_file_integer(const gchar *section, const gchar *what)
1448 gint val = -1;
1449 GError *grc = NULL;
1451 if (g_key_file_has_key(keyfileh, section ? section : "global", what, NULL) == TRUE) {
1452 val = g_key_file_get_integer(keyfileh, section ? section : "global", what, &grc);
1454 if (grc) {
1455 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1456 g_clear_error(&grc);
1459 else {
1460 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1461 val = g_key_file_get_integer(keyfileh, "global", what, &grc);
1463 if (grc) {
1464 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1465 g_clear_error(&grc);
1470 return val;
1473 gboolean get_key_file_boolean(const gchar *section, const gchar *what)
1475 gboolean val = FALSE;
1476 GError *grc = NULL;
1478 if (g_key_file_has_key(keyfileh, section, what, NULL) == TRUE) {
1479 val = g_key_file_get_boolean(keyfileh, section, what, &grc);
1481 if (grc) {
1482 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1483 g_clear_error(&grc);
1486 else {
1487 if (g_key_file_has_key(keyfileh, "global", what, NULL) == TRUE) {
1488 val = g_key_file_get_boolean(keyfileh, "global", what, &grc);
1490 if (grc) {
1491 log_write("%s(%i): %s", __FILE__, __LINE__, grc->message);
1492 g_clear_error(&grc);
1497 return val;
1500 static gboolean parse_rcfile_keys()
1502 gsize n;
1503 gchar **groups;
1504 gchar **p;
1505 gchar *str;
1507 groups = g_key_file_get_groups(keyfileh, &n);
1509 for (p = groups; *p; p++) {
1510 GError *rc = NULL;
1512 if (g_key_file_has_key(keyfileh, *p, "key", &rc) == TRUE) {
1513 str = g_key_file_get_string(keyfileh, *p, "key", &rc);
1515 if (!str) {
1516 if (rc) {
1517 log_write("%s: key: %s", rcfile, rc->message);
1518 g_clear_error(&rc);
1520 continue;
1523 do_cache_push(*p, str);
1524 g_free(str);
1525 continue;
1528 if (rc) {
1529 log_write("%s: key: %s", rcfile, rc->message);
1530 g_clear_error(&rc);
1531 continue;
1534 gpg_error_t ret;
1535 str = parse_rcfile_keyfile(*p, FALSE, &ret);
1537 if (!str)
1538 continue;
1540 do_cache_push(*p, str);
1541 gcry_free(str);
1544 g_strfreev(groups);
1545 return TRUE;
1548 static gboolean do_cache_push(const gchar *filename, const gchar *password)
1550 guchar md5file[16];
1551 gint timeout;
1552 const gchar *p = filename;
1553 struct client_crypto_s *crypto;
1554 gpg_error_t rc;
1556 while (isspace(*p))
1557 p++;
1559 if (!*p)
1560 return FALSE;
1562 if (valid_filename(p) == FALSE) {
1563 log_write(N_("%s: Invalid characters in filename"), p);
1564 return FALSE;
1567 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, p, strlen(p));
1569 if (access(p, R_OK|W_OK) != 0) {
1570 log_write("%s: %s", p, strerror(errno));
1571 return FALSE;
1574 crypto = init_client_crypto();
1576 if (!crypto)
1577 return FALSE;
1579 crypto->fh = read_file_header(filename, FALSE, &rc);
1581 if (!crypto->fh) {
1582 log_write("%s: %s", p, pwmd_strerror(rc));
1583 cleanup_crypto(&crypto);
1584 return FALSE;
1587 crypto->key = gcry_malloc(gcrykeysize);
1589 if (!crypto->key) {
1590 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1591 cleanup_crypto(&crypto);
1592 return FALSE;
1595 log_write(N_("Adding '%s' to the file cache ..."), filename);
1597 if (crypto->fh->fh2.iter <= 0) {
1598 memset(crypto->key, '!', gcrykeysize);
1599 goto try_decrypt;
1602 if (!password) {
1603 rc = get_password(p, crypto, md5file, crypto->key, PINENTRY_OPEN);
1605 if (rc) {
1606 send_error(NULL, rc);
1607 cleanup_crypto(&crypto);
1608 return FALSE;
1611 gcry_free(crypto->fh->doc);
1612 crypto->fh->doc = NULL;
1614 else
1615 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, password,
1616 strlen(password) ? strlen(password) : 1);
1618 try_decrypt:
1619 rc = try_xml_decrypt(NULL, crypto->key, crypto, NULL, NULL);
1621 if (rc) {
1622 log_write("%s: %s", filename, pwmd_strerror(rc));
1623 cleanup_crypto(&crypto);
1624 return FALSE;
1627 if (cache_update_key(md5file, crypto->key) == FALSE) {
1628 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1629 cleanup_crypto(&crypto);
1630 return FALSE;
1633 timeout = get_key_file_integer(p, "cache_timeout");
1634 cache_set_timeout(md5file, timeout);
1635 log_write(N_("File '%s' now cached"), filename);
1636 cleanup_crypto(&crypto);
1637 return TRUE;
1640 static void init_new_connection(gint fd, gchar *addr)
1642 pthread_t tid;
1643 pthread_attr_t attr;
1644 struct client_thread_s *new;
1645 int n;
1647 new = g_malloc0(sizeof(struct client_thread_s));
1649 if (!new) {
1650 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1651 return;
1654 MUTEX_LOCK(&cn_mutex);
1655 new->fd = fd;
1657 #ifdef WITH_GNUTLS
1658 if (addr)
1659 new->remote = TRUE;
1660 #endif
1662 pthread_attr_init(&attr);
1663 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1664 n = pthread_create(&tid, &attr, client_thread, new);
1665 pthread_attr_destroy(&attr);
1667 if (n) {
1668 g_free(new);
1669 log_write("pthread_create(): %s", strerror(n));
1670 MUTEX_UNLOCK(&cn_mutex);
1671 return;
1674 new->tid = tid;
1675 cn_thread_list = g_slist_append(cn_thread_list, new);
1676 MUTEX_UNLOCK(&cn_mutex);
1678 if (addr)
1679 log_write(N_("new connection: fd=%i, addr=%s"), fd, addr);
1680 else
1681 log_write(N_("new connection: fd=%i"), fd);
1684 #ifdef WITH_GNUTLS
1685 /* From Beej's Guide to Network Programming. It's a good tutorial. */
1686 static void *get_in_addr(struct sockaddr *sa)
1688 if (sa->sa_family == AF_INET)
1689 return &(((struct sockaddr_in*)sa)->sin_addr);
1691 return &(((struct sockaddr_in6*)sa)->sin6_addr);
1694 static void *tcp_accept_thread(void *arg)
1696 gint sockfd = (gint)arg;
1698 for (;;) {
1699 struct sockaddr_storage raddr;
1700 socklen_t slen = sizeof(raddr);
1701 gint fd = -1;
1702 gulong n;
1703 gchar *t;
1705 fd = accept(sockfd, (struct sockaddr *)&raddr, &slen);
1706 pthread_testcancel();
1708 if (fd == -1) {
1709 if (errno != EAGAIN) {
1710 if (!quit) // probably EBADF
1711 log_write("accept(): %s", strerror(errno));
1713 break;
1716 continue;
1719 if (quit)
1720 break;
1722 if (fd >= 0) {
1723 gchar s[INET6_ADDRSTRLEN];
1725 inet_ntop(raddr.ss_family, get_in_addr((struct sockaddr *)&raddr),
1726 s, sizeof s);
1727 init_new_connection(fd, s);
1730 t = get_key_file_string("global", "tcp_wait");
1731 n = strtol(t, NULL, 10);
1732 g_free(t);
1734 if (n < 0)
1735 n = 0;
1737 usleep(n*100000);
1740 /* Just in case accept() failed for some reason other than EBADF */
1741 quit = 1;
1742 pthread_exit(PTHREAD_CANCELED);
1743 return NULL;
1745 #endif
1747 static void *accept_thread(void *arg)
1749 gint sockfd = (gint)arg;
1751 for (;;) {
1752 socklen_t slen = sizeof(struct sockaddr_un);
1753 struct sockaddr_un raddr;
1754 gint fd = -1;
1756 fd = accept(sockfd, (struct sockaddr *)&raddr, &slen);
1757 pthread_testcancel();
1759 if (fd == -1) {
1760 if (errno != EAGAIN) {
1761 if (!quit) // probably EBADF
1762 log_write("accept(): %s", strerror(errno));
1764 break;
1767 continue;
1770 if (fd >= 0)
1771 init_new_connection(fd, NULL);
1774 /* Just in case accept() failed for some reason other than EBADF */
1775 quit = 1;
1776 pthread_exit(PTHREAD_CANCELED);
1777 return NULL;
1780 static void *adjust_cache_timer_thread(void *arg)
1782 for (;;) {
1783 sleep(1);
1784 pthread_testcancel();
1785 CACHE_LOCK(NULL);
1786 cache_adjust_timer();
1787 CACHE_UNLOCK;
1790 return NULL;
1793 static void *keepalive_thread(void *arg)
1795 struct timespec ts;
1796 gint to = (gint)arg;
1798 for (;;) {
1799 clock_gettime(CLOCK_REALTIME, &ts);
1800 ts.tv_sec += to;
1801 pthread_cond_timedwait(&keepalive_cond, &keepalive_cond_mutex, &ts);
1802 pthread_testcancel();
1803 send_status_all(STATUS_KEEPALIVE);
1806 return NULL;
1809 static void startStopKeepAlive(gboolean term)
1811 pthread_attr_t attr;
1812 gint n = get_key_file_integer("global", "keepalive");
1814 if (keepalive_tid)
1815 pthread_cancel(keepalive_tid);
1817 keepalive_tid = 0;
1818 pthread_mutex_trylock(&keepalive_cond_mutex);
1820 if (term)
1821 return;
1823 if (n > 0) {
1824 pthread_attr_init(&attr);
1825 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1826 pthread_create(&keepalive_tid, &attr, keepalive_thread, (void *)n);
1827 pthread_attr_destroy(&attr);
1831 static void server_loop(gint sockfd, gchar **socketpath)
1833 pthread_t accept_tid;
1834 guint n;
1835 sigset_t sigset;
1836 gint n_clients = 0;
1837 pthread_attr_t attr;
1838 pthread_t cache_timeout_tid;
1839 pthread_mutexattr_t mattr;
1841 sigemptyset(&sigset);
1843 /* Termination */
1844 sigaddset(&sigset, SIGTERM);
1845 sigaddset(&sigset, SIGINT);
1847 /* Clears the file cache. */
1848 sigaddset(&sigset, SIGUSR1);
1850 /* Configuration file reloading. */
1851 sigaddset(&sigset, SIGHUP);
1853 /* Caught in client_thread(). Sends a cache status message. */
1854 sigaddset(&sigset, SIGUSR2);
1856 /* Ignored everywhere. When a client disconnects abnormally this signal
1857 * gets raised. It isn't needed though because client_thread() will check
1858 * for rcs even after the client disconnects. */
1859 signal(SIGPIPE, SIG_IGN);
1860 sigprocmask(SIG_BLOCK, &sigset, NULL);
1862 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1863 pthread_mutexattr_init(&mattr);
1864 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
1865 pthread_mutex_init(&cn_mutex, &mattr);
1866 pthread_mutexattr_destroy(&mattr);
1867 log_write(N_("%s started for user %s"), PACKAGE_STRING, g_get_user_name());
1868 pthread_attr_init(&attr);
1869 pthread_create(&accept_tid, &attr, accept_thread, (void *)sockfd);
1870 startStopKeepAlive(FALSE);
1871 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1872 pthread_create(&cache_timeout_tid, &attr, adjust_cache_timer_thread, NULL);
1873 pthread_attr_destroy(&attr);
1874 pthread_mutex_init(&reload_rcfile_mutex, NULL);
1876 do {
1877 gint sig;
1879 sigwait(&sigset, &sig);
1880 log_write(N_("caught signal %i (%s)"), sig, strsignal(sig));
1882 /* Caught a signal. */
1883 switch (sig) {
1884 case SIGHUP:
1885 reload_rcfile();
1886 break;
1887 case SIGABRT:
1888 CACHE_LOCK(NULL);
1889 cache_clear(NULL, 2);
1890 CACHE_UNLOCK;
1891 #ifndef MEM_DEBUG
1892 xpanic();
1893 #endif
1894 exit(EXIT_FAILURE);
1895 case SIGUSR1:
1896 CACHE_LOCK(NULL);
1897 log_write(N_("clearing file cache"));
1898 cache_clear(NULL, 2);
1899 CACHE_UNLOCK;
1900 break;
1901 default:
1902 quit = 1;
1903 break;
1905 } while (!quit);
1908 * We're out of the main server loop. This happens when a signal was sent
1909 * to terminate the daemon. We'll wait for all clients to disconnect
1910 * before exiting and ignore any following signals.
1912 shutdown(sockfd, SHUT_RDWR);
1913 close(sockfd);
1914 pthread_cancel(accept_tid);
1915 pthread_join(accept_tid, NULL);
1916 #ifdef WITH_GNUTLS
1917 startStopTcp(TRUE);
1918 #endif
1919 unlink(*socketpath);
1920 g_free(*socketpath);
1921 *socketpath = NULL;
1922 MUTEX_LOCK(&cn_mutex);
1923 n = g_slist_length(cn_thread_list);
1924 MUTEX_UNLOCK(&cn_mutex);
1926 if (n)
1927 log_write(N_("waiting for all clients to disconnect"));
1929 while (n) {
1930 if (n != n_clients) {
1931 log_write(N_("%i clients remain"), n);
1932 n_clients = n;
1935 sleep(1);
1936 MUTEX_LOCK(&cn_mutex);
1937 n = g_slist_length(cn_thread_list);
1938 MUTEX_UNLOCK(&cn_mutex);
1941 startStopKeepAlive(TRUE);
1942 pthread_cancel(cache_timeout_tid);
1943 cache_free();
1947 * Called from pinentry_fork() in the child process.
1949 void free_client_list()
1951 gint i, t = g_slist_length(cn_thread_list);
1953 for (i = 0; i < t; i++) {
1954 struct client_thread_s *cn = g_slist_nth_data(cn_thread_list, i);
1956 free_client(cn->cl);
1959 cache_free();
1962 struct client_crypto_s *init_client_crypto()
1964 struct client_crypto_s *new = g_malloc0(sizeof(struct client_crypto_s));
1965 gpg_error_t rc;
1967 if (!new) {
1968 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1969 return NULL;
1972 rc = gcry_cipher_open(&new->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
1974 if (rc) {
1975 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
1976 g_free(new);
1977 return NULL;
1980 return new;
1983 static gpg_error_t convert_file(const gchar *filename, const gchar *keyfile,
1984 const gchar *outfile)
1986 gpg_error_t rc;
1987 guchar md5file[16];
1988 guint iter;
1989 struct client_crypto_s *crypto = init_client_crypto();
1991 if (!crypto)
1992 return GPG_ERR_ENOMEM;
1994 crypto->key = gcry_malloc(gcrykeysize);
1996 if (!crypto->key) {
1997 cleanup_crypto(&crypto);
1998 return GPG_ERR_ENOMEM;
2001 log_write(N_("Converting version 1 data file '%s' to version 2 ..."),
2002 filename);
2003 crypto->fh = read_file_header(filename, TRUE, &rc);
2005 if (!crypto->fh)
2006 goto done;
2008 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, filename, strlen(filename));
2010 /* The header in version 1 had a bug where the iterations were off-by-one.
2011 * So 0 iterations was really -1 in the header. This is fixed in v2 of the
2012 * header.
2014 if (crypto->fh->fh1.iter >= 0) {
2015 if (keyfile) {
2016 crypto->tkey = parse_rcfile_keyfile(keyfile, TRUE, &rc);
2018 if (!crypto->tkey)
2019 goto done;
2021 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, crypto->tkey,
2022 strlen(crypto->tkey) ? strlen(crypto->tkey) : 1);
2024 else {
2025 rc = get_password(filename, crypto, md5file, crypto->key,
2026 PINENTRY_OPEN);
2028 if (rc)
2029 goto done;
2033 rc = try_xml_decrypt(NULL, crypto->key, crypto, &crypto->fh->doc,
2034 &crypto->fh->len);
2036 if (rc)
2037 goto done;
2039 rc = convert_xml((gchar **)&crypto->fh->doc, &crypto->fh->len);
2041 if (rc) {
2042 log_write("%s: %s", filename, pwmd_strerror(rc));
2043 goto done;
2046 crypto->fh->v1 = FALSE;
2047 iter = crypto->fh->fh1.iter;
2048 memset(&crypto->fh->fh2, 0, sizeof(crypto->fh->fh2));
2049 /* Keep the iterations and key from the original file. */
2050 crypto->fh->fh2.iter = iter+1; // Bugfix for v1 data files.
2051 rc = export_common(outfile, crypto, crypto->fh->doc, crypto->fh->len);
2053 done:
2054 if (rc)
2055 send_error(NULL, rc);
2057 /* fh->doc is freed from do_xml_decrypt() via the inbuf pointer. */
2058 cleanup_crypto(&crypto);
2059 return rc;
2062 #ifdef WITH_GNUTLS
2063 static gboolean startStopTcp(gboolean term)
2065 struct addrinfo hints, *servinfo, *p;
2066 gint port = get_key_file_integer("global", "tcp_port");
2067 char buf[7];
2068 int n;
2069 pthread_attr_t attr;
2071 if (term || get_key_file_boolean("global", "enable_tcp") == FALSE) {
2072 if (tcpSockFd != -1) {
2073 pthread_cancel(tcpAcceptTid);
2074 pthread_join(tcpAcceptTid, NULL);
2075 shutdown(tcpSockFd, SHUT_RDWR);
2076 close(tcpSockFd);
2077 tcpSockFd = -1;
2079 /* A client may still be connected. */
2080 if (!quit)
2081 deinitTlsParams();
2084 return TRUE;
2087 if (tcpSockFd != -1)
2088 return TRUE;
2090 memset(&hints, 0, sizeof(hints));
2091 hints.ai_family = AF_UNSPEC;
2092 hints.ai_socktype = SOCK_STREAM;
2093 hints.ai_flags = AI_PASSIVE;
2095 if ((n = getaddrinfo(NULL, print_fmt(buf, sizeof(buf), "%i", port),
2096 &hints, &servinfo)) == -1) {
2097 log_write("getaddrinfo(): %s", gai_strerror(n));
2098 return FALSE;
2101 for(p = servinfo; p != NULL; p = p->ai_next) {
2102 if ((tcpSockFd = socket(p->ai_family, p->ai_socktype,
2103 p->ai_protocol)) == -1) {
2104 log_write("socket(): %s", strerror(errno));
2105 continue;
2108 n = 1;
2110 if (setsockopt(tcpSockFd, SOL_SOCKET, SO_REUSEADDR, &n,
2111 sizeof(int)) == -1) {
2112 log_write("setsockopt(): %s", strerror(errno));
2113 freeaddrinfo(servinfo);
2114 goto fail;
2117 if (bind(tcpSockFd, p->ai_addr, p->ai_addrlen) == -1) {
2118 close(tcpSockFd);
2119 log_write("bind(): %s", strerror(errno));
2120 continue;
2123 n++;
2124 break;
2127 freeaddrinfo(servinfo);
2129 if (!p) {
2130 log_write("%s", N_("could not bind"));
2131 goto fail;
2134 if (g_key_file_has_key(keyfileh, "global", "tcp_interface", NULL)) {
2135 gchar *tmp = get_key_file_string("global", "tcp_interface");
2137 if (setsockopt(tcpSockFd, SOL_SOCKET, SO_BINDTODEVICE, tmp, 1)
2138 == -1) {
2139 log_write("setsockopt(): %s", strerror(errno));
2140 g_free(tmp);
2141 goto fail;
2144 g_free(tmp);
2147 if (!initTlsParams())
2148 goto fail;
2150 if (listen(tcpSockFd, 0) == -1) {
2151 log_write("listen(): %s", strerror(errno));
2152 goto fail;
2155 pthread_attr_init(&attr);
2156 pthread_create(&tcpAcceptTid, &attr, tcp_accept_thread, (void *)tcpSockFd);
2157 pthread_attr_destroy(&attr);
2158 return TRUE;
2160 fail:
2161 deinitTlsParams();
2163 if (tcpSockFd != -1)
2164 close(tcpSockFd);
2166 tcpSockFd = -1;
2167 return FALSE;
2169 #endif
2171 int main(int argc, char *argv[])
2173 gint opt;
2174 struct sockaddr_un addr;
2175 struct passwd *pw = getpwuid(getuid());
2176 gchar buf[PATH_MAX];
2177 gchar *socketpath = NULL, *socketdir, *socketname = NULL;
2178 gchar *socketarg = NULL;
2179 gchar *datadir = NULL;
2180 gboolean n;
2181 gchar *p;
2182 gchar **cache_push = NULL;
2183 gint iter = 0;
2184 gchar *import = NULL, *keyfile = NULL;
2185 gulong cmd_iterations = -1;
2186 gint default_timeout;
2187 gboolean rcfile_spec = FALSE;
2188 gint estatus = EXIT_FAILURE;
2189 gint sockfd;
2190 gchar *outfile = NULL;
2191 GMemVTable mtable = { xmalloc, xrealloc, xfree, xcalloc, NULL, NULL };
2192 gint do_unlink = 1;
2193 gboolean secure = FALSE;
2194 guint ptotal = 0;
2195 gint background = 1;
2196 gchar *convert = NULL;
2197 pthread_mutexattr_t mattr;
2198 #ifdef WITH_PINENTRY
2199 gboolean disable_pinentry = FALSE;
2200 #endif
2201 #ifdef WITH_GNUTLS
2202 struct assuan_io_hooks io_hooks = {read_hook, write_hook};
2203 #endif
2204 #if 0
2205 #ifndef DEBUG
2206 #ifdef HAVE_SETRLIMIT
2207 struct rlimit rl;
2209 rl.rlim_cur = rl.rlim_max = 0;
2211 if (setrlimit(RLIMIT_CORE, &rl) != 0)
2212 err(EXIT_FAILURE, "setrlimit()");
2213 #endif
2214 #endif
2215 #endif
2217 #ifdef ENABLE_NLS
2218 setlocale(LC_ALL, "");
2219 bindtextdomain("pwmd", LOCALEDIR);
2220 textdomain("pwmd");
2221 #endif
2223 #ifndef MEM_DEBUG
2224 xmem_init();
2225 #endif
2226 gpg_err_init();
2227 assuan_set_assuan_err_source(GPG_ERR_SOURCE_DEFAULT);
2228 g_mem_set_vtable(&mtable);
2229 assuan_set_malloc_hooks(xmalloc, xrealloc, xfree);
2230 xmlMemSetup(xfree, xmalloc, xrealloc, xstrdup);
2231 xmlInitMemory();
2232 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
2233 gcry_check_version(GCRYPT_VERSION);
2234 #ifdef WITH_GNUTLS
2235 gnutls_global_set_mem_functions(xmalloc, xmalloc, gcry_SecureCheck,
2236 xrealloc, xfree);
2237 gnutls_global_init();
2238 gnutls_global_set_log_function(tls_log);
2239 gnutls_global_set_log_level(1);
2240 assuan_set_io_hooks(&io_hooks);
2241 #endif
2242 xmlInitGlobals();
2243 xmlInitParser();
2244 xmlXPathInit();
2245 g_snprintf(buf, sizeof(buf), "%s/.pwmd", pw->pw_dir);
2247 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2248 err(EXIT_FAILURE, "%s", buf);
2250 g_snprintf(buf, sizeof(buf), "%s/.pwmd/data", pw->pw_dir);
2252 if (mkdir(buf, 0700) == -1 && errno != EEXIST)
2253 err(EXIT_FAILURE, "%s", buf);
2255 rcfile = g_strdup_printf("%s/.pwmd/config", pw->pw_dir);
2256 cmdline = TRUE;
2257 #ifdef WITH_GNUTLS
2258 tcpSockFd = -1;
2259 #endif
2261 while ((opt = getopt(argc, argv, "Po:C:nI:i:k:hvf:D")) != EOF) {
2262 switch (opt) {
2263 #ifdef WITH_PINENTRY
2264 case 'P':
2265 disable_pinentry = TRUE;
2266 break;
2267 #endif
2268 case 'o':
2269 outfile = optarg;
2270 break;
2271 case 'C':
2272 convert = optarg;
2273 break;
2274 case 'n':
2275 background = 0;
2276 break;
2277 case 'D':
2278 secure = TRUE;
2279 break;
2280 case 'I':
2281 import = optarg;
2282 break;
2283 case 'i':
2284 cmd_iterations = strtol(optarg, NULL, 10);
2285 break;
2286 case 'k':
2287 keyfile = optarg;
2288 break;
2289 case 'f':
2290 g_free(rcfile);
2291 rcfile = g_strdup(optarg);
2292 rcfile_spec = TRUE;
2293 break;
2294 case 'v':
2295 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,
2296 PACKAGE_BUGREPORT,
2297 #ifdef WITH_PINENTRY
2298 "+WITH_PINENTRY\n"
2299 #else
2300 "-WITH_PINENTRY\n"
2301 #endif
2302 #ifdef WITH_QUALITY
2303 "+WITH_QUALITY\n"
2304 #else
2305 "-WITH_QUALITY\n"
2306 #endif
2307 #ifdef WITH_GNUTLS
2308 "+WITH_GNUTLS\n"
2309 #else
2310 "-WITH_GNUTLS\n"
2311 #endif
2312 #ifdef DEBUG
2313 "+DEBUG\n"
2314 #else
2315 "-DEBUG\n"
2316 #endif
2317 #ifdef MEM_DEBUG
2318 "+MEM_DEBUG\n"
2319 #else
2320 "-MEM_DEBUG\n"
2321 #endif
2323 exit(EXIT_SUCCESS);
2324 case 'h':
2325 default:
2326 usage(argv[0]);
2330 if ((keyfileh = parse_rcfile(rcfile_spec)) == NULL)
2331 exit(EXIT_FAILURE);
2333 #ifdef WITH_PINENTRY
2334 if (disable_pinentry == TRUE)
2335 g_key_file_set_boolean(keyfileh, "global", "enable_pinentry", FALSE);
2336 #endif
2338 if (g_key_file_has_key(keyfileh, "global", "syslog", NULL) == TRUE)
2339 log_syslog = g_key_file_get_boolean(keyfileh, "global", "syslog", NULL);
2341 if (log_syslog == TRUE)
2342 openlog("pwmd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
2344 if (g_key_file_has_key(keyfileh, "global", "priority", NULL)) {
2345 iter = g_key_file_get_integer(keyfileh, "global", "priority", NULL);
2346 errno = 0;
2348 if (setpriority(PRIO_PROCESS, 0, iter) == -1) {
2349 log_write("setpriority(): %s", strerror(errno));
2350 goto do_exit;
2354 #ifdef HAVE_MLOCKALL
2355 if (disable_mlock == FALSE && mlockall(MCL_FUTURE) == -1) {
2356 log_write("mlockall(): %s", strerror(errno));
2357 goto do_exit;
2359 #endif
2361 setup_gcrypt();
2363 if (convert) {
2364 if (!outfile)
2365 usage(argv[0]);
2367 opt = convert_file(convert, keyfile, outfile);
2368 g_key_file_free(keyfileh);
2369 g_free(rcfile);
2370 exit(opt ? EXIT_FAILURE : EXIT_SUCCESS);
2373 if (import) {
2374 if (!outfile)
2375 usage(argv[0]);
2377 if (cmd_iterations == -1)
2378 cmd_iterations = get_key_file_integer("global", "iterations");
2380 opt = xml_import(import, outfile, keyfile, cmd_iterations);
2381 g_key_file_free(keyfileh);
2382 g_free(rcfile);
2383 exit(opt == FALSE ? EXIT_FAILURE : EXIT_SUCCESS);
2386 g_key_file_set_list_separator(keyfileh, ',');
2388 if ((p = g_key_file_get_string(keyfileh, "global", "socket_path", NULL)) == NULL)
2389 errx(EXIT_FAILURE, N_("%s: socket_path not defined"), rcfile);
2391 if (*p == '~') {
2392 p++;
2393 g_snprintf(buf, sizeof(buf), "%s%s", g_get_home_dir(), p--);
2394 g_free(p);
2395 socketarg = g_strdup(buf);
2397 else
2398 socketarg = p;
2400 if ((p = g_key_file_get_string(keyfileh, "global", "data_directory", NULL)) == NULL)
2401 errx(EXIT_FAILURE, N_("%s: data_directory not defined"), rcfile);
2403 datadir = expand_homedir(p);
2404 g_free(p);
2406 if (secure == FALSE && g_key_file_has_key(keyfileh, "global", "disable_list_and_dump", NULL) == TRUE) {
2407 n = g_key_file_get_boolean(keyfileh, "global", "disable_list_and_dump", NULL);
2408 disable_list_and_dump = n;
2410 else
2411 disable_list_and_dump = secure;
2413 if (g_key_file_has_key(keyfileh, "global", "cache_timeout", NULL) == TRUE)
2414 default_timeout = g_key_file_get_integer(keyfileh, "global", "cache_timeout", NULL);
2415 else
2416 default_timeout = -1;
2418 setup_logging(keyfileh);
2420 if (g_key_file_has_key(keyfileh, "global", "cache_push", NULL) == TRUE)
2421 cache_push = g_key_file_get_string_list(keyfileh, "global", "cache_push", NULL, NULL);
2423 if (argc != optind) {
2424 if (cache_push)
2425 ptotal = g_strv_length(cache_push);
2427 for (; optind < argc; optind++) {
2428 if (strv_printf(&cache_push, "%s", argv[optind]) == FALSE)
2429 errx(EXIT_FAILURE, "%s", strerror(ENOMEM));
2433 if (strchr(socketarg, '/') == NULL) {
2434 socketdir = g_get_current_dir();
2435 socketname = g_strdup(socketarg);
2436 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2438 else {
2439 socketname = g_strdup(strrchr(socketarg, '/'));
2440 socketname++;
2441 socketarg[strlen(socketarg) - strlen(socketname) -1] = 0;
2442 socketdir = g_strdup(socketarg);
2443 socketpath = g_strdup_printf("%s/%s", socketdir, socketname);
2446 if (chdir(datadir)) {
2447 log_write("%s: %s", datadir, strerror(errno));
2448 unlink(socketpath);
2449 goto do_exit;
2452 if (parse_rcfile_keys() == FALSE)
2453 goto do_exit;
2455 clear_rcfile_keys();
2458 * Set the cache entry for a file. Prompts for the password.
2460 if (cache_push) {
2461 for (opt = 0; cache_push[opt]; opt++)
2462 do_cache_push(cache_push[opt], NULL);
2464 g_strfreev(cache_push);
2465 log_write(background ? N_("Done. Daemonizing...") : N_("Done. Waiting for connections..."));
2469 * bind() doesn't like the full pathname of the socket or any non alphanum
2470 * characters so change to the directory where the socket is wanted then
2471 * create it then change to datadir.
2473 if (chdir(socketdir)) {
2474 log_write("%s: %s", socketdir, strerror(errno));
2475 goto do_exit;
2478 g_free(socketdir);
2480 if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
2481 log_write("socket(): %s", strerror(errno));
2482 goto do_exit;
2485 addr.sun_family = AF_UNIX;
2486 g_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socketname);
2488 if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
2489 log_write("bind(): %s", strerror(errno));
2491 if (errno == EADDRINUSE)
2492 log_write(N_("Either there is another pwmd running or '%s' is a \n"
2493 "stale socket. Please remove it manually."), socketpath);
2495 do_unlink = 0;
2496 goto do_exit;
2499 if (g_key_file_has_key(keyfileh, "global", "socket_perms", NULL) == TRUE) {
2500 gchar *t = g_key_file_get_string(keyfileh, "global", "socket_perms", NULL);
2501 mode_t mode = strtol(t, NULL, 8);
2502 mode_t mask = umask(0);
2504 g_free(t);
2506 if (chmod(socketname, mode) == -1) {
2507 log_write("%s: %s", socketname, strerror(errno));
2508 close(sockfd);
2509 unlink(socketpath);
2510 umask(mask);
2511 goto do_exit;
2514 umask(mask);
2517 g_free(--socketname);
2519 if (chdir(datadir)) {
2520 log_write("%s: %s", datadir, strerror(errno));
2521 close(sockfd);
2522 unlink(socketpath);
2523 goto do_exit;
2526 g_free(datadir);
2527 pthread_mutexattr_init(&mattr);
2528 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
2529 pthread_mutex_init(&cache_mutex, &mattr);
2530 pthread_mutexattr_destroy(&mattr);
2531 pthread_mutex_init(&keepalive_cond_mutex, NULL);
2532 pthread_cond_init(&keepalive_cond, NULL);
2533 #ifdef WITH_PINENTRY
2534 pthread_mutex_init(&pin_mutex, NULL);
2535 #endif
2537 if (listen(sockfd, 0) == -1) {
2538 log_write("listen(): %s", strerror(errno));
2539 goto do_exit;
2542 cmdline = FALSE;
2544 #ifdef WITH_GNUTLS
2545 if (startStopTcp(FALSE) == FALSE)
2546 goto do_exit;
2547 #endif
2549 if (background) {
2550 switch (fork()) {
2551 case -1:
2552 log_write("fork(): %s", strerror(errno));
2553 goto do_exit;
2554 case 0:
2555 close(0);
2556 close(1);
2557 close(2);
2558 setsid();
2559 break;
2560 default:
2561 exit(EXIT_SUCCESS);
2565 server_loop(sockfd, &socketpath);
2566 estatus = EXIT_SUCCESS;
2568 do_exit:
2569 if (socketpath && do_unlink) {
2570 unlink(socketpath);
2571 g_free(socketpath);
2574 #ifdef WITH_GNUTLS
2575 startStopTcp(TRUE);
2576 gnutls_global_deinit();
2577 #endif
2579 g_key_file_free(keyfileh);
2580 g_free(rcfile);
2581 xmlCleanupParser();
2582 xmlCleanupGlobals();
2584 if (estatus == EXIT_SUCCESS)
2585 log_write(N_("pwmd exiting normally"));
2587 #if defined(DEBUG) && !defined(MEM_DEBUG)
2588 xdump();
2589 #endif
2590 #ifndef MEM_DEBUG
2591 xmem_deinit();
2592 #endif
2593 exit(estatus);