Switched the CACHETIMEOUT seconds and filename arguments to keep
[pwmd.git] / src / commands.c
blobaef7f102433a9032583ce84f81fc6015a4a07ddd
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 #ifdef WITH_LIBACL
37 #include <sys/acl.h>
38 #endif
40 #include "mem.h"
41 #include "xml.h"
42 #include "common.h"
44 #ifdef WITH_PINENTRY
45 #include "pinentry.h"
46 #endif
48 #include "pwmd_error.h"
49 #include "cache.h"
50 #include "misc.h"
51 #include "commands.h"
52 #include "lock.h"
54 struct gz_s {
55 z_stream z;
56 gpointer out;
57 gboolean done;
58 status_msg_t which;
61 static void *z_alloc(void *data, unsigned items, unsigned size)
63 return gcry_calloc(items, size);
66 static void z_free(void *data, void *p)
68 gcry_free(p);
71 static gpg_error_t file_modified(struct client_s *client)
73 struct stat st;
74 gpg_error_t rc;
76 if (client->state != STATE_OPEN)
77 return EPWMD_NO_FILE;
79 rc = lock_file_mutex(client);
81 if (rc)
82 return rc;
84 if (lstat(client->filename, &st) == 0 && client->mtime) {
85 if (client->mtime != st.st_mtime)
86 return EPWMD_FILE_MODIFIED;
89 pth_cancel_point();
90 return 0;
93 static gpg_error_t parse_xml(assuan_context_t ctx)
95 struct client_s *client = assuan_get_pointer(ctx);
97 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
99 if (!client->doc)
100 return EPWMD_LIBXML_ERROR;
102 return 0;
105 void unlock_file_mutex(struct client_s *client)
107 pth_mutex_t *m;
109 #ifdef WITH_PINENTRY
110 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
111 #else
112 if (client->has_lock == FALSE)
113 #endif
114 return;
116 CACHE_LOCK(client->ctx);
118 if (cache_get_mutex(client->md5file, &m) == FALSE) {
119 CACHE_UNLOCK;
120 return;
123 CACHE_UNLOCK;
124 MUTEX_UNLOCK(m);
125 client->has_lock = client->is_lock_cmd = FALSE;
128 gpg_error_t lock_file_mutex(struct client_s *client)
130 pth_mutex_t *m;
131 gpg_error_t rc = 0;
133 if (client->has_lock == TRUE)
134 return 0;
136 CACHE_LOCK(client->ctx);
138 if (cache_get_mutex(client->md5file, &m) == FALSE) {
139 CACHE_UNLOCK;
140 return 0;
143 CACHE_UNLOCK;
144 MUTEX_TRYLOCK(client->ctx, m, rc);
146 if (!rc)
147 client->has_lock = TRUE;
149 return rc;
152 void free_client(struct client_s *client)
154 if (client->doc)
155 xmlFreeDoc(client->doc);
157 if (client->xml)
158 gcry_free(client->xml);
160 if (client->filename)
161 g_free(client->filename);
163 if (client->crypto)
164 cleanup_crypto(&client->crypto);
166 if (client->xml_error)
167 xmlResetError(client->xml_error);
170 void cleanup_client(struct client_s *client)
172 assuan_context_t ctx = client->ctx;
173 struct client_thread_s *thd = client->thd;
174 gboolean has_lock = client->has_lock;
175 #ifdef WITH_PINENTRY
176 struct pinentry_s *pin = client->pinentry;
177 #endif
179 unlock_file_mutex(client);
180 CACHE_LOCK(client->ctx);
181 cache_decr_refcount(client->md5file);
184 * This may be a new file so don't use a cache slot. save_command() will
185 * set this to FALSE on success.
187 if (client->new == TRUE)
188 cache_clear(client->md5file, 1);
190 CACHE_UNLOCK;
191 free_client(client);
192 memset(client, 0, sizeof(struct client_s));
193 client->state = STATE_CONNECTED;
194 client->ctx = ctx;
195 client->thd = thd;
196 client->freed = TRUE;
197 #ifdef WITH_PINENTRY
198 client->pinentry = pin;
199 #endif
200 client->has_lock = has_lock;
203 static void gz_cleanup(void *arg)
205 struct gz_s **gz = (struct gz_s **)arg;
207 if (!gz)
208 return;
210 if (!(*gz)->done && (*gz)->out)
211 gcry_free((*gz)->out);
213 if ((*gz)->which == STATUS_COMPRESS) {
214 if ((*gz)->z.zalloc)
215 deflateEnd(&(*gz)->z);
217 else {
218 if ((*gz)->z.zalloc)
219 inflateEnd(&(*gz)->z);
222 g_free(*gz);
223 *gz = NULL;
226 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
227 gpointer *out, gulong *outsize, gint *rc)
229 struct gz_s *gz;
230 gz_header h;
231 gchar buf[17];
233 gz = g_malloc0(sizeof(struct gz_s));
235 if (!gz) {
236 *rc = gpg_error_from_errno(ENOMEM);
237 return FALSE;
240 pth_cleanup_push(gz_cleanup, &gz);
241 gz->which = STATUS_DECOMPRESS;
242 gz->z.zalloc = z_alloc;
243 gz->z.zfree = z_free;
244 gz->z.next_in = in;
245 gz->z.avail_in = (uInt)insize;
246 gz->z.avail_out = zlib_bufsize;
247 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
249 if (!gz->out) {
250 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
251 *rc = Z_MEM_ERROR;
252 pth_cleanup_pop(1);
253 return FALSE;
256 *rc = inflateInit2(&gz->z, 47);
258 if (*rc != Z_OK) {
259 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
260 pth_cleanup_pop(1);
261 return FALSE;
264 memset(&h, 0, sizeof(gz_header));
265 h.comment = (guchar *)buf;
266 h.comm_max = sizeof(buf);
267 *rc = inflateGetHeader(&gz->z, &h);
269 if (*rc != Z_OK) {
270 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
271 pth_cleanup_pop(1);
272 return FALSE;
275 *rc = inflate(&gz->z, Z_BLOCK);
277 if (*rc != Z_OK) {
278 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
279 pth_cleanup_pop(1);
280 return FALSE;
283 if (h.comment)
284 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
286 do {
287 gpointer p;
289 *rc = inflate(&gz->z, Z_FINISH);
291 switch (*rc) {
292 case Z_OK:
293 break;
294 case Z_BUF_ERROR:
295 if (!gz->z.avail_out) {
296 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
298 if (!p) {
299 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
300 *rc = Z_MEM_ERROR;
301 goto fail;
304 gz->out = p;
305 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
306 gz->z.avail_out = zlib_bufsize;
307 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
308 gz->z.total_out, insize);
310 if (*rc)
311 goto fail;
313 break;
314 case Z_STREAM_END:
315 break;
316 default:
317 goto fail;
318 break;
320 } while (*rc != Z_STREAM_END);
322 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
323 insize);
325 if (*rc)
326 goto fail;
328 *out = gz->out;
329 *outsize = gz->z.total_out;
330 gz->done = TRUE;
331 pth_cleanup_pop(1);
332 *rc = 0;
333 return TRUE;
335 fail:
336 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
337 pth_cleanup_pop(1);
338 return FALSE;
341 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
342 gpg_error_t *rc)
344 gint fd;
345 gsize len;
346 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
347 gsize fh_size;
348 gpointer p;
350 *rc = 0;
352 if (!fh) {
353 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
354 *rc = gpg_error_from_errno(ENOMEM);
355 return NULL;
358 pth_cleanup_push(g_free, fh);
359 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
361 if (lstat(filename, &fh->st) == -1) {
362 *rc = gpg_error_from_syserror();
363 pth_cleanup_pop(1);
364 return NULL;
367 if (!S_ISREG(fh->st.st_mode)) {
368 *rc = GPG_ERR_ENOANO;
369 pth_cleanup_pop(1);
370 return NULL;
373 fd = open(filename, O_RDONLY);
375 if (fd == -1) {
376 *rc = gpg_error_from_errno(errno);
377 pth_cleanup_pop(1);
378 return NULL;
381 pth_cleanup_push(cleanup_fd_cb, &fd);
382 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
383 len = pth_read(fd, p, fh_size);
385 if (len != fh_size) {
386 gint n = errno;
387 pth_cleanup_pop(1);
388 pth_cleanup_pop(1);
389 *rc = gpg_error_from_errno(n);
390 return NULL;
393 fh->v1 = v1;
394 fh->fd = fd;
395 pth_cleanup_pop(0);
396 pth_cleanup_pop(0);
397 return fh;
400 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
401 gboolean cached)
403 struct client_s *client = assuan_get_pointer(ctx);
404 gpg_error_t rc;
405 gint timeout;
407 /* New file. */
408 if (!client->crypto->fh) {
409 if (key[0])
410 goto update_cache;
412 goto done;
415 rc = try_xml_decrypt(ctx, key, client->crypto, NULL, NULL);
417 if (rc) {
418 cleanup_client(client);
419 return send_error(ctx, rc);
422 update_cache:
423 CACHE_LOCK(client->ctx);
425 if (cached == FALSE) {
426 if (cache_update_key(client->md5file, key) == FALSE) {
427 cleanup_client(client);
428 CACHE_UNLOCK;
429 return send_syserror(ctx, ENOMEM);
432 timeout = get_key_file_integer(client->filename, "cache_timeout");
433 cache_reset_timeout(client->md5file, timeout);
435 else
436 cache_set_timeout(client->md5file, -2);
438 CACHE_UNLOCK;
440 done:
441 rc = parse_xml(ctx);
443 if (client->xml) {
444 gcry_free(client->xml);
445 client->xml = NULL;
448 if (!rc) {
449 if (client->new == FALSE)
450 send_status_all(STATUS_CACHE);
452 client->state = STATE_OPEN;
455 if (!rc && client->new == FALSE &&
456 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_integer(client->filename, "iterations")) {
457 MUTEX_LOCK(&rcfile_mutex);
458 g_key_file_set_integer(keyfileh, client->filename, "iterations",
459 client->crypto->fh->ver.fh2.iter);
460 MUTEX_UNLOCK(&rcfile_mutex);
461 send_status_all(STATUS_CONFIG);
464 if (!rc)
465 log_write("OPEN '%s'", client->filename);
467 cleanup_crypto(&client->crypto);
468 return send_error(ctx, rc);
471 static void req_cleanup(void *arg)
473 if (!arg)
474 return;
476 g_strfreev((gchar **)arg);
479 static int open_command(assuan_context_t ctx, char *line)
481 gboolean cached = FALSE;
482 gpg_error_t rc;
483 struct client_s *client = assuan_get_pointer(ctx);
484 gchar **req;
485 gchar *filename = NULL;
487 if ((req = split_input_line(line, " ", 2)) != NULL)
488 filename = req[0];
490 pth_cleanup_push(req_cleanup, req);
492 if (!filename || !*filename) {
493 pth_cleanup_pop(1);
494 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
497 if (valid_filename(filename) == FALSE) {
498 pth_cleanup_pop(1);
499 return send_error(ctx, EPWMD_INVALID_FILENAME);
502 if (client->state == STATE_OPEN)
503 cleanup_client(client);
505 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
506 CACHE_LOCK(client->ctx);
508 if (cache_has_file(client->md5file) == FALSE) {
509 if (cache_add_file(client->md5file, NULL) == FALSE) {
510 pth_cleanup_pop(1);
511 CACHE_UNLOCK;
512 return send_syserror(ctx, ENOMEM);
516 cache_incr_refcount(client->md5file);
517 CACHE_UNLOCK;
518 rc = lock_file_mutex(client);
520 if (rc) {
521 pth_cleanup_pop(1);
522 return send_error(ctx, rc);
525 client->freed = FALSE;
526 client->crypto = init_client_crypto();
528 if (!client->crypto) {
529 pth_cleanup_pop(1);
530 cleanup_client(client);
531 return send_syserror(ctx, ENOMEM);
534 client->crypto->key = gcry_malloc(gcrykeysize);
536 if (!client->crypto->key) {
537 pth_cleanup_pop(1);
538 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
539 gpg_error_from_errno(ENOMEM));
540 cleanup_client(client);
541 return send_syserror(ctx, ENOMEM);
544 memset(client->crypto->key, 0, gcrykeysize);
545 client->crypto->fh = read_file_header(filename, FALSE, &rc);
547 if (!client->crypto->fh) {
548 if (gpg_err_code_to_errno(rc) != ENOENT) {
549 log_write("%s: %s", filename, pwmd_strerror(rc));
550 pth_cleanup_pop(1);
551 cleanup_client(client);
552 return send_error(ctx, rc);
556 * New files don't need a key.
558 if ((client->xml = new_document()) == NULL) {
559 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
560 pth_cleanup_pop(1);
561 cleanup_client(client);
562 return send_syserror(ctx, ENOMEM);
565 client->len = xmlStrlen(client->xml);
566 client->new = TRUE;
567 client->filename = g_strdup(filename);
569 if (!client->filename) {
570 pth_cleanup_pop(1);
571 cleanup_client(client);
572 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
573 return send_syserror(ctx, ENOMEM);
576 if (req[1] && *req[1])
577 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
578 strlen(req[1]));
580 pth_cleanup_pop(1);
581 #ifdef WITH_PINENTRY
582 client->pinentry->filename = g_strdup(client->filename);
584 if (!client->pinentry->filename) {
585 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
586 cleanup_client(client);
587 return send_syserror(ctx, ENOMEM);
589 #endif
590 return open_command_finalize(ctx, client->crypto->key, cached);
592 else
593 client->mtime = client->crypto->fh->st.st_mtime;
595 client->filename = g_strdup(filename);
597 if (!client->filename) {
598 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
599 pth_cleanup_pop(1);
600 cleanup_client(client);
601 return send_syserror(ctx, ENOMEM);
604 #ifdef WITH_PINENTRY
605 client->pinentry->filename = g_strdup(client->filename);
607 if (!client->pinentry->filename) {
608 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
609 pth_cleanup_pop(1);
610 cleanup_client(client);
611 return send_syserror(ctx, ENOMEM);
613 #endif
615 if (client->crypto->fh->ver.fh2.iter <= 0)
616 goto done;
618 CACHE_LOCK(client->ctx);
619 cached = cache_get_key(client->md5file, client->crypto->key);
620 CACHE_UNLOCK;
622 if (cached == FALSE) {
623 gchar *tmp = get_key_file_string(filename, "key_file");
625 if (tmp) {
626 g_free(tmp);
627 pth_cleanup_pop(1);
628 cleanup_client(client);
629 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
633 * No key specified and no matching filename found in the cache. Use
634 * pinentry to retrieve the key. Cannot return assuan_process_done()
635 * here otherwise the command will be interrupted. The event loop in
636 * client_thread() will poll the file descriptor waiting for it to
637 * become ready to read a pinentry_key_s which will contain the
638 * entered key or an error code. It will then call
639 * open_command_finalize() to to finish the command.
641 if (!req[1] || !*req[1]) {
642 #ifdef WITH_PINENTRY
643 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
645 /* From set_pinentry_defaults(). */
646 if (client->pinentry->enable == FALSE ||
647 (client->pinentry->enable == -1 && b == FALSE)) {
648 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
649 goto done;
652 pth_cleanup_pop(1);
653 rc = lock_pin_mutex(client);
655 if (rc) {
656 unlock_pin_mutex(client->pinentry);
657 cleanup_client(client);
658 return send_error(ctx, rc);
661 client->pinentry->which = PINENTRY_OPEN;
662 rc = pinentry_fork(ctx);
664 if (rc) {
665 unlock_pin_mutex(client->pinentry);
666 cleanup_client(client);
667 return send_error(ctx, rc);
670 // Called from pinentry iterate.
671 client->pinentry->cb = open_command_finalize;
672 client->pinentry->status = PINENTRY_INIT;
673 return 0;
674 #else
675 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
676 goto done;
677 #endif
680 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
681 strlen(req[1]));
684 done:
685 pth_cleanup_pop(1);
686 return open_command_finalize(ctx, client->crypto->key, cached);
689 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
690 gulong size, gpointer *out, gulong *outsize, gint *rc)
692 struct gz_s *gz;
693 gz_header h;
694 gchar buf[17];
695 gint cmd = Z_NO_FLUSH;
697 gz = g_malloc0(sizeof(struct gz_s));
699 if (!gz) {
700 *rc = gpg_error_from_errno(ENOMEM);
701 return FALSE;
704 pth_cleanup_push(gz_cleanup, &gz);
705 gz->which = STATUS_COMPRESS;
706 gz->z.zalloc = z_alloc;
707 gz->z.zfree = z_free;
708 gz->z.next_in = data;
709 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
710 gz->z.avail_out = (uInt)zlib_bufsize;
711 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
713 if (!gz->out) {
714 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
715 *rc = Z_MEM_ERROR;
716 pth_cleanup_pop(1);
717 return FALSE;
720 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
722 if (*rc != Z_OK) {
723 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
724 pth_cleanup_pop(1);
725 return FALSE;
728 /* Rather than store the size of the uncompressed data in the file header,
729 * store it in the comment field of the gzip header. Don't give anyone too
730 * much information. Not sure why really, but it seems the right way. :)
732 memset(&h, 0, sizeof(gz_header));
733 g_snprintf(buf, sizeof(buf), "%li", size);
734 h.comment = (guchar *)buf;
735 *rc = deflateSetHeader(&gz->z, &h);
737 if (*rc != Z_OK) {
738 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
739 pth_cleanup_pop(1);
740 return FALSE;
743 do {
744 gpointer p;
746 *rc = deflate(&gz->z, cmd);
748 switch (*rc) {
749 case Z_OK:
750 break;
751 case Z_BUF_ERROR:
752 if (!gz->z.avail_out) {
753 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
755 if (!p) {
756 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
757 *rc = Z_MEM_ERROR;
758 goto fail;
761 gz->out = p;
762 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
763 gz->z.avail_out = zlib_bufsize;
766 if (!gz->z.avail_in && gz->z.total_in < size) {
767 if (gz->z.total_in + zlib_bufsize > size)
768 gz->z.avail_in = size - gz->z.total_in;
769 else
770 gz->z.avail_in = zlib_bufsize;
772 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li",
773 gz->z.total_in, size);
775 if (*rc)
776 goto fail;
779 if (gz->z.total_in >= size)
780 cmd = Z_FINISH;
782 break;
783 case Z_STREAM_END:
784 break;
785 default:
786 goto fail;
788 } while (*rc != Z_STREAM_END);
790 *rc = send_status(ctx, STATUS_COMPRESS, "%li %li", gz->z.total_in, size);
792 if (*rc)
793 goto fail;
795 *out = gz->out;
796 *outsize = gz->z.total_out;
797 *rc = 0;
798 gz->done = TRUE;
799 pth_cleanup_pop(1);
800 return TRUE;
802 fail:
803 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
804 pth_cleanup_pop(1);
805 return FALSE;
808 #define CRYPTO_BLOCKSIZE (gcryblocksize * 1024)
810 static gpg_error_t iterate_crypto_once(struct client_s *client,
811 struct client_crypto_s *crypto, status_msg_t which)
813 gpg_error_t rc = 0;
814 goffset len = CRYPTO_BLOCKSIZE;
815 gpointer p = gcry_malloc(len);
816 goffset total = 0;
817 gpointer inbuf;
819 if (!p)
820 return gpg_err_code_from_errno(ENOMEM);
822 if (crypto->insize < CRYPTO_BLOCKSIZE)
823 len = crypto->insize;
825 pth_cleanup_push(gcry_free, p);
827 for (;;) {
828 inbuf = (guchar *)crypto->inbuf + total;
829 guchar *tmp;
831 if (len + total > crypto->insize)
832 len = gcryblocksize;
834 if (which == STATUS_ENCRYPT)
835 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
836 else
837 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
839 if (rc)
840 goto done;
842 tmp = (guchar *)crypto->inbuf + total;
843 memmove(tmp, p, len);
844 total += len;
846 if (total >= crypto->insize)
847 break;
849 pth_cancel_point();
852 done:
853 pth_cleanup_pop(1);
854 return rc;
857 /* The crypto struct must be setup for iterations and .key. */
858 gpg_error_t do_xml_encrypt(struct client_s *client,
859 struct client_crypto_s *crypto, const gchar *filename)
861 goffset len = crypto->insize;
862 gpointer inbuf;
863 gchar *p;
864 gpg_error_t rc;
865 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
866 gchar tmp[FILENAME_MAX];
867 struct stat st;
868 mode_t mode = 0;
870 if (!crypto->fh->ver.fh2.iter) {
872 * cache_file_count() needs both .used == TRUE and a valid key in
873 * order for it to count as a used cache entry. Fixes CACHE status
874 * messages.
876 memset(crypto->key, '!', gcrykeysize);
877 goto write_file;
881 * Resize the existing xml buffer to the block size required by gcrypt
882 * rather than duplicating it and wasting memory.
884 if (crypto->insize / gcryblocksize) {
885 len = (crypto->insize / gcryblocksize) * gcryblocksize;
887 if (crypto->insize % gcryblocksize)
888 len += gcryblocksize;
891 inbuf = gcry_realloc(crypto->inbuf, len);
893 if (!inbuf) {
894 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
895 return gpg_error_from_errno(ENOMEM);
898 crypto->inbuf = inbuf;
899 crypto->insize = len;
900 gcry_create_nonce(crypto->fh->ver.fh2.iv, sizeof(crypto->fh->ver.fh2.iv));
901 crypto->tkey = gcry_malloc(gcrykeysize);
903 if (!crypto->tkey) {
904 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
905 return gpg_error_from_errno(ENOMEM);
908 memcpy(crypto->tkey, crypto->key, gcrykeysize);
909 guchar *tkey = crypto->tkey;
910 tkey[0] ^= 1;
912 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
913 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
914 return rc;
917 iter_progress = (guint64)get_key_file_integer(
918 client ? client->filename : "global", "iteration_progress");
920 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
921 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
922 "0 %llu", crypto->fh->ver.fh2.iter);
924 if (rc)
925 return rc;
928 while (xiter < crypto->fh->ver.fh2.iter-1) {
929 if (iter_progress > 0 && xiter >= iter_progress) {
930 if (!(xiter % iter_progress)) {
931 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
932 "%llu %llu", ++n_iter * iter_progress,
933 crypto->fh->ver.fh2.iter);
935 if (rc)
936 return rc;
940 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
941 sizeof(crypto->fh->ver.fh2.iv)))) {
942 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
943 return rc;
946 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
948 if (rc) {
949 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
950 return rc;
953 xiter++;
956 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
957 sizeof(crypto->fh->ver.fh2.iv)))) {
958 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
959 return rc;
962 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, gcrykeysize))) {
963 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
964 return rc;
967 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
969 if (rc)
970 return rc;
972 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
973 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
974 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
976 if (rc)
977 return rc;
980 write_file:
981 tmp[0] = 0;
983 if (filename) {
984 if (!client && !g_strcmp0(filename, "-")) {
985 crypto->fh->fd = STDOUT_FILENO;
986 goto do_write_file;
989 if (lstat(filename, &st) == 0) {
990 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
992 if (!(mode & S_IWUSR))
993 return gpg_error_from_errno(EACCES);
995 else if (errno != ENOENT)
996 return gpg_error_from_errno(errno);
998 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
999 crypto->fh->fd = mkstemp(tmp);
1001 if (crypto->fh->fd == -1) {
1002 rc = errno;
1003 p = strrchr(tmp, '/');
1004 p++;
1005 log_write("%s: %s", p, strerror(rc));
1006 return gpg_error_from_errno(rc);
1009 pth_cleanup_push(cleanup_unlink_cb, tmp);
1011 else
1013 * xml_import() or convert_file() from command line.
1015 crypto->fh->fd = STDOUT_FILENO;
1017 do_write_file:
1018 crypto->fh->ver.fh2.magic[0] = '\177';
1019 crypto->fh->ver.fh2.magic[1] = 'P';
1020 crypto->fh->ver.fh2.magic[2] = 'W';
1021 crypto->fh->ver.fh2.magic[3] = 'M';
1022 crypto->fh->ver.fh2.magic[4] = 'D';
1023 crypto->fh->ver.fh2.version = VERSION_HEX;
1024 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1026 if (len != sizeof(crypto->fh->ver.fh2)) {
1027 len = errno;
1029 if (tmp[0])
1030 pth_cleanup_pop(1);
1032 return gpg_error_from_errno(len);
1035 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1037 if (len != crypto->insize) {
1038 len = errno;
1040 if (tmp[0])
1041 pth_cleanup_pop(1);
1043 return gpg_error_from_errno(len);
1046 if (fsync(crypto->fh->fd) == -1) {
1047 len = errno;
1049 if (tmp[0])
1050 pth_cleanup_pop(1);
1052 return gpg_error_from_errno(len);
1055 if (tmp[0]) {
1056 #ifdef WITH_LIBACL
1057 acl_t acl;
1058 #endif
1059 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1060 gchar tmp2[FILENAME_MAX];
1062 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1063 #ifdef WITH_LIBACL
1064 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1066 if (!acl)
1067 log_write("ACL: %s: %s", filename, strerror(errno));
1068 #endif
1070 if (rename(filename, tmp2) == -1) {
1071 len = errno;
1072 pth_cleanup_pop(1);
1073 #ifdef WITH_LIBACL
1074 if (acl)
1075 acl_free(acl);
1076 #endif
1077 return gpg_error_from_errno(len);
1080 #ifdef WITH_LIBACL
1081 else {
1082 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1084 if (!acl)
1085 log_write("ACL: %s: %s", filename, strerror(errno));
1087 #endif
1089 if (rename(tmp, filename) == -1) {
1090 len = errno;
1091 pth_cleanup_pop(1);
1092 #ifdef WITH_LIBACL
1093 if (acl)
1094 acl_free(acl);
1095 #endif
1096 return gpg_error_from_errno(len);
1099 pth_cleanup_pop(0);
1101 if (mode)
1102 chmod(filename, mode);
1104 #ifdef WITH_LIBACL
1105 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1106 log_write("ACL: %s: %s", filename, strerror(errno));
1108 if (acl)
1109 acl_free(acl);
1110 #endif
1113 if (client && lstat(filename, &st) == 0)
1114 client->mtime = st.st_mtime;
1116 return 0;
1119 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1120 gboolean cached)
1122 struct client_s *client = assuan_get_pointer(ctx);
1123 gpointer xmlbuf;
1124 gulong len, outsize = 0;
1125 guint iter;
1126 gint timeout;
1127 gpointer outbuf;
1128 gint zrc;
1129 gpg_error_t rc;
1131 if (client->crypto->key && client->crypto->key != key)
1132 gcry_free(client->crypto->key);
1134 client->crypto->key = key;
1135 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1136 pth_cleanup_push(xmlFree, xmlbuf);
1137 iter = (guint)get_key_file_integer(client->filename, "compression_level");
1139 if (iter < 0)
1140 iter = 0;
1142 if (do_compress(ctx, (gint)iter, xmlbuf, len, &outbuf, &outsize, &zrc)
1143 == FALSE) {
1144 pth_cleanup_pop(1);
1145 cleanup_crypto(&client->crypto);
1147 if (zrc == Z_MEM_ERROR)
1148 return send_syserror(ctx, ENOMEM);
1149 else
1150 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1152 else {
1153 pth_cleanup_pop(1);
1154 xmlbuf = outbuf;
1155 len = outsize;
1158 client->crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1160 if (!client->crypto->fh) {
1161 cleanup_crypto(&client->crypto);
1162 gcry_free(outbuf);
1163 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1164 return send_syserror(ctx, ENOMEM);
1167 iter = get_key_file_integer(client->filename, "iterations");
1168 client->crypto->fh->ver.fh2.iter = iter < 0 ? 0 : iter;
1169 client->crypto->inbuf = xmlbuf;
1170 client->crypto->insize = len;
1171 rc = do_xml_encrypt(client, client->crypto, client->filename);
1173 if (rc) {
1174 cleanup_crypto(&client->crypto);
1175 return send_error(ctx, rc);
1178 timeout = get_key_file_integer(client->filename, "cache_timeout");
1179 CACHE_LOCK(client->ctx);
1181 if (cached) {
1182 cache_reset_timeout(client->md5file, timeout);
1183 CACHE_UNLOCK;
1185 if (client->new == TRUE)
1186 send_status_all(STATUS_CACHE);
1188 client->new = FALSE;
1189 cleanup_crypto(&client->crypto);
1190 return send_error(ctx, 0);
1193 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1194 CACHE_UNLOCK;
1195 cleanup_crypto(&client->crypto);
1196 return send_syserror(ctx, ENOMEM);
1199 client->new = FALSE;
1200 cache_reset_timeout(client->md5file, timeout);
1201 CACHE_UNLOCK;
1202 send_status_all(STATUS_CACHE);
1203 cleanup_crypto(&client->crypto);
1204 return send_error(ctx, 0);
1207 static int save_command(assuan_context_t ctx, char *line)
1209 gboolean cached = FALSE;
1210 struct stat st;
1211 struct client_s *client = assuan_get_pointer(ctx);
1213 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1214 return send_syserror(ctx, errno);
1216 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1217 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1218 return send_error(ctx, GPG_ERR_ENOANO);
1221 CACHE_LOCK(ctx);
1222 cached = cache_iscached(client->md5file);
1223 CACHE_UNLOCK;
1226 * If a cache entry doesn't exist for this file and the file has a
1227 * "key_file" or "key" parameter, then it's an error. The reason is that
1228 * cache expiration would be useless.
1230 if (cached == FALSE) {
1231 gchar *tmp = get_key_file_string(client->filename, "key_file");
1233 if (tmp) {
1234 g_free(tmp);
1235 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1239 cached = FALSE;
1240 client->crypto = init_client_crypto();
1242 if (!client->crypto) {
1243 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1244 return send_syserror(ctx, ENOMEM);
1247 client->crypto->key = gcry_malloc(gcrykeysize);
1249 if (!client->crypto->key) {
1250 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1251 cleanup_crypto(&client->crypto);
1252 return send_syserror(ctx, ENOMEM);
1255 memset(client->crypto->key, '!', gcrykeysize);
1257 if (get_key_file_integer(client->filename, "iterations") <= 0)
1258 goto done;
1260 if (!line || !*line) {
1261 client->crypto->tkey = gcry_malloc(gcrykeysize);
1263 if (!client->crypto->tkey) {
1264 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1265 cleanup_crypto(&client->crypto);
1266 return send_syserror(ctx, ENOMEM);
1269 memset(client->crypto->tkey, '!', gcrykeysize);
1270 CACHE_LOCK(ctx);
1272 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1273 memcmp(client->crypto->key, client->crypto->tkey,
1274 gcrykeysize) == 0) {
1275 CACHE_UNLOCK;
1277 #ifdef WITH_PINENTRY
1278 gpg_error_t rc;
1280 if (client->pinentry->enable == FALSE ||
1281 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1282 /* Empty keys are allowed. */
1283 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1284 goto done;
1287 lock_pin_mutex(client);
1288 client->pinentry->which = PINENTRY_SAVE;
1289 rc = pinentry_fork(ctx);
1291 if (rc) {
1292 unlock_pin_mutex(client->pinentry);
1293 return send_error(ctx, rc);
1296 client->pinentry->cb = save_command_finalize;
1297 client->pinentry->status = PINENTRY_INIT;
1298 return 0;
1299 #else
1300 /* Empty keys are allowed. */
1301 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1302 goto done;
1303 #endif
1305 else {
1306 CACHE_UNLOCK;
1307 cached = TRUE;
1310 else
1311 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1312 strlen(line));
1314 done:
1315 return save_command_finalize(ctx, client->crypto->key, cached);
1318 static int delete_command(assuan_context_t ctx, char *line)
1320 struct client_s *client = assuan_get_pointer(ctx);
1321 gchar **req;
1322 gpg_error_t rc;
1323 xmlNodePtr n;
1325 if (strchr(line, '\t'))
1326 req = split_input_line(line, "\t", -1);
1327 else
1328 req = split_input_line(line, " ", -1);
1330 if (!req || !*req)
1331 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1333 n = find_account(client->doc, &req, &rc, NULL, 0);
1335 if (!n) {
1336 g_strfreev(req);
1337 return send_error(ctx, rc);
1341 * No sub-node defined. Remove the entire node (account).
1343 if (!req[1]) {
1344 if (n) {
1345 xmlUnlinkNode(n);
1346 xmlFreeNode(n);
1349 g_strfreev(req);
1350 return send_error(ctx, 0);
1353 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1354 g_strfreev(req);
1356 if (!n)
1357 return send_error(ctx, rc);
1359 if (n) {
1360 xmlUnlinkNode(n);
1361 xmlFreeNode(n);
1364 return send_error(ctx, 0);
1368 * Don't return with assuan_process_done() here. This has been called from
1369 * assuan_process_next() and the command should be finished in
1370 * client_thread().
1372 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1373 gsize len)
1375 assuan_context_t ctx = data;
1376 struct client_s *client = assuan_get_pointer(ctx);
1377 gchar **req;
1378 xmlNodePtr n;
1379 gpg_error_t rc = file_modified(client);
1381 if (assuan_rc || rc) {
1382 if (line)
1383 xfree(line);
1384 return assuan_rc ? assuan_rc : rc;
1387 req = split_input_line((gchar *)line, "\t", 0);
1388 xfree(line);
1390 if (!req || !*req)
1391 return EPWMD_COMMAND_SYNTAX;
1393 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1394 g_strfreev(req);
1395 return EPWMD_INVALID_ELEMENT;
1398 if (valid_element_path(req+1, TRUE) == FALSE) {
1399 g_strfreev(req);
1400 return EPWMD_INVALID_ELEMENT;
1403 again:
1404 n = find_account(client->doc, &req, &rc, NULL, 0);
1406 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1407 rc = new_account(client->doc, *req);
1409 if (rc) {
1410 g_strfreev(req);
1411 return rc;
1414 goto again;
1417 if (!n) {
1418 g_strfreev(req);
1419 return rc;
1422 if (req[1]) {
1423 if (!n->children)
1424 create_elements_cb(n, req+1, &rc, NULL);
1425 else
1426 find_elements(client->doc, n->children, req+1, &rc,
1427 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1430 g_strfreev(req);
1431 client->inquire_status = INQUIRE_DONE;
1432 return rc;
1435 static int store_command(assuan_context_t ctx, char *line)
1437 struct client_s *client = assuan_get_pointer(ctx);
1438 gpg_error_t rc;
1440 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1442 if (rc)
1443 return send_error(ctx, rc);
1445 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1446 client->inquire_status = INQUIRE_BUSY;
1447 return 0;
1450 static void *send_data_cb(void *arg)
1452 struct assuan_cmd_s *data = arg;
1453 gint old;
1454 gpg_error_t rc;
1456 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1457 rc = assuan_send_data(data->ctx, data->line, data->line_len);
1458 pth_cancel_state(old, NULL);
1459 pth_exit((void *)rc);
1460 return NULL;
1463 /* For every assuan command that needs to be sent to the client, a timeout is
1464 * needed to determine if the client lost the connection. The timeout is the
1465 * same as the "keepalive" configuration parameter or a default if unset.
1467 gpg_error_t do_assuan_command(assuan_context_t ctx,
1468 void *(*cb)(void *data), void *data)
1470 pth_attr_t attr = pth_attr_new();
1471 pth_t tid;
1472 gint n;
1473 gint to = get_key_file_integer("global", "keepalive");
1474 pth_event_t ev, tev;
1475 pth_status_t st;
1476 gpg_error_t rc;
1478 pth_attr_init(attr);
1479 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1480 pth_cleanup_push(cleanup_attr_cb, attr);
1481 tid = pth_spawn(attr, cb, data);
1482 n = errno;
1483 pth_cleanup_pop(1);
1485 if (!tid) {
1486 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1487 _gpg_strerror(gpg_error_from_errno(n)));
1488 return gpg_error_from_errno(n);
1491 pth_cleanup_push(cleanup_cancel_cb, tid);
1492 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1493 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1494 tev = pth_event(PTH_EVENT_TIME, pth_timeout(to, 0));
1495 ev = pth_event_concat(ev, tev, NULL);
1496 pth_cleanup_push(cleanup_ev_cb, ev);
1497 pth_yield(tid);
1498 pth_wait(ev);
1499 st = pth_event_status(ev);
1501 if (st == PTH_STATUS_FAILED) {
1502 pth_cancel(tid);
1503 rc = GPG_ERR_ASS_WRITE_ERROR;
1505 else if (st == PTH_STATUS_OCCURRED)
1506 pth_join(tid, (void **)&rc);
1507 else {
1508 st = pth_event_status(tev);
1510 if (st == PTH_STATUS_OCCURRED) {
1511 pth_cancel(tid);
1512 rc = GPG_ERR_ASS_WRITE_ERROR;
1516 pth_cleanup_pop(1);
1517 pth_cleanup_pop(0);
1518 return rc;
1521 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1522 gint total)
1524 int to_send;
1525 int sent = 0;
1526 gpg_error_t rc;
1527 struct assuan_cmd_s data;
1528 int progress = get_key_file_integer("global", "xfer_progress");
1529 int flush = 0;
1531 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1532 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1533 data.ctx = ctx;
1534 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1536 if (rc)
1537 return rc;
1539 again:
1540 do {
1541 if (sent + to_send > total)
1542 to_send = total - sent;
1544 data.line = flush ? NULL : (gchar *)line+sent;
1545 data.line_len = flush ? 0 : to_send;
1546 rc = do_assuan_command(ctx, send_data_cb, &data);
1548 if (!rc) {
1549 sent += flush ? 0 : to_send;
1551 if ((progress && !(sent % progress) && sent != total) ||
1552 (sent == total && flush))
1553 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1555 if (!flush && !rc && sent == total) {
1556 flush = 1;
1557 goto again;
1560 } while (!rc && sent < total);
1562 return rc;
1565 static int get_command(assuan_context_t ctx, char *line)
1567 struct client_s *client = assuan_get_pointer(ctx);
1568 gchar **req;
1569 gpg_error_t rc;
1570 xmlNodePtr n;
1572 req = split_input_line(line, "\t", -1);
1574 if (!req || !*req) {
1575 g_strfreev(req);
1576 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1579 n = find_account(client->doc, &req, &rc, NULL, 0);
1581 if (!n) {
1582 g_strfreev(req);
1583 return send_error(ctx, rc);
1586 if (req[1])
1587 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1589 g_strfreev(req);
1591 if (rc)
1592 return send_error(ctx, rc);
1594 if (!n || !n->children)
1595 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1597 n = find_text_node(n->children);
1599 if (!n || !n->content || !*n->content)
1600 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1602 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1603 return send_error(ctx, rc);
1606 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1607 gpg_error_t *rc, gchar **req_orig, void *data)
1609 gchar *path = *(gchar **)data;
1610 gchar *tmp = NULL, *result;
1612 if (path) {
1613 g_free(path);
1614 *(gchar **)data = NULL;
1617 path = g_strjoinv("\t", target);
1619 if (!path) {
1620 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1621 *rc = gpg_error_from_errno(ENOMEM);
1622 return NULL;
1625 if (req_orig) {
1626 tmp = g_strjoinv("\t", req_orig);
1628 if (!tmp) {
1629 g_free(path);
1630 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1631 *rc = gpg_error_from_errno(ENOMEM);
1632 return NULL;
1636 if (tmp && *tmp)
1637 result = g_strdup_printf("%s\t%s", path, tmp);
1638 else
1639 result = g_strdup(path);
1641 if (!result) {
1642 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1643 *rc = gpg_error_from_errno(ENOMEM);
1644 g_free(path);
1645 g_free(tmp);
1646 return NULL;
1649 g_free(path);
1650 g_free(tmp);
1651 *(gchar **)data = result;
1652 return node;
1655 static void list_command_cleanup1(void *arg);
1656 static int realpath_command(assuan_context_t ctx, char *line)
1658 gpg_error_t rc;
1659 struct client_s *client = assuan_get_pointer(ctx);
1660 gchar **req;
1661 gchar *t;
1662 gint i;
1663 xmlNodePtr n;
1664 GString *string;
1665 gchar *rp = NULL;
1667 if (strchr(line, '\t') != NULL) {
1668 if ((req = split_input_line(line, "\t", 0)) == NULL)
1669 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1671 else {
1672 if ((req = split_input_line(line, " ", 0)) == NULL)
1673 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1676 n = find_account(client->doc, &req, &rc, NULL, 0);
1678 if (!n) {
1679 g_strfreev(req);
1680 return send_error(ctx, rc);
1683 rp = g_strjoinv("\t", req);
1685 if (!rp) {
1686 g_strfreev(req);
1687 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1688 return send_syserror(ctx, ENOMEM);
1691 if (req[1]) {
1692 n = find_elements(client->doc, n->children, req+1, &rc,
1693 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1695 if (!n) {
1696 g_free(rp);
1697 g_strfreev(req);
1698 return send_error(ctx, rc);
1702 string = g_string_new(rp);
1703 g_free(rp);
1704 g_strfreev(req);
1706 if (!string) {
1707 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1708 return send_syserror(ctx, ENOMEM);
1711 again:
1712 for (i = 0, t = string->str + i; *t; t++, i++) {
1713 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1714 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1715 goto again;
1719 pth_cleanup_push(list_command_cleanup1, string);
1720 rc = xfer_data(ctx, string->str, string->len);
1721 pth_cleanup_pop(1);
1722 return send_error(ctx, rc);
1725 static void list_command_cleanup1(void *arg)
1727 g_string_free((GString *)arg, TRUE);
1730 static void list_command_cleanup2(void *arg)
1732 struct element_list_s *elements = arg;
1734 if (elements) {
1735 gint total = g_slist_length(elements->list);
1736 gint i;
1738 for (i = 0; i < total; i++) {
1739 gchar *tmp = g_slist_nth_data(elements->list, i);
1740 g_free(tmp);
1743 g_slist_free(elements->list);
1745 if (elements->prefix)
1746 g_free(elements->prefix);
1748 g_free(elements);
1752 static int list_command(assuan_context_t ctx, char *line)
1754 struct client_s *client = assuan_get_pointer(ctx);
1755 gpg_error_t rc;
1756 struct element_list_s *elements = NULL;
1757 gchar *tmp;
1759 if (disable_list_and_dump == TRUE)
1760 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1762 if (!*line) {
1763 GString *str;
1765 rc = list_accounts(client->doc, &str);
1767 if (rc)
1768 return send_error(ctx, rc);
1770 pth_cleanup_push(list_command_cleanup1, str);
1771 rc = xfer_data(ctx, str->str, str->len);
1772 pth_cleanup_pop(1);
1773 return send_error(ctx, rc);
1776 elements = g_malloc0(sizeof(struct element_list_s));
1778 if (!elements) {
1779 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1780 rc = gpg_err_code_from_errno(ENOMEM);
1781 goto fail;
1784 pth_cleanup_push(list_command_cleanup2, elements);
1785 rc = create_path_list(client->doc, elements, line);
1787 if (rc)
1788 goto fail;
1790 if (elements) {
1791 gint total = g_slist_length(elements->list);
1792 gint i;
1793 GString *str;
1795 if (!total) {
1796 rc = EPWMD_EMPTY_ELEMENT;
1797 goto fail;
1800 str = g_string_new(NULL);
1802 if (!str) {
1803 rc = gpg_err_code_from_errno(ENOMEM);
1804 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1805 goto fail;
1808 for (i = 0; i < total; i++) {
1809 tmp = g_slist_nth_data(elements->list, i);
1810 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1813 pth_cleanup_push(list_command_cleanup1, str);
1814 rc = xfer_data(ctx, str->str, str->len);
1815 pth_cleanup_pop(1);
1817 else
1818 rc = EPWMD_EMPTY_ELEMENT;
1820 fail:
1821 pth_cleanup_pop(1);
1822 return send_error(ctx, rc);
1825 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1826 const gchar *value)
1828 xmlAttrPtr a;
1830 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1831 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1833 if (!a)
1834 return EPWMD_LIBXML_ERROR;
1836 else
1837 xmlNodeSetContent(a->children, (xmlChar *)value);
1839 return 0;
1843 * req[0] - element path
1845 static int attribute_list(assuan_context_t ctx, gchar **req)
1847 struct client_s *client = assuan_get_pointer(ctx);
1848 gchar **attrlist = NULL;
1849 gint i = 0;
1850 gchar **path = NULL;
1851 xmlAttrPtr a;
1852 xmlNodePtr n, an;
1853 gchar *line;
1854 gpg_error_t rc;
1856 if (!req || !req[0])
1857 return EPWMD_COMMAND_SYNTAX;
1859 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1861 * The first argument may be only an account.
1863 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1864 return EPWMD_COMMAND_SYNTAX;
1867 n = find_account(client->doc, &path, &rc, NULL, 0);
1869 if (!n) {
1870 g_strfreev(path);
1871 return rc;
1874 if (path[1]) {
1875 n = find_elements(client->doc, n->children, path+1, &rc,
1876 NULL, NULL, NULL, FALSE, 0, NULL);
1878 if (!n) {
1879 g_strfreev(path);
1880 return rc;
1884 g_strfreev(path);
1886 for (a = n->properties; a; a = a->next) {
1887 gchar **pa;
1889 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1890 if (attrlist)
1891 g_strfreev(attrlist);
1893 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1894 return gpg_error_from_errno(ENOMEM);
1897 attrlist = pa;
1898 an = a->children;
1899 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name, (gchar *)an->content);
1901 if (!attrlist[i]) {
1902 g_strfreev(attrlist);
1903 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1904 return gpg_error_from_errno(ENOMEM);
1907 attrlist[++i] = NULL;
1910 if (!attrlist)
1911 return EPWMD_EMPTY_ELEMENT;
1913 line = g_strjoinv("\n", attrlist);
1915 if (!line) {
1916 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1917 g_strfreev(attrlist);
1918 return gpg_error_from_errno(ENOMEM);
1921 pth_cleanup_push(g_free, line);
1922 pth_cleanup_push(req_cleanup, attrlist);
1923 rc = xfer_data(ctx, line, strlen(line));
1924 pth_cleanup_pop(1);
1925 pth_cleanup_pop(1);
1926 return rc;
1930 * req[0] - attribute
1931 * req[1] - element path
1933 static int attribute_delete(struct client_s *client, gchar **req)
1935 xmlAttrPtr a;
1936 xmlNodePtr n;
1937 gchar **path = NULL;
1938 gpg_error_t rc;
1940 if (!req || !req[0] || !req[1])
1941 return EPWMD_COMMAND_SYNTAX;
1943 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1945 * The first argument may be only an account.
1947 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1948 return EPWMD_COMMAND_SYNTAX;
1952 * Don't remove the "name" attribute for the account element. To remove an
1953 * account use DELETE <account>.
1955 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1956 rc = EPWMD_ATTR_SYNTAX;
1957 goto fail;
1960 n = find_account(client->doc, &path, &rc, NULL, 0);
1962 if (!n)
1963 goto fail;
1965 if (path[1]) {
1966 n = find_elements(client->doc, n->children, path+1, &rc,
1967 NULL, NULL, NULL, FALSE, 0, NULL);
1969 if (!n)
1970 goto fail;
1973 g_strfreev(path);
1975 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1976 return EPWMD_ATTR_NOT_FOUND;
1978 if (xmlRemoveProp(a) == -1)
1979 return EPWMD_LIBXML_ERROR;
1981 return 0;
1983 fail:
1984 g_strfreev(path);
1985 return rc;
1988 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1989 gpg_error_t *rc)
1991 gchar **src = *path;
1992 gchar **src_orig = g_strdupv(src);
1993 xmlNodePtr n = NULL;
1995 *rc = 0;
1997 if (!src_orig) {
1998 *rc = gpg_error_from_errno(ENOMEM);
1999 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2000 goto fail;
2003 again:
2004 n = find_account(client->doc, &src, rc, NULL, 0);
2006 if (!n) {
2007 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
2008 *rc = new_account(client->doc, src[0]);
2010 if (*rc)
2011 goto fail;
2013 goto again;
2015 else
2016 goto fail;
2019 if (src[1]) {
2020 if (!n->children)
2021 n = create_target_elements_cb(n, src+1, rc, NULL);
2022 else
2023 n = find_elements(client->doc, n->children, src+1, rc,
2024 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2026 if (!n)
2027 goto fail;
2030 * Reset the position of the element tree now that the elements
2031 * have been created.
2033 g_strfreev(src);
2034 src = src_orig;
2035 src_orig = NULL;
2036 n = find_account(client->doc, &src, rc, NULL, 0);
2038 if (!n)
2039 goto fail;
2041 n = find_elements(client->doc, n->children, src+1, rc,
2042 NULL, NULL, NULL, FALSE, 0, NULL);
2044 if (!n)
2045 goto fail;
2048 fail:
2049 if (src_orig)
2050 g_strfreev(src_orig);
2052 *path = src;
2053 return n;
2057 * Creates a "target" attribute. When other commands encounter an element with
2058 * this attribute, the element path is modified to the target value. If the
2059 * source element path doesn't exist when using 'ATTR SET target', it is
2060 * created, but the destination element path must exist.
2062 * req[0] - source element path
2063 * req[1] - destination element path
2065 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2067 gchar **src, **dst, *line = NULL;
2068 gpg_error_t rc;
2069 xmlNodePtr n;
2071 if (!req || !req[0] || !req[1])
2072 return EPWMD_COMMAND_SYNTAX;
2074 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2076 * The first argument may be only an account.
2078 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2079 return EPWMD_COMMAND_SYNTAX;
2082 if (valid_element_path(src, FALSE) == FALSE) {
2083 g_strfreev(src);
2084 return EPWMD_INVALID_ELEMENT;
2087 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2089 * The first argument may be only an account.
2091 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2092 rc = EPWMD_COMMAND_SYNTAX;
2093 goto fail;
2097 n = find_account(client->doc, &dst, &rc, NULL, 0);
2100 * Make sure the destination element path exists.
2102 if (!n)
2103 goto fail;
2105 if (dst[1]) {
2106 n = find_elements(client->doc, n->children, dst+1, &rc,
2107 NULL, NULL, NULL, FALSE, 0, NULL);
2109 if (!n)
2110 goto fail;
2113 n = create_element_path(client, &src, &rc);
2115 if (rc)
2116 goto fail;
2118 line = g_strjoinv("\t", dst);
2120 if (!line) {
2121 rc = gpg_error_from_errno(ENOMEM);
2122 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2123 goto fail;
2126 rc = add_attribute(n, "target", line);
2128 fail:
2129 g_free(line);
2130 g_strfreev(src);
2131 g_strfreev(dst);
2132 return rc;
2136 * req[0] - account name
2137 * req[1] - new name
2139 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2141 gpg_error_t rc;
2142 gchar **tmp;
2143 xmlNodePtr n;
2145 tmp = g_strdupv(req);
2147 if (!tmp) {
2148 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2149 return gpg_error_from_errno(ENOMEM);
2152 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2153 g_strfreev(tmp);
2155 if (!n)
2156 return rc;
2158 if (g_utf8_collate(req[0], req[1]) == 0)
2159 return 0;
2162 * Will not overwrite an existing account.
2164 tmp = g_strdupv(req+1);
2166 if (!tmp) {
2167 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2168 return gpg_error_from_errno(ENOMEM);
2171 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2172 g_strfreev(tmp);
2174 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
2175 return rc;
2177 if (n)
2178 return EPWMD_ACCOUNT_EXISTS;
2181 * Whitespace not allowed in account names.
2183 if (contains_whitespace(req[1]) == TRUE)
2184 return EPWMD_ATTR_SYNTAX;
2186 tmp = g_strdupv(req);
2188 if (!tmp) {
2189 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2190 return gpg_error_from_errno(ENOMEM);
2193 n = find_account(client->doc, &tmp, &rc, NULL, 0);
2194 g_strfreev(tmp);
2196 if (!n)
2197 return EPWMD_ELEMENT_NOT_FOUND;
2199 return add_attribute(n, "name", req[1]);
2203 * req[0] - attribute
2204 * req[1] - element path
2206 static int attribute_get(assuan_context_t ctx, gchar **req)
2208 struct client_s *client = assuan_get_pointer(ctx);
2209 xmlNodePtr n;
2210 xmlChar *a;
2211 gchar **path= NULL;
2212 gpg_error_t rc;
2214 if (!req || !req[0] || !req[1])
2215 return EPWMD_COMMAND_SYNTAX;
2217 if (strchr(req[1], '\t')) {
2218 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2219 return EPWMD_COMMAND_SYNTAX;
2221 else {
2222 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2223 return EPWMD_COMMAND_SYNTAX;
2226 n = find_account(client->doc, &path, &rc, NULL, 0);
2228 if (!n)
2229 goto fail;
2231 if (path[1]) {
2232 n = find_elements(client->doc, n->children, path+1, &rc,
2233 NULL, NULL, NULL, FALSE, 0, NULL);
2235 if (!n)
2236 goto fail;
2239 g_strfreev(path);
2241 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2242 return EPWMD_ATTR_NOT_FOUND;
2244 pth_cleanup_push(xmlFree, a);
2245 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2246 pth_cleanup_pop(1);
2247 return rc;
2249 fail:
2250 g_strfreev(path);
2251 return rc;
2255 * req[0] - attribute
2256 * req[1] - element path
2257 * req[2] - value
2259 static int attribute_set(struct client_s *client, gchar **req)
2261 gchar **path = NULL;
2262 gpg_error_t rc;
2263 xmlNodePtr n;
2265 if (!req || !req[0] || !req[1] || !req[2])
2266 return EPWMD_COMMAND_SYNTAX;
2269 * Reserved attribute names.
2271 if (g_utf8_collate(req[0], "name") == 0) {
2273 * Only reserved for the account element. Not the rest of the
2274 * document.
2276 if (strchr(req[1], '\t') == NULL)
2277 return name_attribute(client, req + 1);
2279 else if (g_utf8_collate(req[0], "target") == 0)
2280 return target_attribute(client, req + 1);
2282 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2284 * The first argument may be only an account.
2286 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2287 return EPWMD_COMMAND_SYNTAX;
2290 n = find_account(client->doc, &path, &rc, NULL, 0);
2292 if (!n)
2293 goto fail;
2295 if (path[1]) {
2296 n = find_elements(client->doc, n->children, path+1, &rc,
2297 NULL, NULL, NULL, FALSE, 0, NULL);
2299 if (!n)
2300 goto fail;
2303 g_strfreev(path);
2304 return add_attribute(n, req[0], req[2]);
2306 fail:
2307 g_strfreev(path);
2308 return rc;
2312 * req[0] - command
2313 * req[1] - attribute name or element path if command is LIST
2314 * req[2] - element path
2315 * req[2] - element path or value
2317 static int attr_command(assuan_context_t ctx, char *line)
2319 struct client_s *client = assuan_get_pointer(ctx);
2320 gchar **req;
2321 gpg_error_t rc = 0;
2323 req = split_input_line(line, " ", 4);
2325 if (!req || !req[0] || !req[1]) {
2326 g_strfreev(req);
2327 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2330 pth_cleanup_push(req_cleanup, req);
2332 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2333 rc = attribute_set(client, req+1);
2334 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2335 rc = attribute_get(ctx, req+1);
2336 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2337 rc = attribute_delete(client, req+1);
2338 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2339 rc = attribute_list(ctx, req+1);
2340 else
2341 rc = EPWMD_COMMAND_SYNTAX;
2343 pth_cleanup_pop(1);
2344 return send_error(ctx, rc);
2347 static int iscached_command(assuan_context_t ctx, char *line)
2349 gchar **req = split_input_line(line, " ", 0);
2350 guchar md5file[16];
2351 gchar *path, *tmp;
2353 if (!req || !*req) {
2354 g_strfreev(req);
2355 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2358 if (!valid_filename(req[0])) {
2359 g_strfreev(req);
2360 return EPWMD_INVALID_FILENAME;
2363 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2364 CACHE_LOCK(ctx);
2366 if (cache_iscached(md5file)) {
2367 g_strfreev(req);
2368 CACHE_UNLOCK;
2369 return send_error(ctx, 0);
2372 tmp = get_key_file_string("global", "data_directory");
2374 if (!tmp) {
2375 g_strfreev(req);
2376 return gpg_error_from_errno(ENOMEM);
2379 path = expand_homedir(tmp);
2381 if (!path) {
2382 g_strfreev(req);
2383 g_free(tmp);
2384 return gpg_error_from_errno(ENOMEM);
2387 g_free(tmp);
2388 tmp = path;
2389 path = g_strdup_printf("%s/%s", tmp, req[0]);
2390 g_free(tmp);
2392 if (!path) {
2393 g_strfreev(req);
2394 return gpg_error_from_errno(ENOMEM);
2397 if (access(path, R_OK) == -1) {
2398 gpg_error_t rc = gpg_error_from_syserror();
2400 g_free(path);
2401 g_strfreev(req);
2402 return send_error(ctx, rc);
2405 g_free(path);
2406 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2409 static int clearcache_command(assuan_context_t ctx, char *line)
2411 struct client_s *client = assuan_get_pointer(ctx);
2412 gchar **req = split_input_line(line, " ", 0);
2413 guchar md5file[16];
2415 CACHE_LOCK(ctx);
2417 if (!req || !*req) {
2418 g_strfreev(req);
2419 cache_clear(client->md5file, 2);
2420 CACHE_UNLOCK;
2421 return send_error(ctx, 0);
2424 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2425 g_strfreev(req);
2427 if (cache_clear(md5file, 1) == FALSE) {
2428 CACHE_UNLOCK;
2429 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2432 CACHE_UNLOCK;
2433 return send_error(ctx, 0);
2436 static int cachetimeout_command(assuan_context_t ctx, char *line)
2438 guchar md5file[16];
2439 glong timeout;
2440 gchar **req = split_input_line(line, " ", 0);
2441 gchar *p;
2443 if (!req || !*req || !req[1]) {
2444 g_strfreev(req);
2445 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2448 errno = 0;
2449 timeout = strtol(req[1], &p, 10);
2451 if (errno != 0 || *p != 0 || timeout < -1) {
2452 g_strfreev(req);
2453 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2456 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2457 CACHE_LOCK(client->ctx);
2459 if (cache_set_timeout(md5file, timeout) == FALSE) {
2460 CACHE_UNLOCK;
2461 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2464 CACHE_UNLOCK;
2465 return send_error(ctx, 0);
2468 static int dump_command(assuan_context_t ctx, char *line)
2470 xmlChar *xml;
2471 gssize len;
2472 struct client_s *client = assuan_get_pointer(ctx);
2473 gpg_error_t rc;
2475 if (disable_list_and_dump == TRUE)
2476 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2478 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2480 if (!xml) {
2481 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2482 return send_syserror(ctx, ENOMEM);
2485 pth_cleanup_push(xmlFree, xml);
2486 rc = xfer_data(ctx, (gchar *)xml, len);
2487 pth_cleanup_pop(1);
2488 return send_error(ctx, rc);
2491 static int getconfig_command(assuan_context_t ctx, gchar *line)
2493 struct client_s *client = assuan_get_pointer(ctx);
2494 gpg_error_t rc = 0;
2495 gchar filename[255]={0}, param[747]={0};
2496 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2498 if (strchr(line, ' ')) {
2499 sscanf(line, " %254[^ ] %746c", filename, param);
2500 paramp = param;
2501 fp = filename;
2504 if (fp && !valid_filename(fp))
2505 return send_error(ctx, EPWMD_INVALID_FILENAME);
2507 paramp = g_ascii_strdown(paramp, -1);
2509 if (!paramp) {
2510 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2511 return send_syserror(ctx, ENOMEM);
2514 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2515 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2516 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2518 if (!fh && rc != GPG_ERR_ENOENT)
2519 return send_error(ctx, rc);
2521 if (!rc) {
2522 g_free(paramp);
2523 p = g_strdup_printf("%llu", fh->ver.fh2.iter);
2524 close_file_header(fh);
2526 if (!p) {
2527 log_write("%s(%i): %s", __FILE__, __LINE__,
2528 strerror(ENOMEM));
2529 return send_syserror(ctx, ENOMEM);
2532 goto done;
2536 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2537 #ifdef WITH_PINENTRY
2538 gboolean n;
2540 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2541 n = client->pinentry->enable;
2542 else
2543 n = get_key_file_boolean(fp, "enable_pinentry");
2545 p = g_strdup_printf("%s", n ? "true" : "false");
2547 if (!p) {
2548 log_write("%s(%i): %s", __FILE__, __LINE__,
2549 strerror(ENOMEM));
2550 return send_syserror(ctx, ENOMEM);
2553 goto done;
2554 #else
2555 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2556 #endif
2558 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2559 #ifdef WITH_PINENTRY
2560 if (fp == client->filename && (client->opts & OPT_PINENTRY_TO))
2561 p = g_strdup_printf("%i", client->pinentry->timeout);
2562 else
2563 p = g_strdup_printf("%i",
2564 get_key_file_integer(fp, "pinentry_timeout"));
2566 if (!p) {
2567 log_write("%s(%i): %s", __FILE__, __LINE__,
2568 strerror(ENOMEM));
2569 return send_syserror(ctx, ENOMEM);
2572 goto done;
2573 #else
2574 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2575 #endif
2578 p = get_key_file_string(fp ? fp : "global", paramp);
2579 g_free(paramp);
2581 if (!p)
2582 return send_error(ctx, GPG_ERR_NO_VALUE);
2584 tmp = expand_homedir(p);
2585 g_free(p);
2587 if (!tmp) {
2588 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2589 return send_syserror(ctx, ENOMEM);
2592 p = tmp;
2593 done:
2594 pth_cleanup_push(g_free, p);
2595 rc = xfer_data(ctx, p, strlen(p));
2596 pth_cleanup_pop(1);
2597 return send_error(ctx, rc);
2600 struct xpath_s {
2601 xmlXPathContextPtr xp;
2602 xmlXPathObjectPtr result;
2603 xmlBufferPtr buf;
2604 gchar **req;
2607 static void xpath_command_cleanup(void *arg)
2609 struct xpath_s *xpath = arg;
2611 req_cleanup(xpath->req);
2613 if (xpath->buf)
2614 xmlBufferFree(xpath->buf);
2616 if (xpath->result)
2617 xmlXPathFreeObject(xpath->result);
2619 if (xpath->xp)
2620 xmlXPathFreeContext(xpath->xp);
2623 static int xpath_command(assuan_context_t ctx, gchar *line)
2625 struct client_s *client = assuan_get_pointer(ctx);
2626 gpg_error_t rc;
2627 struct xpath_s xpath;
2629 if (disable_list_and_dump == TRUE)
2630 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2632 if (!line || !*line)
2633 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2635 memset(&xpath, 0, sizeof(struct xpath_s));
2637 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2638 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2639 return send_syserror(ctx, ENOMEM);
2642 xpath.xp = xmlXPathNewContext(client->doc);
2644 if (!xpath.xp) {
2645 xpath_command_cleanup(&xpath);
2646 return send_error(ctx, EPWMD_LIBXML_ERROR);
2649 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2651 if (!xpath.result) {
2652 xpath_command_cleanup(&xpath);
2653 return send_error(ctx, EPWMD_LIBXML_ERROR);
2656 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2657 rc = EPWMD_EMPTY_ELEMENT;
2658 goto fail;
2661 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2662 (xmlChar *)xpath.req[1], &xpath.buf);
2664 if (rc)
2665 goto fail;
2666 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2667 rc = EPWMD_EMPTY_ELEMENT;
2668 goto fail;
2670 else if (xpath.req[1])
2671 goto fail;
2673 pth_cleanup_push(xpath_command_cleanup, &xpath);
2674 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2675 xmlBufferLength(xpath.buf));
2676 pth_cleanup_pop(0);
2678 fail:
2679 xpath_command_cleanup(&xpath);
2680 return send_error(ctx, rc);
2683 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2684 gsize len)
2686 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2687 gpg_error_t rc = file_modified(client);
2688 gchar **req, **path = NULL, **path_orig = NULL, *content;
2689 xmlDocPtr doc;
2690 xmlNodePtr n, root, copy;
2692 if (assuan_rc || rc) {
2693 if (line)
2694 xfree(line);
2695 return assuan_rc ? assuan_rc : rc;
2698 req = split_input_line((gchar *)line, " ", 2);
2699 xfree(line);
2701 if (!req || !*req)
2702 return EPWMD_COMMAND_SYNTAX;
2704 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2705 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2706 return EPWMD_COMMAND_SYNTAX;
2709 content = req[1];
2711 if (!content || !*content) {
2712 rc = EPWMD_COMMAND_SYNTAX;
2713 goto fail;
2716 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2717 rc = EPWMD_INVALID_ELEMENT;
2718 goto fail;
2721 if (valid_element_path(path+1, FALSE) == FALSE) {
2722 rc = EPWMD_INVALID_ELEMENT;
2723 goto fail;
2726 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2728 if (!doc) {
2729 rc = EPWMD_LIBXML_ERROR;
2730 goto fail;
2733 root = xmlDocGetRootElement(doc);
2734 path_orig = g_strdupv(path);
2736 if (!path_orig) {
2737 xmlFreeDoc(doc);
2738 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2739 rc = gpg_error_from_errno(ENOMEM);
2740 goto fail;
2743 if (strv_printf(&path, "%s", (gchar *)root->name) == FALSE) {
2744 g_strfreev(path_orig);
2745 xmlFreeDoc(doc);
2746 rc = gpg_error_from_errno(ENOMEM);
2747 goto fail;
2750 n = find_account(client->doc, &path, &rc, NULL, 0);
2752 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2753 g_strfreev(path_orig);
2754 xmlFreeDoc(doc);
2755 goto fail;
2757 else if (!rc) {
2758 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
2760 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND) {
2761 g_strfreev(path_orig);
2762 xmlFreeDoc(doc);
2763 goto fail;
2765 else if (!rc) {
2766 xmlNodePtr parent = n->parent;
2768 xmlUnlinkNode(n);
2769 xmlFreeNode(n);
2770 n = parent;
2774 g_strfreev(path);
2775 path = path_orig;
2777 if (rc == EPWMD_ELEMENT_NOT_FOUND) {
2778 n = create_element_path(client, &path, &rc);
2780 if (rc) {
2781 xmlFreeDoc(doc);
2782 goto fail;
2786 copy = xmlCopyNode(root, 1);
2787 n = xmlAddChild(n, copy);
2788 xmlFreeDoc(doc);
2790 if (!n)
2791 rc = EPWMD_LIBXML_ERROR;
2793 fail:
2794 g_strfreev(path);
2795 g_strfreev(req);
2796 client->inquire_status = INQUIRE_DONE;
2797 return rc;
2800 static int import_command(assuan_context_t ctx, gchar *line)
2802 gpg_error_t rc;
2803 struct client_s *client = assuan_get_pointer(ctx);
2805 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2807 if (rc)
2808 return send_error(ctx, rc);
2810 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2811 client->inquire_status = INQUIRE_BUSY;
2812 return 0;
2815 static int lock_command(assuan_context_t ctx, gchar *line)
2817 gpg_error_t rc;
2818 struct client_s *client = assuan_get_pointer(ctx);
2820 rc = lock_file_mutex(client);
2822 if (!rc)
2823 client->is_lock_cmd = TRUE;
2825 return send_error(ctx, rc);
2828 static int unlock_command(assuan_context_t ctx, gchar *line)
2830 struct client_s *client = assuan_get_pointer(ctx);
2832 unlock_file_mutex(client);
2833 return send_error(ctx, 0);
2836 static int getpid_command(assuan_context_t ctx, gchar *line)
2838 gpg_error_t rc;
2839 gchar buf[32];
2840 pid_t pid = getpid();
2842 print_fmt(buf, sizeof(buf), "%i", pid);
2843 rc = xfer_data(ctx, buf, strlen(buf));
2844 return send_error(ctx, rc);
2847 static int version_command(assuan_context_t ctx, gchar *line)
2849 gpg_error_t rc;
2850 gchar buf[32];
2852 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
2853 rc = xfer_data(ctx, buf, strlen(buf));
2854 return send_error(ctx, rc);
2857 #ifdef WITH_PINENTRY
2858 static void set_option_value(gchar **opt, const gchar *value)
2860 if (opt)
2861 g_free(*opt);
2863 *opt = NULL;
2865 if (value)
2866 *opt = g_strdup(value);
2868 #endif
2870 static int set_unset_common(assuan_context_t ctx, const gchar *name,
2871 const gchar *value)
2873 struct client_s *client = assuan_get_pointer(ctx);
2875 if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
2876 long n;
2877 gchar *p = NULL;
2879 if (!client->filename)
2880 return EPWMD_NO_FILE;
2882 if (!value) {
2883 MUTEX_LOCK(&rcfile_mutex);
2884 g_key_file_set_integer(keyfileh, client->filename, "iterations",
2885 get_key_file_integer("global", "iterations"));
2886 MUTEX_UNLOCK(&rcfile_mutex);
2887 goto done;
2890 errno = 0;
2891 n = strtol(value, &p, 10);
2893 if (errno || (p && *p) || n < 0)
2894 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2896 MUTEX_LOCK(&rcfile_mutex);
2897 g_key_file_set_integer(keyfileh,
2898 client->filename ? client->filename : "global", "iterations",
2899 (guint)n);
2900 MUTEX_UNLOCK(&rcfile_mutex);
2902 if (client->filename)
2903 client->opts |= OPT_ITERATIONS;
2905 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
2906 pth_attr_t attr = pth_attr_of(pth_self());
2907 gchar buf[41];
2909 if (!value) {
2910 pth_attr_destroy(attr);
2911 goto done;
2914 print_fmt(buf, sizeof(buf), "%s", value);
2915 pth_attr_set(attr, PTH_ATTR_NAME, buf);
2916 pth_attr_destroy(attr);
2917 #ifdef WITH_PINENTRY
2918 if (client->pinentry->name)
2919 g_free(client->pinentry->name);
2921 client->pinentry->name = g_strdup(buf);
2923 if (!client->pinentry->name)
2924 return gpg_error_from_errno(ENOMEM);
2925 #endif
2927 #ifdef WITH_PINENTRY
2928 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
2929 set_option_value(&client->pinentry->lcmessages, value);
2930 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
2931 set_option_value(&client->pinentry->lcctype, value);
2932 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
2933 set_option_value(&client->pinentry->ttyname, value);
2934 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
2935 set_option_value(&client->pinentry->ttytype, value);
2936 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
2937 set_option_value(&client->pinentry->display, value);
2938 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
2939 set_option_value(&client->pinentry->path, value);
2940 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
2941 set_option_value(&client->pinentry->title, value);
2942 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
2943 set_option_value(&client->pinentry->prompt, value);
2944 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
2945 set_option_value(&client->pinentry->desc, value);
2946 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
2947 gchar *p = NULL;
2948 gint n;
2950 if (!value) {
2951 client->pinentry->timeout =
2952 get_key_file_integer(client->filename, "pinentry_timeout");
2953 client->opts &= ~(OPT_PINENTRY_TO);
2954 goto done;
2957 n = strtol(value, &p, 10);
2959 if (*p || n < 0)
2960 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2962 client->pinentry->timeout = n;
2963 client->opts |= OPT_PINENTRY_TO;
2965 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
2966 gchar *p = NULL;
2967 gint n;
2969 if (!value) {
2970 client->pinentry->enable = -1;
2971 client->opts &= ~(OPT_PINENTRY);
2972 goto done;
2975 n = strtol(value, &p, 10);
2977 if (*p || n < 0 || n > 1)
2978 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2980 client->pinentry->enable = n == 0 ? FALSE : TRUE;
2981 client->opts |= OPT_PINENTRY;
2983 #endif
2984 else
2985 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2987 done:
2988 log_write("%s %s%s%s", value ? "SET" : "UNSET", name,
2989 value ? "=" : "", value ? value : "");
2990 return 0;
2993 static int unset_command(assuan_context_t ctx, gchar *line)
2995 return send_error(ctx, set_unset_common(ctx, line, NULL));
2998 static int set_command(assuan_context_t ctx, gchar *line)
3000 gchar name[64] = {0}, value[256] = {0};
3002 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3003 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3005 return send_error(ctx, set_unset_common(ctx, name, value));
3008 static void bye_notify(assuan_context_t ctx)
3010 struct client_s *cl = assuan_get_pointer(ctx);
3012 /* This will let assuan_process_next() return. */
3013 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3016 static void reset_notify(assuan_context_t ctx)
3018 struct client_s *cl = assuan_get_pointer(ctx);
3020 if (cl)
3021 cleanup_client(cl);
3025 * This is called before every Assuan command.
3027 int command_startup(assuan_context_t ctx, const char *name)
3029 struct client_s *cl = assuan_get_pointer(ctx);
3030 gpg_error_t rc;
3032 if (!g_strcmp0(name, "ISCACHED") ||
3033 !g_strcmp0(name, "CLEARCACHE") ||
3034 !g_strcmp0(name, "CACHETIMEOUT") ||
3035 !g_strcmp0(name, "GETCONFIG") ||
3036 !g_strcmp0(name, "GETPID") ||
3037 !g_strcmp0(name, "VERSION") ||
3038 !g_strcmp0(name, "SET") ||
3039 !g_strcmp0(name, "BYE") ||
3040 !g_strcmp0(name, "NOP") ||
3041 !g_strcmp0(name, "CANCEL") ||
3042 !g_strcmp0(name, "RESET") ||
3043 !g_strcmp0(name, "END") ||
3044 !g_strcmp0(name, "HELP") ||
3045 !g_strcmp0(name, "OPTION") ||
3046 !g_strcmp0(name, "INPUT") ||
3047 !g_strcmp0(name, "OUTPUT") ||
3048 !g_strcmp0(name, "UNSET"))
3049 return 0;
3051 rc = file_modified(cl);
3053 if (rc) {
3054 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3055 !g_strcmp0(name, "OPEN"))
3056 rc = 0;
3059 return rc;
3063 * This is called after every Assuan command.
3065 void command_finalize(assuan_context_t ctx, gint rc)
3067 struct client_s *client = assuan_get_pointer(ctx);
3069 if (!client->is_lock_cmd)
3070 unlock_file_mutex(client);
3073 gpg_error_t register_commands(assuan_context_t ctx)
3075 static struct {
3076 const gchar *name;
3077 gint (*handler)(assuan_context_t, gchar *line);
3078 } table[] = {
3079 { "OPEN", open_command },
3080 { "SAVE", save_command },
3081 { "LIST", list_command },
3082 { "REALPATH", realpath_command },
3083 { "STORE", store_command },
3084 { "DELETE", delete_command },
3085 { "GET", get_command },
3086 { "ATTR", attr_command },
3087 { "ISCACHED", iscached_command },
3088 { "CLEARCACHE", clearcache_command },
3089 { "CACHETIMEOUT", cachetimeout_command },
3090 { "GETCONFIG", getconfig_command },
3091 { "DUMP", dump_command },
3092 { "XPATH", xpath_command },
3093 { "IMPORT", import_command },
3094 { "LOCK", lock_command },
3095 { "UNLOCK", unlock_command },
3096 { "GETPID", getpid_command },
3097 { "VERSION", version_command },
3098 { "SET", set_command },
3099 { "UNSET", unset_command },
3100 { "INPUT", NULL },
3101 { "OUTPUT", NULL },
3102 { NULL, NULL }
3104 gint i, rc;
3106 for (i=0; table[i].name; i++) {
3107 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3109 if (rc)
3110 return rc;
3113 rc = assuan_register_bye_notify(ctx, bye_notify);
3115 if (rc)
3116 return rc;
3118 rc = assuan_register_reset_notify(ctx, reset_notify);
3120 if (rc)
3121 return rc;
3123 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
3125 if (rc)
3126 return rc;
3128 return assuan_register_post_cmd_notify(ctx, command_finalize);
3131 gpg_error_t try_xml_decrypt(assuan_context_t ctx, guchar *key,
3132 struct client_crypto_s *crypto, gpointer *dst, goffset *dst_len)
3134 goffset insize, len;
3135 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3136 guint64 iter = 0, n_iter = 0, iter_progress = 0;
3137 gint zrc = 0;
3138 gulong outsize = 0;
3139 gpg_error_t rc;
3140 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
3141 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
3143 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3144 insize = crypto->fh->st.st_size - fh_size;
3145 crypto->iv = gcry_malloc(gcryblocksize);
3147 if (!crypto->iv) {
3148 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3149 return gpg_error_from_errno(ENOMEM);
3152 /* No encryption iterations. This is a plain (gzipped) file. */
3153 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0)) {
3155 * cache_file_count() needs both .used == TRUE and a valid key in
3156 * order for it to count as a used cache entry. Fixes CACHE status
3157 * messages.
3159 memset(key, '!', gcrykeysize);
3162 if (crypto->fh->v1)
3163 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, gcryblocksize);
3164 else
3165 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, gcryblocksize);
3167 crypto->inbuf = gcry_malloc(insize);
3169 if (!crypto->inbuf) {
3170 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3171 return gpg_error_from_errno(ENOMEM);
3174 crypto->insize = insize;
3175 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
3177 if (len != crypto->insize)
3178 return GPG_ERR_INV_LENGTH;
3180 if ((crypto->fh->v1 && fh_iter < 0) || (!crypto->fh->v1 && fh_iter <= 0))
3181 goto decompress;
3183 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3184 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3185 return rc;
3188 if ((rc = gcry_cipher_setkey(crypto->gh, key, gcrykeysize))) {
3189 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3190 return rc;
3193 iter_progress = (guint64)get_key_file_integer(client && client->filename ?
3194 client->filename : "global", "iteration_progress");
3196 if (iter_progress > 0 && fh_iter >= iter_progress) {
3197 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
3199 if (rc)
3200 return rc;
3203 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3205 if (rc)
3206 return rc;
3208 crypto->tkey = gcry_malloc(gcrykeysize);
3210 if (!crypto->tkey) {
3211 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
3212 return gpg_error_from_errno(ENOMEM);
3215 memcpy(crypto->tkey, key, gcrykeysize);
3216 guchar *tkey = crypto->tkey;
3217 tkey[0] ^= 1;
3219 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, gcrykeysize))) {
3220 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3221 return rc;
3224 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
3225 if (iter_progress > 0 && iter >= iter_progress) {
3226 if (!(iter % iter_progress)) {
3227 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
3228 ++n_iter * iter_progress, fh_iter);
3230 if (rc)
3231 return rc;
3235 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, gcryblocksize))) {
3236 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3237 return rc;
3240 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
3242 if (rc) {
3243 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
3244 return rc;
3247 iter++;
3250 if (iter_progress && fh_iter >= iter_progress) {
3251 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
3253 if (rc)
3254 return rc;
3257 decompress:
3258 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
3259 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
3260 if (zrc == Z_MEM_ERROR)
3261 return gpg_error_from_errno(ENOMEM);
3262 else
3263 return EPWMD_BADKEY; // Not a valid gzip header. Must be a bad key.
3266 if (g_strncasecmp(crypto->outbuf, "<?xml version=", 14) != 0) {
3267 gcry_free(crypto->outbuf);
3268 crypto->outbuf = NULL;
3269 return EPWMD_BADKEY;
3272 if (ctx) {
3273 client->xml = crypto->outbuf;
3274 client->len = outsize;
3275 crypto->outbuf = NULL;
3277 else if (dst) {
3278 *dst = crypto->outbuf;
3279 *dst_len = outsize;
3280 crypto->outbuf = NULL;
3283 /* The calling function should free the crypto struct. */
3284 return 0;