Renamed SET parameters: PINENTRY -> ENABLE_PINENTRY,
[pwmd.git] / src / commands.c
blob6a8a1b8b884676f2a4bee0b6fe789a2b1ef71a8c
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <zlib.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "mem.h"
37 #include "xml.h"
38 #include "common.h"
40 #ifdef WITH_PINENTRY
41 #include "pinentry.h"
42 #endif
44 #include "pwmd_error.h"
45 #include "cache.h"
46 #include "misc.h"
47 #include "commands.h"
48 #include "lock.h"
50 struct gz_s {
51 z_stream z;
52 gpointer out;
53 gboolean done;
54 status_msg_t which;
57 static void *z_alloc(void *data, unsigned items, unsigned size)
59 return gcry_calloc(items, size);
62 static void z_free(void *data, void *p)
64 gcry_free(p);
67 static gpg_error_t file_modified(struct client_s *client)
69 struct stat st;
70 gpg_error_t rc;
72 if (client->state != STATE_OPEN)
73 return EPWMD_NO_FILE;
75 rc = lock_file_mutex(client);
77 if (rc)
78 return rc;
80 if (lstat(client->filename, &st) == 0 && client->mtime) {
81 if (client->mtime != st.st_mtime)
82 return EPWMD_FILE_MODIFIED;
85 pth_cancel_point();
86 return 0;
89 static gpg_error_t parse_xml(assuan_context_t ctx)
91 struct client_s *client = assuan_get_pointer(ctx);
93 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
95 if (!client->doc)
96 return EPWMD_LIBXML_ERROR;
98 return 0;
101 void unlock_file_mutex(struct client_s *client)
103 pth_mutex_t *m;
105 #ifdef WITH_PINENTRY
106 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
107 #else
108 if (client->has_lock == FALSE)
109 #endif
110 return;
112 CACHE_LOCK(client->ctx);
114 if (cache_get_mutex(client->md5file, &m) == FALSE) {
115 CACHE_UNLOCK;
116 return;
119 CACHE_UNLOCK;
120 MUTEX_UNLOCK(m);
121 client->has_lock = client->is_lock_cmd = FALSE;
124 gpg_error_t lock_file_mutex(struct client_s *client)
126 pth_mutex_t *m;
127 gpg_error_t rc = 0;
129 if (client->has_lock == TRUE)
130 return 0;
132 CACHE_LOCK(client->ctx);
134 if (cache_get_mutex(client->md5file, &m) == FALSE) {
135 CACHE_UNLOCK;
136 return 0;
139 CACHE_UNLOCK;
140 MUTEX_TRYLOCK(client->ctx, m, rc);
142 if (!rc)
143 client->has_lock = TRUE;
145 return rc;
148 void free_client(struct client_s *client)
150 if (client->doc)
151 xmlFreeDoc(client->doc);
153 if (client->xml)
154 gcry_free(client->xml);
156 if (client->filename)
157 g_free(client->filename);
159 if (client->crypto)
160 cleanup_crypto(&client->crypto);
162 if (client->xml_error)
163 xmlResetError(client->xml_error);
166 void cleanup_client(struct client_s *client)
168 assuan_context_t ctx = client->ctx;
169 struct client_thread_s *thd = client->thd;
170 gboolean has_lock = client->has_lock;
171 #ifdef WITH_PINENTRY
172 struct pinentry_s *pin = client->pinentry;
173 #endif
175 unlock_file_mutex(client);
176 CACHE_LOCK(client->ctx);
177 cache_decr_refcount(client->md5file);
180 * This may be a new file so don't use a cache slot. save_command() will
181 * set this to FALSE on success.
183 if (client->new == TRUE)
184 cache_clear(client->md5file, 1);
186 CACHE_UNLOCK;
187 free_client(client);
188 memset(client, 0, sizeof(struct client_s));
189 client->state = STATE_CONNECTED;
190 client->ctx = ctx;
191 client->thd = thd;
192 client->freed = TRUE;
193 #ifdef WITH_PINENTRY
194 client->pinentry = pin;
195 #endif
196 client->has_lock = has_lock;
199 static void gz_cleanup(void *arg)
201 struct gz_s **gz = (struct gz_s **)arg;
203 if (!gz)
204 return;
206 if (!(*gz)->done && (*gz)->out)
207 gcry_free((*gz)->out);
209 if ((*gz)->which == STATUS_COMPRESS) {
210 if ((*gz)->z.zalloc)
211 deflateEnd(&(*gz)->z);
213 else {
214 if ((*gz)->z.zalloc)
215 inflateEnd(&(*gz)->z);
218 g_free(*gz);
219 *gz = NULL;
222 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
223 gpointer *out, gulong *outsize, gint *rc)
225 struct gz_s *gz;
226 gz_header h;
227 gchar buf[17];
229 gz = g_malloc0(sizeof(struct gz_s));
231 if (!gz) {
232 *rc = gpg_error_from_errno(ENOMEM);
233 return FALSE;
236 pth_cleanup_push(gz_cleanup, &gz);
237 gz->which = STATUS_DECOMPRESS;
238 gz->z.zalloc = z_alloc;
239 gz->z.zfree = z_free;
240 gz->z.next_in = in;
241 gz->z.avail_in = (uInt)insize;
242 gz->z.avail_out = zlib_bufsize;
243 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
245 if (!gz->out) {
246 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
247 *rc = Z_MEM_ERROR;
248 pth_cleanup_pop(1);
249 return FALSE;
252 *rc = inflateInit2(&gz->z, 47);
254 if (*rc != Z_OK) {
255 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
256 pth_cleanup_pop(1);
257 return FALSE;
260 memset(&h, 0, sizeof(gz_header));
261 h.comment = (guchar *)buf;
262 h.comm_max = sizeof(buf);
263 *rc = inflateGetHeader(&gz->z, &h);
265 if (*rc != Z_OK) {
266 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
267 pth_cleanup_pop(1);
268 return FALSE;
271 *rc = inflate(&gz->z, Z_BLOCK);
273 if (*rc != Z_OK) {
274 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
275 pth_cleanup_pop(1);
276 return FALSE;
279 if (h.comment)
280 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
282 do {
283 gpointer p;
285 *rc = inflate(&gz->z, Z_FINISH);
287 switch (*rc) {
288 case Z_OK:
289 break;
290 case Z_BUF_ERROR:
291 if (!gz->z.avail_out) {
292 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
294 if (!p) {
295 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
296 *rc = Z_MEM_ERROR;
297 goto fail;
300 gz->out = p;
301 gz->z.next_out = gz->out + gz->z.total_out;
302 gz->z.avail_out = zlib_bufsize;
303 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
304 gz->z.total_out, insize);
306 if (*rc)
307 goto fail;
309 break;
310 case Z_STREAM_END:
311 break;
312 default:
313 goto fail;
314 break;
316 } while (*rc != Z_STREAM_END);
318 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
319 insize);
321 if (*rc)
322 goto fail;
324 *out = gz->out;
325 *outsize = gz->z.total_out;
326 gz->done = TRUE;
327 pth_cleanup_pop(1);
328 *rc = 0;
329 return TRUE;
331 fail:
332 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
333 pth_cleanup_pop(1);
334 return FALSE;
337 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
338 gpg_error_t *rc)
340 gint fd;
341 gsize len;
342 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
343 gsize fh_size;
344 gpointer p;
346 *rc = 0;
348 if (!fh) {
349 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
350 *rc = gpg_error_from_errno(ENOMEM);
351 return NULL;
354 pth_cleanup_push(g_free, fh);
355 fh_size = v1 ? sizeof(fh->fh1) : sizeof(fh->fh2);
357 if (lstat(filename, &fh->st) == -1) {
358 *rc = gpg_error_from_syserror();
359 pth_cleanup_pop(1);
360 return NULL;
363 if (!S_ISREG(fh->st.st_mode)) {
364 *rc = GPG_ERR_ENOANO;
365 pth_cleanup_pop(1);
366 return NULL;
369 fd = open(filename, O_RDONLY);
371 if (fd == -1) {
372 *rc = gpg_error_from_errno(errno);
373 pth_cleanup_pop(1);
374 return NULL;
377 pth_cleanup_push(close, (void *)fd);
378 p = v1 ? (void *)&fh->fh1 : (void *)&fh->fh2;
379 len = pth_read(fd, p, fh_size);
381 if (len != fh_size) {
382 gint n = errno;
383 pth_cleanup_pop(1);
384 pth_cleanup_pop(1);
385 *rc = gpg_error_from_errno(n);
386 return NULL;
389 fh->v1 = v1;
390 fh->fd = fd;
391 pth_cleanup_pop(0);
392 pth_cleanup_pop(0);
393 return fh;
396 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
397 gboolean cached)
399 struct client_s *client = assuan_get_pointer(ctx);
400 gpg_error_t rc;
401 gint timeout;
403 /* New file. */
404 if (!client->crypto->fh) {
405 if (key[0])
406 goto update_cache;
408 goto done;
411 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
413 if (rc) {
414 cleanup_client(client);
415 return send_error(ctx, rc);
418 update_cache:
419 CACHE_LOCK(client->ctx);
421 if (cached == FALSE) {
422 if (cache_update_key(client->md5file, key) == FALSE) {
423 cleanup_client(client);
424 CACHE_UNLOCK;
425 return send_syserror(ctx, ENOMEM);
428 timeout = get_key_file_integer(client->filename, "cache_timeout");
429 cache_reset_timeout(client->md5file, timeout);
431 else
432 cache_set_timeout(client->md5file, -2);
434 CACHE_UNLOCK;
436 done:
437 rc = parse_xml(ctx);
439 if (client->xml) {
440 gcry_free(client->xml);
441 client->xml = NULL;
444 if (!rc) {
445 if (client->new == FALSE)
446 send_status_all(STATUS_CACHE);
448 client->state = STATE_OPEN;
451 if (!rc && client->new == FALSE &&
452 client->crypto->fh->fh2.iter != (guint64)get_key_file_integer(client->filename, "iterations")) {
453 MUTEX_LOCK(&rcfile_mutex);
454 g_key_file_set_integer(keyfileh, client->filename, "iterations",
455 client->crypto->fh->fh2.iter);
456 MUTEX_UNLOCK(&rcfile_mutex);
457 send_status_all(STATUS_CONFIG);
460 if (!rc)
461 log_write("OPEN '%s'", client->filename);
463 cleanup_crypto(&client->crypto);
464 return send_error(ctx, rc);
467 static void req_cleanup(void *arg)
469 if (!arg)
470 return;
472 g_strfreev((gchar **)arg);
475 static int open_command(assuan_context_t ctx, char *line)
477 gboolean cached = FALSE;
478 gpg_error_t rc;
479 struct client_s *client = assuan_get_pointer(ctx);
480 gchar **req;
481 gchar *filename = NULL;
483 if ((req = split_input_line(line, " ", 2)) != NULL)
484 filename = req[0];
486 pth_cleanup_push(req_cleanup, req);
488 if (!filename || !*filename) {
489 pth_cleanup_pop(1);
490 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
493 if (valid_filename(filename) == FALSE) {
494 pth_cleanup_pop(1);
495 return send_error(ctx, EPWMD_INVALID_FILENAME);
498 if (client->state == STATE_OPEN)
499 cleanup_client(client);
501 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
502 CACHE_LOCK(client->ctx);
504 if (cache_has_file(client->md5file) == FALSE) {
505 if (cache_add_file(client->md5file, NULL) == FALSE) {
506 pth_cleanup_pop(1);
507 CACHE_UNLOCK;
508 return send_syserror(ctx, ENOMEM);
512 cache_incr_refcount(client->md5file);
513 CACHE_UNLOCK;
514 rc = lock_file_mutex(client);
516 if (rc) {
517 pth_cleanup_pop(1);
518 return send_error(ctx, rc);
521 client->freed = FALSE;
522 client->crypto = init_client_crypto();
524 if (!client->crypto) {
525 pth_cleanup_pop(1);
526 cleanup_client(client);
527 return send_syserror(ctx, ENOMEM);
530 client->crypto->key = gcry_malloc(gcrykeysize);
532 if (!client->crypto->key) {
533 pth_cleanup_pop(1);
534 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
535 gpg_error_from_errno(ENOMEM));
536 cleanup_client(client);
537 return send_syserror(ctx, ENOMEM);
540 memset(client->crypto->key, 0, gcrykeysize);
541 client->crypto->fh = read_file_header(filename, FALSE, &rc);
543 if (!client->crypto->fh) {
544 if (gpg_err_code_to_errno(rc) != ENOENT) {
545 log_write("%s: %s", filename, pwmd_strerror(rc));
546 pth_cleanup_pop(1);
547 cleanup_client(client);
548 return send_error(ctx, rc);
552 * New files don't need a key.
554 if ((client->xml = new_document()) == NULL) {
555 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
556 pth_cleanup_pop(1);
557 cleanup_client(client);
558 return send_syserror(ctx, ENOMEM);
561 client->len = xmlStrlen(client->xml);
562 client->new = TRUE;
563 client->filename = g_strdup(filename);
565 if (!client->filename) {
566 pth_cleanup_pop(1);
567 cleanup_client(client);
568 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
569 return send_syserror(ctx, ENOMEM);
572 if (req[1] && *req[1])
573 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
574 strlen(req[1]));
576 pth_cleanup_pop(1);
577 #ifdef WITH_PINENTRY
578 client->pinentry->filename = g_strdup(client->filename);
580 if (!client->pinentry->filename) {
581 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
582 cleanup_client(client);
583 return send_syserror(ctx, ENOMEM);
585 #endif
586 return open_command_finalize(ctx, client->crypto->key, cached);
588 else
589 client->mtime = client->crypto->fh->st.st_mtime;
591 client->filename = g_strdup(filename);
593 if (!client->filename) {
594 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
595 pth_cleanup_pop(1);
596 cleanup_client(client);
597 return send_syserror(ctx, ENOMEM);
600 #ifdef WITH_PINENTRY
601 client->pinentry->filename = g_strdup(client->filename);
603 if (!client->pinentry->filename) {
604 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
605 pth_cleanup_pop(1);
606 cleanup_client(client);
607 return send_syserror(ctx, ENOMEM);
609 #endif
611 if (client->crypto->fh->fh2.iter <= 0)
612 goto done;
614 CACHE_LOCK(client->ctx);
615 cached = cache_get_key(client->md5file, client->crypto->key);
616 CACHE_UNLOCK;
618 if (cached == FALSE) {
619 gchar *tmp = get_key_file_string(filename, "key_file");
621 if (tmp) {
622 g_free(tmp);
623 pth_cleanup_pop(1);
624 cleanup_client(client);
625 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
629 * No key specified and no matching filename found in the cache. Use
630 * pinentry to retrieve the key. Cannot return assuan_process_done()
631 * here otherwise the command will be interrupted. The event loop in
632 * client_thread() will poll the file descriptor waiting for it to
633 * become ready to read a pinentry_key_s which will contain the
634 * entered key or an error code. It will then call
635 * open_command_finalize() to to finish the command.
637 if (!req[1] || !*req[1]) {
638 #ifdef WITH_PINENTRY
639 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
641 /* From set_pinentry_defaults(). */
642 if (client->pinentry->enable == FALSE ||
643 (client->pinentry->enable == -1 && b == FALSE)) {
644 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
645 goto done;
648 pth_cleanup_pop(1);
649 rc = lock_pin_mutex(client);
651 if (rc) {
652 unlock_pin_mutex(client->pinentry);
653 cleanup_client(client);
654 return send_error(ctx, rc);
657 client->pinentry->which = PINENTRY_OPEN;
658 rc = pinentry_fork(ctx);
660 if (rc) {
661 unlock_pin_mutex(client->pinentry);
662 cleanup_client(client);
663 return send_error(ctx, rc);
666 // Called from pinentry iterate.
667 client->pinentry->cb = open_command_finalize;
668 client->pinentry->status = PINENTRY_INIT;
669 return 0;
670 #else
671 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
672 goto done;
673 #endif
676 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
677 strlen(req[1]));
680 done:
681 pth_cleanup_pop(1);
682 return open_command_finalize(ctx, client->crypto->key, cached);
685 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
686 gulong size, gpointer *out, gulong *outsize, gint *rc)
688 struct gz_s *gz;
689 gz_header h;
690 gchar buf[17];
691 gint cmd = Z_NO_FLUSH;
693 gz = g_malloc0(sizeof(struct gz_s));
695 if (!gz) {
696 *rc = gpg_error_from_errno(ENOMEM);
697 return FALSE;
700 pth_cleanup_push(gz_cleanup, &gz);
701 gz->which = STATUS_COMPRESS;
702 gz->z.zalloc = z_alloc;
703 gz->z.zfree = z_free;
704 gz->z.next_in = data;
705 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
706 gz->z.avail_out = (uInt)zlib_bufsize;
707 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
709 if (!gz->out) {
710 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
711 *rc = Z_MEM_ERROR;
712 pth_cleanup_pop(1);
713 return FALSE;
716 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
718 if (*rc != Z_OK) {
719 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
720 pth_cleanup_pop(1);
721 return FALSE;
724 /* Rather than store the size of the uncompressed data in the file header,
725 * store it in the comment field of the gzip header. Don't give anyone too
726 * much information. Not sure why really, but it seems the right way. :)
728 memset(&h, 0, sizeof(gz_header));
729 g_snprintf(buf, sizeof(buf), "%li", size);
730 h.comment = (guchar *)buf;
731 *rc = deflateSetHeader(&gz->z, &h);
733 if (*rc != Z_OK) {
734 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
735 pth_cleanup_pop(1);
736 return FALSE;
739 do {
740 gpointer p;
742 *rc = deflate(&gz->z, cmd);
744 switch (*rc) {
745 case Z_OK:
746 break;
747 case Z_BUF_ERROR:
748 if (!gz->z.avail_out) {
749 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
751 if (!p) {
752 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
753 *rc = Z_MEM_ERROR;
754 goto fail;
757 gz->out = p;
758 gz->z.next_out = gz->out + gz->z.total_out;
759 gz->z.avail_out = zlib_bufsize;
762 if (!gz->z.avail_in && gz->z.total_in < size) {
763 if (gz->z.total_in + zlib_bufsize > size)
764 gz->z.avail_in = size - gz->z.total_in;
765 else
766 gz->z.avail_in = zlib_bufsize;
768 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
769 gz->z.total_in, size);
771 if (*rc)
772 goto fail;
775 if (gz->z.total_in >= size)
776 cmd = Z_FINISH;
778 break;
779 case Z_STREAM_END:
780 break;
781 default:
782 goto fail;
784 } while (*rc != Z_STREAM_END);
786 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", gz->z.total_in, size);
788 if (*rc)
789 goto fail;
791 *out = gz->out;
792 *outsize = gz->z.total_out;
793 *rc = 0;
794 gz->done = TRUE;
795 pth_cleanup_pop(1);
796 return TRUE;
798 fail:
799 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
800 pth_cleanup_pop(1);
801 return FALSE;
804 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
806 static gpg_error_t iterate_crypto_once(struct client_s *client,
807 struct client_crypto_s *crypto, status_msg_t which)
809 gpg_error_t rc = 0;
810 goffset len = CRYPTO_BLOCKSIZE;
811 gpointer p = gcry_malloc(len);
812 goffset total = 0;
813 gpointer inbuf;
815 if (!p)
816 return gpg_err_code_from_errno(ENOMEM);
818 if (crypto->insize < CRYPTO_BLOCKSIZE)
819 len = crypto->insize;
821 pth_cleanup_push(gcry_free, p);
823 for (;;) {
824 inbuf = crypto->inbuf + total;
825 guchar *tmp;
827 if (len + total > crypto->insize)
828 len = gcryblocksize;
830 if (which == STATUS_ENCRYPT)
831 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
832 else
833 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
835 if (rc)
836 goto done;
838 tmp = crypto->inbuf+total;
839 memmove(tmp, p, len);
840 total += len;
842 if (total >= crypto->insize)
843 break;
845 pth_cancel_point();
848 done:
849 pth_cleanup_pop(1);
850 return rc;
853 /* The crypto struct must be setup for iterations and .key. */
854 gpg_error_t do_xml_encrypt(struct client_s *client,
855 struct client_crypto_s *crypto, const gchar *filename)
857 goffset len = crypto->insize;
858 gpointer inbuf;
859 gchar *p;
860 gpg_error_t rc;
861 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
862 gchar tmp[FILENAME_MAX];
863 struct stat st;
864 mode_t mode = 0;
866 if (!crypto->fh->fh2.iter) {
868 * cache_file_count() needs both .used == TRUE and a valid key in
869 * order for it to count as a used cache entry. Fixes CACHE status
870 * messages.
872 memset(crypto->key, '!', gcrykeysize);
873 goto write_file;
877 * Resize the existing xml buffer to the block size required by gcrypt
878 * rather than duplicating it and wasting memory.
880 if (crypto->insize / gcryblocksize) {
881 len = (crypto->insize / gcryblocksize) * gcryblocksize;
883 if (crypto->insize % gcryblocksize)
884 len += gcryblocksize;
887 inbuf = gcry_realloc(crypto->inbuf, len);
889 if (!inbuf) {
890 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
891 return gpg_error_from_errno(ENOMEM);
894 crypto->inbuf = inbuf;
895 crypto->insize = len;
896 gcry_create_nonce(crypto->fh->fh2.iv, sizeof(crypto->fh->fh2.iv));
897 crypto->tkey = gcry_malloc(gcrykeysize);
899 if (!crypto->tkey) {
900 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
901 return gpg_error_from_errno(ENOMEM);
904 memcpy(crypto->tkey, crypto->key, gcrykeysize);
905 guchar *tkey = crypto->tkey;
906 tkey[0] ^= 1;
908 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
909 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
910 return rc;
913 iter_progress = (guint64)get_key_file_integer(
914 client ? client->filename : "global", "iteration_progress");
916 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
917 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
918 "0 %llu", crypto->fh->fh2.iter);
920 if (rc)
921 return rc;
924 while (xiter < crypto->fh->fh2.iter-1) {
925 if (iter_progress > 0 && xiter >= iter_progress) {
926 if (!(xiter % iter_progress)) {
927 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
928 "%llu %llu", ++n_iter * iter_progress,
929 crypto->fh->fh2.iter);
931 if (rc)
932 return rc;
936 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
937 sizeof(crypto->fh->fh2.iv)))) {
938 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
939 return rc;
942 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
944 if (rc) {
945 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
946 return rc;
949 xiter++;
952 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->fh2.iv,
953 sizeof(crypto->fh->fh2.iv)))) {
954 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
955 return rc;
958 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
959 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
960 return rc;
963 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
965 if (rc)
966 return rc;
968 if (iter_progress && crypto->fh->fh2.iter >= iter_progress) {
969 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
970 "%llu %llu", crypto->fh->fh2.iter, crypto->fh->fh2.iter);
972 if (rc)
973 return rc;
976 write_file:
977 tmp[0] = 0;
979 if (filename) {
980 if (!client && !g_strcmp0(filename, "-")) {
981 crypto->fh->fd = STDOUT_FILENO;
982 goto do_write_file;
985 if (lstat(filename, &st) == 0) {
986 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
989 * FIXME What if the file has an ACL?
991 if (!(mode & S_IWUSR))
992 return gpg_error_from_errno(EACCES);
994 else if (errno != ENOENT)
995 return gpg_error_from_errno(errno);
997 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
998 crypto->fh->fd = mkstemp(tmp);
1000 if (crypto->fh->fd == -1) {
1001 rc = errno;
1002 p = strrchr(tmp, '/');
1003 p++;
1004 log_write("%s: %s", p, strerror(rc));
1005 return gpg_error_from_errno(rc);
1008 pth_cleanup_push(unlink, tmp);
1010 else
1012 * xml_import() or convert_file() from command line.
1014 crypto->fh->fd = STDOUT_FILENO;
1016 do_write_file:
1017 crypto->fh->fh2.magic[0] = '\177';
1018 crypto->fh->fh2.magic[1] = 'P';
1019 crypto->fh->fh2.magic[2] = 'W';
1020 crypto->fh->fh2.magic[3] = 'M';
1021 crypto->fh->fh2.magic[4] = 'D';
1022 crypto->fh->fh2.version = VERSION_HEX;
1023 len = pth_write(crypto->fh->fd, &crypto->fh->fh2, sizeof(crypto->fh->fh2));
1025 if (len != sizeof(crypto->fh->fh2)) {
1026 len = errno;
1028 if (tmp[0])
1029 pth_cleanup_pop(1);
1031 return gpg_error_from_errno(len);
1034 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1036 if (len != crypto->insize) {
1037 len = errno;
1039 if (tmp[0])
1040 pth_cleanup_pop(1);
1042 return gpg_error_from_errno(len);
1045 if (fsync(crypto->fh->fd) == -1) {
1046 len = errno;
1048 if (tmp[0])
1049 pth_cleanup_pop(1);
1051 return gpg_error_from_errno(len);
1054 if (tmp[0]) {
1055 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1056 gchar tmp2[FILENAME_MAX];
1058 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1060 if (rename(filename, tmp2) == -1) {
1061 pth_cleanup_pop(1);
1062 len = errno;
1063 return gpg_error_from_errno(len);
1067 if (rename(tmp, filename) == -1) {
1068 len = errno;
1069 pth_cleanup_pop(1);
1070 return gpg_error_from_errno(len);
1073 pth_cleanup_pop(0);
1075 if (mode)
1076 chmod(filename, mode);
1079 if (client && lstat(filename, &st) == 0)
1080 client->mtime = st.st_mtime;
1082 return 0;
1085 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1086 gboolean cached)
1088 struct client_s *client = assuan_get_pointer(ctx);
1089 gpointer xmlbuf;
1090 gulong len, outsize = 0;
1091 guint iter;
1092 gint timeout;
1093 gpointer outbuf;
1094 gint zrc;
1095 gpg_error_t rc;
1097 if (client->crypto->key && client->crypto->key != key)
1098 gcry_free(client->crypto->key);
1100 client->crypto->key = key;
1101 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1102 pth_cleanup_push(xmlFree, xmlbuf);
1103 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1105 if (iter < 0)
1106 iter = 0;
1108 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1109 == FALSE) {
1110 pth_cleanup_pop(1);
1111 cleanup_crypto(&client->crypto);
1113 if (zrc == Z_MEM_ERROR)
1114 return send_syserror(ctx, ENOMEM);
1115 else
1116 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1118 else {
1119 pth_cleanup_pop(1);
1120 xmlbuf = outbuf;
1121 len = outsize;
1124 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1126 if (!client->crypto->fh) {
1127 cleanup_crypto(&client->crypto);
1128 gcry_free(outbuf);
1129 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1130 return send_syserror(ctx, ENOMEM);
1133 iter = get_key_file_integer(client->filename, "iterations");
1134 client->crypto->fh->fh2.iter = iter < 0 ? 0 : iter;
1135 client->crypto->inbuf = xmlbuf;
1136 client->crypto->insize = len;
1137 rc = do_xml_encrypt(client, client->crypto, client->filename);
1139 if (rc) {
1140 cleanup_crypto(&client->crypto);
1141 return send_error(ctx, rc);
1144 timeout = get_key_file_integer(client->filename, "cache_timeout");
1145 CACHE_LOCK(client->ctx);
1147 if (cached) {
1148 cache_reset_timeout(client->md5file, timeout);
1149 CACHE_UNLOCK;
1151 if (client->new == TRUE)
1152 send_status_all(STATUS_CACHE);
1154 client->new = FALSE;
1155 cleanup_crypto(&client->crypto);
1156 return send_error(ctx, 0);
1159 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1160 CACHE_UNLOCK;
1161 cleanup_crypto(&client->crypto);
1162 return send_syserror(ctx, ENOMEM);
1165 client->new = FALSE;
1166 cache_reset_timeout(client->md5file, timeout);
1167 CACHE_UNLOCK;
1168 send_status_all(STATUS_CACHE);
1169 cleanup_crypto(&client->crypto);
1170 return send_error(ctx, 0);
1173 static int save_command(assuan_context_t ctx, char *line)
1175 gboolean cached = FALSE;
1176 struct stat st;
1177 struct client_s *client = assuan_get_pointer(ctx);
1178 gpg_error_t rc;
1180 rc = lock_file_mutex(client);
1182 if (rc)
1183 return send_error(ctx, rc);
1185 rc = file_modified(client);
1187 if (rc)
1188 return send_error(ctx, rc);
1190 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1191 return send_syserror(ctx, errno);
1193 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1194 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1195 return send_error(ctx, GPG_ERR_ENOANO);
1198 CACHE_LOCK(ctx);
1199 cached = cache_iscached(client->md5file);
1200 CACHE_UNLOCK;
1203 * If a cache entry doesn't exist for this file and the file has a
1204 * "key_file" or "key" parameter, then it's an error. The reason is that
1205 * cache expiration would be useless.
1207 if (cached == FALSE) {
1208 gchar *tmp = get_key_file_string(client->filename, "key_file");
1210 if (tmp) {
1211 g_free(tmp);
1212 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1216 cached = FALSE;
1217 client->crypto = init_client_crypto();
1219 if (!client->crypto) {
1220 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1221 return send_syserror(ctx, ENOMEM);
1224 client->crypto->key = gcry_malloc(gcrykeysize);
1226 if (!client->crypto->key) {
1227 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1228 cleanup_crypto(&client->crypto);
1229 return send_syserror(ctx, ENOMEM);
1232 memset(client->crypto->key, '!', gcrykeysize);
1234 if (get_key_file_integer(client->filename, "iterations") <= 0)
1235 goto done;
1237 if (!line || !*line) {
1238 client->crypto->tkey = gcry_malloc(gcrykeysize);
1240 if (!client->crypto->tkey) {
1241 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1242 cleanup_crypto(&client->crypto);
1243 return send_syserror(ctx, ENOMEM);
1246 memset(client->crypto->tkey, '!', gcrykeysize);
1247 CACHE_LOCK(ctx);
1249 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1250 memcmp(client->crypto->key, client->crypto->tkey,
1251 gcrykeysize) == 0) {
1252 CACHE_UNLOCK;
1254 #ifdef WITH_PINENTRY
1255 if (client->pinentry->enable == FALSE ||
1256 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1257 /* Empty keys are allowed. */
1258 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1259 goto done;
1262 lock_pin_mutex(client);
1263 client->pinentry->which = PINENTRY_SAVE;
1264 rc = pinentry_fork(ctx);
1266 if (rc) {
1267 unlock_pin_mutex(client->pinentry);
1268 return send_error(ctx, rc);
1271 client->pinentry->cb = save_command_finalize;
1272 client->pinentry->status = PINENTRY_INIT;
1273 return 0;
1274 #else
1275 /* Empty keys are allowed. */
1276 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1277 goto done;
1278 #endif
1280 else {
1281 CACHE_UNLOCK;
1282 cached = TRUE;
1285 else
1286 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1287 strlen(line));
1289 done:
1290 return save_command_finalize(ctx, client->crypto->key, cached);
1293 static int delete_command(assuan_context_t ctx, char *line)
1295 struct client_s *client = assuan_get_pointer(ctx);
1296 gchar **req;
1297 gpg_error_t rc;
1298 xmlNodePtr n;
1300 rc = file_modified(client);
1302 if (rc)
1303 return send_error(ctx, rc);
1305 if (strchr(line, '\t'))
1306 req = split_input_line(line, "\t", -1);
1307 else
1308 req = split_input_line(line, " ", -1);
1310 if (!req || !*req)
1311 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1313 n = find_account(client->doc, &req, &rc, NULL, 0);
1315 if (!n) {
1316 g_strfreev(req);
1317 return send_error(ctx, rc);
1321 * No sub-node defined. Remove the entire node (account).
1323 if (!req[1]) {
1324 if (n) {
1325 xmlUnlinkNode(n);
1326 xmlFreeNode(n);
1329 g_strfreev(req);
1330 return send_error(ctx, 0);
1333 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1334 g_strfreev(req);
1336 if (!n)
1337 return send_error(ctx, rc);
1339 if (n) {
1340 xmlUnlinkNode(n);
1341 xmlFreeNode(n);
1344 return send_error(ctx, 0);
1348 * Don't return with assuan_process_done() here. This has been called from
1349 * assuan_process_next() and the command should be finished in
1350 * client_thread().
1352 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1353 gsize len)
1355 assuan_context_t ctx = data;
1356 struct client_s *client = assuan_get_pointer(ctx);
1357 gchar **req;
1358 xmlNodePtr n;
1359 gpg_error_t rc = file_modified(client);
1361 if (assuan_rc || rc) {
1362 if (line)
1363 xfree(line);
1364 return assuan_rc ? assuan_rc : rc;
1367 req = split_input_line((gchar *)line, "\t", 0);
1368 xfree(line);
1370 if (!req || !*req)
1371 return EPWMD_COMMAND_SYNTAX;
1373 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1374 g_strfreev(req);
1375 return EPWMD_INVALID_ELEMENT;
1378 if (valid_element_path(req+1, TRUE) == FALSE) {
1379 g_strfreev(req);
1380 return EPWMD_INVALID_ELEMENT;
1383 again:
1384 n = find_account(client->doc, &req, &rc, NULL, 0);
1386 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1387 rc = new_account(client->doc, *req);
1389 if (rc) {
1390 g_strfreev(req);
1391 return rc;
1394 goto again;
1397 if (!n) {
1398 g_strfreev(req);
1399 return rc;
1402 if (req[1]) {
1403 if (!n->children)
1404 create_elements_cb(n, req+1, &rc, NULL);
1405 else
1406 find_elements(client->doc, n->children, req+1, &rc,
1407 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1410 g_strfreev(req);
1411 client->inquire_status = INQUIRE_DONE;
1412 return rc;
1415 static int store_command(assuan_context_t ctx, char *line)
1417 struct client_s *client = assuan_get_pointer(ctx);
1418 gpg_error_t rc = file_modified(client);
1420 if (rc)
1421 return send_error(ctx, rc);
1423 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1425 if (rc)
1426 return send_error(ctx, rc);
1428 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1429 client->inquire_status = INQUIRE_BUSY;
1430 return 0;
1433 static void *send_data_cb(void *arg)
1435 struct assuan_cmd_s *data = arg;
1436 gint old;
1437 gpg_error_t rc;
1439 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1440 rc = assuan_send_data(data->ctx, data->line, data->line_len);
1441 pth_cancel_state(old, NULL);
1442 pth_exit((void *)rc);
1443 return NULL;
1446 /* For every assuan command that needs to be sent to the client, a timeout is
1447 * needed to determine if the client lost the connection. The timeout is the
1448 * same as the "keepalive" configuration parameter or a default if unset.
1450 gpg_error_t do_assuan_command(assuan_context_t ctx,
1451 void *(*cb)(void *data), void *data)
1453 pth_attr_t attr = pth_attr_new();
1454 pth_t tid;
1455 gint n;
1456 gint to = get_key_file_integer("global", "keepalive");
1457 pth_event_t ev, tev;
1458 pth_status_t st;
1459 gpg_error_t rc;
1461 pth_attr_init(attr);
1462 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1463 pth_cleanup_push(pth_attr_destroy, attr);
1464 tid = pth_spawn(attr, cb, data);
1465 n = errno;
1466 pth_cleanup_pop(1);
1468 if (!tid) {
1469 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1470 _gpg_strerror(gpg_error_from_errno(n)));
1471 return gpg_error_from_errno(n);
1474 pth_cleanup_push(pth_cancel, tid);
1475 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1476 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1477 tev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1478 ev = pth_event_concat(ev, tev, NULL);
1479 pth_cleanup_push(cleanup_ev_cb, ev);
1480 pth_yield(tid);
1481 pth_wait(ev);
1482 st = pth_event_status(ev);
1484 if (st == PTH_STATUS_FAILED) {
1485 pth_cancel(tid);
1486 rc = GPG_ERR_ASS_WRITE_ERROR;
1488 else if (st == PTH_STATUS_OCCURRED)
1489 pth_join(tid, (void **)&rc);
1490 else {
1491 st = pth_event_status(tev);
1493 if (st == PTH_STATUS_OCCURRED) {
1494 pth_cancel(tid);
1495 rc = GPG_ERR_ASS_WRITE_ERROR;
1499 pth_cleanup_pop(1);
1500 pth_cleanup_pop(0);
1501 return rc;
1504 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1505 gint total)
1507 int to_send;
1508 int sent = 0;
1509 gpg_error_t rc;
1510 struct assuan_cmd_s data;
1511 int progress = get_key_file_integer("global", "xfer_progress");
1512 int flush = 0;
1514 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1515 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1516 data.ctx = ctx;
1517 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1519 if (rc)
1520 return rc;
1522 again:
1523 do {
1524 if (sent + to_send > total)
1525 to_send = total - sent;
1527 data.line = flush ? NULL : (gchar *)line+sent;
1528 data.line_len = flush ? 0 : to_send;
1529 rc = do_assuan_command(ctx, send_data_cb, &data);
1531 if (!rc) {
1532 sent += flush ? 0 : to_send;
1534 if ((progress && !(sent % progress) && sent != total) ||
1535 (sent == total && flush))
1536 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1538 if (!flush && !rc && sent == total) {
1539 flush = 1;
1540 goto again;
1543 } while (!rc && sent < total);
1545 return rc;
1548 static int get_command(assuan_context_t ctx, char *line)
1550 struct client_s *client = assuan_get_pointer(ctx);
1551 gchar **req;
1552 gpg_error_t rc;
1553 xmlNodePtr n;
1555 rc = file_modified(client);
1557 if (rc)
1558 return send_error(ctx, rc);
1560 req = split_input_line(line, "\t", -1);
1562 if (!req || !*req) {
1563 g_strfreev(req);
1564 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1567 n = find_account(client->doc, &req, &rc, NULL, 0);
1569 if (!n) {
1570 g_strfreev(req);
1571 return send_error(ctx, rc);
1574 if (req[1])
1575 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1577 g_strfreev(req);
1579 if (rc)
1580 return send_error(ctx, rc);
1582 if (!n || !n->children)
1583 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1585 n = find_text_node(n->children);
1587 if (!n || !n->content || !*n->content)
1588 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1590 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1591 return send_error(ctx, rc);
1594 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1595 gpg_error_t *rc, gchar **req_orig, void *data)
1597 gchar *path = *(gchar **)data;
1598 gchar *tmp = NULL, *result;
1600 if (path) {
1601 g_free(path);
1602 *(gchar **)data = NULL;
1605 path = g_strjoinv("\t", target);
1607 if (!path) {
1608 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1609 *rc = gpg_error_from_errno(ENOMEM);
1610 return NULL;
1613 if (req_orig) {
1614 tmp = g_strjoinv("\t", req_orig);
1616 if (!tmp) {
1617 g_free(path);
1618 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1619 *rc = gpg_error_from_errno(ENOMEM);
1620 return NULL;
1624 if (tmp && *tmp)
1625 result = g_strdup_printf("%s\t%s", path, tmp);
1626 else
1627 result = g_strdup(path);
1629 if (!result) {
1630 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1631 *rc = gpg_error_from_errno(ENOMEM);
1632 g_free(path);
1633 g_free(tmp);
1634 return NULL;
1637 g_free(path);
1638 g_free(tmp);
1639 *(gchar **)data = result;
1640 return node;
1643 static void list_command_cleanup1(void *arg);
1644 static int realpath_command(assuan_context_t ctx, char *line)
1646 gpg_error_t rc;
1647 struct client_s *client = assuan_get_pointer(ctx);
1648 gchar **req;
1649 gchar *t;
1650 gint i;
1651 xmlNodePtr n;
1652 GString *string;
1653 gchar *rp = NULL;
1655 rc = file_modified(client);
1657 if (rc)
1658 return send_error(ctx, rc);
1660 if (strchr(line, '\t') != NULL) {
1661 if ((req = split_input_line(line, "\t", 0)) == NULL)
1662 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1664 else {
1665 if ((req = split_input_line(line, " ", 0)) == NULL)
1666 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1669 n = find_account(client->doc, &req, &rc, NULL, 0);
1671 if (!n) {
1672 g_strfreev(req);
1673 return send_error(ctx, rc);
1676 rp = g_strjoinv("\t", req);
1678 if (!rp) {
1679 g_strfreev(req);
1680 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1681 return send_syserror(ctx, ENOMEM);
1684 if (req[1]) {
1685 n = find_elements(client->doc, n->children, req+1, &rc,
1686 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1688 if (!n) {
1689 g_free(rp);
1690 g_strfreev(req);
1691 return send_error(ctx, rc);
1695 string = g_string_new(rp);
1696 g_free(rp);
1697 g_strfreev(req);
1699 if (!string) {
1700 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1701 return send_syserror(ctx, ENOMEM);
1704 again:
1705 for (i = 0, t = string->str + i; *t; t++, i++) {
1706 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1707 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1708 goto again;
1712 pth_cleanup_push(list_command_cleanup1, string);
1713 rc = xfer_data(ctx, string->str, string->len);
1714 pth_cleanup_pop(1);
1715 return send_error(ctx, rc);
1718 static void list_command_cleanup1(void *arg)
1720 g_string_free((GString *)arg, TRUE);
1723 static void list_command_cleanup2(void *arg)
1725 struct element_list_s *elements = arg;
1727 if (elements) {
1728 gint total = g_slist_length(elements->list);
1729 gint i;
1731 for (i = 0; i < total; i++) {
1732 gchar *tmp = g_slist_nth_data(elements->list, i);
1733 g_free(tmp);
1736 g_slist_free(elements->list);
1738 if (elements->prefix)
1739 g_free(elements->prefix);
1741 g_free(elements);
1745 static int list_command(assuan_context_t ctx, char *line)
1747 struct client_s *client = assuan_get_pointer(ctx);
1748 gpg_error_t rc;
1749 struct element_list_s *elements = NULL;
1750 gchar *tmp;
1752 if (disable_list_and_dump == TRUE)
1753 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1755 rc = file_modified(client);
1757 if (rc)
1758 return send_error(ctx, rc);
1760 if (!*line) {
1761 GString *str;
1763 rc = list_accounts(client->doc, &str);
1765 if (rc)
1766 return send_error(ctx, rc);
1768 pth_cleanup_push(list_command_cleanup1, str);
1769 rc = xfer_data(ctx, str->str, str->len);
1770 pth_cleanup_pop(1);
1771 return send_error(ctx, rc);
1774 elements = g_malloc0(sizeof(struct element_list_s));
1776 if (!elements) {
1777 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1778 rc = gpg_err_code_from_errno(ENOMEM);
1779 goto fail;
1782 pth_cleanup_push(list_command_cleanup2, elements);
1783 rc = create_path_list(client->doc, elements, line);
1785 if (rc)
1786 goto fail;
1788 if (elements) {
1789 gint total = g_slist_length(elements->list);
1790 gint i;
1791 GString *str;
1793 if (!total) {
1794 rc = EPWMD_EMPTY_ELEMENT;
1795 goto fail;
1798 str = g_string_new(NULL);
1800 if (!str) {
1801 rc = gpg_err_code_from_errno(ENOMEM);
1802 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1803 goto fail;
1806 for (i = 0; i < total; i++) {
1807 tmp = g_slist_nth_data(elements->list, i);
1808 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1811 pth_cleanup_push(list_command_cleanup1, str);
1812 rc = xfer_data(ctx, str->str, str->len);
1813 pth_cleanup_pop(1);
1815 else
1816 rc = EPWMD_EMPTY_ELEMENT;
1818 fail:
1819 pth_cleanup_pop(1);
1820 return send_error(ctx, rc);
1823 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1824 const gchar *value)
1826 xmlAttrPtr a;
1828 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1829 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1831 if (!a)
1832 return EPWMD_LIBXML_ERROR;
1834 else
1835 xmlNodeSetContent(a->children, (xmlChar *)value);
1837 return 0;
1841 * req[0] - element path
1843 static int attribute_list(assuan_context_t ctx, gchar **req)
1845 struct client_s *client = assuan_get_pointer(ctx);
1846 gchar **attrlist = NULL;
1847 gint i = 0;
1848 gchar **path = NULL;
1849 xmlAttrPtr a;
1850 xmlNodePtr n, an;
1851 gchar *line;
1852 gpg_error_t rc;
1854 if (!req || !req[0])
1855 return EPWMD_COMMAND_SYNTAX;
1857 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1859 * The first argument may be only an account.
1861 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1862 return EPWMD_COMMAND_SYNTAX;
1865 n = find_account(client->doc, &path, &rc, NULL, 0);
1867 if (!n) {
1868 g_strfreev(path);
1869 return rc;
1872 if (path[1]) {
1873 n = find_elements(client->doc, n->children, path+1, &rc,
1874 NULL, NULL, NULL, FALSE, 0, NULL);
1876 if (!n) {
1877 g_strfreev(path);
1878 return rc;
1882 g_strfreev(path);
1884 for (a = n->properties; a; a = a->next) {
1885 gchar **pa;
1887 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1888 if (attrlist)
1889 g_strfreev(attrlist);
1891 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1892 return gpg_error_from_errno(ENOMEM);
1895 attrlist = pa;
1896 an = a->children;
1897 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1899 if (!attrlist[i]) {
1900 g_strfreev(attrlist);
1901 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1902 return gpg_error_from_errno(ENOMEM);
1905 attrlist[++i] = NULL;
1908 if (!attrlist)
1909 return EPWMD_EMPTY_ELEMENT;
1911 line = g_strjoinv("\n", attrlist);
1913 if (!line) {
1914 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1915 g_strfreev(attrlist);
1916 return gpg_error_from_errno(ENOMEM);
1919 pth_cleanup_push(g_free, line);
1920 pth_cleanup_push(req_cleanup, attrlist);
1921 rc = xfer_data(ctx, line, strlen(line));
1922 pth_cleanup_pop(1);
1923 pth_cleanup_pop(1);
1924 return rc;
1928 * req[0] - attribute
1929 * req[1] - element path
1931 static int attribute_delete(struct client_s *client, gchar **req)
1933 xmlAttrPtr a;
1934 xmlNodePtr n;
1935 gchar **path = NULL;
1936 gpg_error_t rc;
1938 if (!req || !req[0] || !req[1])
1939 return EPWMD_COMMAND_SYNTAX;
1941 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1943 * The first argument may be only an account.
1945 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1946 return EPWMD_COMMAND_SYNTAX;
1950 * Don't remove the "name" attribute for the account element. To remove an
1951 * account use DELETE <account>.
1953 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1954 rc = EPWMD_ATTR_SYNTAX;
1955 goto fail;
1958 n = find_account(client->doc, &path, &rc, NULL, 0);
1960 if (!n)
1961 goto fail;
1963 if (path[1]) {
1964 n = find_elements(client->doc, n->children, path+1, &rc,
1965 NULL, NULL, NULL, FALSE, 0, NULL);
1967 if (!n)
1968 goto fail;
1971 g_strfreev(path);
1973 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1974 return EPWMD_ATTR_NOT_FOUND;
1976 if (xmlRemoveProp(a) == -1)
1977 return EPWMD_LIBXML_ERROR;
1979 return 0;
1981 fail:
1982 g_strfreev(path);
1983 return rc;
1986 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1987 gpg_error_t *rc)
1989 gchar **src = *path;
1990 gchar **src_orig = g_strdupv(src);
1991 xmlNodePtr n = NULL;
1993 *rc = 0;
1995 if (!src_orig) {
1996 *rc = gpg_error_from_errno(ENOMEM);
1997 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1998 goto fail;
2001 again:
2002 n = find_account(client->doc, &src, rc, NULL, 0);
2004 if (!n) {
2005 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
2006 *rc = new_account(client->doc, src[0]);
2008 if (*rc)
2009 goto fail;
2011 goto again;
2013 else
2014 goto fail;
2017 if (src[1]) {
2018 if (!n->children)
2019 n = create_target_elements_cb(n, src+1, rc, NULL);
2020 else
2021 n = find_elements(client->doc, n->children, src+1, rc,
2022 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2024 if (!n)
2025 goto fail;
2028 * Reset the position of the element tree now that the elements
2029 * have been created.
2031 g_strfreev(src);
2032 src = src_orig;
2033 src_orig = NULL;
2034 n = find_account(client->doc, &src, rc, NULL, 0);
2036 if (!n)
2037 goto fail;
2039 n = find_elements(client->doc, n->children, src+1, rc,
2040 NULL, NULL, NULL, FALSE, 0, NULL);
2042 if (!n)
2043 goto fail;
2046 fail:
2047 if (src_orig)
2048 g_strfreev(src_orig);
2050 *path = src;
2051 return n;
2055 * Creates a "target" attribute. When other commands encounter an element with
2056 * this attribute, the element path is modified to the target value. If the
2057 * source element path doesn't exist when using 'ATTR SET target', it is
2058 * created, but the destination element path must exist.
2060 * req[0] - source element path
2061 * req[1] - destination element path
2063 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2065 gchar **src, **dst, *line = NULL;
2066 gpg_error_t rc;
2067 xmlNodePtr n;
2069 if (!req || !req[0] || !req[1])
2070 return EPWMD_COMMAND_SYNTAX;
2072 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2074 * The first argument may be only an account.
2076 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2077 return EPWMD_COMMAND_SYNTAX;
2080 if (valid_element_path(src, FALSE) == FALSE) {
2081 g_strfreev(src);
2082 return EPWMD_INVALID_ELEMENT;
2085 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2087 * The first argument may be only an account.
2089 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2090 rc = EPWMD_COMMAND_SYNTAX;
2091 goto fail;
2095 n = find_account(client->doc, &dst, &rc, NULL, 0);
2098 * Make sure the destination element path exists.
2100 if (!n)
2101 goto fail;
2103 if (dst[1]) {
2104 n = find_elements(client->doc, n->children, dst+1, &rc,
2105 NULL, NULL, NULL, FALSE, 0, NULL);
2107 if (!n)
2108 goto fail;
2111 n = create_element_path(client, &src, &rc);
2113 if (rc)
2114 goto fail;
2116 line = g_strjoinv("\t", dst);
2118 if (!line) {
2119 rc = gpg_error_from_errno(ENOMEM);
2120 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2121 goto fail;
2124 rc = add_attribute(n, "target", line);
2126 fail:
2127 g_free(line);
2128 g_strfreev(src);
2129 g_strfreev(dst);
2130 return rc;
2134 * req[0] - account name
2135 * req[1] - new name
2137 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2139 gpg_error_t rc;
2140 gchar **tmp;
2141 xmlNodePtr n;
2143 tmp = g_strdupv(req);
2145 if (!tmp) {
2146 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2147 return gpg_error_from_errno(ENOMEM);
2150 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2151 g_strfreev(tmp);
2153 if (!n)
2154 return rc;
2156 if (g_utf8_collate(req[0], req[1]) == 0)
2157 return 0;
2160 * Will not overwrite an existing account.
2162 tmp = g_strdupv(req+1);
2164 if (!tmp) {
2165 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2166 return gpg_error_from_errno(ENOMEM);
2169 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2170 g_strfreev(tmp);
2172 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2173 return rc;
2175 if (n)
2176 return EPWMD_ACCOUNT_EXISTS;
2179 * Whitespace not allowed in account names.
2181 if (contains_whitespace(req[1]) == TRUE)
2182 return EPWMD_ATTR_SYNTAX;
2184 tmp = g_strdupv(req);
2186 if (!tmp) {
2187 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2188 return gpg_error_from_errno(ENOMEM);
2191 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2192 g_strfreev(tmp);
2194 if (!n)
2195 return EPWMD_ELEMENT_NOT_FOUND;
2197 return add_attribute(n, "name", req[1]);
2201 * req[0] - attribute
2202 * req[1] - element path
2204 static int attribute_get(assuan_context_t ctx, gchar **req)
2206 struct client_s *client = assuan_get_pointer(ctx);
2207 xmlNodePtr n;
2208 xmlChar *a;
2209 gchar **path= NULL;
2210 gpg_error_t rc;
2212 if (!req || !req[0] || !req[1])
2213 return EPWMD_COMMAND_SYNTAX;
2215 if (strchr(req[1], '\t')) {
2216 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2217 return EPWMD_COMMAND_SYNTAX;
2219 else {
2220 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2221 return EPWMD_COMMAND_SYNTAX;
2224 n = find_account(client->doc, &path, &rc, NULL, 0);
2226 if (!n)
2227 goto fail;
2229 if (path[1]) {
2230 n = find_elements(client->doc, n->children, path+1, &rc,
2231 NULL, NULL, NULL, FALSE, 0, NULL);
2233 if (!n)
2234 goto fail;
2237 g_strfreev(path);
2239 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2240 return EPWMD_ATTR_NOT_FOUND;
2242 pth_cleanup_push(xmlFree, a);
2243 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2244 pth_cleanup_pop(1);
2245 return rc;
2247 fail:
2248 g_strfreev(path);
2249 return rc;
2253 * req[0] - attribute
2254 * req[1] - element path
2255 * req[2] - value
2257 static int attribute_set(struct client_s *client, gchar **req)
2259 gchar **path = NULL;
2260 gpg_error_t rc;
2261 xmlNodePtr n;
2263 if (!req || !req[0] || !req[1] || !req[2])
2264 return EPWMD_COMMAND_SYNTAX;
2267 * Reserved attribute names.
2269 if (g_utf8_collate(req[0], "name") == 0) {
2271 * Only reserved for the account element. Not the rest of the
2272 * document.
2274 if (strchr(req[1], '\t') == NULL)
2275 return name_attribute(client, req + 1);
2277 else if (g_utf8_collate(req[0], "target") == 0)
2278 return target_attribute(client, req + 1);
2280 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2282 * The first argument may be only an account.
2284 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2285 return EPWMD_COMMAND_SYNTAX;
2288 n = find_account(client->doc, &path, &rc, NULL, 0);
2290 if (!n)
2291 goto fail;
2293 if (path[1]) {
2294 n = find_elements(client->doc, n->children, path+1, &rc,
2295 NULL, NULL, NULL, FALSE, 0, NULL);
2297 if (!n)
2298 goto fail;
2301 g_strfreev(path);
2302 return add_attribute(n, req[0], req[2]);
2304 fail:
2305 g_strfreev(path);
2306 return rc;
2310 * req[0] - command
2311 * req[1] - attribute name or element path if command is LIST
2312 * req[2] - element path
2313 * req[2] - element path or value
2315 static int attr_command(assuan_context_t ctx, char *line)
2317 struct client_s *client = assuan_get_pointer(ctx);
2318 gchar **req;
2319 gpg_error_t rc = 0;
2321 rc = file_modified(client);
2323 if (rc)
2324 return send_error(ctx, rc);
2326 req = split_input_line(line, " ", 4);
2328 if (!req || !req[0] || !req[1]) {
2329 g_strfreev(req);
2330 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2333 pth_cleanup_push(req_cleanup, req);
2335 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2336 rc = attribute_set(client, req+1);
2337 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2338 rc = attribute_get(ctx, req+1);
2339 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2340 rc = attribute_delete(client, req+1);
2341 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2342 rc = attribute_list(ctx, req+1);
2343 else
2344 rc = EPWMD_COMMAND_SYNTAX;
2346 pth_cleanup_pop(1);
2347 return send_error(ctx, rc);
2350 static int iscached_command(assuan_context_t ctx, char *line)
2352 gchar **req = split_input_line(line, " ", 0);
2353 guchar md5file[16];
2354 gchar *path, *tmp;
2356 if (!req || !*req) {
2357 g_strfreev(req);
2358 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2361 if (!valid_filename(req[0])) {
2362 g_strfreev(req);
2363 return EPWMD_INVALID_FILENAME;
2366 tmp = get_key_file_string("global", "data_directory");
2368 if (!tmp) {
2369 g_strfreev(req);
2370 return gpg_error_from_errno(ENOMEM);
2373 path = expand_homedir(tmp);
2375 if (!path) {
2376 g_strfreev(req);
2377 g_free(tmp);
2378 return gpg_error_from_errno(ENOMEM);
2381 g_free(tmp);
2382 tmp = path;
2383 path = g_strdup_printf("%s/%s", tmp, req[0]);
2384 g_free(tmp);
2386 if (!path) {
2387 g_strfreev(req);
2388 return gpg_error_from_errno(ENOMEM);
2391 if (access(path, R_OK) == -1) {
2392 gpg_error_t rc = gpg_error_from_syserror();
2394 g_free(path);
2395 g_strfreev(req);
2396 return send_error(ctx, rc);
2399 g_free(path);
2400 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2401 g_strfreev(req);
2402 CACHE_LOCK(ctx);
2404 if (cache_iscached(md5file) == FALSE) {
2405 CACHE_UNLOCK;
2406 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2409 CACHE_UNLOCK;
2410 return send_error(ctx, 0);
2413 static int clearcache_command(assuan_context_t ctx, char *line)
2415 struct client_s *client = assuan_get_pointer(ctx);
2416 gchar **req = split_input_line(line, " ", 0);
2417 guchar md5file[16];
2419 CACHE_LOCK(ctx);
2421 if (!req || !*req) {
2422 g_strfreev(req);
2423 cache_clear(client->md5file, 2);
2424 CACHE_UNLOCK;
2425 return send_error(ctx, 0);
2428 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2429 g_strfreev(req);
2431 if (cache_clear(md5file, 1) == FALSE) {
2432 CACHE_UNLOCK;
2433 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2436 CACHE_UNLOCK;
2437 return send_error(ctx, 0);
2440 static int cachetimeout_command(assuan_context_t ctx, char *line)
2442 guchar md5file[16];
2443 glong timeout;
2444 gchar **req = split_input_line(line, " ", 0);
2445 gchar *p;
2447 if (!req || !*req || !req[1]) {
2448 g_strfreev(req);
2449 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2452 errno = 0;
2453 timeout = strtol(req[0], &p, 10);
2455 if (errno != 0 || *p != 0) {
2456 g_strfreev(req);
2457 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2460 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2461 CACHE_LOCK(client->ctx);
2463 if (cache_set_timeout(md5file, timeout) == FALSE) {
2464 CACHE_UNLOCK;
2465 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2468 CACHE_UNLOCK;
2469 return send_error(ctx, 0);
2472 static int dump_command(assuan_context_t ctx, char *line)
2474 xmlChar *xml;
2475 gssize len;
2476 struct client_s *client = assuan_get_pointer(ctx);
2477 gpg_error_t rc;
2479 if (disable_list_and_dump == TRUE)
2480 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2482 rc = file_modified(client);
2484 if (rc)
2485 return send_error(ctx, rc);
2487 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2489 if (!xml) {
2490 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2491 return send_syserror(ctx, ENOMEM);
2494 pth_cleanup_push(xmlFree, xml);
2495 rc = xfer_data(ctx, (gchar *)xml, len);
2496 pth_cleanup_pop(1);
2497 return send_error(ctx, rc);
2500 static int getconfig_command(assuan_context_t ctx, gchar *line)
2502 struct client_s *client = assuan_get_pointer(ctx);
2503 gpg_error_t rc = 0;
2504 gchar filename[255]={0}, param[747]={0};
2505 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2507 if (strchr(line, ' ')) {
2508 sscanf(line, " %254[^ ] %746c", filename, param);
2509 paramp = param;
2510 fp = filename;
2513 if (fp && !valid_filename(fp))
2514 return send_error(ctx, EPWMD_INVALID_FILENAME);
2516 paramp = g_ascii_strdown(paramp, -1);
2518 if (!paramp) {
2519 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2520 return send_syserror(ctx, ENOMEM);
2523 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2524 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2525 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2527 if (!fh && rc != GPG_ERR_ENOENT)
2528 return send_error(ctx, rc);
2530 if (!rc) {
2531 g_free(paramp);
2532 p = g_strdup_printf("%llu", fh->fh2.iter);
2533 close_file_header(fh);
2535 if (!p) {
2536 log_write("%s(%i): %s", __FILE__, __LINE__,
2537 strerror(ENOMEM));
2538 return send_syserror(ctx, ENOMEM);
2541 goto done;
2545 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2546 gboolean n;
2548 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2549 n = client->pinentry->enable;
2550 else
2551 n = get_key_file_boolean(fp, "enable_pinentry");
2553 p = g_strdup_printf("%s", n ? "true" : "false");
2555 if (!p) {
2556 log_write("%s(%i): %s", __FILE__, __LINE__,
2557 strerror(ENOMEM));
2558 return send_syserror(ctx, ENOMEM);
2561 goto done;
2563 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2564 if (fp == client->filename && (client->opts & OPT_PINENTRY_TO))
2565 p = g_strdup_printf("%i", client->pinentry->timeout);
2566 else
2567 p = g_strdup_printf("%i",
2568 get_key_file_integer(fp, "pinentry_timeout"));
2570 if (!p) {
2571 log_write("%s(%i): %s", __FILE__, __LINE__,
2572 strerror(ENOMEM));
2573 return send_syserror(ctx, ENOMEM);
2576 goto done;
2579 p = get_key_file_string(fp ? fp : "global", paramp);
2580 g_free(paramp);
2582 if (!p)
2583 return send_error(ctx, GPG_ERR_NO_VALUE);
2585 tmp = expand_homedir(p);
2586 g_free(p);
2588 if (!tmp) {
2589 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2590 return send_syserror(ctx, ENOMEM);
2593 p = tmp;
2594 done:
2595 pth_cleanup_push(g_free, p);
2596 rc = xfer_data(ctx, p, strlen(p));
2597 pth_cleanup_pop(1);
2598 return send_error(ctx, rc);
2601 struct xpath_s {
2602 xmlXPathContextPtr xp;
2603 xmlXPathObjectPtr result;
2604 xmlBufferPtr buf;
2605 gchar **req;
2608 static void xpath_command_cleanup(void *arg)
2610 struct xpath_s *xpath = arg;
2612 req_cleanup(xpath->req);
2614 if (xpath->buf)
2615 xmlBufferFree(xpath->buf);
2617 if (xpath->result)
2618 xmlXPathFreeObject(xpath->result);
2620 if (xpath->xp)
2621 xmlXPathFreeContext(xpath->xp);
2624 static int xpath_command(assuan_context_t ctx, gchar *line)
2626 struct client_s *client = assuan_get_pointer(ctx);
2627 gpg_error_t rc;
2628 struct xpath_s xpath;
2630 if (disable_list_and_dump == TRUE)
2631 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2633 rc = file_modified(client);
2635 if (rc)
2636 return send_error(ctx, rc);
2638 if (!line || !*line)
2639 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2641 memset(&xpath, 0, sizeof(struct xpath_s));
2643 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2644 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2645 return send_syserror(ctx, ENOMEM);
2648 xpath.xp = xmlXPathNewContext(client->doc);
2650 if (!xpath.xp) {
2651 xpath_command_cleanup(&xpath);
2652 return send_error(ctx, EPWMD_LIBXML_ERROR);
2655 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2657 if (!xpath.result) {
2658 xpath_command_cleanup(&xpath);
2659 return send_error(ctx, EPWMD_LIBXML_ERROR);
2662 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2663 rc = EPWMD_EMPTY_ELEMENT;
2664 goto fail;
2667 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2668 (xmlChar *)xpath.req[1], &xpath.buf);
2670 if (rc)
2671 goto fail;
2672 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2673 rc = EPWMD_EMPTY_ELEMENT;
2674 goto fail;
2676 else if (xpath.req[1])
2677 goto fail;
2679 pth_cleanup_push(xpath_command_cleanup, &xpath);
2680 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2681 xmlBufferLength(xpath.buf));
2682 pth_cleanup_pop(0);
2684 fail:
2685 xpath_command_cleanup(&xpath);
2686 return send_error(ctx, rc);
2689 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2690 gsize len)
2692 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2693 gpg_error_t rc = file_modified(client);
2694 gchar **req, **path = NULL, **path_orig = NULL, *content;
2695 xmlDocPtr doc;
2696 xmlNodePtr n, root, copy;
2698 if (assuan_rc || rc) {
2699 if (line)
2700 xfree(line);
2701 return assuan_rc ? assuan_rc : rc;
2704 req = split_input_line((gchar *)line, " ", 2);
2705 xfree(line);
2707 if (!req || !*req)
2708 return EPWMD_COMMAND_SYNTAX;
2710 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2711 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2712 return EPWMD_COMMAND_SYNTAX;
2715 content = req[1];
2717 if (!content || !*content) {
2718 rc = EPWMD_COMMAND_SYNTAX;
2719 goto fail;
2722 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2723 rc = EPWMD_INVALID_ELEMENT;
2724 goto fail;
2727 if (valid_element_path(path+1, FALSE) == FALSE) {
2728 rc = EPWMD_INVALID_ELEMENT;
2729 goto fail;
2732 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2734 if (!doc) {
2735 rc = EPWMD_LIBXML_ERROR;
2736 goto fail;
2739 root = xmlDocGetRootElement(doc);
2740 path_orig = g_strdupv(path);
2742 if (!path_orig) {
2743 xmlFreeDoc(doc);
2744 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2745 rc = gpg_error_from_errno(ENOMEM);
2746 goto fail;
2749 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2750 g_strfreev(path_orig);
2751 xmlFreeDoc(doc);
2752 rc = gpg_error_from_errno(ENOMEM);
2753 goto fail;
2756 n = find_account(client->doc, &path, &rc, NULL, 0);
2758 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2759 g_strfreev(path_orig);
2760 xmlFreeDoc(doc);
2761 goto fail;
2763 else if (!rc) {
2764 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2766 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2767 g_strfreev(path_orig);
2768 xmlFreeDoc(doc);
2769 goto fail;
2771 else if (!rc) {
2772 xmlNodePtr parent = n->parent;
2774 xmlUnlinkNode(n);
2775 xmlFreeNode(n);
2776 n = parent;
2780 g_strfreev(path);
2781 path = path_orig;
2783 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2784 n = create_element_path(client, &path, &rc);
2786 if (rc) {
2787 xmlFreeDoc(doc);
2788 goto fail;
2792 copy = xmlCopyNode(root, 1);
2793 n = xmlAddChild(n, copy);
2794 xmlFreeDoc(doc);
2796 if (!n)
2797 rc = EPWMD_LIBXML_ERROR;
2799 fail:
2800 g_strfreev(path);
2801 g_strfreev(req);
2802 client->inquire_status = INQUIRE_DONE;
2803 return rc;
2806 static int import_command(assuan_context_t ctx, gchar *line)
2808 gpg_error_t rc;
2809 struct client_s *client = assuan_get_pointer(ctx);
2811 rc = file_modified(client);
2813 if (rc)
2814 return send_error(ctx, rc);
2816 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2818 if (rc)
2819 return send_error(ctx, rc);
2821 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2822 client->inquire_status = INQUIRE_BUSY;
2823 return 0;
2826 static int lock_command(assuan_context_t ctx, gchar *line)
2828 gpg_error_t rc;
2829 struct client_s *client = assuan_get_pointer(ctx);
2831 rc = file_modified(client);
2833 if (rc)
2834 return send_error(ctx, rc);
2836 rc = lock_file_mutex(client);
2838 if (!rc)
2839 client->is_lock_cmd = TRUE;
2841 return send_error(ctx, rc);
2844 static int unlock_command(assuan_context_t ctx, gchar *line)
2846 struct client_s *client = assuan_get_pointer(ctx);
2847 gpg_error_t rc = file_modified(client);
2849 if (rc)
2850 return send_error(ctx, rc);
2852 unlock_file_mutex(client);
2853 return send_error(ctx, 0);
2856 static int getpid_command(assuan_context_t ctx, gchar *line)
2858 gpg_error_t rc;
2859 gchar buf[32];
2860 pid_t pid = getpid();
2862 print_fmt(buf, sizeof(buf), "%i", pid);
2863 rc = xfer_data(ctx, buf, strlen(buf));
2864 return send_error(ctx, rc);
2867 static int version_command(assuan_context_t ctx, gchar *line)
2869 gpg_error_t rc;
2870 gchar buf[32];
2872 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
2873 rc = xfer_data(ctx, buf, strlen(buf));
2874 return send_error(ctx, rc);
2877 static void set_option_value(gchar **opt, const gchar *value)
2879 if (opt)
2880 g_free(*opt);
2882 *opt = NULL;
2884 if (value)
2885 *opt = g_strdup(value);
2888 static int set_unset_common(assuan_context_t ctx, const gchar *name,
2889 const gchar *value)
2891 struct client_s *client = assuan_get_pointer(ctx);
2893 if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
2894 long n;
2895 gchar *p = NULL;
2897 if (!client->filename)
2898 return EPWMD_NO_FILE;
2900 if (!value) {
2901 MUTEX_LOCK(&rcfile_mutex);
2902 g_key_file_set_integer(keyfileh, client->filename, "iterations",
2903 get_key_file_integer("global", "iterations"));
2904 MUTEX_UNLOCK(&rcfile_mutex);
2905 goto done;
2908 errno = 0;
2909 n = strtol(value, &p, 10);
2911 if (errno || (p && *p) || n < 0)
2912 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2914 MUTEX_LOCK(&rcfile_mutex);
2915 g_key_file_set_integer(keyfileh,
2916 client->filename ? client->filename : "global", "iterations",
2917 (guint)n);
2918 MUTEX_UNLOCK(&rcfile_mutex);
2920 if (client->filename)
2921 client->opts |= OPT_ITERATIONS;
2923 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
2924 pth_attr_t attr = pth_attr_of(pth_self());
2925 gchar buf[41];
2927 if (!value) {
2928 pth_attr_destroy(attr);
2929 goto done;
2932 print_fmt(buf, sizeof(buf), "%s", value);
2933 pth_attr_set(attr, PTH_ATTR_NAME, buf);
2934 pth_attr_destroy(attr);
2935 #ifdef WITH_PINENTRY
2936 if (client->pinentry->name)
2937 g_free(client->pinentry->name);
2939 client->pinentry->name = g_strdup(buf);
2941 if (!client->pinentry->name)
2942 return gpg_error_from_errno(ENOMEM);
2943 #endif
2945 #ifdef WITH_PINENTRY
2946 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
2947 set_option_value(&client->pinentry->lcmessages, value);
2948 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
2949 set_option_value(&client->pinentry->lcctype, value);
2950 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
2951 set_option_value(&client->pinentry->ttyname, value);
2952 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
2953 set_option_value(&client->pinentry->ttytype, value);
2954 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
2955 set_option_value(&client->pinentry->display, value);
2956 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
2957 set_option_value(&client->pinentry->path, value);
2958 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
2959 set_option_value(&client->pinentry->title, value);
2960 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
2961 set_option_value(&client->pinentry->prompt, value);
2962 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
2963 set_option_value(&client->pinentry->desc, value);
2964 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
2965 gchar *p = NULL;
2966 gint n;
2968 if (!value) {
2969 client->pinentry->timeout =
2970 get_key_file_integer(client->filename, "pinentry_timeout");
2971 client->opts &= ~(OPT_PINENTRY_TO);
2972 goto done;
2975 n = strtol(value, &p, 10);
2977 if (*p || n < 0)
2978 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2980 client->pinentry->timeout = n;
2981 client->opts |= OPT_PINENTRY_TO;
2983 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
2984 gchar *p = NULL;
2985 gint n;
2987 if (!value) {
2988 client->pinentry->enable = -1;
2989 client->opts &= ~(OPT_PINENTRY);
2990 goto done;
2993 n = strtol(value, &p, 10);
2995 if (*p || n < 0 || n > 1)
2996 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2998 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2999 client->opts |= OPT_PINENTRY;
3001 #endif
3002 else
3003 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3005 done:
3006 log_write("%s %s%s%s", value ? "SET" : "UNSET", name,
3007 value ? "=" : "", value ? value : "");
3008 return 0;
3011 static int unset_command(assuan_context_t ctx, gchar *line)
3013 return send_error(ctx, set_unset_common(ctx, line, NULL));
3016 static int set_command(assuan_context_t ctx, gchar *line)
3018 gchar name[64] = {0}, value[256] = {0};
3020 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3021 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3023 return send_error(ctx, set_unset_common(ctx, name, value));
3026 static void bye_notify(assuan_context_t ctx)
3028 struct client_s *cl = assuan_get_pointer(ctx);
3030 /* This will let assuan_process_next() return. */
3031 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3034 static void reset_notify(assuan_context_t ctx)
3036 struct client_s *cl = assuan_get_pointer(ctx);
3038 if (cl)
3039 cleanup_client(cl);
3042 gpg_error_t register_commands(assuan_context_t ctx)
3044 static struct {
3045 const gchar *name;
3046 gint (*handler)(assuan_context_t, gchar *line);
3047 } table[] = {
3048 { "OPEN", open_command },
3049 { "SAVE", save_command },
3050 { "LIST", list_command },
3051 { "REALPATH", realpath_command },
3052 { "STORE", store_command },
3053 { "DELETE", delete_command },
3054 { "GET", get_command },
3055 { "ATTR", attr_command },
3056 { "ISCACHED", iscached_command },
3057 { "CLEARCACHE", clearcache_command },
3058 { "CACHETIMEOUT", cachetimeout_command },
3059 { "GETCONFIG", getconfig_command },
3060 { "DUMP", dump_command },
3061 { "XPATH", xpath_command },
3062 { "IMPORT", import_command },
3063 { "LOCK", lock_command },
3064 { "UNLOCK", unlock_command },
3065 { "GETPID", getpid_command },
3066 { "VERSION", version_command },
3067 { "SET", set_command },
3068 { "UNSET", unset_command },
3069 { "INPUT", NULL },
3070 { "OUTPUT", NULL },
3071 { NULL, NULL }
3073 gint i, rc;
3075 for (i=0; table[i].name; i++) {
3076 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3078 if (rc)
3079 return rc;
3082 rc = assuan_register_bye_notify(ctx, bye_notify);
3084 if (rc)
3085 return rc;
3087 rc = assuan_register_reset_notify(ctx, reset_notify);
3089 if (rc)
3090 return rc;
3092 return assuan_register_post_cmd_notify(ctx, command_finalize);
3095 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
3096 struct client_crypto_s *crypto, gpointer *dst, goffset *dst_len)
3098 goffset insize, len;
3099 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3100 guint64 iter = 0, n_iter = 0, iter_progress = 0;
3101 gint zrc = 0;
3102 gulong outsize = 0;
3103 gpg_error_t rc;
3104 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->fh1) : sizeof(crypto->fh->fh2);
3105 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->fh1.iter : crypto->fh->fh2.iter;
3107 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3108 insize = crypto->fh->st.st_size - fh_size;
3109 crypto->iv = gcry_malloc(gcryblocksize);
3111 if (!crypto->iv) {
3112 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3113 return gpg_error_from_errno(ENOMEM);
3116 /* No encryption iterations. This is a plain (gzipped) file. */
3117 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
3119 * cache_file_count() needs both .used == TRUE and a valid key in
3120 * order for it to count as a used cache entry. Fixes CACHE status
3121 * messages.
3123 memset(key, '!', gcrykeysize);
3126 if (crypto->fh->v1)
3127 memcpy(crypto->iv, crypto->fh->fh1.iv, gcryblocksize);
3128 else
3129 memcpy(crypto->iv, crypto->fh->fh2.iv, gcryblocksize);
3131 crypto->inbuf = gcry_malloc(insize);
3133 if (!crypto->inbuf) {
3134 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3135 return gpg_error_from_errno(ENOMEM);
3138 crypto->insize = insize;
3139 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
3141 if (len != crypto->insize)
3142 return GPG_ERR_INV_LENGTH;
3144 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
3145 goto decompress;
3147 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3148 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3149 return rc;
3152 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
3153 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3154 return rc;
3157 iter_progress = (guint64)get_key_file_integer(client && client->filename ?
3158 client->filename : "global", "iteration_progress");
3160 if (iter_progress > 0 && fh_iter >= iter_progress) {
3161 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
3163 if (rc)
3164 return rc;
3167 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3169 if (rc)
3170 return rc;
3172 crypto->tkey = gcry_malloc(gcrykeysize);
3174 if (!crypto->tkey) {
3175 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
3176 return gpg_error_from_errno(ENOMEM);
3179 memcpy(crypto->tkey, key, gcrykeysize);
3180 guchar *tkey = crypto->tkey;
3181 tkey[0] ^= 1;
3183 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
3184 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3185 return rc;
3188 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
3189 if (iter_progress > 0 && iter >= iter_progress) {
3190 if (!(iter % iter_progress)) {
3191 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
3192 ++n_iter * iter_progress, fh_iter);
3194 if (rc)
3195 return rc;
3199 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3200 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3201 return rc;
3204 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3206 if (rc) {
3207 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3208 return rc;
3211 iter++;
3214 if (iter_progress && fh_iter >= iter_progress) {
3215 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
3217 if (rc)
3218 return rc;
3221 decompress:
3222 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
3223 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
3224 if (zrc == Z_MEM_ERROR)
3225 return gpg_error_from_errno(ENOMEM);
3226 else
3227 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
3230 if (g_strncasecmp(crypto->outbuf, "<?xml version=", 14) != 0) {
3231 gcry_free(crypto->outbuf);
3232 crypto->outbuf = NULL;
3233 return EPWMD_BADKEY;
3236 if (ctx) {
3237 client->xml = crypto->outbuf;
3238 client->len = outsize;
3239 crypto->outbuf = NULL;
3241 else if (dst) {
3242 *dst = crypto->outbuf;
3243 *dst_len = outsize;
3244 crypto->outbuf = NULL;
3247 /* The calling function should free the crypto struct. */
3248 return 0;
3252 * This is called after every Assuan command.
3254 void command_finalize(assuan_context_t ctx, gint rc)
3256 struct client_s *client = assuan_get_pointer(ctx);
3258 if (!client->is_lock_cmd)
3259 unlock_file_mutex(client);