Fixed RC_ON_LOCKED and LOCK_ON_OPEN when opening another file in the same
[pwmd.git] / src / commands.c
blobff3b2e148652abd43560a214d7078b25818273b4
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2010 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>
31 #include <dirent.h>
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #ifdef WITH_LIBACL
38 #include <sys/acl.h>
39 #endif
41 #include "mem.h"
42 #include "xml.h"
43 #include "common.h"
45 #ifdef WITH_PINENTRY
46 #include "pinentry.h"
47 #endif
49 #include "pwmd_error.h"
50 #include "cache.h"
51 #include "misc.h"
52 #include "commands.h"
53 #include "lock.h"
55 struct gz_s {
56 z_stream z;
57 gpointer out;
58 gboolean done;
59 status_msg_t which;
62 static gpg_error_t do_lock_command(struct client_s *client);
64 static void *z_alloc(void *data, unsigned items, unsigned size)
66 return gcry_calloc(items, size);
69 static void z_free(void *data, void *p)
71 gcry_free(p);
74 static gpg_error_t file_modified(struct client_s *client)
76 struct stat st;
77 gpg_error_t rc;
79 if (client->state != STATE_OPEN)
80 return EPWMD_NO_FILE;
82 rc = lock_file_mutex(client);
84 if (rc)
85 return rc;
87 if (lstat(client->filename, &st) == 0 && client->mtime) {
88 if (client->mtime != st.st_mtime)
89 return EPWMD_FILE_MODIFIED;
92 pth_cancel_point();
93 return 0;
96 static gpg_error_t parse_xml(assuan_context_t ctx)
98 struct client_s *client = assuan_get_pointer(ctx);
100 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
102 if (!client->doc)
103 return EPWMD_LIBXML_ERROR;
105 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
106 return 0;
108 return convert_elements(client->doc);
111 void unlock_file_mutex(struct client_s *client)
113 pth_mutex_t *m;
115 #ifdef WITH_PINENTRY
116 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
117 #else
118 if (client->has_lock == FALSE)
119 #endif
120 return;
122 CACHE_LOCK(client->ctx);
124 if (cache_get_mutex(client->md5file, &m) == FALSE) {
125 CACHE_UNLOCK;
126 return;
129 CACHE_UNLOCK;
130 MUTEX_UNLOCK(m);
131 client->has_lock = client->is_lock_cmd = FALSE;
134 gpg_error_t lock_file_mutex(struct client_s *client)
136 pth_mutex_t *m;
137 gpg_error_t rc = 0;
139 if (client->has_lock == TRUE)
140 return 0;
142 CACHE_LOCK(client->ctx);
144 if (cache_get_mutex(client->md5file, &m) == FALSE) {
145 CACHE_UNLOCK;
146 return 0;
149 CACHE_UNLOCK;
151 if (client->rc_on_locked) {
152 if (!pth_mutex_acquire(m, TRUE, NULL))
153 return GPG_ERR_LOCKED;
154 #ifdef DEBUG
155 MUTEX_LOCK_DEBUG(m);
156 #endif
158 else
159 MUTEX_TRYLOCK(client->ctx, m, rc);
161 if (!rc)
162 client->has_lock = TRUE;
164 return rc;
167 void free_client(struct client_s *client)
169 if (client->doc)
170 xmlFreeDoc(client->doc);
172 if (client->xml)
173 gcry_free(client->xml);
175 if (client->filename)
176 g_free(client->filename);
178 if (client->crypto)
179 cleanup_crypto(&client->crypto);
181 if (client->xml_error)
182 xmlResetError(client->xml_error);
185 void cleanup_client(struct client_s *client)
187 assuan_context_t ctx = client->ctx;
188 struct client_thread_s *thd = client->thd;
189 gboolean lock_on_open = client->lockonopen;
190 gboolean rc_on_locked = client->rc_on_locked;
191 #ifdef WITH_PINENTRY
192 struct pinentry_s *pin = client->pinentry;
193 #endif
195 unlock_file_mutex(client);
196 CACHE_LOCK(client->ctx);
197 cache_decr_refcount(client->md5file);
200 * This may be a new file so don't use a cache slot. save_command() will
201 * set this to FALSE on success.
203 if (client->new == TRUE)
204 cache_clear(client->md5file, 1);
206 CACHE_UNLOCK;
207 free_client(client);
208 memset(client, 0, sizeof(struct client_s));
209 client->state = STATE_CONNECTED;
210 client->ctx = ctx;
211 client->thd = thd;
212 client->freed = TRUE;
213 #ifdef WITH_PINENTRY
214 client->pinentry = pin;
215 #endif
216 client->rc_on_locked = rc_on_locked;
217 client->lockonopen = lock_on_open;
220 static void gz_cleanup(void *arg)
222 struct gz_s **gz = (struct gz_s **)arg;
224 if (!gz)
225 return;
227 if (!(*gz)->done && (*gz)->out)
228 gcry_free((*gz)->out);
230 if ((*gz)->which == STATUS_COMPRESS) {
231 if ((*gz)->z.zalloc)
232 deflateEnd(&(*gz)->z);
234 else {
235 if ((*gz)->z.zalloc)
236 inflateEnd(&(*gz)->z);
239 g_free(*gz);
240 *gz = NULL;
243 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
244 gpointer *out, gulong *outsize, gint *rc)
246 struct gz_s *gz;
247 gz_header h;
248 gchar buf[17];
250 gz = g_malloc0(sizeof(struct gz_s));
252 if (!gz) {
253 *rc = gpg_error_from_errno(ENOMEM);
254 return FALSE;
257 pth_cleanup_push(gz_cleanup, &gz);
258 gz->which = STATUS_DECOMPRESS;
259 gz->z.zalloc = z_alloc;
260 gz->z.zfree = z_free;
261 gz->z.next_in = in;
262 gz->z.avail_in = (uInt)insize;
263 gz->z.avail_out = zlib_bufsize;
264 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
266 if (!gz->out) {
267 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
268 *rc = Z_MEM_ERROR;
269 pth_cleanup_pop(1);
270 return FALSE;
273 *rc = inflateInit2(&gz->z, 47);
275 if (*rc != Z_OK) {
276 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
277 pth_cleanup_pop(1);
278 return FALSE;
281 memset(&h, 0, sizeof(gz_header));
282 h.comment = (guchar *)buf;
283 h.comm_max = sizeof(buf);
284 *rc = inflateGetHeader(&gz->z, &h);
286 if (*rc != Z_OK) {
287 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
288 pth_cleanup_pop(1);
289 return FALSE;
292 *rc = inflate(&gz->z, Z_BLOCK);
294 if (*rc != Z_OK) {
295 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
296 pth_cleanup_pop(1);
297 return FALSE;
300 if (h.comment)
301 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
303 do {
304 gpointer p;
306 *rc = inflate(&gz->z, Z_FINISH);
308 switch (*rc) {
309 case Z_OK:
310 break;
311 case Z_BUF_ERROR:
312 if (!gz->z.avail_out) {
313 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
315 if (!p) {
316 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
317 *rc = Z_MEM_ERROR;
318 goto fail;
321 gz->out = p;
322 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
323 gz->z.avail_out = zlib_bufsize;
324 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
325 gz->z.total_out, insize);
327 if (*rc)
328 goto fail;
330 break;
331 case Z_STREAM_END:
332 break;
333 default:
334 goto fail;
335 break;
337 } while (*rc != Z_STREAM_END);
339 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
340 insize);
342 if (*rc)
343 goto fail;
345 *out = gz->out;
346 *outsize = gz->z.total_out;
347 gz->done = TRUE;
348 pth_cleanup_pop(1);
349 *rc = 0;
350 return TRUE;
352 fail:
353 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
354 pth_cleanup_pop(1);
355 return FALSE;
358 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
359 gpg_error_t *rc)
361 gint fd;
362 gsize len;
363 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
364 gsize fh_size;
365 gpointer p;
367 *rc = 0;
369 if (!fh) {
370 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
371 *rc = gpg_error_from_errno(ENOMEM);
372 return NULL;
375 pth_cleanup_push(g_free, fh);
376 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
378 if (lstat(filename, &fh->st) == -1) {
379 *rc = gpg_error_from_syserror();
380 pth_cleanup_pop(1);
381 return NULL;
384 if (!S_ISREG(fh->st.st_mode)) {
385 *rc = GPG_ERR_ENOANO;
386 pth_cleanup_pop(1);
387 return NULL;
390 fd = open(filename, O_RDONLY);
392 if (fd == -1) {
393 *rc = gpg_error_from_errno(errno);
394 pth_cleanup_pop(1);
395 return NULL;
398 pth_cleanup_push(cleanup_fd_cb, &fd);
399 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
400 len = pth_read(fd, p, fh_size);
402 if (len != fh_size) {
403 gint n = errno;
404 pth_cleanup_pop(1);
405 pth_cleanup_pop(1);
406 *rc = gpg_error_from_errno(n);
407 return NULL;
410 fh->v1 = v1;
411 fh->fd = fd;
412 pth_cleanup_pop(0);
413 pth_cleanup_pop(0);
414 return fh;
417 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
418 gboolean cached)
420 struct client_s *client = assuan_get_pointer(ctx);
421 gpg_error_t rc;
422 gint timeout;
423 guchar *key = client->crypto->key;
425 /* New file. */
426 if (!client->crypto->fh) {
427 if (key[0])
428 goto update_cache;
430 goto done;
433 rc = init_client_crypto2(client->filename, client->crypto);
435 if (rc) {
436 cleanup_client(client);
437 return send_error(ctx, rc);
440 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
442 if (rc) {
443 cleanup_client(client);
444 return send_error(ctx, rc);
447 update_cache:
448 CACHE_LOCK(client->ctx);
450 if (cached == FALSE) {
451 if (cache_update_key(client->md5file, key) == FALSE) {
452 cleanup_client(client);
453 CACHE_UNLOCK;
454 return send_syserror(ctx, ENOMEM);
457 timeout = get_key_file_integer(client->filename, "cache_timeout");
458 cache_reset_timeout(client->md5file, timeout);
460 else
461 cache_set_timeout(client->md5file, -2);
463 CACHE_UNLOCK;
465 done:
466 rc = parse_xml(ctx);
468 if (client->xml) {
469 gcry_free(client->xml);
470 client->xml = NULL;
473 if (!rc) {
474 if (client->new == FALSE)
475 send_status_all(STATUS_CACHE);
477 client->state = STATE_OPEN;
480 if (!rc && client->new == FALSE &&
481 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
482 MUTEX_LOCK(&rcfile_mutex);
483 g_key_file_set_double(keyfileh, client->filename, "iterations",
484 client->crypto->fh->ver.fh2.iter);
485 MUTEX_UNLOCK(&rcfile_mutex);
486 send_status_all(STATUS_CONFIG);
489 cleanup_crypto(&client->crypto);
491 if (!rc && client->lockonopen)
492 return do_lock_command(client);
494 return send_error(ctx, rc);
497 static void req_cleanup(void *arg)
499 if (!arg)
500 return;
502 g_strfreev((gchar **)arg);
505 static gint open_command(assuan_context_t ctx, gchar *line)
507 gboolean cached = FALSE;
508 gpg_error_t rc;
509 struct client_s *client = assuan_get_pointer(ctx);
510 gchar **req;
511 gchar *filename = NULL;
512 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
514 if ((req = split_input_line(line, " ", 2)) != NULL)
515 filename = req[0];
517 pth_cleanup_push(req_cleanup, req);
519 if (!filename || !*filename) {
520 pth_cleanup_pop(1);
521 return send_error(ctx, GPG_ERR_SYNTAX);
524 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
526 if (valid_filename(filename) == FALSE) {
527 pth_cleanup_pop(1);
528 return send_error(ctx, GPG_ERR_INV_VALUE);
531 if (client->state == STATE_OPEN)
532 cleanup_client(client);
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 pth_cleanup_pop(1);
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 pth_cleanup_pop(1);
551 return send_error(ctx, rc);
554 client->freed = FALSE;
555 client->crypto = init_client_crypto();
557 if (!client->crypto) {
558 pth_cleanup_pop(1);
559 cleanup_client(client);
560 return send_syserror(ctx, ENOMEM);
563 client->crypto->key = gcry_malloc(hashlen);
565 if (!client->crypto->key) {
566 pth_cleanup_pop(1);
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, hashlen);
574 client->crypto->fh = read_file_header(filename, FALSE, &rc);
576 if (!client->crypto->fh) {
577 if (gpg_err_code_to_errno(rc) != ENOENT) {
578 log_write("%s: %s", filename, pwmd_strerror(rc));
579 pth_cleanup_pop(1);
580 cleanup_client(client);
581 return send_error(ctx, rc);
585 * New files don't need a key.
587 if ((client->xml = new_document()) == NULL) {
588 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
589 pth_cleanup_pop(1);
590 cleanup_client(client);
591 return send_syserror(ctx, ENOMEM);
594 client->len = xmlStrlen(client->xml);
595 client->new = TRUE;
596 client->filename = g_strdup(filename);
598 if (!client->filename) {
599 pth_cleanup_pop(1);
600 cleanup_client(client);
601 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
602 return send_syserror(ctx, ENOMEM);
605 if (req[1] && *req[1])
606 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
607 strlen(req[1]));
609 pth_cleanup_pop(1);
610 #ifdef WITH_PINENTRY
611 client->pinentry->filename = g_strdup(client->filename);
613 if (!client->pinentry->filename) {
614 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
615 cleanup_client(client);
616 return send_syserror(ctx, ENOMEM);
618 #endif
619 return open_command_finalize(ctx, NULL, cached);
621 else
622 client->mtime = client->crypto->fh->st.st_mtime;
624 client->filename = g_strdup(filename);
626 if (!client->filename) {
627 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
628 pth_cleanup_pop(1);
629 cleanup_client(client);
630 return send_syserror(ctx, ENOMEM);
633 #ifdef WITH_PINENTRY
634 if (client->pinentry->filename)
635 g_free(client->pinentry->filename);
637 client->pinentry->filename = g_strdup(client->filename);
639 if (!client->pinentry->filename) {
640 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
641 pth_cleanup_pop(1);
642 cleanup_client(client);
643 return send_syserror(ctx, ENOMEM);
645 #endif
647 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
648 goto done;
650 CACHE_LOCK(client->ctx);
651 cached = cache_get_key(client->md5file, client->crypto->key);
652 CACHE_UNLOCK;
654 if (cached == FALSE) {
655 gchar *tmp = get_key_file_string(filename, "key_file");
657 if (tmp) {
658 g_free(tmp);
659 pth_cleanup_pop(1);
660 cleanup_client(client);
661 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
665 * No key specified and no matching filename found in the cache. Use
666 * pinentry to retrieve the key. Cannot return assuan_process_done()
667 * here otherwise the command will be interrupted. The event loop in
668 * client_thread() will poll the file descriptor waiting for it to
669 * become ready to read a pinentry_key_s which will contain the
670 * entered key or an error code. It will then call
671 * open_command_finalize() to to finish the command.
673 if (!req[1] || !*req[1]) {
674 #ifdef WITH_PINENTRY
675 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
677 /* From set_pinentry_defaults(). */
678 if (client->pinentry->enable == FALSE ||
679 (client->pinentry->enable == -1 && b == FALSE)) {
680 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
681 goto done;
684 pth_cleanup_pop(1);
685 rc = lock_pin_mutex(client);
687 if (rc) {
688 unlock_pin_mutex(client->pinentry);
689 cleanup_client(client);
690 return send_error(ctx, rc);
693 client->pinentry->which = PINENTRY_OPEN;
694 rc = pinentry_fork(ctx);
696 if (rc) {
697 unlock_pin_mutex(client->pinentry);
698 cleanup_client(client);
699 return send_error(ctx, rc);
702 // Called from pinentry iterate.
703 client->pinentry->cb = open_command_finalize;
704 client->pinentry->status = PINENTRY_INIT;
705 return 0;
706 #else
707 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
708 goto done;
709 #endif
712 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
713 strlen(req[1]));
715 else if (req && req[1] && *req[1]) {
716 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
717 strlen(req[1]) ? strlen(req[1]) : 1);
720 done:
721 pth_cleanup_pop(1);
722 return open_command_finalize(ctx, NULL, cached);
725 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
726 guint size, gpointer *out, gulong *outsize, gint *rc)
728 struct gz_s *gz;
729 gz_header h;
730 gchar buf[17];
731 gint cmd = Z_NO_FLUSH;
733 gz = g_malloc0(sizeof(struct gz_s));
735 if (!gz) {
736 *rc = gpg_error_from_errno(ENOMEM);
737 return FALSE;
740 pth_cleanup_push(gz_cleanup, &gz);
741 gz->which = STATUS_COMPRESS;
742 gz->z.zalloc = z_alloc;
743 gz->z.zfree = z_free;
744 gz->z.next_in = data;
745 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
746 gz->z.avail_out = (uInt)zlib_bufsize;
747 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
749 if (!gz->out) {
750 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
751 *rc = Z_MEM_ERROR;
752 pth_cleanup_pop(1);
753 return FALSE;
756 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
758 if (*rc != Z_OK) {
759 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
760 pth_cleanup_pop(1);
761 return FALSE;
764 /* Rather than store the size of the uncompressed data in the file header,
765 * store it in the comment field of the gzip header. Don't give anyone too
766 * much information. Not sure why really, but it seems the right way. :)
768 memset(&h, 0, sizeof(gz_header));
769 g_snprintf(buf, sizeof(buf), "%u", size);
770 h.comment = (guchar *)buf;
771 *rc = deflateSetHeader(&gz->z, &h);
773 if (*rc != Z_OK) {
774 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
775 pth_cleanup_pop(1);
776 return FALSE;
779 do {
780 gpointer p;
782 *rc = deflate(&gz->z, cmd);
784 switch (*rc) {
785 case Z_OK:
786 break;
787 case Z_BUF_ERROR:
788 if (!gz->z.avail_out) {
789 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
791 if (!p) {
792 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
793 *rc = Z_MEM_ERROR;
794 goto fail;
797 gz->out = p;
798 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
799 gz->z.avail_out = zlib_bufsize;
802 if (!gz->z.avail_in && gz->z.total_in < size) {
803 if (gz->z.total_in + zlib_bufsize > size)
804 gz->z.avail_in = size - gz->z.total_in;
805 else
806 gz->z.avail_in = zlib_bufsize;
808 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
809 gz->z.total_in, size);
811 if (*rc)
812 goto fail;
815 if (gz->z.total_in >= size)
816 cmd = Z_FINISH;
818 break;
819 case Z_STREAM_END:
820 break;
821 default:
822 goto fail;
824 } while (*rc != Z_STREAM_END);
826 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
828 if (*rc)
829 goto fail;
831 *out = gz->out;
832 *outsize = gz->z.total_out;
833 *rc = 0;
834 gz->done = TRUE;
835 pth_cleanup_pop(1);
836 return TRUE;
838 fail:
839 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
840 pth_cleanup_pop(1);
841 return FALSE;
844 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
847 * Useful for a large amount of data. Rather than doing all of the data in one
848 * iteration do it in chunks. This lets the command be cancelable rather than
849 * waiting for it to complete.
851 static gpg_error_t iterate_crypto_once(struct client_s *client,
852 struct crypto_s *crypto, status_msg_t which)
854 gpg_error_t rc = 0;
855 goffset len = CRYPTO_BLOCKSIZE(crypto);
856 gpointer p = gcry_malloc(len);
857 goffset total = 0;
858 gpointer inbuf;
860 if (!p)
861 return gpg_err_code_from_errno(ENOMEM);
863 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
864 len = crypto->insize;
866 pth_cleanup_push(gcry_free, p);
868 for (;;) {
869 inbuf = (guchar *)crypto->inbuf + total;
870 guchar *tmp;
872 if (len + total > crypto->insize)
873 len = crypto->blocksize;
875 if (which == STATUS_ENCRYPT)
876 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
877 else
878 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
880 if (rc)
881 goto done;
883 tmp = (guchar *)crypto->inbuf + total;
884 memmove(tmp, p, len);
885 total += len;
887 if (total >= crypto->insize)
888 break;
890 pth_cancel_point();
893 done:
894 pth_cleanup_pop(1);
895 return rc;
898 /* The crypto struct must be setup for iterations and .key. */
899 gpg_error_t do_xml_encrypt(struct client_s *client,
900 struct crypto_s *crypto, const gchar *filename)
902 goffset len = crypto->insize;
903 gpointer inbuf;
904 gchar *p;
905 gpg_error_t rc;
906 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
907 gchar tmp[FILENAME_MAX];
908 struct stat st;
909 mode_t mode = 0;
910 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
912 if (!crypto->fh->ver.fh2.iter) {
914 * cache_file_count() needs both .used == TRUE and a valid key in
915 * order for it to count as a used cache entry. Fixes CACHE status
916 * messages.
918 memset(crypto->key, '!', hashlen);
919 goto write_file;
923 * Resize the existing xml buffer to the block size required by gcrypt
924 * rather than duplicating it and wasting memory.
926 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
928 if (crypto->insize % crypto->blocksize)
929 len += crypto->blocksize;
931 inbuf = gcry_realloc(crypto->inbuf, len);
933 if (!inbuf) {
934 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
935 return gpg_error_from_errno(ENOMEM);
938 crypto->inbuf = inbuf;
939 crypto->insize = len;
940 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
942 if (crypto->tkey)
943 gcry_free(crypto->tkey);
945 crypto->tkey = gcry_malloc(hashlen);
947 if (!crypto->tkey) {
948 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
949 return gpg_error_from_errno(ENOMEM);
952 memcpy(crypto->tkey, crypto->key, hashlen);
953 guchar *tkey = crypto->tkey;
954 tkey[0] ^= 1;
956 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
957 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
958 return rc;
961 iter_progress = (guint64)get_key_file_double(
962 client ? client->filename : "global", "iteration_progress");
964 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
965 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
966 "0 %llu", crypto->fh->ver.fh2.iter);
968 if (rc)
969 return rc;
972 while (xiter < crypto->fh->ver.fh2.iter-1) {
973 if (iter_progress > 0ULL && xiter >= iter_progress) {
974 if (!(xiter % iter_progress)) {
975 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
976 "%llu %llu", ++n_iter * iter_progress,
977 crypto->fh->ver.fh2.iter);
979 if (rc)
980 return rc;
984 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
985 crypto->blocksize))) {
986 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
987 return rc;
990 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
992 if (rc) {
993 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
994 return rc;
997 xiter++;
1000 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1001 crypto->blocksize))) {
1002 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1003 return rc;
1006 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1007 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1008 return rc;
1011 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1013 if (rc)
1014 return rc;
1016 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1017 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1018 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1020 if (rc)
1021 return rc;
1024 write_file:
1025 tmp[0] = 0;
1027 if (filename) {
1028 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1029 crypto->fh->fd = STDOUT_FILENO;
1030 goto do_write_file;
1033 if (lstat(filename, &st) == 0) {
1034 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1036 if (!(mode & S_IWUSR))
1037 return gpg_error_from_errno(EACCES);
1039 else if (errno != ENOENT)
1040 return gpg_error_from_errno(errno);
1042 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1043 crypto->fh->fd = mkstemp(tmp);
1045 if (crypto->fh->fd == -1) {
1046 rc = errno;
1047 p = strrchr(tmp, '/');
1048 p++;
1049 log_write("%s: %s", p, strerror(rc));
1050 return gpg_error_from_errno(rc);
1053 pth_cleanup_push(cleanup_unlink_cb, tmp);
1055 else
1057 * xml_import() or convert_file() from command line.
1059 crypto->fh->fd = STDOUT_FILENO;
1061 do_write_file:
1062 crypto->fh->ver.fh2.magic[0] = '\177';
1063 crypto->fh->ver.fh2.magic[1] = 'P';
1064 crypto->fh->ver.fh2.magic[2] = 'W';
1065 crypto->fh->ver.fh2.magic[3] = 'M';
1066 crypto->fh->ver.fh2.magic[4] = 'D';
1067 crypto->fh->ver.fh2.version = VERSION_HEX;
1068 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1070 if (len != sizeof(crypto->fh->ver.fh2)) {
1071 len = errno;
1073 if (tmp[0])
1074 pth_cleanup_pop(1);
1076 return gpg_error_from_errno(len);
1079 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1081 if (len != crypto->insize) {
1082 len = errno;
1084 if (tmp[0])
1085 pth_cleanup_pop(1);
1087 return gpg_error_from_errno(len);
1090 if (fsync(crypto->fh->fd) == -1) {
1091 len = errno;
1093 if (tmp[0])
1094 pth_cleanup_pop(1);
1096 return gpg_error_from_errno(len);
1099 if (tmp[0]) {
1100 #ifdef WITH_LIBACL
1101 acl_t acl;
1102 #endif
1103 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1104 gchar tmp2[FILENAME_MAX];
1106 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1107 #ifdef WITH_LIBACL
1108 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1110 if (!acl)
1111 log_write("ACL: %s: %s", filename, strerror(errno));
1112 #endif
1114 if (rename(filename, tmp2) == -1) {
1115 len = errno;
1116 pth_cleanup_pop(1);
1117 #ifdef WITH_LIBACL
1118 if (acl)
1119 acl_free(acl);
1120 #endif
1121 return gpg_error_from_errno(len);
1124 #ifdef WITH_LIBACL
1125 else {
1126 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1128 if (!acl)
1129 log_write("ACL: %s: %s", filename, strerror(errno));
1131 #endif
1133 if (rename(tmp, filename) == -1) {
1134 len = errno;
1135 pth_cleanup_pop(1);
1136 #ifdef WITH_LIBACL
1137 if (acl)
1138 acl_free(acl);
1139 #endif
1140 return gpg_error_from_errno(len);
1143 pth_cleanup_pop(0);
1145 if (mode)
1146 chmod(filename, mode);
1148 #ifdef WITH_LIBACL
1149 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1150 log_write("ACL: %s: %s", filename, strerror(errno));
1152 if (acl)
1153 acl_free(acl);
1154 #endif
1157 if (client && lstat(filename, &st) == 0)
1158 client->mtime = st.st_mtime;
1160 return 0;
1163 gpg_error_t update_save_flags(const gchar *filename,
1164 struct crypto_s *crypto)
1166 gpg_error_t rc;
1167 guint64 iter;
1169 /* New file? */
1170 if (!crypto->fh) {
1171 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1173 if (!crypto->fh)
1174 return GPG_ERR_ENOMEM;
1177 rc = init_client_crypto2(filename, crypto);
1179 if (rc)
1180 return rc;
1182 if (filename && !crypto->fh->v1) {
1183 iter = (guint64)get_key_file_double(filename, "iterations");
1184 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1187 return 0;
1190 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1191 gboolean cached)
1193 struct client_s *client = assuan_get_pointer(ctx);
1194 gpointer xmlbuf;
1195 gulong outsize = 0;
1196 guint len;
1197 gint clevel;
1198 gint timeout;
1199 gpointer outbuf;
1200 gint zrc;
1201 gpg_error_t rc;
1203 if (client->crypto->key && client->crypto->key != key)
1204 gcry_free(client->crypto->key);
1206 client->crypto->key = key;
1207 rc = update_timestamp(client->doc);
1209 if (rc)
1210 return send_error(ctx, rc);
1212 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1213 pth_cleanup_push(xmlFree, xmlbuf);
1214 clevel = get_key_file_integer(client->filename, "compression_level");
1216 if (clevel < 0)
1217 clevel = 0;
1219 if (do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1220 pth_cleanup_pop(1);
1221 cleanup_crypto(&client->crypto);
1223 if (zrc == Z_MEM_ERROR)
1224 return send_syserror(ctx, ENOMEM);
1225 else
1226 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1228 else {
1229 pth_cleanup_pop(1);
1230 xmlbuf = outbuf;
1231 len = outsize;
1234 client->crypto->inbuf = xmlbuf;
1235 client->crypto->insize = len;
1236 rc = update_save_flags(client->filename, client->crypto);
1238 if (rc) {
1239 cleanup_crypto(&client->crypto);
1240 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1241 return send_error(ctx, rc);
1244 rc = do_xml_encrypt(client, client->crypto, client->filename);
1246 if (rc) {
1247 cleanup_crypto(&client->crypto);
1248 return send_error(ctx, rc);
1251 timeout = get_key_file_integer(client->filename, "cache_timeout");
1252 CACHE_LOCK(client->ctx);
1254 if (cached) {
1255 cache_reset_timeout(client->md5file, timeout);
1256 CACHE_UNLOCK;
1258 if (client->new == TRUE)
1259 send_status_all(STATUS_CACHE);
1261 client->new = FALSE;
1262 cleanup_crypto(&client->crypto);
1263 return send_error(ctx, 0);
1266 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1267 CACHE_UNLOCK;
1268 cleanup_crypto(&client->crypto);
1269 return send_syserror(ctx, ENOMEM);
1272 client->new = FALSE;
1273 cache_reset_timeout(client->md5file, timeout);
1274 CACHE_UNLOCK;
1275 send_status_all(STATUS_CACHE);
1276 cleanup_crypto(&client->crypto);
1277 return send_error(ctx, 0);
1280 static gint save_command(assuan_context_t ctx, gchar *line)
1282 gboolean cached = FALSE;
1283 struct stat st;
1284 struct client_s *client = assuan_get_pointer(ctx);
1285 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1287 if (line && *line)
1288 log_write2("ARGS=%s", "<passphrase>");
1290 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1291 return send_syserror(ctx, errno);
1293 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1294 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1295 return send_error(ctx, GPG_ERR_ENOANO);
1298 CACHE_LOCK(ctx);
1299 cached = cache_iscached(client->md5file);
1300 CACHE_UNLOCK;
1303 * If a cache entry doesn't exist for this file and the file has a
1304 * "key_file" or "key" parameter, then it's an error. The reason is that
1305 * cache expiration would be useless.
1307 if (cached == FALSE) {
1308 gchar *tmp = get_key_file_string(client->filename, "key_file");
1310 if (tmp) {
1311 g_free(tmp);
1312 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1316 cached = FALSE;
1318 /* New file? */
1319 if (!client->crypto) {
1320 client->crypto = init_client_crypto();
1322 if (!client->crypto) {
1323 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1324 return send_syserror(ctx, ENOMEM);
1328 client->crypto->key = gcry_malloc(hashlen);
1330 if (!client->crypto->key) {
1331 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1332 cleanup_crypto(&client->crypto);
1333 return send_syserror(ctx, ENOMEM);
1336 memset(client->crypto->key, '!', hashlen);
1338 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1339 (!line || !*line))
1340 goto done;
1342 if (!line || !*line) {
1343 client->crypto->tkey = gcry_malloc(hashlen);
1345 if (!client->crypto->tkey) {
1346 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1347 cleanup_crypto(&client->crypto);
1348 return send_syserror(ctx, ENOMEM);
1351 memset(client->crypto->tkey, '!', hashlen);
1352 CACHE_LOCK(ctx);
1354 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1355 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1356 CACHE_UNLOCK;
1358 #ifdef WITH_PINENTRY
1359 gpg_error_t rc;
1361 if (client->pinentry->enable == FALSE ||
1362 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1363 /* Empty keys are allowed. */
1364 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1365 goto done;
1368 lock_pin_mutex(client);
1369 client->pinentry->which = PINENTRY_SAVE;
1370 rc = pinentry_fork(ctx);
1372 if (rc) {
1373 unlock_pin_mutex(client->pinentry);
1374 cleanup_crypto(&client->crypto);
1375 return send_error(ctx, rc);
1378 client->pinentry->cb = save_command_finalize;
1379 client->pinentry->status = PINENTRY_INIT;
1380 return 0;
1381 #else
1382 /* Empty keys are allowed. */
1383 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1384 goto done;
1385 #endif
1387 else {
1388 CACHE_UNLOCK;
1389 cached = TRUE;
1392 else {
1393 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1394 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1396 if (iter <= 0L)
1397 iter = 1;
1399 MUTEX_LOCK(&rcfile_mutex);
1400 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1401 MUTEX_UNLOCK(&rcfile_mutex);
1402 client->opts |= OPT_ITERATIONS;
1403 gpg_error_t rc = send_status(ctx, STATUS_CONFIG, NULL);
1405 if (rc)
1406 return send_error(ctx, rc);
1409 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1410 strlen(line));
1413 done:
1414 return save_command_finalize(ctx, client->crypto->key, cached);
1417 static gint delete_command(assuan_context_t ctx, gchar *line)
1419 struct client_s *client = assuan_get_pointer(ctx);
1420 gchar **req;
1421 gpg_error_t rc;
1422 xmlNodePtr n;
1424 log_write2("ARGS=\"%s\"", line);
1426 if (strchr(line, '\t'))
1427 req = split_input_line(line, "\t", -1);
1428 else
1429 req = split_input_line(line, " ", -1);
1431 if (!req || !*req)
1432 return send_error(ctx, GPG_ERR_SYNTAX);
1434 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1436 if (!n) {
1437 g_strfreev(req);
1438 return send_error(ctx, rc);
1442 * No sub-node defined. Remove the entire node (root element).
1444 if (!req[1]) {
1445 if (n) {
1446 xmlUnlinkNode(n);
1447 xmlFreeNode(n);
1450 g_strfreev(req);
1451 return send_error(ctx, 0);
1454 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1455 g_strfreev(req);
1457 if (!n)
1458 return send_error(ctx, rc);
1460 if (n) {
1461 xmlUnlinkNode(n);
1462 xmlFreeNode(n);
1465 return send_error(ctx, 0);
1469 * Don't return with assuan_process_done() here. This has been called from
1470 * assuan_process_next() and the command should be finished in
1471 * client_thread().
1473 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1474 gsize len)
1476 assuan_context_t ctx = data;
1477 struct client_s *client = assuan_get_pointer(ctx);
1478 gchar **req;
1479 xmlNodePtr n;
1480 gpg_error_t rc = file_modified(client);
1482 if (assuan_rc || rc) {
1483 if (line)
1484 xfree(line);
1485 return assuan_rc ? assuan_rc : rc;
1488 req = split_input_line((gchar *)line, "\t", 0);
1489 xfree(line);
1491 if (!req || !*req)
1492 return GPG_ERR_SYNTAX;
1494 again:
1495 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1497 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1498 rc = new_root_element(client->doc, *req);
1500 if (rc) {
1501 g_strfreev(req);
1502 return rc;
1505 goto again;
1508 if (!n) {
1509 g_strfreev(req);
1510 return rc;
1513 if (req[1]) {
1514 if (!n->children)
1515 create_elements_cb(n, req+1, &rc, NULL);
1516 else
1517 find_elements(client->doc, n->children, req+1, &rc,
1518 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1521 g_strfreev(req);
1522 client->inquire_status = INQUIRE_DONE;
1523 return rc;
1526 static gint store_command(assuan_context_t ctx, gchar *line)
1528 struct client_s *client = assuan_get_pointer(ctx);
1529 gpg_error_t rc;
1531 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1533 if (rc)
1534 return send_error(ctx, rc);
1536 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1537 client->inquire_status = INQUIRE_BUSY;
1538 return 0;
1541 static void *send_data_cb(void *arg)
1543 struct assuan_cmd_s *data = arg;
1544 gint old;
1545 gpg_error_t *rc;
1547 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1548 rc = g_malloc(sizeof(gpg_error_t));
1549 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1550 pth_cancel_state(old, NULL);
1551 pth_exit(rc);
1552 return NULL;
1555 /* For every assuan command that needs to be sent to the client, a timeout is
1556 * needed to determine if the client lost the connection. The timeout is the
1557 * same as the "keepalive" configuration parameter or a default if unset.
1559 gpg_error_t do_assuan_command(assuan_context_t ctx,
1560 void *(*cb)(void *data), void *data)
1562 pth_attr_t attr = pth_attr_new();
1563 pth_t tid;
1564 gint n;
1565 gint to = get_key_file_integer("global", "keepalive");
1566 pth_event_t ev, tev;
1567 pth_status_t st;
1568 gpg_error_t rc = 0;
1569 void *p;
1571 pth_attr_init(attr);
1572 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1573 tid = pth_spawn(attr, cb, data);
1574 n = errno;
1575 pth_attr_destroy(attr);
1577 if (!tid) {
1578 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1579 _gpg_strerror(gpg_error_from_errno(n)));
1580 return gpg_error_from_errno(n);
1583 pth_cleanup_push(cleanup_cancel_cb, tid);
1584 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1585 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1586 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1587 ev = pth_event_concat(ev, tev, NULL);
1588 pth_cleanup_push(cleanup_ev_cb, ev);
1589 pth_yield(tid);
1590 pth_wait(ev);
1592 if (tev) {
1593 st = pth_event_status(tev);
1595 if (st == PTH_STATUS_OCCURRED) {
1596 pth_cleanup_pop(1);
1597 pth_cleanup_pop(1);
1598 return GPG_ERR_TIMEOUT;
1602 st = pth_event_status(ev);
1604 if (st == PTH_STATUS_FAILED) {
1605 pth_cancel(tid);
1606 pth_join(tid, &p);
1607 g_free(p);
1608 rc = GPG_ERR_ASS_WRITE_ERROR;
1610 else if (st == PTH_STATUS_OCCURRED) {
1611 pth_join(tid, &p);
1612 rc = *(gpg_error_t *)p;
1613 g_free(p);
1616 pth_cleanup_pop(1);
1617 pth_cleanup_pop(0);
1618 return rc;
1621 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1622 gint total)
1624 gint to_send;
1625 gint sent = 0;
1626 gpg_error_t rc;
1627 struct assuan_cmd_s data;
1628 gint progress = get_key_file_integer("global", "xfer_progress");
1629 gint flush = 0;
1631 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1632 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1633 data.ctx = ctx;
1634 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1636 if (rc)
1637 return rc;
1639 again:
1640 do {
1641 if (sent + to_send > total)
1642 to_send = total - sent;
1644 data.line = flush ? NULL : (gchar *)line+sent;
1645 data.line_len = flush ? 0 : to_send;
1646 rc = do_assuan_command(ctx, send_data_cb, &data);
1648 if (!rc) {
1649 sent += flush ? 0 : to_send;
1651 if ((progress && !(sent % progress) && sent != total) ||
1652 (sent == total && flush))
1653 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1655 if (!flush && !rc && sent == total) {
1656 flush = 1;
1657 goto again;
1660 } while (!rc && sent < total);
1662 return rc;
1665 static gint get_command(assuan_context_t ctx, gchar *line)
1667 struct client_s *client = assuan_get_pointer(ctx);
1668 gchar **req;
1669 gpg_error_t rc;
1670 xmlNodePtr n;
1672 log_write2("ARGS=\"%s\"", line);
1673 req = split_input_line(line, "\t", -1);
1675 if (!req || !*req) {
1676 g_strfreev(req);
1677 return send_error(ctx, GPG_ERR_SYNTAX);
1680 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1682 if (!n) {
1683 g_strfreev(req);
1684 return send_error(ctx, rc);
1687 if (req[1])
1688 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1690 g_strfreev(req);
1692 if (rc)
1693 return send_error(ctx, rc);
1695 if (!n || !n->children)
1696 return send_error(ctx, GPG_ERR_NO_VALUE);
1698 n = find_text_node(n->children);
1700 if (!n || !n->content || !*n->content)
1701 return send_error(ctx, GPG_ERR_NO_VALUE);
1703 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1704 return send_error(ctx, rc);
1707 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1708 gpg_error_t *rc, gchar **req_orig, void *data)
1710 gchar *path = *(gchar **)data;
1711 gchar *tmp = NULL, *result;
1713 if (path) {
1714 g_free(path);
1715 *(gchar **)data = NULL;
1718 path = g_strjoinv("\t", target);
1720 if (!path) {
1721 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1722 *rc = gpg_error_from_errno(ENOMEM);
1723 return NULL;
1726 if (req_orig) {
1727 tmp = g_strjoinv("\t", req_orig);
1729 if (!tmp) {
1730 g_free(path);
1731 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1732 *rc = gpg_error_from_errno(ENOMEM);
1733 return NULL;
1737 if (tmp && *tmp)
1738 result = g_strdup_printf("%s\t%s", path, tmp);
1739 else
1740 result = g_strdup(path);
1742 if (!result) {
1743 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1744 *rc = gpg_error_from_errno(ENOMEM);
1745 g_free(path);
1746 g_free(tmp);
1747 return NULL;
1750 g_free(path);
1751 g_free(tmp);
1752 *(gchar **)data = result;
1753 return node;
1756 static void list_command_cleanup1(void *arg);
1757 static gint realpath_command(assuan_context_t ctx, gchar *line)
1759 gpg_error_t rc;
1760 struct client_s *client = assuan_get_pointer(ctx);
1761 gchar **req;
1762 gchar *t;
1763 gint i;
1764 xmlNodePtr n;
1765 GString *string;
1766 gchar *rp = NULL;
1768 log_write2("ARGS=\"%s\"", line);
1770 if (strchr(line, '\t') != NULL) {
1771 if ((req = split_input_line(line, "\t", 0)) == NULL)
1772 return send_error(ctx, GPG_ERR_SYNTAX);
1774 else {
1775 if ((req = split_input_line(line, " ", 0)) == NULL)
1776 return send_error(ctx, GPG_ERR_SYNTAX);
1779 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1781 if (!n) {
1782 g_strfreev(req);
1783 return send_error(ctx, rc);
1786 rp = g_strjoinv("\t", req);
1788 if (!rp) {
1789 g_strfreev(req);
1790 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1791 return send_syserror(ctx, ENOMEM);
1794 if (req[1]) {
1795 n = find_elements(client->doc, n->children, req+1, &rc,
1796 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
1798 if (!n) {
1799 g_free(rp);
1800 g_strfreev(req);
1801 return send_error(ctx, rc);
1805 string = g_string_new(rp);
1806 g_free(rp);
1807 g_strfreev(req);
1809 if (!string) {
1810 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1811 return send_syserror(ctx, ENOMEM);
1814 again:
1815 for (i = 0, t = string->str + i; *t; t++, i++) {
1816 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1817 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1818 goto again;
1822 pth_cleanup_push(list_command_cleanup1, string);
1823 rc = xfer_data(ctx, string->str, string->len);
1824 pth_cleanup_pop(1);
1825 return send_error(ctx, rc);
1828 static void list_command_cleanup1(void *arg)
1830 g_string_free((GString *)arg, TRUE);
1833 static void list_command_cleanup2(void *arg)
1835 struct element_list_s *elements = arg;
1837 if (elements) {
1838 gint total = g_slist_length(elements->list);
1839 gint i;
1841 for (i = 0; i < total; i++) {
1842 gchar *tmp = g_slist_nth_data(elements->list, i);
1843 g_free(tmp);
1846 g_slist_free(elements->list);
1848 if (elements->prefix)
1849 g_free(elements->prefix);
1851 g_free(elements);
1855 static gint list_command(assuan_context_t ctx, gchar *line)
1857 struct client_s *client = assuan_get_pointer(ctx);
1858 gpg_error_t rc;
1859 struct element_list_s *elements = NULL;
1860 gchar *tmp;
1862 if (disable_list_and_dump == TRUE)
1863 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1865 log_write2("ARGS=\"%s\"", line);
1867 if (!*line) {
1868 GString *str;
1870 rc = list_root_elements(client->doc, &str);
1872 if (rc)
1873 return send_error(ctx, rc);
1875 pth_cleanup_push(list_command_cleanup1, str);
1876 rc = xfer_data(ctx, str->str, str->len);
1877 pth_cleanup_pop(1);
1878 return send_error(ctx, rc);
1881 elements = g_malloc0(sizeof(struct element_list_s));
1883 if (!elements) {
1884 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1885 rc = gpg_err_code_from_errno(ENOMEM);
1886 goto fail;
1889 pth_cleanup_push(list_command_cleanup2, elements);
1890 rc = create_path_list(client->doc, elements, line);
1892 if (rc)
1893 goto fail;
1895 if (elements) {
1896 gint total = g_slist_length(elements->list);
1897 gint i;
1898 GString *str;
1900 if (!total) {
1901 rc = GPG_ERR_NO_VALUE;
1902 goto fail;
1905 str = g_string_new(NULL);
1907 if (!str) {
1908 rc = gpg_err_code_from_errno(ENOMEM);
1909 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1910 goto fail;
1913 for (i = 0; i < total; i++) {
1914 tmp = g_slist_nth_data(elements->list, i);
1915 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1918 pth_cleanup_push(list_command_cleanup1, str);
1919 rc = xfer_data(ctx, str->str, str->len);
1920 pth_cleanup_pop(1);
1922 else
1923 rc = GPG_ERR_NO_VALUE;
1925 fail:
1926 pth_cleanup_pop(1);
1927 return send_error(ctx, rc);
1931 * req[0] - element path
1933 static gint attribute_list(assuan_context_t ctx, gchar **req)
1935 struct client_s *client = assuan_get_pointer(ctx);
1936 gchar **attrlist = NULL;
1937 gint i = 0;
1938 gchar **path = NULL;
1939 xmlAttrPtr a;
1940 xmlNodePtr n, an;
1941 gchar *line;
1942 gpg_error_t rc;
1944 if (!req || !req[0])
1945 return GPG_ERR_SYNTAX;
1947 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1949 * The first argument may be only a root element.
1951 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1952 return GPG_ERR_SYNTAX;
1955 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
1957 if (!n) {
1958 g_strfreev(path);
1959 return rc;
1962 if (path[1]) {
1963 n = find_elements(client->doc, n->children, path+1, &rc,
1964 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1966 if (!n) {
1967 g_strfreev(path);
1968 return rc;
1972 g_strfreev(path);
1974 for (a = n->properties; a; a = a->next) {
1975 gchar **pa;
1977 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1978 if (attrlist)
1979 g_strfreev(attrlist);
1981 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1982 return gpg_error_from_errno(ENOMEM);
1985 attrlist = pa;
1986 an = a->children;
1987 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
1988 an && an->content ? (gchar *)an->content : "");
1990 if (!attrlist[i]) {
1991 g_strfreev(attrlist);
1992 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1993 return gpg_error_from_errno(ENOMEM);
1996 attrlist[++i] = NULL;
1999 if (!attrlist)
2000 return GPG_ERR_NO_VALUE;
2002 line = g_strjoinv("\n", attrlist);
2004 if (!line) {
2005 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2006 g_strfreev(attrlist);
2007 return gpg_error_from_errno(ENOMEM);
2010 pth_cleanup_push(g_free, line);
2011 pth_cleanup_push(req_cleanup, attrlist);
2012 rc = xfer_data(ctx, line, strlen(line));
2013 pth_cleanup_pop(1);
2014 pth_cleanup_pop(1);
2015 return rc;
2019 * req[0] - attribute
2020 * req[1] - element path
2022 static gint attribute_delete(struct client_s *client, gchar **req)
2024 xmlNodePtr n;
2025 gchar **path = NULL;
2026 gpg_error_t rc;
2028 if (!req || !req[0] || !req[1])
2029 return GPG_ERR_SYNTAX;
2031 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2033 * The first argument may be only a root element.
2035 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2036 return GPG_ERR_SYNTAX;
2040 * Don't remove the "_name" attribute for the root element. To remove an
2041 * root element use DELETE <name>.
2043 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2044 rc = GPG_ERR_SYNTAX;
2045 goto fail;
2048 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2050 if (!n)
2051 goto fail;
2053 if (path[1]) {
2054 n = find_elements(client->doc, n->children, path+1, &rc,
2055 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2057 if (!n)
2058 goto fail;
2061 g_strfreev(path);
2062 return delete_attribute(n, (xmlChar *)req[0]);
2064 fail:
2065 g_strfreev(path);
2066 return rc;
2069 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2070 gpg_error_t *rc)
2072 gchar **src = *path;
2073 gchar **src_orig = g_strdupv(src);
2074 xmlNodePtr n = NULL;
2076 *rc = 0;
2078 if (!src_orig) {
2079 *rc = gpg_error_from_errno(ENOMEM);
2080 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2081 goto fail;
2084 again:
2085 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2087 if (!n) {
2088 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2089 *rc = new_root_element(client->doc, src[0]);
2091 if (*rc)
2092 goto fail;
2094 goto again;
2096 else
2097 goto fail;
2100 if (src[1]) {
2101 if (!n->children)
2102 n = create_target_elements_cb(n, src+1, rc, NULL);
2103 else
2104 n = find_elements(client->doc, n->children, src+1, rc,
2105 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2107 if (!n)
2108 goto fail;
2111 * Reset the position of the element tree now that the elements
2112 * have been created.
2114 g_strfreev(src);
2115 src = src_orig;
2116 src_orig = NULL;
2117 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2119 if (!n)
2120 goto fail;
2122 n = find_elements(client->doc, n->children, src+1, rc,
2123 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2125 if (!n)
2126 goto fail;
2129 fail:
2130 if (src_orig)
2131 g_strfreev(src_orig);
2133 *path = src;
2134 return n;
2138 * Creates a "target" attribute. When other commands encounter an element with
2139 * this attribute, the element path is modified to the target value. If the
2140 * source element path doesn't exist when using 'ATTR SET target', it is
2141 * created, but the destination element path must exist.
2143 * req[0] - source element path
2144 * req[1] - destination element path
2146 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2148 gchar **src, **dst, *line = NULL, **odst = NULL;
2149 gpg_error_t rc;
2150 xmlNodePtr n;
2152 if (!req || !req[0] || !req[1])
2153 return GPG_ERR_SYNTAX;
2155 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2157 * The first argument may be only a root element.
2159 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2160 return GPG_ERR_SYNTAX;
2163 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2165 * The first argument may be only a root element.
2167 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2168 rc = GPG_ERR_SYNTAX;
2169 goto fail;
2173 odst = g_strdupv(dst);
2175 if (!odst) {
2176 rc = gpg_error_from_errno(ENOMEM);
2177 goto fail;
2180 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2183 * Make sure the destination element path exists.
2185 if (!n)
2186 goto fail;
2188 if (dst[1]) {
2189 n = find_elements(client->doc, n->children, dst+1, &rc,
2190 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2192 if (!n)
2193 goto fail;
2196 n = create_element_path(client, &src, &rc);
2198 if (rc)
2199 goto fail;
2201 line = g_strjoinv("\t", odst);
2203 if (!line) {
2204 rc = gpg_error_from_errno(ENOMEM);
2205 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2206 goto fail;
2209 rc = add_attribute(n, "target", line);
2211 fail:
2212 g_free(line);
2213 g_strfreev(src);
2214 g_strfreev(dst);
2215 g_strfreev(odst);
2216 return rc;
2220 * req[0] - name
2221 * req[1] - new name
2223 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2225 gpg_error_t rc;
2226 gchar **tmp;
2227 xmlNodePtr n;
2229 tmp = g_strdupv(req);
2231 if (!tmp) {
2232 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2233 return gpg_error_from_errno(ENOMEM);
2236 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2237 g_strfreev(tmp);
2239 if (!n)
2240 return rc;
2242 if (g_utf8_collate(req[0], req[1]) == 0)
2243 return 0;
2246 * Will not overwrite an existing root.
2248 tmp = g_strdupv(req+1);
2250 if (!tmp) {
2251 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2252 return gpg_error_from_errno(ENOMEM);
2255 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2256 g_strfreev(tmp);
2258 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2259 return rc;
2261 if (n)
2262 return GPG_ERR_AMBIGUOUS_NAME;
2265 * Whitespace not allowed in root names.
2267 if (contains_whitespace(req[1]) == TRUE)
2268 return GPG_ERR_SYNTAX;
2270 tmp = g_strdupv(req);
2272 if (!tmp) {
2273 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2274 return gpg_error_from_errno(ENOMEM);
2277 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2278 g_strfreev(tmp);
2280 if (!n)
2281 return GPG_ERR_ELEMENT_NOT_FOUND;
2283 return add_attribute(n, "_name", req[1]);
2287 * req[0] - attribute
2288 * req[1] - element path
2290 static gint attribute_get(assuan_context_t ctx, gchar **req)
2292 struct client_s *client = assuan_get_pointer(ctx);
2293 xmlNodePtr n;
2294 xmlChar *a;
2295 gchar **path= NULL;
2296 gpg_error_t rc;
2298 if (!req || !req[0] || !req[1])
2299 return GPG_ERR_SYNTAX;
2301 if (strchr(req[1], '\t')) {
2302 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2303 return GPG_ERR_SYNTAX;
2305 else {
2306 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2307 return GPG_ERR_SYNTAX;
2310 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2312 if (!n)
2313 goto fail;
2315 if (path[1]) {
2316 n = find_elements(client->doc, n->children, path+1, &rc,
2317 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2319 if (!n)
2320 goto fail;
2323 g_strfreev(path);
2325 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2326 return GPG_ERR_NOT_FOUND;
2328 pth_cleanup_push(xmlFree, a);
2330 if (*a)
2331 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2332 else
2333 rc = GPG_ERR_NO_VALUE;
2335 pth_cleanup_pop(1);
2336 return rc;
2338 fail:
2339 g_strfreev(path);
2340 return rc;
2344 * req[0] - attribute
2345 * req[1] - element path
2346 * req[2] - value
2348 static gint attribute_set(struct client_s *client, gchar **req)
2350 gchar **path = NULL;
2351 gpg_error_t rc;
2352 xmlNodePtr n;
2354 if (!req || !req[0] || !req[1])
2355 return GPG_ERR_SYNTAX;
2358 * Reserved attribute names.
2360 if (!strcmp(req[0], "_name")) {
2362 * Only reserved for the root element. Not the rest of the
2363 * document.
2365 if (strchr(req[1], '\t') == NULL)
2366 return name_attribute(client, req + 1);
2368 else if (!strcmp(req[0], "target"))
2369 return target_attribute(client, req + 1);
2371 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2373 * The first argument may be only a root element.
2375 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2376 return GPG_ERR_SYNTAX;
2379 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2381 if (!n)
2382 goto fail;
2384 if (path[1]) {
2385 n = find_elements(client->doc, n->children, path+1, &rc,
2386 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2388 if (!n)
2389 goto fail;
2392 g_strfreev(path);
2393 return add_attribute(n, req[0], req[2]);
2395 fail:
2396 g_strfreev(path);
2397 return rc;
2401 * req[0] - command
2402 * req[1] - attribute name or element path if command is LIST
2403 * req[2] - element path
2404 * req[2] - element path or value
2406 static gint attr_command(assuan_context_t ctx, gchar *line)
2408 struct client_s *client = assuan_get_pointer(ctx);
2409 gchar **req;
2410 gpg_error_t rc = 0;
2412 log_write2("ARGS=\"%s\"", line);
2413 req = split_input_line(line, " ", 4);
2415 if (!req || !req[0] || !req[1]) {
2416 g_strfreev(req);
2417 return send_error(ctx, GPG_ERR_SYNTAX);
2420 pth_cleanup_push(req_cleanup, req);
2422 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2423 rc = attribute_set(client, req+1);
2424 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2425 rc = attribute_get(ctx, req+1);
2426 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2427 rc = attribute_delete(client, req+1);
2428 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2429 rc = attribute_list(ctx, req+1);
2430 else
2431 rc = GPG_ERR_SYNTAX;
2433 pth_cleanup_pop(1);
2434 return send_error(ctx, rc);
2437 static gint iscached_command(assuan_context_t ctx, gchar *line)
2439 gchar **req = split_input_line(line, " ", 0);
2440 guchar md5file[16];
2441 gchar *path, *tmp;
2443 if (!req || !*req) {
2444 g_strfreev(req);
2445 return send_error(ctx, GPG_ERR_SYNTAX);
2448 log_write2("ARGS=\"%s\"", line);
2450 if (!valid_filename(req[0])) {
2451 g_strfreev(req);
2452 return GPG_ERR_INV_VALUE;
2455 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2456 CACHE_LOCK(ctx);
2458 if (cache_iscached(md5file)) {
2459 g_strfreev(req);
2460 CACHE_UNLOCK;
2461 return send_error(ctx, 0);
2464 CACHE_UNLOCK;
2465 tmp = get_key_file_string("global", "data_directory");
2467 if (!tmp) {
2468 g_strfreev(req);
2469 return gpg_error_from_errno(ENOMEM);
2472 path = expand_homedir(tmp);
2474 if (!path) {
2475 g_strfreev(req);
2476 g_free(tmp);
2477 return gpg_error_from_errno(ENOMEM);
2480 g_free(tmp);
2481 tmp = path;
2482 path = g_strdup_printf("%s/%s", tmp, req[0]);
2483 g_free(tmp);
2485 if (!path) {
2486 g_strfreev(req);
2487 return gpg_error_from_errno(ENOMEM);
2490 if (access(path, R_OK) == -1) {
2491 gpg_error_t rc = gpg_error_from_syserror();
2493 g_free(path);
2494 g_strfreev(req);
2495 return send_error(ctx, rc);
2498 g_free(path);
2499 return send_error(ctx, GPG_ERR_NOT_FOUND);
2502 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2504 struct client_s *client = assuan_get_pointer(ctx);
2505 gchar **req = split_input_line(line, " ", 0);
2506 guchar md5file[16];
2508 log_write2("ARGS=\"%s\"", line);
2509 CACHE_LOCK(ctx);
2511 if (!req || !*req) {
2512 g_strfreev(req);
2513 cache_clear(client->md5file, 2);
2514 CACHE_UNLOCK;
2515 return send_error(ctx, 0);
2518 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2519 g_strfreev(req);
2521 if (cache_clear(md5file, 1) == FALSE) {
2522 CACHE_UNLOCK;
2523 return send_error(ctx, GPG_ERR_NOT_FOUND);
2526 CACHE_UNLOCK;
2527 return send_error(ctx, 0);
2530 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2532 guchar md5file[16];
2533 glong timeout;
2534 gchar **req = split_input_line(line, " ", 0);
2535 gchar *p;
2537 if (!req || !*req || !req[1]) {
2538 g_strfreev(req);
2539 return send_error(ctx, GPG_ERR_SYNTAX);
2542 errno = 0;
2543 timeout = strtol(req[1], &p, 10);
2545 if (errno != 0 || *p != 0 || timeout < -1) {
2546 g_strfreev(req);
2547 return send_error(ctx, GPG_ERR_SYNTAX);
2550 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2551 CACHE_LOCK(client->ctx);
2553 if (cache_set_timeout(md5file, timeout) == FALSE) {
2554 CACHE_UNLOCK;
2555 return send_error(ctx, GPG_ERR_NOT_FOUND);
2558 CACHE_UNLOCK;
2559 return send_error(ctx, 0);
2562 static gint dump_command(assuan_context_t ctx, gchar *line)
2564 xmlChar *xml;
2565 gint len;
2566 struct client_s *client = assuan_get_pointer(ctx);
2567 gpg_error_t rc;
2569 if (disable_list_and_dump == TRUE)
2570 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2572 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2574 if (!xml) {
2575 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2576 return send_syserror(ctx, ENOMEM);
2579 pth_cleanup_push(xmlFree, xml);
2580 rc = xfer_data(ctx, (gchar *)xml, len);
2581 pth_cleanup_pop(1);
2582 return send_error(ctx, rc);
2585 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2587 struct client_s *client = assuan_get_pointer(ctx);
2588 gpg_error_t rc = 0;
2589 gchar filename[255]={0}, param[747]={0};
2590 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2592 log_write2("ARGS=\"%s\"", line);
2594 if (strchr(line, ' ')) {
2595 sscanf(line, " %254[^ ] %746c", filename, param);
2596 paramp = param;
2597 fp = filename;
2600 if (fp && !valid_filename(fp))
2601 return send_error(ctx, GPG_ERR_INV_VALUE);
2603 paramp = g_ascii_strdown(paramp, -1);
2605 if (!paramp) {
2606 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2607 return send_syserror(ctx, ENOMEM);
2610 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2611 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2612 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2614 if (!fh && rc != GPG_ERR_ENOENT)
2615 return send_error(ctx, rc);
2617 if (!rc) {
2618 g_free(paramp);
2619 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2620 close_file_header(fh);
2622 if (!p) {
2623 log_write("%s(%i): %s", __FILE__, __LINE__,
2624 strerror(ENOMEM));
2625 return send_syserror(ctx, ENOMEM);
2628 goto done;
2632 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2633 #ifdef WITH_PINENTRY
2634 gboolean n;
2636 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2637 n = client->pinentry->enable;
2638 else
2639 n = get_key_file_boolean(fp, "enable_pinentry");
2641 p = g_strdup_printf("%s", n ? "true" : "false");
2643 if (!p) {
2644 log_write("%s(%i): %s", __FILE__, __LINE__,
2645 strerror(ENOMEM));
2646 return send_syserror(ctx, ENOMEM);
2649 goto done;
2650 #else
2651 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2652 #endif
2654 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2655 #ifdef WITH_PINENTRY
2656 if (fp == client->filename && (client->opts & OPT_PINENTRY_TO))
2657 p = g_strdup_printf("%i", client->pinentry->timeout);
2658 else
2659 p = g_strdup_printf("%i",
2660 get_key_file_integer(fp, "pinentry_timeout"));
2662 if (!p) {
2663 log_write("%s(%i): %s", __FILE__, __LINE__,
2664 strerror(ENOMEM));
2665 return send_syserror(ctx, ENOMEM);
2668 goto done;
2669 #else
2670 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2671 #endif
2674 p = get_key_file_string(fp ? fp : "global", paramp);
2675 g_free(paramp);
2677 if (!p)
2678 return send_error(ctx, GPG_ERR_NO_VALUE);
2680 tmp = expand_homedir(p);
2681 g_free(p);
2683 if (!tmp) {
2684 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2685 return send_syserror(ctx, ENOMEM);
2688 p = tmp;
2689 done:
2690 pth_cleanup_push(g_free, p);
2691 rc = xfer_data(ctx, p, strlen(p));
2692 pth_cleanup_pop(1);
2693 return send_error(ctx, rc);
2696 struct xpath_s {
2697 xmlXPathContextPtr xp;
2698 xmlXPathObjectPtr result;
2699 xmlBufferPtr buf;
2700 gchar **req;
2703 static void xpath_command_cleanup(void *arg)
2705 struct xpath_s *xpath = arg;
2707 req_cleanup(xpath->req);
2709 if (xpath->buf)
2710 xmlBufferFree(xpath->buf);
2712 if (xpath->result)
2713 xmlXPathFreeObject(xpath->result);
2715 if (xpath->xp)
2716 xmlXPathFreeContext(xpath->xp);
2719 static gint xpath_command(assuan_context_t ctx, gchar *line)
2721 struct client_s *client = assuan_get_pointer(ctx);
2722 gpg_error_t rc;
2723 struct xpath_s xpath;
2725 log_write2("ARGS=\"%s\"", line);
2727 if (disable_list_and_dump == TRUE)
2728 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2730 if (!line || !*line)
2731 return send_error(ctx, GPG_ERR_SYNTAX);
2733 memset(&xpath, 0, sizeof(struct xpath_s));
2735 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2736 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2737 return send_syserror(ctx, ENOMEM);
2740 xpath.xp = xmlXPathNewContext(client->doc);
2742 if (!xpath.xp) {
2743 xpath_command_cleanup(&xpath);
2744 return send_error(ctx, EPWMD_LIBXML_ERROR);
2747 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2749 if (!xpath.result) {
2750 xpath_command_cleanup(&xpath);
2751 return send_error(ctx, EPWMD_LIBXML_ERROR);
2754 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2755 rc = GPG_ERR_ELEMENT_NOT_FOUND;
2756 goto fail;
2759 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2760 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
2762 if (rc)
2763 goto fail;
2764 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2765 rc = GPG_ERR_NO_VALUE;
2766 goto fail;
2768 else if (xpath.req[1])
2769 goto fail;
2771 pth_cleanup_push(xpath_command_cleanup, &xpath);
2772 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2773 xmlBufferLength(xpath.buf));
2774 pth_cleanup_pop(0);
2776 fail:
2777 xpath_command_cleanup(&xpath);
2778 return send_error(ctx, rc);
2781 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2782 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
2784 struct client_s *client = assuan_get_pointer(ctx);
2785 gpg_error_t rc;
2786 struct xpath_s xpath;
2787 gchar **req = NULL;
2788 gboolean cmd = FALSE; //SET
2790 log_write2("ARGS=\"%s\"", line);
2792 if (disable_list_and_dump == TRUE)
2793 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2795 if (!line || !*line)
2796 return send_error(ctx, GPG_ERR_SYNTAX);
2798 memset(&xpath, 0, sizeof(struct xpath_s));
2800 if ((req = split_input_line(line, " ", 3)) == NULL)
2801 return send_syserror(ctx, ENOMEM);
2803 if (!req[0]) {
2804 rc = GPG_ERR_SYNTAX;
2805 goto fail;
2808 if (!g_ascii_strcasecmp(req[0], "SET"))
2809 cmd = FALSE;
2810 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
2811 cmd = TRUE;
2812 else {
2813 rc = GPG_ERR_SYNTAX;
2814 goto fail;
2817 if (!req[1] || !req[2]) {
2818 rc = GPG_ERR_SYNTAX;
2819 goto fail;
2822 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
2823 rc = gpg_err_code_from_errno(ENOMEM);
2824 goto fail;
2827 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
2828 rc = GPG_ERR_SYNTAX;
2829 goto fail;
2832 xpath.xp = xmlXPathNewContext(client->doc);
2834 if (!xpath.xp) {
2835 rc = EPWMD_LIBXML_ERROR;
2836 goto fail;
2839 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2841 if (!xpath.result) {
2842 rc = EPWMD_LIBXML_ERROR;
2843 goto fail;
2846 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2847 rc = GPG_ERR_ELEMENT_NOT_FOUND;
2848 goto fail;
2851 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2852 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
2854 fail:
2855 g_strfreev(req);
2856 xpath_command_cleanup(&xpath);
2857 return send_error(ctx, rc);
2860 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2861 gsize len)
2863 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2864 gpg_error_t rc = file_modified(client);
2865 gchar **req, **path = NULL, **path_orig = NULL, *content;
2866 xmlDocPtr doc = NULL;
2867 xmlNodePtr n, root, copy;
2869 if (assuan_rc || rc) {
2870 if (line)
2871 xfree(line);
2872 return assuan_rc ? assuan_rc : rc;
2875 req = split_input_line((gchar *)line, "\t", 2);
2876 xfree(line);
2878 if (!req || !*req)
2879 return GPG_ERR_SYNTAX;
2881 content = req[0];
2882 path = split_input_line(req[1], "\t", 0);
2884 if (!content || !*content) {
2885 rc = GPG_ERR_SYNTAX;
2886 goto fail;
2889 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2891 if (!doc) {
2892 rc = EPWMD_LIBXML_ERROR;
2893 goto fail;
2896 root = xmlDocGetRootElement(doc);
2897 rc = validate_import(root);
2899 if (rc)
2900 goto fail;
2902 if (path) {
2903 path_orig = g_strdupv(path);
2905 if (!path_orig) {
2906 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2907 rc = gpg_error_from_errno(ENOMEM);
2908 goto fail;
2911 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
2913 if (!a) {
2914 g_strfreev(path_orig);
2915 rc = gpg_error_from_errno(ENOMEM);
2916 goto fail;
2919 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
2920 xmlFree(a);
2921 g_strfreev(path_orig);
2922 rc = gpg_error_from_errno(ENOMEM);
2923 goto fail;
2926 xmlFree(a);
2927 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2929 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
2930 g_strfreev(path_orig);
2931 goto fail;
2934 if (!rc) {
2935 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
2937 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
2938 g_strfreev(path_orig);
2939 goto fail;
2941 else if (!rc) {
2942 xmlNodePtr parent = n->parent;
2944 xmlUnlinkNode(n);
2945 xmlFreeNode(n);
2946 n = parent;
2950 g_strfreev(path);
2951 path = path_orig;
2953 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2954 n = create_element_path(client, &path, &rc);
2956 if (rc)
2957 goto fail;
2960 copy = xmlCopyNodeList(root);
2961 n = xmlAddChildList(n, copy);
2963 if (!n)
2964 rc = EPWMD_LIBXML_ERROR;
2966 else {
2967 /* Check if the content root element can create a DTD root element. */
2968 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
2969 rc = GPG_ERR_SYNTAX;
2970 goto fail;
2973 xmlChar *a;
2975 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
2976 rc = GPG_ERR_SYNTAX;
2977 goto fail;
2980 gchar *tmp = g_strdup((gchar *)a);
2981 xmlFree(a);
2982 gboolean literal = is_literal_element(&tmp);
2984 if (!valid_xml_element((xmlChar *)tmp) || literal) {
2985 g_free(tmp);
2986 rc = GPG_ERR_INV_VALUE;
2987 goto fail;
2990 if (strv_printf(&path, "%s", tmp) == FALSE) {
2991 g_free(tmp);
2992 rc = gpg_error_from_errno(ENOMEM);
2993 goto fail;
2996 g_free(tmp);
2997 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
2999 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3000 rc = EPWMD_LIBXML_ERROR;
3001 goto fail;
3004 /* Overwriting the existing tree. */
3005 if (!rc) {
3006 xmlUnlinkNode(n);
3007 xmlFreeNodeList(n);
3010 rc = 0;
3011 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3012 n = xmlCopyNode(root, 1);
3013 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3016 fail:
3017 if (doc)
3018 xmlFreeDoc(doc);
3020 if (path)
3021 g_strfreev(path);
3023 g_strfreev(req);
3024 client->inquire_status = INQUIRE_DONE;
3025 return rc;
3028 static gint import_command(assuan_context_t ctx, gchar *line)
3030 gpg_error_t rc;
3031 struct client_s *client = assuan_get_pointer(ctx);
3033 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3035 if (rc)
3036 return send_error(ctx, rc);
3038 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3039 client->inquire_status = INQUIRE_BUSY;
3040 return 0;
3043 static gpg_error_t do_lock_command(struct client_s *client)
3045 gpg_error_t rc = lock_file_mutex(client);
3047 if (!rc)
3048 client->is_lock_cmd = TRUE;
3050 return send_error(client->ctx, rc);
3053 static gint lock_command(assuan_context_t ctx, gchar *line)
3055 struct client_s *client = assuan_get_pointer(ctx);
3057 return do_lock_command(client);
3060 static gint unlock_command(assuan_context_t ctx, gchar *line)
3062 struct client_s *client = assuan_get_pointer(ctx);
3064 unlock_file_mutex(client);
3065 return send_error(ctx, 0);
3068 static gint getpid_command(assuan_context_t ctx, gchar *line)
3070 gpg_error_t rc;
3071 gchar buf[32];
3072 pid_t pid = getpid();
3074 print_fmt(buf, sizeof(buf), "%i", pid);
3075 rc = xfer_data(ctx, buf, strlen(buf));
3076 return send_error(ctx, rc);
3079 static gint version_command(assuan_context_t ctx, gchar *line)
3081 gpg_error_t rc;
3082 gchar buf[32];
3084 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3085 rc = xfer_data(ctx, buf, strlen(buf));
3086 return send_error(ctx, rc);
3089 #ifdef WITH_PINENTRY
3090 static void set_option_value(gchar **opt, const gchar *value)
3092 if (opt)
3093 g_free(*opt);
3095 *opt = NULL;
3097 if (value)
3098 *opt = g_strdup(value);
3100 #endif
3102 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3103 const gchar *value)
3105 struct client_s *client = assuan_get_pointer(ctx);
3107 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3108 glong l = 0;
3110 if (value) {
3111 l = strtol(value, NULL, 10);
3113 if (l < 0 || l > 2)
3114 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3117 log_write1("log_level=%li", l);
3118 MUTEX_LOCK(&rcfile_mutex);
3119 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3120 MUTEX_UNLOCK(&rcfile_mutex);
3121 goto done;
3123 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3124 glong l = 0;
3126 if (value) {
3127 l = strtol(value, NULL, 10);
3129 if (l < 0 || l > 1)
3130 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3133 log_write1("rc_on_locked=%li", l);
3134 client->rc_on_locked = l ? TRUE : FALSE;
3135 goto done;
3137 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3138 glong l = 0;
3140 if (value) {
3141 l = strtol(value, NULL, 10);
3143 if (l < 0 || l > 1)
3144 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3147 log_write1("lock_on_open=%li", l);
3148 client->lockonopen = l ? TRUE : FALSE;
3149 goto done;
3151 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3152 guint64 flags;
3153 const gchar *p = value;
3155 if (!client->filename)
3156 return EPWMD_NO_FILE;
3158 if (value) {
3159 flags = pwmd_cipher_str_to_cipher(value);
3161 if (!flags)
3162 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3164 else if (!value)
3165 p = get_key_file_string("global", "cipher");
3167 MUTEX_LOCK(&rcfile_mutex);
3168 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
3169 MUTEX_UNLOCK(&rcfile_mutex);
3170 log_write1("cipher=%s", p);
3172 if (!value)
3173 g_free((gchar *)p);
3175 goto done;
3177 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3178 guint64 n;
3179 gchar *p = NULL;
3181 if (!client->filename)
3182 return EPWMD_NO_FILE;
3184 if (!value) {
3185 MUTEX_LOCK(&rcfile_mutex);
3186 g_key_file_set_double(keyfileh, client->filename, "iterations",
3187 get_key_file_double("global", "iterations"));
3188 MUTEX_UNLOCK(&rcfile_mutex);
3189 log_write1("iterations=%lu",
3190 (guint64)get_key_file_double(client->filename, "iterations"));
3191 goto done;
3194 errno = 0;
3195 n = strtoul(value, &p, 10);
3197 if (errno || (p && *p) || n == G_MAXULONG)
3198 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3200 MUTEX_LOCK(&rcfile_mutex);
3201 g_key_file_set_double(keyfileh,
3202 client->filename ? client->filename : "global", "iterations", n);
3203 MUTEX_UNLOCK(&rcfile_mutex);
3205 if (client->filename)
3206 client->opts |= OPT_ITERATIONS;
3208 log_write1("iterations=%lu", n);
3209 goto done;
3211 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3212 pth_attr_t attr = pth_attr_of(pth_self());
3213 gchar buf[41];
3215 if (!value) {
3216 pth_attr_destroy(attr);
3217 goto done;
3220 print_fmt(buf, sizeof(buf), "%s", value);
3221 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3222 pth_attr_destroy(attr);
3223 log_write1("name=%s", buf);
3224 #ifdef WITH_PINENTRY
3225 if (client->pinentry->name)
3226 g_free(client->pinentry->name);
3228 client->pinentry->name = g_strdup(buf);
3230 if (!client->pinentry->name)
3231 return gpg_error_from_errno(ENOMEM);
3232 #endif
3234 goto done;
3236 #ifdef WITH_PINENTRY
3237 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3238 set_option_value(&client->pinentry->lcmessages, value);
3239 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3240 set_option_value(&client->pinentry->lcctype, value);
3241 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3242 set_option_value(&client->pinentry->ttyname, value);
3243 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3244 set_option_value(&client->pinentry->ttytype, value);
3245 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3246 set_option_value(&client->pinentry->display, value);
3247 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3248 set_option_value(&client->pinentry->path, value);
3249 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3250 set_option_value(&client->pinentry->title, value);
3251 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3252 set_option_value(&client->pinentry->prompt, value);
3253 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3254 set_option_value(&client->pinentry->desc, value);
3255 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3256 gchar *p = NULL;
3257 gint n;
3259 if (!value) {
3260 client->pinentry->timeout =
3261 get_key_file_integer(client->filename, "pinentry_timeout");
3262 client->opts &= ~(OPT_PINENTRY_TO);
3263 log_write1("pinentry_timeout=%i",
3264 get_key_file_integer(client->filename, "pinentry_timeout"));
3265 goto done;
3268 n = strtol(value, &p, 10);
3270 if (*p || n < 0)
3271 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3273 client->pinentry->timeout = n;
3274 client->opts |= OPT_PINENTRY_TO;
3275 log_write1("pinentry_timeout=%i", n);
3276 goto done;
3278 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3279 gchar *p = NULL;
3280 gint n;
3282 if (!value) {
3283 client->pinentry->enable = -1;
3284 client->opts &= ~(OPT_PINENTRY);
3285 goto done;
3288 n = strtol(value, &p, 10);
3290 if (*p || n < 0 || n > 1)
3291 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3293 client->pinentry->enable = n == 0 ? FALSE : TRUE;
3294 client->opts |= OPT_PINENTRY;
3295 log_write1("enable_pinentry=%i", n);
3296 goto done;
3298 #endif
3299 else
3300 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3302 log_write1("%s=%s", name, value ? value : "");
3304 done:
3305 return 0;
3308 static gint unset_command(assuan_context_t ctx, gchar *line)
3310 log_write2("ARGS=\"%s\"", line);
3311 return send_error(ctx, set_unset_common(ctx, line, NULL));
3314 static gint set_command(assuan_context_t ctx, gchar *line)
3316 gchar name[64] = {0}, value[256] = {0};
3318 log_write2("ARGS=\"%s\"", line);
3320 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3321 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3323 return send_error(ctx, set_unset_common(ctx, name, value));
3326 static gint rename_command(assuan_context_t ctx, gchar *line)
3328 struct client_s *client = assuan_get_pointer(ctx);
3329 gpg_error_t rc;
3330 gchar **req, **src, *dst;
3331 xmlNodePtr n, ndst;
3333 log_write2("ARGS=\"%s\"", line);
3334 req = split_input_line(line, " ", -1);
3336 if (!req || !req[0] || !req[1]) {
3337 g_strfreev(req);
3338 return send_error(ctx, GPG_ERR_SYNTAX);
3341 dst = req[1];
3342 is_literal_element(&dst);
3344 if (!valid_xml_element((xmlChar *)dst)) {
3345 g_strfreev(req);
3346 return GPG_ERR_INV_VALUE;
3349 if (strchr(req[0], '\t'))
3350 src = split_input_line(req[0], "\t", -1);
3351 else
3352 src = split_input_line(req[0], " ", -1);
3354 if (!src || !*src) {
3355 rc = GPG_ERR_SYNTAX;
3356 goto fail;
3359 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3361 if (src[1] && n)
3362 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3363 NULL, FALSE, 0, NULL, FALSE);
3365 if (!n)
3366 goto fail;
3369 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3371 if (!a) {
3372 rc = gpg_error_from_errno(ENOMEM);
3373 goto fail;
3376 /* To prevent unwanted effects:
3378 * <root name="a"><b/></root>
3380 * RENAME a<TAB>b b
3382 if (xmlStrEqual(a, (xmlChar *)dst)) {
3383 xmlFree(a);
3384 rc = GPG_ERR_AMBIGUOUS_NAME;
3385 goto fail;
3388 xmlFree(a);
3389 gchar **tmp = NULL;
3391 if (src[1]) {
3392 gchar **p;
3394 for (p = src; *p; p++) {
3395 if (!*(p+1))
3396 break;
3398 strv_printf(&tmp, "%s", *p);
3402 strv_printf(&tmp, "!%s", dst);
3403 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3405 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3406 g_strfreev(tmp);
3407 goto fail;
3410 if (tmp[1] && ndst)
3411 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3412 NULL, NULL, FALSE, 0, NULL, FALSE);
3414 g_strfreev(tmp);
3416 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3417 goto fail;
3419 rc = 0;
3421 /* Target may exist:
3423 * <root name="a"/>
3424 * <root name="b" target="a"/>
3426 * RENAME b a
3428 * Would need to do:
3429 * RENAME !b a
3431 if (ndst == n) {
3432 rc = GPG_ERR_AMBIGUOUS_NAME;
3433 goto fail;
3436 if (ndst) {
3437 xmlUnlinkNode(ndst);
3438 xmlFreeNodeList(ndst);
3441 rc = add_attribute(n, "_name", dst);
3443 fail:
3444 g_strfreev(req);
3445 g_strfreev(src);
3446 return send_error(ctx, rc);
3449 static gint copy_command(assuan_context_t ctx, gchar *line)
3451 struct client_s *client = assuan_get_pointer(ctx);
3452 gpg_error_t rc;
3453 gchar **req, **src = NULL, **dst = NULL;
3454 xmlNodePtr nsrc, ndst, new;
3456 log_write2("ARGS=\"%s\"", line);
3457 req = split_input_line(line, " ", -1);
3459 if (!req || !req[0] || !req[1]) {
3460 g_strfreev(req);
3461 return send_error(ctx, GPG_ERR_SYNTAX);
3464 if (strchr(req[0], '\t'))
3465 src = split_input_line(req[0], "\t", -1);
3466 else
3467 src = split_input_line(req[0], " ", -1);
3469 if (!src || !*src) {
3470 rc = GPG_ERR_SYNTAX;
3471 goto fail;
3474 if (strchr(req[1], '\t'))
3475 dst = split_input_line(req[1], "\t", -1);
3476 else
3477 dst = split_input_line(req[1], " ", -1);
3479 if (!dst || !*dst) {
3480 rc = GPG_ERR_SYNTAX;
3481 goto fail;
3484 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3486 if (nsrc && src[1])
3487 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3488 NULL, NULL, FALSE, 0, NULL, FALSE);
3490 if (!nsrc)
3491 goto fail;
3493 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3495 if (ndst && dst[1])
3496 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3497 NULL, NULL, FALSE, 0, NULL, FALSE);
3499 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3500 goto fail;
3502 new = xmlCopyNodeList(nsrc);
3504 if (!new) {
3505 rc = GPG_ERR_ENOMEM;
3506 goto fail;
3509 if (!ndst)
3510 ndst = create_element_path(client, &dst, &rc);
3512 if (!ndst) {
3513 xmlUnlinkNode(new);
3514 xmlFreeNodeList(new);
3515 goto fail;
3518 /* Merge any attributes from the src node to the initial dst node. */
3519 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3520 if ((!src[1] || !dst[1]) && xmlStrEqual(attr->name, (xmlChar *)"_name"))
3521 continue;
3523 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3525 if (a)
3526 xmlRemoveProp(a);
3528 xmlNewProp(ndst, attr->name, attr->children->content);
3531 xmlNodePtr n = ndst->children;
3532 xmlUnlinkNode(n);
3533 xmlFreeNodeList(n);
3534 ndst->children = NULL;
3536 if (!new->children) {
3537 xmlUnlinkNode(new);
3538 xmlFreeNodeList(new);
3539 goto fail;
3542 n = xmlCopyNodeList(new->children);
3544 if (!n) {
3545 rc = GPG_ERR_ENOMEM;
3546 goto fail;
3549 xmlUnlinkNode(new);
3550 xmlFreeNodeList(new);
3551 n = xmlAddChildList(ndst, n);
3553 if (!n) {
3554 rc = GPG_ERR_ENOMEM;
3555 goto fail;
3558 fail:
3559 if (req)
3560 g_strfreev(req);
3562 if (src)
3563 g_strfreev(src);
3565 if (dst)
3566 g_strfreev(dst);
3568 return send_error(ctx, rc);
3571 static gint move_command(assuan_context_t ctx, gchar *line)
3573 struct client_s *client = assuan_get_pointer(ctx);
3574 gpg_error_t rc;
3575 gchar **req, **src = NULL, **dst = NULL;
3576 xmlNodePtr nsrc, ndst = NULL;
3578 log_write2("ARGS=\"%s\"", line);
3579 req = split_input_line(line, " ", -1);
3581 if (!req || !req[0] || !req[1]) {
3582 g_strfreev(req);
3583 return send_error(ctx, GPG_ERR_SYNTAX);
3586 if (strchr(req[0], '\t'))
3587 src = split_input_line(req[0], "\t", -1);
3588 else
3589 src = split_input_line(req[0], " ", -1);
3591 if (!src || !*src) {
3592 rc = GPG_ERR_SYNTAX;
3593 goto fail;
3596 if (strchr(req[1], '\t'))
3597 dst = split_input_line(req[1], "\t", -1);
3598 else
3599 dst = split_input_line(req[1], " ", -1);
3601 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3603 if (nsrc && src[1])
3604 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3605 NULL, NULL, FALSE, 0, NULL, FALSE);
3607 if (!nsrc)
3608 goto fail;
3610 if (dst) {
3611 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3613 if (ndst && dst[1])
3614 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3615 NULL, NULL, FALSE, 0, NULL, FALSE);
3617 else
3618 ndst = xmlDocGetRootElement(client->doc);
3620 for (xmlNodePtr n = ndst; n; n = n->parent) {
3621 if (n == nsrc) {
3622 rc = GPG_ERR_CONFLICT;
3623 goto fail;
3627 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3628 goto fail;
3630 rc = 0;
3632 if (ndst) {
3633 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3634 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3636 xmlFree(a);
3638 if (dup) {
3639 if (dup == nsrc)
3640 goto fail;
3642 if (ndst == xmlDocGetRootElement(client->doc)) {
3643 xmlNodePtr n = nsrc;
3644 gboolean match = FALSE;
3646 while (n->parent && n->parent != ndst)
3647 n = n->parent;
3649 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3650 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3652 if (xmlStrEqual(a, b)) {
3653 match = TRUE;
3654 xmlUnlinkNode(nsrc);
3655 xmlUnlinkNode(n);
3656 xmlFreeNodeList(n);
3659 xmlFree(a);
3660 xmlFree(b);
3662 if (!match) {
3663 xmlUnlinkNode(dup);
3664 xmlFreeNodeList(dup);
3667 else
3668 xmlUnlinkNode(dup);
3672 if (!ndst && dst)
3673 ndst = create_element_path(client, &dst, &rc);
3675 if (!ndst)
3676 goto fail;
3678 xmlUnlinkNode(nsrc);
3679 ndst = xmlAddChildList(ndst, nsrc);
3681 if (!ndst)
3682 rc = GPG_ERR_ENOMEM;
3684 fail:
3685 if (req)
3686 g_strfreev(req);
3688 if (src)
3689 g_strfreev(src);
3691 if (dst)
3692 g_strfreev(dst);
3694 return send_error(ctx, rc);
3697 static int ls_command(assuan_context_t ctx, gchar *line)
3699 log_write2("ARGS=\"%s\"", line);
3700 gpg_error_t rc;
3701 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3702 gchar *dir = expand_homedir(tmp);
3703 DIR *d = opendir(dir);
3704 gint n = errno;
3706 g_free(tmp);
3708 if (!d) {
3709 g_free(dir);
3710 return send_syserror(ctx, n);
3713 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
3714 struct dirent *p = g_malloc(len), *cur = NULL;
3715 gchar *list = NULL;
3717 g_free(dir);
3718 rc = 0;
3720 while (!readdir_r(d, p, &cur) && cur) {
3721 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
3722 continue;
3723 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
3724 continue;
3726 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
3728 if (!tmp) {
3729 if (list)
3730 g_free(list);
3732 rc = GPG_ERR_ENOMEM;
3733 break;
3736 g_free(list);
3737 list = tmp;
3740 closedir(d);
3741 g_free(p);
3743 if (rc)
3744 return send_error(ctx, rc);
3746 if (!list)
3747 return send_error(ctx, GPG_ERR_NO_VALUE);
3749 list[strlen(list)-1] = 0;
3750 rc = xfer_data(ctx, list, strlen(list));
3751 g_free(list);
3752 return send_error(ctx, rc);
3755 static void bye_notify(assuan_context_t ctx)
3757 struct client_s *cl = assuan_get_pointer(ctx);
3759 /* This will let assuan_process_next() return. */
3760 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3763 static void reset_notify(assuan_context_t ctx)
3765 struct client_s *cl = assuan_get_pointer(ctx);
3767 if (cl)
3768 cleanup_client(cl);
3772 * This is called before every Assuan command.
3774 gint command_startup(assuan_context_t ctx, const gchar *name)
3776 struct client_s *cl = assuan_get_pointer(ctx);
3777 gpg_error_t rc;
3779 log_write1("%s", name);
3781 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
3782 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
3783 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
3784 !g_ascii_strcasecmp(name, "GETCONFIG") ||
3785 !g_ascii_strcasecmp(name, "GETPID") ||
3786 !g_ascii_strcasecmp(name, "VERSION") ||
3787 !g_ascii_strcasecmp(name, "SET") ||
3788 !g_ascii_strcasecmp(name, "BYE") ||
3789 !g_ascii_strcasecmp(name, "NOP") ||
3790 !g_ascii_strcasecmp(name, "CANCEL") ||
3791 !g_ascii_strcasecmp(name, "RESET") ||
3792 !g_ascii_strcasecmp(name, "END") ||
3793 !g_ascii_strcasecmp(name, "HELP") ||
3794 !g_ascii_strcasecmp(name, "OPTION") ||
3795 !g_ascii_strcasecmp(name, "INPUT") ||
3796 !g_ascii_strcasecmp(name, "OUTPUT") ||
3797 !g_ascii_strcasecmp(name, "LS") ||
3798 !g_ascii_strcasecmp(name, "UNSET"))
3799 return 0;
3801 cl->last_rc = rc = file_modified(cl);
3803 if (rc) {
3804 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3805 !g_ascii_strcasecmp(name, "OPEN"))
3806 rc = 0;
3809 return rc;
3813 * This is called after every Assuan command.
3815 void command_finalize(assuan_context_t ctx, gint rc)
3817 struct client_s *client = assuan_get_pointer(ctx);
3819 if (!client->is_lock_cmd)
3820 unlock_file_mutex(client);
3822 log_write1(N_("command completed (rc=%u)"), client->last_rc);
3825 gpg_error_t register_commands(assuan_context_t ctx)
3827 static struct {
3828 const gchar *name;
3829 gint (*handler)(assuan_context_t, gchar *line);
3830 } table[] = {
3831 { "OPEN", open_command },
3832 { "SAVE", save_command },
3833 { "LIST", list_command },
3834 { "REALPATH", realpath_command },
3835 { "STORE", store_command },
3836 { "DELETE", delete_command },
3837 { "GET", get_command },
3838 { "ATTR", attr_command },
3839 { "ISCACHED", iscached_command },
3840 { "CLEARCACHE", clearcache_command },
3841 { "CACHETIMEOUT", cachetimeout_command },
3842 { "GETCONFIG", getconfig_command },
3843 { "DUMP", dump_command },
3844 { "XPATH", xpath_command },
3845 { "XPATHATTR", xpathattr_command },
3846 { "IMPORT", import_command },
3847 { "LOCK", lock_command },
3848 { "UNLOCK", unlock_command },
3849 { "GETPID", getpid_command },
3850 { "VERSION", version_command },
3851 { "SET", set_command },
3852 { "UNSET", unset_command },
3853 { "RENAME", rename_command },
3854 { "COPY", copy_command },
3855 { "LS", ls_command },
3856 { "MOVE", move_command },
3857 { "INPUT", NULL },
3858 { "OUTPUT", NULL },
3859 { NULL, NULL }
3861 gint i, rc;
3863 for (i=0; table[i].name; i++) {
3864 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3866 if (rc)
3867 return rc;
3870 rc = assuan_register_bye_notify(ctx, bye_notify);
3872 if (rc)
3873 return rc;
3875 rc = assuan_register_reset_notify(ctx, reset_notify);
3877 if (rc)
3878 return rc;
3880 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
3882 if (rc)
3883 return rc;
3885 return assuan_register_post_cmd_notify(ctx, command_finalize);
3888 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
3889 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
3891 goffset insize, len;
3892 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3893 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
3894 gint zrc = 0;
3895 gulong outsize = 0;
3896 gpg_error_t rc;
3897 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
3898 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
3899 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
3901 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3902 insize = crypto->fh->st.st_size - fh_size;
3903 crypto->iv = gcry_malloc(crypto->blocksize);
3905 if (!crypto->iv) {
3906 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3907 return gpg_error_from_errno(ENOMEM);
3910 if (crypto->fh->v1)
3911 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
3912 else
3913 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
3915 crypto->inbuf = gcry_malloc(insize);
3917 if (!crypto->inbuf) {
3918 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3919 return gpg_error_from_errno(ENOMEM);
3922 crypto->insize = insize;
3923 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
3925 if (len != crypto->insize)
3926 return GPG_ERR_INV_LENGTH;
3928 /* No encryption iterations. This is a plain (gzipped) file. */
3929 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
3930 (!crypto->fh->v1 && fh_iter <= 0L)) {
3932 * cache_file_count() needs both .used == TRUE and a valid key in
3933 * order for it to count as a used cache entry. Fixes CACHE status
3934 * messages.
3936 memset(crypto->key, '!', hashlen);
3937 goto decompress;
3940 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
3941 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3942 return rc;
3945 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
3946 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3947 return rc;
3950 iter_progress = (guint64)get_key_file_double(client && client->filename ?
3951 client->filename : "global", "iteration_progress");
3953 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
3954 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
3956 if (rc)
3957 return rc;
3960 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3962 if (rc)
3963 return rc;
3965 crypto->tkey = gcry_malloc(hashlen);
3967 if (!crypto->tkey) {
3968 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
3969 return gpg_error_from_errno(ENOMEM);
3972 memcpy(crypto->tkey, crypto->key, hashlen);
3973 guchar *tkey = crypto->tkey;
3974 tkey[0] ^= 1;
3976 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
3977 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3978 return rc;
3981 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
3982 if (iter_progress > 0ULL && iter >= iter_progress) {
3983 if (!(iter % iter_progress)) {
3984 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
3985 ++n_iter * iter_progress, fh_iter);
3987 if (rc)
3988 return rc;
3992 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
3993 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3994 return rc;
3997 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3999 if (rc) {
4000 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4001 return rc;
4004 iter++;
4007 if (iter_progress && fh_iter >= iter_progress) {
4008 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4010 if (rc)
4011 return rc;
4014 decompress:
4015 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
4016 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
4017 if (zrc == Z_MEM_ERROR)
4018 return gpg_error_from_errno(ENOMEM);
4019 else
4020 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4023 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4024 gcry_free(crypto->outbuf);
4025 crypto->outbuf = NULL;
4026 return GPG_ERR_INV_PASSPHRASE;
4029 if (ctx) {
4030 client->xml = crypto->outbuf;
4031 client->len = outsize;
4032 crypto->outbuf = NULL;
4034 else if (dst) {
4035 *dst = crypto->outbuf;
4036 *dst_len = outsize;
4037 crypto->outbuf = NULL;
4040 /* The calling function should free the crypto struct. */
4041 return 0;