More thread cancellation tests (more to come) and thread cleanups. Set
[pwmd.git] / src / commands.c
blobd627fe877f95b90504b1ab08a77b3b5610ab49d8
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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <zlib.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "mem.h"
37 #include "xml.h"
38 #include "common.h"
40 #ifdef WITH_PINENTRY
41 #include "pinentry.h"
42 #endif
44 #include "pwmd_error.h"
45 #include "cache.h"
46 #include "misc.h"
47 #ifdef WITH_GNUTLS
48 #include "tls.h"
49 #endif
50 #include "commands.h"
51 #include "lock.h"
53 static void *z_alloc(void *data, unsigned items, unsigned size)
55 return gcry_calloc(items, size);
58 static void z_free(void *data, void *p)
60 gcry_free(p);
63 static gpg_error_t file_modified(struct client_s *client)
65 struct stat st;
66 gpg_error_t rc;
68 if (client->state != STATE_OPEN)
69 return EPWMD_NO_FILE;
71 rc = lock_file_mutex(client);
73 if (rc)
74 return rc;
76 if (lstat(client->filename, &st) == 0 && client->mtime) {
77 if (client->mtime != st.st_mtime)
78 return EPWMD_FILE_MODIFIED;
81 return 0;
84 static gpg_error_t parse_xml(assuan_context_t ctx)
86 struct client_s *client = assuan_get_pointer(ctx);
88 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
90 if (!client->doc)
91 return EPWMD_LIBXML_ERROR;
93 return 0;
96 void unlock_file_mutex(struct client_s *client)
98 struct file_mutex_s *m;
100 #ifdef WITH_PINENTRY
101 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
102 #else
103 if (client->has_lock == FALSE)
104 #endif
105 return;
107 CACHE_LOCK(client->ctx);
109 if (cache_get_mutex(client->md5file, &m) == FALSE) {
110 CACHE_UNLOCK;
111 return;
114 CACHE_UNLOCK;
115 MUTEX_UNLOCK(&m->mutex);
116 client->has_lock = client->is_lock_cmd = FALSE;
119 gpg_error_t lock_file_mutex(struct client_s *client)
121 struct file_mutex_s *m;
123 if (client->has_lock == TRUE)
124 return 0;
126 CACHE_LOCK(client->ctx);
128 if (cache_get_mutex(client->md5file, &m) == FALSE) {
129 CACHE_UNLOCK;
130 return 0;
133 CACHE_UNLOCK;
135 if (pthread_mutex_trylock(&m->mutex) == EBUSY) {
136 if (client->ctx) {
138 * If a client disconnects unexpectedly while waiting for a
139 * lock, this lets the thread terminate because send_status()
140 * will return an error.
142 while (pthread_mutex_trylock(&m->mutex) == EBUSY) {
143 gpg_error_t rc = send_status(client->ctx, STATUS_LOCKED, NULL);
145 if (rc)
146 return rc;
148 sleep(1);
151 else {
152 MUTEX_LOCK(&m->mutex);
155 else {
156 MUTEX_LOCK_DEBUG;
159 client->has_lock = TRUE;
160 return 0;
163 void free_client(struct client_s *client)
165 if (client->doc)
166 xmlFreeDoc(client->doc);
168 if (client->xml)
169 gcry_free(client->xml);
171 if (client->filename)
172 g_free(client->filename);
174 if (client->crypto)
175 cleanup_crypto(&client->crypto);
178 void cleanup_client(struct client_s *client)
180 assuan_context_t ctx = client->ctx;
181 struct client_thread_s *thd = client->thd;
182 gboolean has_lock = client->has_lock;
183 #ifdef WITH_PINENTRY
184 struct pinentry_s *pin = client->pinentry;
185 #endif
187 unlock_file_mutex(client);
188 CACHE_LOCK(client->ctx);
189 cache_decr_refcount(client->md5file);
192 * This may be a new file so don't use a cache slot. save_command() will
193 * set this to FALSE on success.
195 if (client->new == TRUE)
196 cache_clear(client->md5file, 1);
198 free_client(client);
199 memset(client, 0, sizeof(struct client_s));
200 client->state = STATE_CONNECTED;
201 client->ctx = ctx;
202 client->thd = thd;
203 client->freed = TRUE;
204 #ifdef WITH_PINENTRY
205 client->pinentry = pin;
206 #endif
207 client->has_lock = has_lock;
208 CACHE_UNLOCK;
211 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
212 gpointer *out, gulong *outsize, gint *rc)
214 z_stream z;
215 gpointer pout;
216 gz_header h;
217 gchar buf[17];
219 z.zalloc = z_alloc;
220 z.zfree = z_free;
221 z.next_in = in;
222 z.avail_in = (uInt)insize;
223 z.avail_out = zlib_bufsize;
224 z.next_out = pout = gcry_malloc(zlib_bufsize);
226 if (!pout) {
227 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
228 *rc = Z_MEM_ERROR;
229 return FALSE;
232 *rc = inflateInit2(&z, 47);
234 if (*rc != Z_OK) {
235 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
236 gcry_free(pout);
237 return FALSE;
240 memset(&h, 0, sizeof(gz_header));
241 h.comment = (guchar *)buf;
242 h.comm_max = sizeof(buf);
243 *rc = inflateGetHeader(&z, &h);
245 if (*rc != Z_OK) {
246 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
247 gcry_free(pout);
248 inflateEnd(&z);
249 return FALSE;
252 *rc = inflate(&z, Z_BLOCK);
254 if (*rc != Z_OK) {
255 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
256 gcry_free(pout);
257 inflateEnd(&z);
258 return FALSE;
261 if (h.comment)
262 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
264 do {
265 gpointer p;
267 *rc = inflate(&z, Z_FINISH);
269 switch (*rc) {
270 case Z_OK:
271 break;
272 case Z_BUF_ERROR:
273 if (!z.avail_out) {
274 p = gcry_realloc(pout, z.total_out + zlib_bufsize);
276 if (!p) {
277 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
278 *rc = Z_MEM_ERROR;
279 goto fail;
282 pout = p;
283 z.next_out = pout + z.total_out;
284 z.avail_out = zlib_bufsize;
285 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
286 z.total_out, insize);
287 if (*rc)
288 goto fail;
290 break;
291 case Z_STREAM_END:
292 break;
293 default:
294 goto fail;
295 break;
297 } while (*rc != Z_STREAM_END);
299 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", z.total_out,
300 insize);
302 if (*rc)
303 goto fail;
305 *out = pout;
306 *outsize = z.total_out;
307 inflateEnd(&z);
308 *rc = 0;
309 return TRUE;
311 fail:
312 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
313 gcry_free(pout);
314 inflateEnd(&z);
315 return FALSE;
318 static void read_file_header_handler(void *arg)
320 close((int)arg);
323 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
324 gpg_error_t *rc)
326 gint fd;
327 gsize len;
328 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
329 gsize fh_size;
331 *rc = 0;
333 if (!fh) {
334 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
335 *rc = gpg_error_from_errno(ENOMEM);
336 return NULL;
339 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
341 if (lstat(filename, &fh->st) == -1) {
342 *rc = gpg_error_from_syserror();
343 g_free(fh);
344 return NULL;
347 if (!S_ISREG(fh->st.st_mode)) {
348 *rc = GPG_ERR_ENOANO;
349 g_free(fh);
350 return NULL;
353 fd = open(filename, O_RDONLY);
355 if (fd == -1) {
356 *rc = gpg_error_from_errno(errno);
357 g_free(fh);
358 return NULL;
361 if (v1)
362 len = read(fd, &fh->fh1, fh_size);
363 else
364 len = read(fd, &fh->fh2, fh_size);
366 if (len != fh_size) {
367 gint n = errno;
368 pthread_cleanup_push(read_file_header_handler, (void *)fd);
369 g_free(fh);
370 pthread_cleanup_pop(1);
371 *rc = gpg_error_from_errno(n);
372 return NULL;
375 fh->v1 = v1;
376 fh->fd = fd;
377 return fh;
380 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
381 gboolean cached)
383 struct client_s *client = assuan_get_pointer(ctx);
384 gpg_error_t rc;
385 gint timeout;
387 /* New file. */
388 if (!client->crypto->fh) {
389 if (key[0])
390 goto update_cache;
392 goto done;
395 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
397 if (rc) {
398 cleanup_client(client);
399 return send_error(ctx, rc);
402 update_cache:
403 CACHE_LOCK(client->ctx);
405 if (cached == FALSE) {
406 if (cache_update_key(client->md5file, key) == FALSE) {
407 cleanup_client(client);
408 CACHE_UNLOCK;
409 return send_syserror(ctx, ENOMEM);
412 timeout = get_key_file_integer(client->filename, "cache_timeout");
413 cache_reset_timeout(client->md5file, timeout);
415 else
416 cache_set_timeout(client->md5file, -2);
418 CACHE_UNLOCK;
420 done:
421 rc = parse_xml(ctx);
423 if (client->xml) {
424 gcry_free(client->xml);
425 client->xml = NULL;
428 if (!rc) {
429 if (client->new == FALSE)
430 send_status_all(STATUS_CACHE);
432 client->state = STATE_OPEN;
435 if (!rc && client->new == FALSE &&
436 client->crypto->fh->fh2.iter != (guint)get_key_file_integer(client->filename, "iterations")) {
437 g_key_file_set_integer(keyfileh, client->filename, "iterations",
438 client->crypto->fh->fh2.iter);
439 send_status_all(STATUS_CONFIG);
442 if (!rc)
443 log_write("OPEN '%s'", client->filename);
445 cleanup_crypto(&client->crypto);
446 return send_error(ctx, rc);
449 #ifdef WITH_GNUTLS
450 static gboolean validate_access(struct client_s *cl, const gchar *filename)
452 gchar *access = get_key_file_string(filename, "tcp_access");
453 gchar **list, **p;
455 if (!access)
456 return TRUE;
458 list = g_strsplit(access, ",", -1);
459 g_free(access);
461 if (!list) {
462 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
463 return FALSE;
466 for (p = list; *p; p++) {
467 gboolean not = FALSE;
468 gchar *fp = *p;
470 if (*fp == '!') {
471 not = TRUE;
472 fp++;
474 if (!*fp)
475 break;
478 if (strcasecmp(cl->thd->tls->fp, fp) == 0) {
479 if (not == TRUE)
480 continue;
482 g_strfreev(list);
483 return TRUE;
487 /* Not allowed. */
488 g_strfreev(list);
489 return FALSE;
491 #endif
493 static void open_command_cleanup_handler(void *arg)
495 g_strfreev((gchar **)arg);
498 static int open_command(assuan_context_t ctx, char *line)
500 gboolean cached = FALSE;
501 gpg_error_t rc;
502 struct client_s *client = assuan_get_pointer(ctx);
503 gchar **req;
504 gchar *filename = NULL;
506 if ((req = split_input_line(line, " ", 2)) != NULL)
507 filename = req[0];
509 pthread_cleanup_push(open_command_cleanup_handler, req);
511 if (!filename || !*filename) {
512 g_strfreev(req);
513 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
516 if (valid_filename(filename) == FALSE) {
517 g_strfreev(req);
518 return send_error(ctx, EPWMD_INVALID_FILENAME);
521 if (client->state == STATE_OPEN)
522 cleanup_client(client);
524 #ifdef WITH_GNUTLS
525 if (client->thd->remote == TRUE) {
526 if (validate_access(client, filename) == FALSE) {
527 log_write(N_("client validation failed for file '%s'"), filename);
528 g_strfreev(req);
529 return send_error(ctx, EPWMD_FILE_ACCESS);
532 #endif
534 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
535 CACHE_LOCK(client->ctx);
537 if (cache_has_file(client->md5file) == FALSE) {
538 if (cache_add_file(client->md5file, NULL) == FALSE) {
539 g_strfreev(req);
540 CACHE_UNLOCK;
541 return send_syserror(ctx, ENOMEM);
545 cache_incr_refcount(client->md5file);
546 CACHE_UNLOCK;
547 rc = lock_file_mutex(client);
549 if (rc) {
550 g_strfreev(req);
551 return send_error(ctx, rc);
554 client->freed = FALSE;
555 client->crypto = init_client_crypto();
557 if (!client->crypto) {
558 g_strfreev(req);
559 cleanup_client(client);
560 return send_syserror(ctx, ENOMEM);
563 client->crypto->key = gcry_malloc(gcrykeysize);
565 if (!client->crypto->key) {
566 g_strfreev(req);
567 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
568 gpg_error_from_errno(ENOMEM));
569 cleanup_client(client);
570 return send_syserror(ctx, ENOMEM);
573 memset(client->crypto->key, 0, gcrykeysize);
574 client->crypto->fh = read_file_header(filename, FALSE, &rc);
575 pthread_testcancel();
577 if (!client->crypto->fh) {
578 if (gpg_err_code_to_errno(rc) != ENOENT) {
579 log_write("%s: %s", filename, pwmd_strerror(rc));
580 g_strfreev(req);
581 cleanup_client(client);
582 return send_error(ctx, rc);
586 * New files don't need a key.
588 if ((client->xml = new_document()) == NULL) {
589 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
590 g_strfreev(req);
591 cleanup_client(client);
592 return send_syserror(ctx, ENOMEM);
595 client->len = xmlStrlen(client->xml);
596 client->new = TRUE;
597 client->filename = g_strdup(filename);
599 if (!client->filename) {
600 g_strfreev(req);
601 cleanup_client(client);
602 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
603 return send_syserror(ctx, ENOMEM);
606 if (req[1] && *req[1])
607 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
608 strlen(req[1]));
610 g_strfreev(req);
611 #ifdef WITH_PINENTRY
612 client->pinentry->filename = g_strdup(client->filename);
614 if (!client->pinentry->filename) {
615 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
616 cleanup_client(client);
617 return send_syserror(ctx, ENOMEM);
619 #endif
620 return open_command_finalize(ctx, client->crypto->key, cached);
622 else
623 client->mtime = client->crypto->fh->st.st_mtime;
625 client->filename = g_strdup(filename);
627 if (!client->filename) {
628 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
629 g_strfreev(req);
630 cleanup_client(client);
631 return send_syserror(ctx, ENOMEM);
634 #ifdef WITH_PINENTRY
635 client->pinentry->filename = g_strdup(client->filename);
637 if (!client->pinentry->filename) {
638 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
639 g_strfreev(req);
640 cleanup_client(client);
641 return send_syserror(ctx, ENOMEM);
643 #endif
645 if (client->crypto->fh->fh2.iter <= 0)
646 goto done;
648 #ifdef WITH_GNUTLS
649 if (client->thd->remote == FALSE ||
650 get_key_file_boolean(client->filename, "tcp_require_key") == FALSE)
652 #endif
653 CACHE_LOCK(client->ctx);
654 cached = cache_get_key(client->md5file, client->crypto->key);
655 CACHE_UNLOCK;
656 #ifdef WITH_GNUTLS
658 else
659 cached = FALSE;
660 #endif
662 if (cached == FALSE) {
663 gchar *tmp = get_key_file_string(filename, "key_file");
665 if (tmp) {
666 g_free(tmp);
667 cleanup_client(client);
668 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
672 * No key specified and no matching filename found in the cache. Use
673 * pinentry to retrieve the key. Cannot return assuan_process_done()
674 * here otherwise the command will be interrupted. The event loop in
675 * client_thread() will poll the file descriptor waiting for it to
676 * become ready to read a pinentry_key_s which will contain the
677 * entered key or an error code. It will then call
678 * open_command_finalize() to to finish the command.
680 if (!req[1] || !*req[1]) {
681 #ifdef WITH_PINENTRY
682 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
684 /* From set_pinentry_defaults(). */
685 if (client->pinentry->enable == FALSE ||
686 (client->pinentry->enable == -1 && b == FALSE)) {
687 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
688 goto done;
691 g_strfreev(req);
692 rc = lock_pin_mutex(client);
694 if (rc) {
695 unlock_pin_mutex(client->pinentry);
696 cleanup_client(client);
697 return send_error(ctx, rc);
700 client->pinentry->which = PINENTRY_OPEN;
701 rc = pinentry_fork(ctx);
703 if (rc) {
704 unlock_pin_mutex(client->pinentry);
705 cleanup_client(client);
706 return send_error(ctx, rc);
709 // Called from pinentry iterate.
710 client->pinentry->cb = open_command_finalize;
711 client->pinentry->status = PINENTRY_INIT;
712 return 0;
713 #else
714 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
715 goto done;
716 #endif
719 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
720 strlen(req[1]));
723 done:
724 if (1) {}
725 pthread_cleanup_pop(1);
726 return open_command_finalize(ctx, client->crypto->key, cached);
729 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
730 gulong size, gpointer *out, gulong *outsize, gint *rc)
732 z_stream z;
733 gpointer pout, pin;
734 gz_header h;
735 gchar buf[17];
736 gint cmd = Z_NO_FLUSH;
738 z.zalloc = z_alloc;
739 z.zfree = z_free;
740 z.next_in = pin = data;
741 z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
742 z.avail_out = (uInt)zlib_bufsize;
743 z.next_out = pout = gcry_malloc(zlib_bufsize);
745 if (!pout) {
746 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
747 *rc = Z_MEM_ERROR;
748 return FALSE;
751 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
753 if (*rc != Z_OK) {
754 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
755 gcry_free(pout);
756 return FALSE;
759 /* Rather than store the size of the uncompressed data in the file header,
760 * store it in the comment field of the gzip header. Don't give anyone too
761 * much information. Not sure why really, but it seems the right way. :)
763 memset(&h, 0, sizeof(gz_header));
764 g_snprintf(buf, sizeof(buf), "%li", size);
765 h.comment = (guchar *)buf;
766 *rc = deflateSetHeader(&z, &h);
768 if (*rc != Z_OK) {
769 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
770 gcry_free(pout);
771 deflateEnd(&z);
772 return FALSE;
775 do {
776 gpointer p;
778 *rc = deflate(&z, cmd);
780 switch (*rc) {
781 case Z_OK:
782 break;
783 case Z_BUF_ERROR:
784 if (!z.avail_out) {
785 p = gcry_realloc(pout, z.total_out + zlib_bufsize);
787 if (!p) {
788 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
789 *rc = Z_MEM_ERROR;
790 goto fail;
793 pout = p;
794 z.next_out = pout + z.total_out;
795 z.avail_out = zlib_bufsize;
798 if (!z.avail_in && z.total_in < size) {
799 if (z.total_in + zlib_bufsize > size)
800 z.avail_in = size - z.total_in;
801 else
802 z.avail_in = zlib_bufsize;
804 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
805 z.total_in, size);
807 if (*rc)
808 goto fail;
811 if (z.total_in >= size)
812 cmd = Z_FINISH;
814 break;
815 case Z_STREAM_END:
816 break;
817 default:
818 goto fail;
820 } while (*rc != Z_STREAM_END);
822 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", z.total_in, size);
824 if (*rc)
825 goto fail;
827 *out = pout;
828 *outsize = z.total_out;
829 deflateEnd(&z);
830 *rc = 0;
831 return TRUE;
833 fail:
834 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
835 gcry_free(pout);
836 deflateEnd(&z);
837 return FALSE;
840 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
842 static gpg_error_t iterate_crypto_once(struct client_s *client,
843 struct client_crypto_s *crypto, status_msg_t which)
845 gpg_error_t rc = 0;
846 gsize len = CRYPTO_BLOCKSIZE;
847 gpointer p = gcry_malloc(len);
848 gsize total = 0;
849 gpointer inbuf;
851 if (!p)
852 return gpg_err_code_from_errno(ENOMEM);
854 pthread_cleanup_push(gcry_free, p);
856 if (crypto->insize < CRYPTO_BLOCKSIZE)
857 len = crypto->insize;
859 for (;;) {
860 inbuf = crypto->inbuf + total;
861 guchar *tmp;
863 if (len + total > crypto->insize)
864 len = gcryblocksize;
866 if (which == STATUS_ENCRYPT)
867 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
868 else
869 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
871 if (rc)
872 goto done;
874 tmp = crypto->inbuf+total;
875 memmove(tmp, p, len);
876 total += len;
878 if (total >= crypto->insize)
879 break;
881 pthread_testcancel();
884 done:
885 if (1) {}
886 pthread_cleanup_pop(1);
887 return rc;
890 /* The crypto struct must be setup for iterations and .key. */
891 gpg_error_t do_xml_encrypt(struct client_s *client,
892 struct client_crypto_s *crypto, const gchar *filename)
894 gsize len = crypto->insize;
895 gpointer inbuf;
896 gchar *p;
897 gpg_error_t rc;
898 guint iter_progress = 0, n_iter = 0, xiter = 0;
899 gchar tmp[FILENAME_MAX];
900 struct stat st;
901 mode_t mode = 0;
903 if (!crypto->fh->fh2.iter) {
905 * cache_file_count() needs both .used == TRUE and a valid key in
906 * order for it to count as a used cache entry. Fixes CACHE status
907 * messages.
909 memset(crypto->key, '!', gcrykeysize);
910 goto write_file;
914 * Resize the existing xml buffer to the block size required by gcrypt
915 * rather than duplicating it and wasting memory.
917 if (crypto->insize / gcryblocksize) {
918 len = (crypto->insize / gcryblocksize) * gcryblocksize;
920 if (crypto->insize % gcryblocksize)
921 len += gcryblocksize;
924 inbuf = gcry_realloc(crypto->inbuf, len);
926 if (!inbuf) {
927 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
928 return gpg_error_from_errno(ENOMEM);
931 crypto->inbuf = inbuf;
932 crypto->insize = len;
933 gcry_create_nonce(crypto->fh->fh2.iv, sizeof(crypto->fh->fh2.iv));
934 crypto->tkey = gcry_malloc(gcrykeysize);
936 if (!crypto->tkey) {
937 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
938 return gpg_error_from_errno(ENOMEM);
941 memcpy(crypto->tkey, crypto->key, gcrykeysize);
942 guchar *tkey = crypto->tkey;
943 tkey[0] ^= 1;
945 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
946 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
947 return rc;
950 iter_progress = get_key_file_integer(client ? client->filename : "global",
951 "iteration_progress");
953 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
954 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
955 "%u %u", 0, crypto->fh->fh2.iter);
957 if (rc)
958 return rc;
961 while (xiter < crypto->fh->fh2.iter-1) {
962 if (iter_progress > 0 && xiter >= iter_progress) {
963 if (!(xiter % iter_progress)) {
964 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
965 "%u %u", ++n_iter * iter_progress, crypto->fh->fh2.iter);
967 if (rc)
968 return rc;
972 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
973 sizeof(crypto->fh->fh2.iv)))) {
974 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
975 return rc;
978 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
980 if (rc) {
981 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
982 return rc;
985 xiter++;
988 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
989 sizeof(crypto->fh->fh2.iv)))) {
990 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
991 return rc;
994 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
995 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
996 return rc;
999 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1001 if (rc)
1002 return rc;
1004 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
1005 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1006 "%u %u", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
1008 if (rc)
1009 return rc;
1012 write_file:
1013 if (filename) {
1014 if (!client && !strcmp(filename, "-")) {
1015 crypto->fh->fd = STDOUT_FILENO;
1016 goto do_write_file;
1019 if (lstat(filename, &st) == 0) {
1020 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1023 * FIXME What if the file has an ACL?
1025 if (!(mode & S_IWUSR))
1026 return gpg_error_from_errno(EACCES);
1028 else {
1029 if (errno != ENOENT)
1030 return gpg_error_from_errno(errno);
1033 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1034 crypto->fh->fd = mkstemp(tmp);
1036 if (crypto->fh->fd == -1) {
1037 rc = errno;
1038 p = strrchr(tmp, '/');
1039 p++;
1040 log_write("%s: %s", p, strerror(rc));
1041 return gpg_error_from_errno(rc);
1044 else
1046 * xml_import() or convert_file() from command line.
1048 crypto->fh->fd = STDOUT_FILENO;
1050 do_write_file:
1051 crypto->fh->fh2.version = VERSION_HEX;
1052 len = write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1054 if (len != sizeof(crypto->fh->fh2)) {
1055 len = errno;
1057 if (filename && strcmp(filename, "-"))
1058 unlink(tmp);
1060 return gpg_error_from_errno(len);
1063 len = write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1065 if (len != crypto->insize) {
1066 len = errno;
1068 if (filename && strcmp(filename, "-"))
1069 unlink(tmp);
1071 return gpg_error_from_errno(len);
1074 if (fsync(crypto->fh->fd) == -1) {
1075 len = errno;
1077 if (filename && strcmp(filename, "-"))
1078 unlink(tmp);
1080 return gpg_error_from_errno(len);
1083 if (filename && strcmp(filename, "-")) {
1084 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1085 gchar tmp2[FILENAME_MAX];
1087 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1089 if (rename(filename, tmp2) == -1) {
1090 unlink(tmp);
1091 len = errno;
1092 return gpg_error_from_errno(len);
1096 if (rename(tmp, filename) == -1) {
1097 len = errno;
1098 unlink(tmp);
1099 return gpg_error_from_errno(len);
1102 if (mode)
1103 chmod(filename, mode);
1106 if (client && lstat(filename, &st) == 0)
1107 client->mtime = st.st_mtime;
1109 return 0;
1112 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1113 gboolean cached)
1115 struct client_s *client = assuan_get_pointer(ctx);
1116 gpointer xmlbuf;
1117 gulong len, outsize = 0;
1118 guint iter;
1119 gint timeout;
1120 gpointer outbuf;
1121 gint zrc;
1122 gpg_error_t rc;
1124 if (client->crypto->key && client->crypto->key != key)
1125 gcry_free(client->crypto->key);
1127 client->crypto->key = key;
1128 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1129 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1131 if (iter < 0)
1132 iter = 0;
1134 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1135 == FALSE) {
1136 if (key != client->crypto->key)
1137 gcry_free(key);
1139 xmlFree(xmlbuf);
1140 cleanup_crypto(&client->crypto);
1142 if (zrc == Z_MEM_ERROR)
1143 return send_syserror(ctx, ENOMEM);
1144 else
1145 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1147 else {
1148 gcry_free(xmlbuf);
1149 xmlbuf = outbuf;
1150 len = outsize;
1153 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1155 if (!client->crypto->fh) {
1156 cleanup_crypto(&client->crypto);
1157 gcry_free(outbuf);
1158 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1159 return send_syserror(ctx, ENOMEM);
1162 iter = get_key_file_integer(client->filename, "iterations");
1163 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1164 client->crypto->inbuf = xmlbuf;
1165 client->crypto->insize = len;
1166 rc = do_xml_encrypt(client, client->crypto, client->filename);
1168 if (rc) {
1169 cleanup_crypto(&client->crypto);
1170 return send_error(ctx, rc);
1173 timeout = get_key_file_integer(client->filename, "cache_timeout");
1174 CACHE_LOCK(client->ctx);
1176 if (cached) {
1177 cache_reset_timeout(client->md5file, timeout);
1178 CACHE_UNLOCK;
1180 if (client->new == TRUE)
1181 send_status_all(STATUS_CACHE);
1183 client->new = FALSE;
1184 cleanup_crypto(&client->crypto);
1185 return send_error(ctx, 0);
1188 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1189 CACHE_UNLOCK;
1190 cleanup_crypto(&client->crypto);
1191 return send_syserror(ctx, ENOMEM);
1194 client->new = FALSE;
1195 cache_reset_timeout(client->md5file, timeout);
1196 CACHE_UNLOCK;
1197 send_status_all(STATUS_CACHE);
1198 cleanup_crypto(&client->crypto);
1199 return send_error(ctx, 0);
1202 static int save_command(assuan_context_t ctx, char *line)
1204 gboolean cached = FALSE;
1205 struct stat st;
1206 struct client_s *client = assuan_get_pointer(ctx);
1207 gpg_error_t rc;
1209 rc = lock_file_mutex(client);
1211 if (rc)
1212 return send_error(ctx, rc);
1214 rc = file_modified(client);
1216 if (rc)
1217 return send_error(ctx, rc);
1219 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1220 return send_syserror(ctx, errno);
1222 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1223 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1224 return send_error(ctx, GPG_ERR_ENOANO);
1227 CACHE_LOCK(ctx);
1228 cached = cache_iscached(client->md5file);
1229 CACHE_UNLOCK;
1232 * If a cache entry doesn't exist for this file and the file has a
1233 * "key_file" or "key" parameter, then it's an error. The reason is that
1234 * cache expiration would be useless.
1236 if (cached == FALSE) {
1237 gchar *tmp = get_key_file_string(client->filename, "key_file");
1239 if (tmp) {
1240 g_free(tmp);
1241 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1245 cached = FALSE;
1246 client->crypto = init_client_crypto();
1248 if (!client->crypto) {
1249 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1250 return send_syserror(ctx, ENOMEM);
1253 client->crypto->key = gcry_malloc(gcrykeysize);
1255 if (!client->crypto->key) {
1256 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1257 cleanup_crypto(&client->crypto);
1258 return send_syserror(ctx, ENOMEM);
1261 memset(client->crypto->key, '!', gcrykeysize);
1263 if (get_key_file_integer(client->filename, "iterations") <= 0)
1264 goto done;
1266 if (!line || !*line) {
1267 client->crypto->tkey = gcry_malloc(gcrykeysize);
1269 if (!client->crypto->tkey) {
1270 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1271 cleanup_crypto(&client->crypto);
1272 return send_syserror(ctx, ENOMEM);
1275 memset(client->crypto->tkey, '!', gcrykeysize);
1276 CACHE_LOCK(ctx);
1278 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1279 memcmp(client->crypto->key, client->crypto->tkey,
1280 gcrykeysize) == 0) {
1281 CACHE_UNLOCK;
1283 #ifdef WITH_PINENTRY
1284 if (client->pinentry->enable == FALSE ||
1285 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1286 /* Empty keys are allowed. */
1287 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1288 goto done;
1291 lock_pin_mutex(client);
1292 client->pinentry->which = PINENTRY_SAVE;
1293 rc = pinentry_fork(ctx);
1295 if (rc) {
1296 unlock_pin_mutex(client->pinentry);
1297 return send_error(ctx, rc);
1300 client->pinentry->cb = save_command_finalize;
1301 client->pinentry->status = PINENTRY_INIT;
1302 return 0;
1303 #else
1304 /* Empty keys are allowed. */
1305 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1306 goto done;
1307 #endif
1309 else {
1310 CACHE_UNLOCK;
1311 cached = TRUE;
1314 else {
1315 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1316 strlen(line));
1317 memset(line, 0, strlen(line));
1320 done:
1321 return save_command_finalize(ctx, client->crypto->key, cached);
1324 static int delete_command(assuan_context_t ctx, char *line)
1326 struct client_s *client = assuan_get_pointer(ctx);
1327 gchar **req;
1328 gpg_error_t rc;
1329 xmlNodePtr n;
1331 rc = file_modified(client);
1333 if (rc)
1334 return send_error(ctx, rc);
1336 if (strchr(line, '\t'))
1337 req = split_input_line(line, "\t", -1);
1338 else
1339 req = split_input_line(line, " ", -1);
1341 if (!req || !*req)
1342 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1344 n = find_account(client->doc, &req, &rc, NULL, 0);
1346 if (!n) {
1347 g_strfreev(req);
1348 return send_error(ctx, rc);
1352 * No sub-node defined. Remove the entire node (account).
1354 if (!req[1]) {
1355 if (n) {
1356 xmlUnlinkNode(n);
1357 xmlFreeNode(n);
1360 g_strfreev(req);
1361 return send_error(ctx, 0);
1364 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1365 g_strfreev(req);
1367 if (!n)
1368 return send_error(ctx, rc);
1370 if (n) {
1371 xmlUnlinkNode(n);
1372 xmlFreeNode(n);
1375 return send_error(ctx, 0);
1379 * Don't return with assuan_process_done() here. This has been called from
1380 * assuan_process_next() and the command should be finished in
1381 * client_thread().
1383 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1384 gsize len)
1386 assuan_context_t ctx = data;
1387 struct client_s *client = assuan_get_pointer(ctx);
1388 gchar **req;
1389 xmlNodePtr n;
1390 gpg_error_t rc = file_modified(client);
1392 if (assuan_rc || rc) {
1393 if (line)
1394 xfree(line);
1395 return assuan_rc ? assuan_rc : rc;
1398 req = split_input_line((gchar *)line, "\t", 0);
1399 xfree(line);
1401 if (!req || !*req)
1402 return EPWMD_COMMAND_SYNTAX;
1404 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1405 g_strfreev(req);
1406 return EPWMD_INVALID_ELEMENT;
1409 if (valid_element_path(req+1, TRUE) == FALSE) {
1410 g_strfreev(req);
1411 return EPWMD_INVALID_ELEMENT;
1414 again:
1415 n = find_account(client->doc, &req, &rc, NULL, 0);
1417 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1418 rc = new_account(client->doc, *req);
1420 if (rc) {
1421 g_strfreev(req);
1422 return rc;
1425 goto again;
1428 if (!n) {
1429 g_strfreev(req);
1430 return rc;
1433 if (req[1]) {
1434 if (!n->children)
1435 create_elements_cb(n, req+1, &rc, NULL);
1436 else
1437 find_elements(client->doc, n->children, req+1, &rc,
1438 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1441 g_strfreev(req);
1442 client->inquire_status = INQUIRE_DONE;
1443 return rc;
1446 static int store_command(assuan_context_t ctx, char *line)
1448 struct client_s *client = assuan_get_pointer(ctx);
1449 gpg_error_t rc = file_modified(client);
1451 if (rc)
1452 return send_error(ctx, rc);
1454 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1456 if (rc)
1457 return send_error(ctx, rc);
1459 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1460 client->inquire_status = INQUIRE_BUSY;
1461 return 0;
1464 static int get_command(assuan_context_t ctx, char *line)
1466 struct client_s *client = assuan_get_pointer(ctx);
1467 gchar **req;
1468 gpg_error_t rc;
1469 xmlNodePtr n;
1471 rc = file_modified(client);
1473 if (rc)
1474 return send_error(ctx, rc);
1476 req = split_input_line(line, "\t", -1);
1478 if (!req || !*req) {
1479 g_strfreev(req);
1480 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1483 n = find_account(client->doc, &req, &rc, NULL, 0);
1485 if (!n) {
1486 g_strfreev(req);
1487 return send_error(ctx, rc);
1490 if (req[1])
1491 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1493 g_strfreev(req);
1495 if (rc)
1496 return send_error(ctx, rc);
1498 if (!n || !n->children)
1499 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1501 n = find_text_node(n->children);
1503 if (!n || !n->content || !*n->content)
1504 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1506 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1507 return send_error(ctx, rc);
1510 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1511 gpg_error_t *rc, gchar **req_orig, void *data)
1513 gchar *path = *(gchar **)data;
1514 gchar *tmp = NULL, *result;
1516 if (path) {
1517 g_free(path);
1518 *(gchar **)data = NULL;
1521 path = g_strjoinv("\t", target);
1523 if (!path) {
1524 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1525 *rc = gpg_error_from_errno(ENOMEM);
1526 return NULL;
1529 if (req_orig) {
1530 tmp = g_strjoinv("\t", req_orig);
1532 if (!tmp) {
1533 g_free(path);
1534 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1535 *rc = gpg_error_from_errno(ENOMEM);
1536 return NULL;
1540 if (tmp && *tmp)
1541 result = g_strdup_printf("%s\t%s", path, tmp);
1542 else
1543 result = g_strdup(path);
1545 if (!result) {
1546 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1547 *rc = gpg_error_from_errno(ENOMEM);
1548 g_free(path);
1549 g_free(tmp);
1550 return NULL;
1553 g_free(path);
1554 g_free(tmp);
1555 *(gchar **)data = result;
1556 return node;
1559 static int realpath_command(assuan_context_t ctx, char *line)
1561 gpg_error_t rc;
1562 struct client_s *client = assuan_get_pointer(ctx);
1563 gchar **req;
1564 gchar *t;
1565 gint i;
1566 xmlNodePtr n;
1567 GString *string;
1568 gchar *rp = NULL;
1570 rc = file_modified(client);
1572 if (rc)
1573 return send_error(ctx, rc);
1575 if (strchr(line, '\t') != NULL) {
1576 if ((req = split_input_line(line, "\t", 0)) == NULL)
1577 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1579 else {
1580 if ((req = split_input_line(line, " ", 0)) == NULL)
1581 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1584 n = find_account(client->doc, &req, &rc, NULL, 0);
1586 if (!n) {
1587 g_strfreev(req);
1588 return send_error(ctx, rc);
1591 rp = g_strjoinv("\t", req);
1593 if (!rp) {
1594 g_strfreev(req);
1595 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1596 return send_syserror(ctx, ENOMEM);
1599 if (req[1]) {
1600 n = find_elements(client->doc, n->children, req+1, &rc,
1601 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1603 if (!n) {
1604 g_free(rp);
1605 g_strfreev(req);
1606 return send_error(ctx, rc);
1610 string = g_string_new(rp);
1611 g_free(rp);
1612 g_strfreev(req);
1614 if (!string) {
1615 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1616 return send_syserror(ctx, ENOMEM);
1619 again:
1620 for (i = 0, t = string->str + i; *t; t++, i++) {
1621 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1622 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1623 goto again;
1627 rc = assuan_send_data(ctx, string->str, string->len);
1628 g_string_free(string, TRUE);
1629 return send_error(ctx, rc);
1632 static int list_command(assuan_context_t ctx, char *line)
1634 struct client_s *client = assuan_get_pointer(ctx);
1635 gpg_error_t rc;
1636 struct element_list_s *elements = NULL;
1637 gchar *tmp;
1639 if (disable_list_and_dump == TRUE)
1640 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1642 rc = file_modified(client);
1644 if (rc)
1645 return send_error(ctx, rc);
1647 if (!*line) {
1648 GString *str;
1650 rc = list_accounts(client->doc, &str);
1652 if (rc)
1653 return send_error(ctx, rc);
1655 rc = assuan_send_data(ctx, str->str, str->len);
1656 g_string_free(str, TRUE);
1657 return send_error(ctx, rc);
1660 elements = g_malloc0(sizeof(struct element_list_s));
1662 if (!elements) {
1663 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1664 rc = gpg_err_code_from_errno(ENOMEM);
1665 goto fail;
1668 rc = create_path_list(client->doc, elements, line);
1670 if (rc)
1671 goto fail;
1673 if (elements) {
1674 gint total = g_slist_length(elements->list);
1675 gint i;
1676 GString *str;
1678 if (!total) {
1679 rc = EPWMD_EMPTY_ELEMENT;
1680 goto fail;
1683 str = g_string_new(NULL);
1685 if (!str) {
1686 rc = gpg_err_code_from_errno(ENOMEM);
1687 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1688 goto fail;
1691 for (i = 0; i < total; i++) {
1692 tmp = g_slist_nth_data(elements->list, i);
1693 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1696 rc = assuan_send_data(ctx, str->str, str->len);
1697 g_string_free(str, TRUE);
1699 else
1700 rc = EPWMD_EMPTY_ELEMENT;
1702 fail:
1703 if (elements) {
1704 gint total = g_slist_length(elements->list);
1705 gint i;
1707 for (i = 0; i < total; i++) {
1708 tmp = g_slist_nth_data(elements->list, i);
1709 g_free(tmp);
1712 g_slist_free(elements->list);
1714 if (elements->prefix)
1715 g_free(elements->prefix);
1717 g_free(elements);
1720 return send_error(ctx, rc);
1723 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1724 const gchar *value)
1726 xmlAttrPtr a;
1728 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1729 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1731 if (!a)
1732 return EPWMD_LIBXML_ERROR;
1734 else
1735 xmlNodeSetContent(a->children, (xmlChar *)value);
1737 return 0;
1741 * req[0] - element path
1743 static int attribute_list(assuan_context_t ctx, gchar **req)
1745 struct client_s *client = assuan_get_pointer(ctx);
1746 gchar **attrlist = NULL;
1747 gint i = 0;
1748 gchar **path = NULL;
1749 xmlAttrPtr a;
1750 xmlNodePtr n, an;
1751 gchar *line;
1752 gpg_error_t rc;
1754 if (!req || !req[0])
1755 return EPWMD_COMMAND_SYNTAX;
1757 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1759 * The first argument may be only an account.
1761 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1762 return EPWMD_COMMAND_SYNTAX;
1765 n = find_account(client->doc, &path, &rc, NULL, 0);
1767 if (!n) {
1768 g_strfreev(path);
1769 return rc;
1772 if (path[1]) {
1773 n = find_elements(client->doc, n->children, path+1, &rc,
1774 NULL, NULL, NULL, FALSE, 0, NULL);
1776 if (!n) {
1777 g_strfreev(path);
1778 return rc;
1782 g_strfreev(path);
1784 for (a = n->properties; a; a = a->next) {
1785 gchar **pa;
1787 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1788 if (attrlist)
1789 g_strfreev(attrlist);
1791 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1792 return gpg_error_from_errno(ENOMEM);
1795 attrlist = pa;
1796 an = a->children;
1797 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1799 if (!attrlist[i]) {
1800 g_strfreev(attrlist);
1801 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1802 return gpg_error_from_errno(ENOMEM);
1805 attrlist[++i] = NULL;
1808 if (!attrlist)
1809 return EPWMD_EMPTY_ELEMENT;
1811 line = g_strjoinv("\n", attrlist);
1813 if (!line) {
1814 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1815 g_strfreev(attrlist);
1816 return gpg_error_from_errno(ENOMEM);
1819 rc = assuan_send_data(ctx, line, strlen(line));
1820 g_free(line);
1821 g_strfreev(attrlist);
1822 return rc;
1826 * req[0] - attribute
1827 * req[1] - element path
1829 static int attribute_delete(struct client_s *client, gchar **req)
1831 xmlAttrPtr a;
1832 xmlNodePtr n;
1833 gchar **path = NULL;
1834 gpg_error_t rc;
1836 if (!req || !req[0] || !req[1])
1837 return EPWMD_COMMAND_SYNTAX;
1839 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1841 * The first argument may be only an account.
1843 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1844 return EPWMD_COMMAND_SYNTAX;
1848 * Don't remove the "name" attribute for the account element. To remove an
1849 * account use DELETE <account>.
1851 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1852 rc = EPWMD_ATTR_SYNTAX;
1853 goto fail;
1856 n = find_account(client->doc, &path, &rc, NULL, 0);
1858 if (!n)
1859 goto fail;
1861 if (path[1]) {
1862 n = find_elements(client->doc, n->children, path+1, &rc,
1863 NULL, NULL, NULL, FALSE, 0, NULL);
1865 if (!n)
1866 goto fail;
1869 g_strfreev(path);
1871 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1872 return EPWMD_ATTR_NOT_FOUND;
1874 if (xmlRemoveProp(a) == -1)
1875 return EPWMD_LIBXML_ERROR;
1877 return 0;
1879 fail:
1880 g_strfreev(path);
1881 return rc;
1884 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1885 gpg_error_t *rc)
1887 gchar **src = *path;
1888 gchar **src_orig = g_strdupv(src);
1889 xmlNodePtr n = NULL;
1891 *rc = 0;
1893 if (!src_orig) {
1894 *rc = gpg_error_from_errno(ENOMEM);
1895 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1896 goto fail;
1899 again:
1900 n = find_account(client->doc, &src, rc, NULL, 0);
1902 if (!n) {
1903 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1904 *rc = new_account(client->doc, src[0]);
1906 if (*rc)
1907 goto fail;
1909 goto again;
1911 else
1912 goto fail;
1915 if (src[1]) {
1916 if (!n->children)
1917 n = create_target_elements_cb(n, src+1, rc, NULL);
1918 else
1919 n = find_elements(client->doc, n->children, src+1, rc,
1920 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1922 if (!n)
1923 goto fail;
1926 * Reset the position of the element tree now that the elements
1927 * have been created.
1929 g_strfreev(src);
1930 src = src_orig;
1931 src_orig = NULL;
1932 n = find_account(client->doc, &src, rc, NULL, 0);
1934 if (!n)
1935 goto fail;
1937 n = find_elements(client->doc, n->children, src+1, rc,
1938 NULL, NULL, NULL, FALSE, 0, NULL);
1940 if (!n)
1941 goto fail;
1944 fail:
1945 if (src_orig)
1946 g_strfreev(src_orig);
1948 *path = src;
1949 return n;
1953 * Creates a "target" attribute. When other commands encounter an element with
1954 * this attribute, the element path is modified to the target value. If the
1955 * source element path doesn't exist when using 'ATTR SET target', it is
1956 * created, but the destination element path must exist.
1958 * req[0] - source element path
1959 * req[1] - destination element path
1961 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1963 gchar **src, **dst, *line = NULL;
1964 gpg_error_t rc;
1965 xmlNodePtr n;
1967 if (!req || !req[0] || !req[1])
1968 return EPWMD_COMMAND_SYNTAX;
1970 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1972 * The first argument may be only an account.
1974 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1975 return EPWMD_COMMAND_SYNTAX;
1978 if (valid_element_path(src, FALSE) == FALSE) {
1979 g_strfreev(src);
1980 return EPWMD_INVALID_ELEMENT;
1983 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1985 * The first argument may be only an account.
1987 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1988 rc = EPWMD_COMMAND_SYNTAX;
1989 goto fail;
1993 n = find_account(client->doc, &dst, &rc, NULL, 0);
1996 * Make sure the destination element path exists.
1998 if (!n)
1999 goto fail;
2001 if (dst[1]) {
2002 n = find_elements(client->doc, n->children, dst+1, &rc,
2003 NULL, NULL, NULL, FALSE, 0, NULL);
2005 if (!n)
2006 goto fail;
2009 n = create_element_path(client, &src, &rc);
2011 if (rc)
2012 goto fail;
2014 line = g_strjoinv("\t", dst);
2016 if (!line) {
2017 rc = gpg_error_from_errno(ENOMEM);
2018 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2019 goto fail;
2022 rc = add_attribute(n, "target", line);
2024 fail:
2025 g_free(line);
2026 g_strfreev(src);
2027 g_strfreev(dst);
2028 return rc;
2032 * req[0] - account name
2033 * req[1] - new name
2035 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2037 gpg_error_t rc;
2038 gchar **tmp;
2039 xmlNodePtr n;
2041 tmp = g_strdupv(req);
2043 if (!tmp) {
2044 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2045 return gpg_error_from_errno(ENOMEM);
2048 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2049 g_strfreev(tmp);
2051 if (!n)
2052 return rc;
2054 if (g_utf8_collate(req[0], req[1]) == 0)
2055 return 0;
2058 * Will not overwrite an existing account.
2060 tmp = g_strdupv(req+1);
2062 if (!tmp) {
2063 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2064 return gpg_error_from_errno(ENOMEM);
2067 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2068 g_strfreev(tmp);
2070 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2071 return rc;
2073 if (n)
2074 return EPWMD_ACCOUNT_EXISTS;
2077 * Whitespace not allowed in account names.
2079 if (contains_whitespace(req[1]) == TRUE)
2080 return EPWMD_ATTR_SYNTAX;
2082 tmp = g_strdupv(req);
2084 if (!tmp) {
2085 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2086 return gpg_error_from_errno(ENOMEM);
2089 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2090 g_strfreev(tmp);
2092 if (!n)
2093 return EPWMD_ELEMENT_NOT_FOUND;
2095 return add_attribute(n, "name", req[1]);
2099 * req[0] - attribute
2100 * req[1] - element path
2102 static int attribute_get(assuan_context_t ctx, gchar **req)
2104 struct client_s *client = assuan_get_pointer(ctx);
2105 xmlNodePtr n;
2106 xmlChar *a;
2107 gchar **path= NULL;
2108 gpg_error_t rc;
2110 if (!req || !req[0] || !req[1])
2111 return EPWMD_COMMAND_SYNTAX;
2113 if (strchr(req[1], '\t')) {
2114 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2115 return EPWMD_COMMAND_SYNTAX;
2117 else {
2118 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2119 return EPWMD_COMMAND_SYNTAX;
2122 n = find_account(client->doc, &path, &rc, NULL, 0);
2124 if (!n)
2125 goto fail;
2127 if (path[1]) {
2128 n = find_elements(client->doc, n->children, path+1, &rc,
2129 NULL, NULL, NULL, FALSE, 0, NULL);
2131 if (!n)
2132 goto fail;
2135 g_strfreev(path);
2137 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2138 return EPWMD_ATTR_NOT_FOUND;
2140 rc = assuan_send_data(ctx, a, xmlStrlen(a));
2141 xmlFree(a);
2142 return rc;
2144 fail:
2145 g_strfreev(path);
2146 return rc;
2150 * req[0] - attribute
2151 * req[1] - element path
2152 * req[2] - value
2154 static int attribute_set(struct client_s *client, gchar **req)
2156 gchar **path = NULL;
2157 gpg_error_t rc;
2158 xmlNodePtr n;
2160 if (!req || !req[0] || !req[1] || !req[2])
2161 return EPWMD_COMMAND_SYNTAX;
2164 * Reserved attribute names.
2166 if (g_utf8_collate(req[0], "name") == 0) {
2168 * Only reserved for the account element. Not the rest of the
2169 * document.
2171 if (strchr(req[1], '\t') == NULL)
2172 return name_attribute(client, req + 1);
2174 else if (g_utf8_collate(req[0], "target") == 0)
2175 return target_attribute(client, req + 1);
2177 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2179 * The first argument may be only an account.
2181 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2182 return EPWMD_COMMAND_SYNTAX;
2185 n = find_account(client->doc, &path, &rc, NULL, 0);
2187 if (!n)
2188 goto fail;
2190 if (path[1]) {
2191 n = find_elements(client->doc, n->children, path+1, &rc,
2192 NULL, NULL, NULL, FALSE, 0, NULL);
2194 if (!n)
2195 goto fail;
2198 g_strfreev(path);
2199 return add_attribute(n, req[0], req[2]);
2201 fail:
2202 g_strfreev(path);
2203 return rc;
2207 * req[0] - command
2208 * req[1] - attribute name or element path if command is LIST
2209 * req[2] - element path
2210 * req[2] - element path or value
2212 static int attr_command(assuan_context_t ctx, char *line)
2214 struct client_s *client = assuan_get_pointer(ctx);
2215 gchar **req;
2216 gpg_error_t rc = 0;
2218 rc = file_modified(client);
2220 if (rc)
2221 return send_error(ctx, rc);
2223 req = split_input_line(line, " ", 4);
2225 if (!req || !req[0] || !req[1]) {
2226 g_strfreev(req);
2227 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2230 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2231 rc = attribute_set(client, req+1);
2232 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2233 rc = attribute_get(ctx, req+1);
2234 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2235 rc = attribute_delete(client, req+1);
2236 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2237 rc = attribute_list(ctx, req+1);
2238 else
2239 rc = EPWMD_COMMAND_SYNTAX;
2241 g_strfreev(req);
2242 return send_error(ctx, rc);
2245 static int iscached_command(assuan_context_t ctx, char *line)
2247 gchar **req = split_input_line(line, " ", 0);
2248 guchar md5file[16];
2250 if (!req || !*req) {
2251 g_strfreev(req);
2252 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2255 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2256 g_strfreev(req);
2257 CACHE_LOCK(ctx);
2259 if (cache_iscached(md5file) == FALSE) {
2260 CACHE_UNLOCK;
2261 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2264 CACHE_UNLOCK;
2265 return send_error(ctx, 0);
2268 static int clearcache_command(assuan_context_t ctx, char *line)
2270 struct client_s *client = assuan_get_pointer(ctx);
2271 gchar **req = split_input_line(line, " ", 0);
2272 guchar md5file[16];
2274 CACHE_LOCK(ctx);
2276 if (!req || !*req) {
2277 g_strfreev(req);
2278 cache_clear(client->md5file, 2);
2279 CACHE_UNLOCK;
2280 return send_error(ctx, 0);
2283 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2284 g_strfreev(req);
2286 if (cache_clear(md5file, 1) == FALSE) {
2287 CACHE_UNLOCK;
2288 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2291 CACHE_UNLOCK;
2292 return send_error(ctx, 0);
2295 static int cachetimeout_command(assuan_context_t ctx, char *line)
2297 guchar md5file[16];
2298 glong timeout;
2299 gchar **req = split_input_line(line, " ", 0);
2300 gchar *p;
2301 struct client_s *client = assuan_get_pointer(ctx);
2303 if (!req || !*req || !req[1]) {
2304 g_strfreev(req);
2305 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2308 errno = 0;
2309 timeout = strtol(req[0], &p, 10);
2311 if (errno != 0 || *p != 0) {
2312 g_strfreev(req);
2313 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2316 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2317 g_strfreev(req);
2318 CACHE_LOCK(client->ctx);
2320 if (cache_set_timeout(md5file, timeout) == FALSE) {
2321 CACHE_UNLOCK;
2322 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2325 CACHE_UNLOCK;
2326 return send_error(ctx, 0);
2329 static int dump_command(assuan_context_t ctx, char *line)
2331 xmlChar *xml;
2332 gssize len;
2333 struct client_s *client = assuan_get_pointer(ctx);
2334 gpg_error_t rc;
2336 if (disable_list_and_dump == TRUE)
2337 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2339 rc = file_modified(client);
2341 if (rc)
2342 return send_error(ctx, rc);
2344 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2346 if (!xml) {
2347 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2348 return send_syserror(ctx, ENOMEM);
2351 rc = assuan_send_data(ctx, xml, len);
2352 xmlFree(xml);
2353 return send_error(ctx, rc);
2356 static int getconfig_command(assuan_context_t ctx, gchar *line)
2358 struct client_s *client = assuan_get_pointer(ctx);
2359 gpg_error_t rc = 0;
2360 gchar filename[255]={0}, param[747]={0};
2361 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2363 if (strchr(line, ' ')) {
2364 sscanf(line, " %254[^ ] %746c", filename, param);
2365 fp = filename;
2366 paramp = param;
2369 if (fp && !valid_filename(fp))
2370 return send_error(ctx, EPWMD_INVALID_FILENAME);
2372 paramp = g_ascii_strdown(paramp, -1);
2374 if (!paramp) {
2375 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2376 return send_syserror(ctx, ENOMEM);
2379 p = get_key_file_string(fp ? fp : "global", paramp);
2380 g_free(paramp);
2382 if (!p)
2383 return send_error(ctx, GPG_ERR_NO_VALUE);
2385 tmp = expand_homedir(p);
2386 g_free(p);
2388 if (!tmp) {
2389 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2390 return send_syserror(ctx, ENOMEM);
2393 p = tmp;
2394 rc = assuan_send_data(ctx, p, strlen(p));
2395 g_free(p);
2396 return send_error(ctx, rc);
2399 static int xpath_command(assuan_context_t ctx, gchar *line)
2401 struct client_s *client = assuan_get_pointer(ctx);
2402 gpg_error_t rc;
2403 xmlXPathContextPtr xp;
2404 xmlXPathObjectPtr result;
2405 xmlBufferPtr buf = NULL;
2406 gchar **req = NULL;
2408 if (disable_list_and_dump == TRUE)
2409 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2411 rc = file_modified(client);
2413 if (rc)
2414 return send_error(ctx, rc);
2416 if (!line || !*line)
2417 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2419 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2420 if (strv_printf(&req, "%s", line) == FALSE)
2421 return send_syserror(ctx, ENOMEM);
2424 xp = xmlXPathNewContext(client->doc);
2426 if (!xp)
2427 return send_error(ctx, EPWMD_LIBXML_ERROR);
2429 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2431 if (!result) {
2432 xmlXPathFreeContext(xp);
2433 return send_error(ctx, EPWMD_LIBXML_ERROR);
2436 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2437 rc = EPWMD_EMPTY_ELEMENT;
2438 goto fail;
2441 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2442 (xmlChar *)req[1], &buf);
2444 if (rc)
2445 goto fail;
2446 else if (!req[1] && !xmlBufferLength(buf)) {
2447 rc = EPWMD_EMPTY_ELEMENT;
2448 goto fail;
2450 else if (req[1])
2451 goto fail;
2453 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2455 fail:
2456 g_strfreev(req);
2458 if (buf)
2459 xmlBufferFree(buf);
2461 if (result)
2462 xmlXPathFreeObject(result);
2464 if (xp)
2465 xmlXPathFreeContext(xp);
2467 return send_error(ctx, rc);
2470 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2471 gsize len)
2473 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2474 gpg_error_t rc = file_modified(client);
2475 gchar **req, **path = NULL, **path_orig = NULL, *content;
2476 xmlDocPtr doc;
2477 xmlNodePtr n, root, copy;
2479 if (assuan_rc || rc) {
2480 if (line)
2481 xfree(line);
2482 return assuan_rc ? assuan_rc : rc;
2485 req = split_input_line((gchar *)line, " ", 2);
2486 xfree(line);
2488 if (!req || !*req)
2489 return EPWMD_COMMAND_SYNTAX;
2491 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2492 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2493 return EPWMD_COMMAND_SYNTAX;
2496 content = req[1];
2498 if (!content || !*content) {
2499 rc = EPWMD_COMMAND_SYNTAX;
2500 goto fail;
2503 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2504 rc = EPWMD_INVALID_ELEMENT;
2505 goto fail;
2508 if (valid_element_path(path+1, FALSE) == FALSE) {
2509 rc = EPWMD_INVALID_ELEMENT;
2510 goto fail;
2513 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2515 if (!doc) {
2516 rc = EPWMD_LIBXML_ERROR;
2517 goto fail;
2520 root = xmlDocGetRootElement(doc);
2521 path_orig = g_strdupv(path);
2523 if (!path_orig) {
2524 xmlFreeDoc(doc);
2525 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2526 rc = gpg_error_from_errno(ENOMEM);
2527 goto fail;
2530 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2531 g_strfreev(path_orig);
2532 xmlFreeDoc(doc);
2533 rc = gpg_error_from_errno(ENOMEM);
2534 goto fail;
2537 n = find_account(client->doc, &path, &rc, NULL, 0);
2539 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2540 g_strfreev(path_orig);
2541 xmlFreeDoc(doc);
2542 goto fail;
2544 else if (!rc) {
2545 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2547 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2548 g_strfreev(path_orig);
2549 xmlFreeDoc(doc);
2550 goto fail;
2552 else if (!rc) {
2553 xmlNodePtr parent = n->parent;
2555 xmlUnlinkNode(n);
2556 xmlFreeNode(n);
2557 n = parent;
2561 g_strfreev(path);
2562 path = path_orig;
2564 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2565 n = create_element_path(client, &path, &rc);
2567 if (rc) {
2568 xmlFreeDoc(doc);
2569 goto fail;
2573 copy = xmlCopyNode(root, 1);
2574 n = xmlAddChild(n, copy);
2575 xmlFreeDoc(doc);
2577 if (!n)
2578 rc = EPWMD_LIBXML_ERROR;
2580 fail:
2581 g_strfreev(path);
2582 g_strfreev(req);
2583 client->inquire_status = INQUIRE_DONE;
2584 return rc;
2587 static int import_command(assuan_context_t ctx, gchar *line)
2589 gpg_error_t rc;
2590 struct client_s *client = assuan_get_pointer(ctx);
2592 rc = file_modified(client);
2594 if (rc)
2595 return send_error(ctx, rc);
2597 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2599 if (rc)
2600 return send_error(ctx, rc);
2602 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2603 client->inquire_status = INQUIRE_BUSY;
2604 return 0;
2607 static int lock_command(assuan_context_t ctx, gchar *line)
2609 gpg_error_t rc;
2610 struct client_s *client = assuan_get_pointer(ctx);
2612 rc = file_modified(client);
2614 if (rc)
2615 return send_error(ctx, rc);
2617 rc = lock_file_mutex(client);
2619 if (!rc)
2620 client->is_lock_cmd = TRUE;
2622 return send_error(ctx, rc);
2625 static int unlock_command(assuan_context_t ctx, gchar *line)
2627 struct client_s *client = assuan_get_pointer(ctx);
2628 gpg_error_t rc = file_modified(client);
2630 if (rc)
2631 return send_error(ctx, rc);
2633 unlock_file_mutex(client);
2634 return send_error(ctx, 0);
2637 static int getpid_command(assuan_context_t ctx, gchar *line)
2639 gpg_error_t rc;
2640 gchar buf[32];
2641 pid_t pid = getpid();
2643 print_fmt(buf, sizeof(buf), "%i", pid);
2644 rc = assuan_send_data(ctx, buf, strlen(buf));
2645 return send_error(ctx, rc);
2648 static int version_command(assuan_context_t ctx, gchar *line)
2650 gpg_error_t rc;
2651 gchar buf[32];
2653 print_fmt(buf, sizeof(buf), "%s", PACKAGE_VERSION);
2654 rc = assuan_send_data(ctx, buf, strlen(buf));
2655 return send_error(ctx, rc);
2658 static void bye_notify(assuan_context_t ctx)
2660 struct client_s *cl = assuan_get_pointer(ctx);
2661 #ifdef WITH_GNUTLS
2662 gint rc;
2664 if (!cl->thd->remote)
2665 return;
2667 do {
2668 rc = gnutls_bye(cl->thd->tls->ses, GNUTLS_SHUT_RDWR);
2669 } while (rc == GNUTLS_E_AGAIN);
2670 #endif
2672 /* This will let assuan_process_next() return. */
2673 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
2676 static void reset_notify(assuan_context_t ctx)
2678 struct client_s *cl = assuan_get_pointer(ctx);
2680 if (cl)
2681 cleanup_client(cl);
2684 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2686 gchar name[32] = {0}, value[256] = {0};
2688 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2689 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2691 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2692 struct client_s *cl = assuan_get_pointer(ctx);
2694 if (cl->thd->name)
2695 g_free(cl->thd->name);
2697 cl->thd->name = g_strdup(value);
2698 log_write("OPTION CLIENT %s", line);
2700 else
2701 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2703 return 0;
2706 static int option_handler(assuan_context_t ctx, const gchar *name,
2707 const gchar *value)
2709 struct client_s *client = assuan_get_pointer(ctx);
2711 if (!value || !*value)
2712 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2714 if (g_strcasecmp(name, (gchar *)"client") == 0)
2715 return parse_client_option(ctx, value);
2717 if (g_strcasecmp(name, (gchar *)"iterations") == 0) {
2718 long n;
2719 gchar *p = NULL;
2721 errno = 0;
2722 n = strtol(value, &p, 10);
2724 if (errno || (p && *p) || n < 0)
2725 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2727 g_key_file_set_integer(keyfileh, client->filename ? client->filename : "global", "iterations", (guint)n);
2728 send_status_all(STATUS_CONFIG);
2730 #ifdef WITH_PINENTRY
2731 else if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2732 g_free(client->pinentry->ttyname);
2733 client->pinentry->ttyname = g_strdup(value);
2735 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2736 g_free(client->pinentry->ttytype);
2737 client->pinentry->ttytype = g_strdup(value);
2739 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2740 g_free(client->pinentry->display);
2741 client->pinentry->display = g_strdup(value);
2743 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2744 g_free(client->pinentry->path);
2745 client->pinentry->path = g_strdup(value);
2747 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2748 g_free(client->pinentry->title);
2749 client->pinentry->title = g_strdup(value);
2751 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2752 g_free(client->pinentry->prompt);
2753 client->pinentry->prompt = g_strdup(value);
2755 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2756 g_free(client->pinentry->desc);
2757 client->pinentry->desc = g_strdup(value);
2760 * Look at client_thread() to see how this works.
2762 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2763 gchar *p = NULL;
2764 gint n = strtol(value, &p, 10);
2766 if (*p || n < 0)
2767 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2769 client->pinentry->timeout = n;
2771 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2772 gchar *p = NULL;
2773 gint n = strtol(value, &p, 10);
2775 if (*p || n < 0 || n > 1)
2776 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2778 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2780 #endif
2781 else
2782 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2784 log_write("OPTION %s=%s", name, value);
2785 return 0;
2788 gpg_error_t register_commands(assuan_context_t ctx)
2790 static struct {
2791 const gchar *name;
2792 gint (*handler)(assuan_context_t, gchar *line);
2793 } table[] = {
2794 { "OPEN", open_command },
2795 { "SAVE", save_command },
2796 { "LIST", list_command },
2797 { "REALPATH", realpath_command },
2798 { "STORE", store_command },
2799 { "DELETE", delete_command },
2800 { "GET", get_command },
2801 { "ATTR", attr_command },
2802 { "ISCACHED", iscached_command },
2803 { "CLEARCACHE", clearcache_command },
2804 { "CACHETIMEOUT", cachetimeout_command },
2805 { "GETCONFIG", getconfig_command },
2806 { "DUMP", dump_command },
2807 { "XPATH", xpath_command },
2808 { "IMPORT", import_command },
2809 { "LOCK", lock_command },
2810 { "UNLOCK", unlock_command },
2811 { "GETPID", getpid_command },
2812 { "VERSION", version_command },
2813 { "INPUT", NULL },
2814 { "OUTPUT", NULL },
2815 { NULL, NULL }
2817 gint i, rc;
2819 for (i=0; table[i].name; i++) {
2820 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2822 if (rc)
2823 return rc;
2826 rc = assuan_register_bye_notify(ctx, bye_notify);
2828 if (rc)
2829 return rc;
2831 rc = assuan_register_option_handler(ctx, option_handler);
2833 if (rc)
2834 return rc;
2836 rc = assuan_register_reset_notify(ctx, reset_notify);
2838 if (rc)
2839 return rc;
2841 return assuan_register_post_cmd_notify(ctx, command_finalize);
2844 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
2845 struct client_crypto_s *crypto, gpointer *dst, gsize *dst_len)
2847 gsize insize, len;
2848 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2849 guint iter = 0, n_iter = 0, iter_progress = 0;
2850 gint zrc = 0;
2851 gulong outsize = 0;
2852 gpg_error_t rc;
2853 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
2854 glong fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
2856 lseek(crypto->fh->fd, fh_size, SEEK_SET);
2857 insize = crypto->fh->st.st_size - fh_size;
2858 crypto->iv = gcry_malloc(gcryblocksize);
2860 if (!crypto->iv) {
2861 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2862 return gpg_error_from_errno(ENOMEM);
2865 /* No encryption iterations. This is a plain (gzipped) file. */
2866 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
2868 * cache_file_count() needs both .used == TRUE and a valid key in
2869 * order for it to count as a used cache entry. Fixes CACHE status
2870 * messages.
2872 memset(key, '!', gcrykeysize);
2875 if (crypto->fh->v1)
2876 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
2877 else
2878 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
2880 crypto->inbuf = gcry_malloc(insize);
2882 if (!crypto->inbuf) {
2883 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2884 return gpg_error_from_errno(ENOMEM);
2887 crypto->insize = insize;
2888 len = read(crypto->fh->fd, crypto->inbuf, crypto->insize);
2890 if (len != crypto->insize)
2891 return GPG_ERR_INV_LENGTH;
2893 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
2894 goto decompress;
2896 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2897 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2898 return rc;
2901 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
2902 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2903 return rc;
2906 iter_progress = (guint)get_key_file_integer(client && client->filename ?
2907 client->filename : "global", "iteration_progress");
2909 if (iter_progress > 0 && fh_iter >= iter_progress) {
2910 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", 0, fh_iter);
2912 if (rc)
2913 return rc;
2916 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2918 if (rc)
2919 return rc;
2921 crypto->tkey = gcry_malloc(gcrykeysize);
2923 if (!crypto->tkey) {
2924 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
2925 return gpg_error_from_errno(ENOMEM);
2928 memcpy(crypto->tkey, key, gcrykeysize);
2929 guchar *tkey = crypto->tkey;
2930 tkey[0] ^= 1;
2932 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
2933 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2934 return rc;
2937 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
2938 if (iter_progress > 0 && iter >= iter_progress) {
2939 if (!(iter % iter_progress)) {
2940 rc = send_status(ctx, STATUS_DECRYPT, "%u %u",
2941 ++n_iter * iter_progress, fh_iter);
2943 if (rc)
2944 return rc;
2948 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
2949 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2950 return rc;
2953 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
2955 if (rc) {
2956 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2957 return rc;
2960 iter++;
2963 if (iter_progress && fh_iter >= iter_progress) {
2964 rc = send_status(ctx, STATUS_DECRYPT, "%u %u", fh_iter, fh_iter);
2966 if (rc)
2967 return rc;
2970 decompress:
2971 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
2972 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
2973 if (zrc == Z_MEM_ERROR)
2974 return gpg_error_from_errno(ENOMEM);
2975 else
2976 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
2979 if (g_strncasecmp(crypto->outbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2980 gcry_free(crypto->outbuf);
2981 crypto->outbuf = NULL;
2982 return EPWMD_BADKEY;
2985 if (ctx) {
2986 client->xml = crypto->outbuf;
2987 client->len = outsize;
2988 crypto->outbuf = NULL;
2990 else if (dst) {
2991 *dst = crypto->outbuf;
2992 *dst_len = outsize;
2993 crypto->outbuf = NULL;
2996 /* The calling function should free the crypto struct. */
2997 return 0;
3001 * This is called after every Assuan command.
3003 void command_finalize(assuan_context_t ctx, gint rc)
3005 struct client_s *client = assuan_get_pointer(ctx);
3007 if (!client->is_lock_cmd)
3008 unlock_file_mutex(client);