ATTR SET TARGET fix for complex targets.
[pwmd.git] / src / commands.c
blob020f78ff0aef40a6e64679a5a33e246f2eb8d0d4
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 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 02111-1307 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 <glib/gprintf.h>
30 #include <gcrypt.h>
31 #include <zlib.h>
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #ifndef MEM_DEBUG
38 #include "mem.h"
39 #endif
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 "commands.h"
52 static void *z_alloc(void *data, unsigned items, unsigned size)
54 #ifndef MEM_DEBUG
55 return gcry_calloc(items, size);
56 #else
57 return calloc(items, size);
58 #endif
61 static void z_free(void *data, void *p)
63 #ifndef MEM_DEBUG
64 gcry_free(p);
65 #else
66 free(p);
67 #endif
70 static gpg_error_t file_modified(struct client_s *client)
72 struct stat st;
74 if (client->state != STATE_OPEN)
75 return EPWMD_NO_FILE;
77 if (stat(client->filename, &st) == 0 && client->mtime) {
78 if (client->mtime != st.st_mtime)
79 return EPWMD_FILE_MODIFIED;
82 return 0;
85 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
86 void *inbuf, gsize insize)
88 gpg_error_t rc;
90 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
91 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
92 return FALSE;
95 return TRUE;
98 gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
99 void *inbuf, gsize insize)
101 gpg_error_t rc;
103 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
104 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
106 return rc;
109 static gpg_error_t parse_xml(assuan_context_t ctx)
111 struct client_s *client = assuan_get_pointer(ctx);
113 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
115 if (!client->doc)
116 return EPWMD_LIBXML_ERROR;
118 return 0;
121 gboolean valid_filename(const gchar *filename)
123 const gchar *p;
125 if (!filename || !*filename)
126 return FALSE;
128 for (p = filename; *p; p++) {
129 if (g_ascii_isalnum(*p) == FALSE && *p != '-' && *p != '_' && *p != '.')
130 return FALSE;
133 return TRUE;
136 gint open_file(const gchar *filename, struct stat *st)
138 gint fd;
140 if ((fd = open(filename, O_RDONLY)) == -1)
141 return -1;
143 if (stat(filename, st) == -1) {
144 close(fd);
145 return -1;
148 return fd;
151 void unlock_file_mutex(struct client_s *client)
153 pth_mutex_t *m;
155 #ifdef WITH_PINENTRY
156 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
157 #else
158 if (client->has_lock == FALSE)
159 #endif
160 return;
162 CACHE_LOCK(client->ctx);
164 if (cache_get_mutex(client->md5file, &m) == FALSE) {
165 CACHE_UNLOCK;
166 return;
169 CACHE_UNLOCK;
170 pth_mutex_release(m);
171 client->has_lock = FALSE;
174 gpg_error_t lock_file_mutex(struct client_s *client)
176 pth_mutex_t *m;
178 if (client->has_lock == TRUE)
179 return 0;
181 CACHE_LOCK(client->ctx);
183 if (cache_get_mutex(client->md5file, &m) == FALSE) {
184 CACHE_UNLOCK;
185 return 0;
188 CACHE_UNLOCK;
190 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
191 if (errno == EBUSY) {
192 if (client->ctx)
193 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
195 pth_mutex_acquire(m, FALSE, NULL);
197 else {
198 gint e = errno;
199 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
200 return gpg_error_from_errno(e);
204 client->has_lock = TRUE;
205 return 0;
208 void free_client(struct client_s *client)
210 if (client->doc)
211 xmlFreeDoc(client->doc);
213 if (client->xml)
214 gcry_free(client->xml);
216 if (client->filename)
217 g_free(client->filename);
219 if (client->gh)
220 gcry_cipher_close(client->gh);
223 static void cleanup_client(struct client_s *client)
225 assuan_context_t ctx = client->ctx;
226 #ifdef WITH_PINENTRY
227 struct pinentry_s *pin = client->pinentry;
228 #endif
230 unlock_file_mutex(client);
231 CACHE_LOCK(client->ctx);
232 cache_decr_refcount(client->md5file);
235 * This may be a new file so don't use a cache slot. save_command() will
236 * set this to FALSE on success.
238 if (client->new == TRUE)
239 cache_clear(client->md5file, 1);
241 free_client(client);
242 memset(client, 0, sizeof(struct client_s));
243 client->state = STATE_CONNECTED;
244 client->ctx = ctx;
245 client->freed = TRUE;
246 #ifdef WITH_PINENTRY
247 client->pinentry = pin;
248 #endif
249 CACHE_UNLOCK;
252 static gchar *print_fmt(const char *fmt, ...)
254 va_list ap;
255 static gchar buf[ASSUAN_LINELENGTH] = {0};
257 va_start(ap, fmt);
258 vsnprintf(buf, sizeof(buf), fmt, ap);
259 va_end(ap);
260 return buf;
263 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
264 gpointer *out, glong *outsize, gint *error)
266 z_stream z;
267 gint ret;
268 gpointer pout;
269 gz_header h;
270 gchar buf[17];
271 gpg_error_t rc;
273 z.zalloc = z_alloc;
274 z.zfree = z_free;
275 z.next_in = in;
276 z.avail_in = insize;
277 z.avail_out = zlib_bufsize;
278 z.next_out = pout = g_malloc(zlib_bufsize);
280 if (!pout) {
281 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
282 *error = Z_MEM_ERROR;
283 return FALSE;
286 ret = inflateInit2(&z, 47);
288 if (ret != Z_OK) {
289 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
290 g_free(pout);
291 return FALSE;
294 memset(&h, 0, sizeof(gz_header));
295 h.comment = (guchar *)buf;
296 h.comm_max = sizeof(buf);
297 ret = inflateGetHeader(&z, &h);
299 if (ret != Z_OK) {
300 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
301 g_free(pout);
302 inflateEnd(&z);
303 return FALSE;
306 ret = inflate(&z, Z_BLOCK);
308 if (ret != Z_OK) {
309 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
310 g_free(pout);
311 inflateEnd(&z);
312 return FALSE;
315 if (h.comment)
316 insize = atoi((gchar *)h.comment);
318 do {
319 gpointer p;
321 ret = inflate(&z, Z_FINISH);
323 switch (ret) {
324 case Z_OK:
325 break;
326 case Z_BUF_ERROR:
327 if (!z.avail_out) {
328 p = g_realloc(pout, z.total_out + zlib_bufsize);
330 if (!p) {
331 ret = Z_MEM_ERROR;
332 goto fail;
335 pout = p;
336 z.next_out = pout + z.total_out;
337 z.avail_out = zlib_bufsize;
339 if (ctx) {
340 rc = assuan_write_status(ctx, "DECOMPRESS",
341 print_fmt("%i %i", z.total_out, insize));
343 if (rc) {
344 ret = rc;
345 goto fail;
349 break;
350 case Z_STREAM_END:
351 break;
352 default:
353 goto fail;
354 break;
357 pth_yield(NULL);
358 } while (ret != Z_STREAM_END);
360 if (ctx) {
361 rc = assuan_write_status(ctx, "DECOMPRESS",
362 print_fmt("%i %i", z.total_out, insize));
364 if (rc) {
365 ret = rc;
366 goto fail;
370 *out = pout;
371 *outsize = z.total_out;
372 inflateEnd(&z);
373 return TRUE;
375 fail:
376 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
377 *error = ret;
378 g_free(pout);
379 inflateEnd(&z);
380 return FALSE;
383 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
385 gint fd;
386 gsize len;
388 fd = open(filename, O_RDONLY);
390 if (fd == -1)
391 return gpg_error_from_errno(errno);
393 len = pth_read(fd, fh, sizeof(file_header_t));
394 close(fd);
396 if (len != sizeof(file_header_t))
397 return gpg_error_from_errno(errno);
399 return 0;
402 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
403 gboolean cached)
405 struct client_s *client = assuan_get_pointer(ctx);
406 gpg_error_t error;
407 struct stat st;
408 gint fd;
409 gint timeout;
411 if ((fd = open_file(client->filename, &st)) == -1) {
412 /* New file. */
413 if (errno == ENOENT) {
414 if (shakey[0])
415 goto update_cache;
417 goto done;
420 error = errno;
421 log_write("%s: %s", client->filename, strerror(errno));
422 cleanup_client(client);
423 memset(shakey, 0, sizeof(shakey));
424 return send_syserror(ctx, error);
427 error = try_xml_decrypt(ctx, fd, st, shakey);
428 close(fd);
430 if (error) {
431 memset(shakey, 0, sizeof(shakey));
432 cleanup_client(client);
433 return send_error(ctx, error);
436 update_cache:
437 CACHE_LOCK(client->ctx);
439 if (cached == FALSE) {
440 if (cache_update_key(client->md5file, shakey) == FALSE) {
441 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
442 cleanup_client(client);
443 CACHE_UNLOCK;
444 return send_error(ctx, EPWMD_MAX_SLOTS);
447 timeout = get_key_file_integer(client->filename, "cache_timeout");
448 cache_reset_timeout(client->md5file, timeout);
450 else
451 cache_set_timeout(client->md5file, -2);
453 CACHE_UNLOCK;
455 done:
456 memset(shakey, 0, sizeof(shakey));
457 error = parse_xml(ctx);
459 if (client->xml) {
460 gcry_free(client->xml);
461 client->xml = NULL;
464 if (!error) {
465 if (client->new == FALSE)
466 send_cache_status_all();
468 client->state = STATE_OPEN;
471 return send_error(ctx, error);
474 static int open_command(assuan_context_t ctx, char *line)
476 struct stat st;
477 guchar shakey[gcrykeysize];
478 gboolean cached = FALSE;
479 gpg_error_t error;
480 struct client_s *client = assuan_get_pointer(ctx);
481 gchar **req;
482 gchar *filename = NULL;
483 file_header_t file_header;
485 memset(shakey, 0, sizeof(shakey));
487 if ((req = split_input_line(line, " ", 2)) != NULL)
488 filename = req[0];
490 if (!filename || !*filename) {
491 g_strfreev(req);
492 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
495 if (valid_filename(filename) == FALSE) {
496 g_strfreev(req);
497 return send_error(ctx, EPWMD_INVALID_FILENAME);
500 if (client->state == STATE_OPEN)
501 cleanup_client(client);
503 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
504 CACHE_LOCK(client->ctx);
506 if (cache_has_file(client->md5file) == FALSE) {
507 if (cache_add_file(client->md5file, NULL) == FALSE) {
508 g_strfreev(req);
509 CACHE_UNLOCK;
510 return send_error(ctx, EPWMD_MAX_SLOTS);
514 cache_incr_refcount(client->md5file);
515 CACHE_UNLOCK;
516 error = lock_file_mutex(client);
518 if (error) {
519 g_strfreev(req);
520 return send_error(ctx, error);
523 client->freed = FALSE;
525 if ((error = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
526 g_strfreev(req);
527 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
528 cleanup_client(client);
529 return send_error(ctx, error);
532 if (stat(filename, &st) == 0) {
533 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
534 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
535 g_strfreev(req);
536 cleanup_client(client);
537 return send_error(ctx, EPWMD_INVALID_FILENAME);
540 client->mtime = st.st_mtime;
543 client->filename = g_strdup(filename);
545 if (!client->filename) {
546 memset(shakey, 0, sizeof(shakey));
547 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
548 cleanup_client(client);
549 g_strfreev(req);
550 return send_syserror(ctx, ENOMEM);
553 #ifdef WITH_PINENTRY
554 client->pinentry->filename = g_strdup(client->filename);
556 if (!client->pinentry->filename) {
557 memset(shakey, 0, sizeof(shakey));
558 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
559 cleanup_client(client);
560 g_strfreev(req);
561 return send_syserror(ctx, ENOMEM);
563 #endif
566 * New files don't need a key.
568 if (access(filename, R_OK|W_OK) != 0) {
569 if (errno != ENOENT) {
570 error = errno;
571 log_write("%s: %s", filename, strerror(errno));
572 g_strfreev(req);
573 cleanup_client(client);
574 return send_syserror(ctx, error);
577 if ((client->xml = new_document()) == NULL) {
578 log_write("%s", strerror(ENOMEM));
579 g_strfreev(req);
580 cleanup_client(client);
581 return send_syserror(ctx, ENOMEM);
584 client->len = xmlStrlen(client->xml);
585 client->new = TRUE;
586 client->filename = g_strdup(filename);
588 if (!client->filename) {
589 g_strfreev(req);
590 cleanup_client(client);
591 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
592 return send_syserror(ctx, ENOMEM);
595 memset(shakey, 0, sizeof(shakey));
597 if (req[1] && *req[1])
598 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
600 g_strfreev(req);
601 return open_command_finalize(ctx, shakey, cached);
604 error = read_file_header(filename, &file_header);
606 if (error) {
607 g_strfreev(req);
608 cleanup_client(client);
609 return send_error(ctx, error);
612 if (file_header.iter == -1)
613 goto done;
615 CACHE_LOCK(client->ctx);
616 cached = cache_get_key(client->md5file, shakey);
617 CACHE_UNLOCK;
619 if (cached == FALSE) {
621 * No key specified and no matching filename found in the cache. Use
622 * pinentry to retrieve the key. Cannot return assuan_process_done()
623 * here otherwise the command will be interrupted. The event loop in
624 * client_thread() will poll the file descriptor waiting for it to
625 * become ready to read a pinentry_key_s which will contain the
626 * entered key or error. It will then call open_command_finalize() to
627 * to finish the command.
629 if (!req[1] || !*req[1]) {
630 #ifdef WITH_PINENTRY
631 if (get_key_file_boolean(filename, "enable_pinentry") == FALSE) {
632 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
633 goto done;
636 g_strfreev(req);
637 client->pinentry->which = PINENTRY_OPEN;
638 error = pinentry_fork(ctx);
640 if (error) {
641 cleanup_client(client);
642 return send_error(ctx, error);
645 client->pinentry->cb = open_command_finalize;
646 client->pinentry->status = PINENTRY_INIT;
647 return 0;
648 #else
649 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
650 goto done;
651 #endif
654 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
657 done:
658 g_strfreev(req);
659 return open_command_finalize(ctx, shakey, cached);
662 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
663 gint size, gpointer *out, glong *outsize, gint *error)
665 z_stream z;
666 gpointer pout, pin;
667 gint ret;
668 gz_header h;
669 gchar buf[17];
670 gint cmd = Z_NO_FLUSH;
671 gpg_error_t rc;
673 z.zalloc = z_alloc;
674 z.zfree = z_free;
675 z.next_in = pin = data;
676 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
677 z.avail_out = zlib_bufsize;
678 z.next_out = pout = g_malloc(zlib_bufsize);
680 if (!pout) {
681 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
682 *error = Z_MEM_ERROR;
683 return FALSE;
686 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
688 if (ret != Z_OK) {
689 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
690 *error = ret;
691 g_free(pout);
692 return FALSE;
695 memset(&h, 0, sizeof(gz_header));
696 snprintf(buf, sizeof(buf), "%i", size);
697 h.comment = (guchar *)buf;
698 ret = deflateSetHeader(&z, &h);
700 if (ret != Z_OK) {
701 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
702 *error = ret;
703 g_free(pout);
704 deflateEnd(&z);
705 return FALSE;
708 do {
709 gpointer p;
711 ret = deflate(&z, cmd);
713 switch (ret) {
714 case Z_OK:
715 break;
716 case Z_BUF_ERROR:
717 if (!z.avail_out) {
718 p = g_realloc(pout, z.total_out + zlib_bufsize);
720 if (!p) {
721 ret = Z_MEM_ERROR;
722 goto fail;
725 pout = p;
726 z.next_out = pout + z.total_out;
727 z.avail_out = zlib_bufsize;
730 if (!z.avail_in && z.total_in < size) {
731 if (z.total_in + zlib_bufsize > size)
732 z.avail_in = size - z.total_in;
733 else
734 z.avail_in = zlib_bufsize;
736 if (ctx) {
737 rc = assuan_write_status(ctx, "COMPRESS",
738 print_fmt("%i %i", z.total_in, size));
740 if (rc) {
741 ret = rc;
742 goto fail;
747 if (z.total_in >= size)
748 cmd = Z_FINISH;
750 break;
751 case Z_STREAM_END:
752 break;
753 default:
754 goto fail;
757 pth_yield(NULL);
758 } while (ret != Z_STREAM_END);
760 if (ctx) {
761 rc = assuan_write_status(ctx, "COMPRESS",
762 print_fmt("%i %i", z.total_in, size));
764 if (rc) {
765 ret = rc;
766 goto fail;
770 *out = pout;
771 *outsize = z.total_out;
772 deflateEnd(&z);
773 return TRUE;
775 fail:
776 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
777 *error = ret;
778 g_free(pout);
779 deflateEnd(&z);
780 return FALSE;
783 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
784 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
785 gint iter)
787 gsize len = insize;
788 gint fd;
789 gpointer inbuf;
790 guchar tkey[gcrykeysize];
791 gchar *p;
792 gint error;
793 gpg_error_t rc;
794 guint iter_progress = 0, n_iter = 0, xiter = 0;
795 gchar tmp[FILENAME_MAX];
796 file_header_t file_header;
798 if (iter == -1) {
800 * cache_file_count() needs both .used == TRUE and a valid key in
801 * order for it to count as a used cache entry. Fixes CACHE status
802 * messages.
804 memset(shakey, '!', gcrykeysize);
805 inbuf = data;
806 file_header.iter = iter;
807 goto write_file;
810 if (insize / gcryblocksize) {
811 len = (insize / gcryblocksize) * gcryblocksize;
813 if (insize % gcryblocksize)
814 len += gcryblocksize;
818 * Resize the existing xml buffer to the block size required by gcrypt
819 * rather than duplicating it and wasting memory.
821 inbuf = gcry_realloc(data, len);
823 if (!inbuf)
824 return gpg_error_from_errno(ENOMEM);
826 insize = len;
827 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
828 memcpy(tkey, shakey, sizeof(tkey));
829 tkey[0] ^= 1;
831 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
832 gcry_free(inbuf);
833 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
834 return rc;
837 file_header.iter = iter;
839 if (client)
840 iter_progress = get_key_file_integer("global", "iteration_progress");
842 if (client && iter_progress && file_header.iter >= iter_progress) {
843 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
845 if (error) {
846 gcry_free(inbuf);
847 return error;
851 while (xiter < file_header.iter) {
852 if (client && iter_progress > 0 && xiter >= iter_progress) {
853 if (!(xiter % iter_progress)) {
854 error = assuan_write_status(client->ctx, "ENCRYPT", print_fmt("%i",
855 ++n_iter * iter_progress));
857 if (error) {
858 gcry_free(inbuf);
859 return error;
864 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
865 sizeof(file_header.iv)))) {
866 gcry_free(inbuf);
867 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
868 return rc;
871 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
872 == FALSE) {
873 gcry_free(inbuf);
874 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
875 return rc;
878 xiter++;
879 pth_yield(NULL);
882 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
883 sizeof(file_header.iv)))) {
884 gcry_free(inbuf);
885 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
886 return rc;
889 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
890 gcry_free(inbuf);
891 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
892 return rc;
895 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
896 gcry_free(inbuf);
897 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
898 return rc;
901 if (client && iter_progress && file_header.iter >= iter_progress) {
902 error = assuan_write_status(client->ctx, "ENCRYPT",
903 print_fmt("%i", file_header.iter));
905 if (error) {
906 gcry_free(inbuf);
907 return error;
911 write_file:
912 if (filename) {
913 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
915 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
916 error = errno;
917 gcry_free(inbuf);
918 p = strrchr(tmp, '/');
919 p++;
920 log_write("%s: %s", p, strerror(errno));
921 return gpg_error_from_errno(error);
924 else
926 * xml_import() from command line.
928 fd = STDOUT_FILENO;
930 len = pth_write(fd, &file_header, sizeof(file_header_t));
932 if (len != sizeof(file_header)) {
933 len = errno;
935 if (filename)
936 close(fd);
938 gcry_free(inbuf);
939 return gpg_error_from_errno(len);
942 len = pth_write(fd, inbuf, insize);
944 if (len != insize) {
945 len = errno;
947 if (filename)
948 close(fd);
950 gcry_free(inbuf);
951 return gpg_error_from_errno(len);
954 if (fsync(fd) == -1) {
955 len = errno;
956 close(fd);
957 gcry_free(inbuf);
958 return gpg_error_from_errno(len);
961 if (filename) {
962 struct stat st;
963 mode_t mode = 0;
965 close(fd);
967 if (stat(filename, &st) == 0)
968 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
970 if (rename(tmp, filename) == -1) {
971 len = errno;
972 gcry_free(inbuf);
973 return gpg_error_from_errno(len);
976 if (mode)
977 chmod(filename, mode);
980 gcry_free(inbuf);
981 return 0;
984 static gpg_error_t save_command_finalize(assuan_context_t ctx,
985 guchar shakey[], gboolean cached)
987 struct client_s *client = assuan_get_pointer(ctx);
988 gpointer xmlbuf;
989 xmlChar *p;
990 gint len;
991 gint iter;
992 gint timeout;
993 gpointer outbuf;
994 glong outsize = 0;
995 gint zerror;
996 gpg_error_t error;
997 struct stat st;
999 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
1000 xmlbuf = p;
1002 iter = get_key_file_integer(client->filename, "compression_level");
1004 if (iter < 0)
1005 iter = 0;
1007 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
1008 memset(shakey, 0, sizeof(shakey));
1009 xmlFree(xmlbuf);
1011 if (zerror == Z_MEM_ERROR) {
1012 return send_syserror(ctx, ENOMEM);
1014 else
1015 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1017 else {
1018 gcry_free(xmlbuf);
1019 xmlbuf = outbuf;
1020 len = outsize;
1023 iter = get_key_file_integer(client->filename, "iterations");
1024 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1026 if (error) {
1027 memset(shakey, 0, sizeof(shakey));
1028 return send_error(ctx, error);
1031 stat(client->filename, &st);
1032 client->mtime = st.st_mtime;
1033 timeout = get_key_file_integer(client->filename, "cache_timeout");
1034 CACHE_LOCK(client->ctx);
1036 if (cached) {
1037 memset(shakey, 0, sizeof(shakey));
1038 cache_reset_timeout(client->md5file, timeout);
1039 CACHE_UNLOCK;
1041 if (client->new == TRUE)
1042 send_cache_status_all();
1044 client->new = FALSE;
1045 return send_error(ctx, 0);
1048 if (cache_update_key(client->md5file, shakey) == FALSE) {
1049 memset(shakey, 0, sizeof(shakey));
1050 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1051 CACHE_UNLOCK;
1052 return send_error(ctx, EPWMD_MAX_SLOTS);
1055 client->new = FALSE;
1056 memset(shakey, 0, sizeof(shakey));
1057 cache_reset_timeout(client->md5file, timeout);
1058 CACHE_UNLOCK;
1059 send_cache_status_all();
1060 return send_error(ctx, 0);
1063 static int save_command(assuan_context_t ctx, char *line)
1065 gboolean cached = FALSE;
1066 guchar shakey[gcrykeysize];
1067 struct stat st;
1068 struct client_s *client = assuan_get_pointer(ctx);
1069 gpg_error_t error;
1071 memset(shakey, 0, sizeof(shakey));
1072 error = file_modified(client);
1074 if (error) {
1075 log_write("%s: %s", client->filename ? client->filename : "",
1076 pwmd_strerror(error));
1077 return send_error(ctx, error);
1080 error = lock_file_mutex(client);
1082 if (error)
1083 return send_error(ctx, error);
1085 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1086 return send_syserror(ctx, errno);
1088 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1089 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1090 return send_error(ctx, EPWMD_INVALID_FILENAME);
1093 if (get_key_file_integer(client->filename, "iterations") == -1)
1094 goto done;
1096 if (!line || !*line) {
1097 guchar tmp[sizeof(shakey)];
1098 CACHE_LOCK(ctx);
1100 memset(tmp, '!', sizeof(tmp));
1102 if (cache_get_key(client->md5file, shakey) == FALSE ||
1103 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1104 CACHE_UNLOCK;
1105 #ifdef WITH_PINENTRY
1106 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1107 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1108 goto done;
1111 client->pinentry->which = PINENTRY_SAVE;
1112 error = pinentry_fork(ctx);
1114 if (error)
1115 return send_error(ctx, error);
1117 client->pinentry->cb = save_command_finalize;
1118 client->pinentry->status = PINENTRY_INIT;
1119 return 0;
1120 #else
1121 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1122 goto done;
1123 #endif
1125 else {
1126 CACHE_UNLOCK;
1127 cached = TRUE;
1130 else {
1131 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1132 memset(line, 0, strlen(line));
1135 done:
1136 return save_command_finalize(ctx, shakey, cached);
1139 static gboolean contains_whitespace(const gchar *str)
1141 const gchar *p = str;
1142 gunichar c;
1143 glong len;
1145 len = g_utf8_strlen(p++, -1) -1;
1147 while (len--) {
1148 c = g_utf8_get_char(p++);
1150 if (g_unichar_isspace(c))
1151 return TRUE;
1154 return FALSE;
1157 static int delete_command(assuan_context_t ctx, char *line)
1159 struct client_s *client = assuan_get_pointer(ctx);
1160 gchar **req;
1161 gpg_error_t error;
1162 xmlNodePtr n;
1164 error = file_modified(client);
1166 if (error) {
1167 log_write("%s: %s", client->filename ? client->filename : "",
1168 pwmd_strerror(error));
1169 return send_error(ctx, error);
1172 if (strchr(line, '\t'))
1173 req = split_input_line(line, "\t", -1);
1174 else
1175 req = split_input_line(line, " ", -1);
1177 if (!req || !*req)
1178 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1180 n = find_account(client->doc, &req, &error, NULL, 0);
1182 if (!n) {
1183 g_strfreev(req);
1184 return send_error(ctx, error);
1188 * No sub-node defined. Remove the entire node (account).
1190 if (!req[1]) {
1191 if (n) {
1192 xmlUnlinkNode(n);
1193 xmlFreeNode(n);
1196 g_strfreev(req);
1197 return send_error(ctx, 0);
1200 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1201 g_strfreev(req);
1203 if (!n)
1204 return send_error(ctx, error);
1206 if (n) {
1207 xmlUnlinkNode(n);
1208 xmlFreeNode(n);
1211 return send_error(ctx, 0);
1215 * Don't return with assuan_process_done() here. This has been called from
1216 * assuan_process_next() and the command should be finished in
1217 * client_thread().
1219 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1220 gsize len)
1222 assuan_context_t ctx = data;
1223 struct client_s *client = assuan_get_pointer(ctx);
1224 gchar **req;
1225 guchar *result = line;
1226 xmlNodePtr n;
1227 gpg_error_t error = file_modified(client);
1229 if (rc) {
1230 if (line)
1231 #ifndef MEM_DEBUG
1232 xfree(line);
1233 #else
1234 free(line);
1235 #endif
1236 return rc;
1239 req = split_input_line((gchar *)result, "\t", 0);
1240 #ifndef MEM_DEBUG
1241 xfree(line);
1242 #else
1243 free(line);
1244 #endif
1246 if (rc) {
1247 if (req)
1248 g_strfreev(req);
1250 return rc;
1253 if (!req || !*req)
1254 return EPWMD_COMMAND_SYNTAX;
1256 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1257 g_strfreev(req);
1258 return EPWMD_INVALID_ELEMENT;
1261 if (valid_element_path(req+1, TRUE) == FALSE) {
1262 g_strfreev(req);
1263 return EPWMD_INVALID_ELEMENT;
1266 again:
1267 n = find_account(client->doc, &req, &error, NULL, 0);
1269 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1270 error = new_account(client->doc, *req);
1272 if (error) {
1273 g_strfreev(req);
1274 return error;
1277 goto again;
1280 if (!n) {
1281 g_strfreev(req);
1282 return error;
1285 if (req[1]) {
1286 if (!n->children)
1287 create_elements_cb(n, req+1, &error, NULL);
1288 else
1289 find_elements(client->doc, n->children, req+1, &error,
1290 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1293 g_strfreev(req);
1294 client->inquire_status = INQUIRE_DONE;
1295 return error;
1298 static int store_command(assuan_context_t ctx, char *line)
1300 struct client_s *client = assuan_get_pointer(ctx);
1301 gpg_error_t error = file_modified(client);
1303 if (error) {
1304 log_write("%s: %s", client->filename ? client->filename : "",
1305 pwmd_strerror(error));
1306 return send_error(ctx, error);
1309 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1311 if (error)
1312 return send_error(ctx, error);
1314 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1315 client->inquire_status = INQUIRE_BUSY;
1316 return 0;
1319 static int get_command(assuan_context_t ctx, char *line)
1321 struct client_s *client = assuan_get_pointer(ctx);
1322 gchar **req;
1323 gpg_error_t error;
1324 xmlNodePtr n;
1326 error = file_modified(client);
1328 if (error) {
1329 log_write("%s: %s", client->filename ? client->filename : "",
1330 pwmd_strerror(error));
1331 return send_error(ctx, error);
1334 req = split_input_line(line, "\t", -1);
1336 if (!req || !*req) {
1337 g_strfreev(req);
1338 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1341 n = find_account(client->doc, &req, &error, NULL, 0);
1343 if (!n) {
1344 g_strfreev(req);
1345 return send_error(ctx, error);
1348 if (req[1])
1349 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1351 g_strfreev(req);
1353 if (error)
1354 return send_error(ctx, error);
1356 if (!n || !n->children)
1357 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1359 n = find_text_node(n->children);
1361 if (!n || !n->content || !*n->content)
1362 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1364 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1365 return send_error(ctx, error);
1368 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
1370 xmlChar *p = path;
1371 gint n;
1372 gchar *buf;
1374 if (!p)
1375 return NULL;
1377 for (n = 0; *p && n < 3; p++) {
1378 if (*p == '/')
1379 n++;
1382 if (strstr((gchar *)p, "text()") != NULL)
1383 p[xmlStrlen(p) - 7] = 0;
1385 for (n = 0; p[n]; n++) {
1386 if (p[n] == '/')
1387 p[n] = '\t';
1390 buf = g_strdup_printf("%s\t%s", account, p);
1391 p = (xmlChar *)buf + strlen(buf) - 1;
1393 while (isspace(*p))
1394 *p-- = 0;
1396 return buf;
1399 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
1401 gchar **a;
1402 va_list ap;
1403 gchar *buf;
1404 gint len = *array ? g_strv_length(*array) : 0;
1405 gint ret;
1407 if (!fmt)
1408 return FALSE;
1410 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL)
1411 return FALSE;
1413 va_start(ap, fmt);
1414 ret = g_vasprintf(&buf, fmt, ap);
1415 va_end(ap);
1417 if (ret == -1)
1418 return FALSE;
1420 a[len++] = buf;
1421 a[len] = NULL;
1422 *array = a;
1423 return TRUE;
1426 struct realpath_s {
1427 gchar *account;
1430 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **req,
1431 gpg_error_t *error, void *data)
1433 struct realpath_s *rp = data;
1435 if (rp->account)
1436 g_free(rp->account);
1438 rp->account = g_strdup(req[0]);
1440 if (!rp->account) {
1441 *error = gpg_error_from_errno(ENOMEM);
1442 return NULL;
1445 return node;
1448 static int realpath_command(assuan_context_t ctx, char *line)
1450 gpg_error_t error;
1451 struct client_s *client = assuan_get_pointer(ctx);
1452 xmlChar *p;
1453 gchar **req;
1454 gchar *result, *t;
1455 gint i;
1456 xmlNodePtr n;
1457 struct realpath_s *rp;
1458 GString *string;
1460 error = file_modified(client);
1462 if (error) {
1463 log_write("%s: %s", client->filename ? client->filename : "",
1464 pwmd_strerror(error));
1465 return send_error(ctx, error);
1468 if (strchr(line, '\t') != NULL) {
1469 if ((req = split_input_line(line, "\t", 0)) == NULL)
1470 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1472 else {
1473 if ((req = split_input_line(line, " ", 0)) == NULL)
1474 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1477 n = find_account(client->doc, &req, &error, NULL, 0);
1479 if (!n) {
1480 g_strfreev(req);
1481 return send_error(ctx, error);
1484 rp = g_malloc(sizeof(struct realpath_s));
1486 if (!rp) {
1487 g_strfreev(req);
1488 return send_syserror(ctx, ENOMEM);
1491 rp->account = g_strdup(req[0]);
1493 if (!rp->account) {
1494 g_strfreev(req);
1495 return send_syserror(ctx, ENOMEM);
1498 if (req[1]) {
1499 n = find_elements(client->doc, n->children, req+1, &error,
1500 NULL, realpath_elements_cb, NULL, FALSE, 0, rp);
1502 if (!n) {
1503 g_free(rp->account);
1504 g_free(rp);
1505 g_strfreev(req);
1506 return send_error(ctx, error);
1510 p = xmlGetNodePath(n);
1511 result = element_path_to_req(rp->account, p);
1513 if (!result) {
1514 g_free(result);
1515 g_free(rp->account);
1516 g_free(rp);
1517 g_strfreev(req);
1518 xmlFree(p);
1519 return send_syserror(ctx, ENOMEM);
1522 string = g_string_new(result);
1523 g_free(result);
1524 g_free(rp->account);
1525 g_free(rp);
1526 g_strfreev(req);
1527 xmlFree(p);
1528 i = 0;
1530 again:
1531 for (t = string->str + i; *t; t++, i++) {
1532 if ((!i && *t != '!') || *t == '\t') {
1533 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1534 goto again;
1538 error = assuan_send_data(ctx, string->str, string->len);
1539 g_string_free(string, TRUE);
1540 return send_error(ctx, error);
1544 * This could be faster especially when finding "target" attributes.
1546 static int list_command(assuan_context_t ctx, char *line)
1548 struct client_s *client = assuan_get_pointer(ctx);
1549 gpg_error_t rc;
1550 struct element_list_s *elements = NULL;
1551 gchar *tmp;
1553 if (disable_list_and_dump == TRUE)
1554 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1556 rc = file_modified(client);
1558 if (rc) {
1559 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1560 return send_error(ctx, rc);
1563 if (!*line) {
1564 GString *str;
1566 rc = list_accounts(client->doc, &str);
1568 if (rc)
1569 return send_error(ctx, rc);
1571 rc = assuan_send_data(ctx, str->str, str->len);
1572 g_string_free(str, TRUE);
1573 return send_error(ctx, rc);
1576 elements = g_malloc0(sizeof(struct element_list_s));
1578 if (!elements) {
1579 rc = gpg_err_code_from_errno(ENOMEM);
1580 goto fail;
1583 rc = create_path_list(client->doc, elements, line);
1585 if (rc)
1586 goto fail;
1588 if (elements) {
1589 gint total = g_slist_length(elements->list);
1590 gint i;
1591 GString *str;
1593 if (!total) {
1594 rc = EPWMD_EMPTY_ELEMENT;
1595 goto fail;
1598 str = g_string_new(NULL);
1600 if (!str) {
1601 rc = gpg_err_code_from_errno(ENOMEM);
1602 goto fail;
1605 for (i = 0; i < total; i++) {
1606 tmp = g_slist_nth_data(elements->list, i);
1607 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1610 rc = assuan_send_data(ctx, str->str, str->len);
1611 g_string_free(str, TRUE);
1613 else
1614 rc = EPWMD_EMPTY_ELEMENT;
1616 fail:
1617 if (elements) {
1618 gint total = g_slist_length(elements->list);
1619 gint i;
1621 for (i = 0; i < total; i++) {
1622 tmp = g_slist_nth_data(elements->list, i);
1623 g_free(tmp);
1626 g_slist_free(elements->list);
1628 if (elements->prefix)
1629 g_free(elements->prefix);
1631 g_free(elements);
1634 return send_error(ctx, rc);
1637 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1638 const gchar *value)
1640 xmlAttrPtr a;
1642 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1643 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1645 if (!a)
1646 return EPWMD_LIBXML_ERROR;
1648 else
1649 xmlNodeSetContent(a->children, (xmlChar *)value);
1651 return 0;
1655 * req[0] - element path
1657 static int attribute_list(assuan_context_t ctx, gchar **req)
1659 struct client_s *client = assuan_get_pointer(ctx);
1660 gchar **attrlist = NULL;
1661 gint i = 0;
1662 gchar **path = NULL;
1663 xmlAttrPtr a;
1664 xmlNodePtr n, an;
1665 gchar *line;
1666 gpg_error_t error;
1668 if (!req || !req[0])
1669 return EPWMD_COMMAND_SYNTAX;
1671 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1673 * The first argument may be only an account.
1675 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1676 return EPWMD_COMMAND_SYNTAX;
1679 n = find_account(client->doc, &path, &error, NULL, 0);
1681 if (!n) {
1682 g_strfreev(path);
1683 return error;
1686 if (path[1]) {
1687 n = find_elements(client->doc, n->children, path+1, &error,
1688 NULL, NULL, NULL, FALSE, 0, NULL);
1690 if (!n) {
1691 g_strfreev(path);
1692 return error;
1696 g_strfreev(path);
1698 for (a = n->properties; a; a = a->next) {
1699 gchar **pa;
1701 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1702 if (attrlist)
1703 g_strfreev(attrlist);
1705 error = errno;
1706 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
1707 return gpg_error_from_errno(error);
1710 attrlist = pa;
1711 an = a->children;
1712 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1714 if (!attrlist[i]) {
1715 g_strfreev(attrlist);
1716 return gpg_error_from_errno(ENOMEM);
1719 attrlist[++i] = NULL;
1722 if (!attrlist)
1723 return EPWMD_EMPTY_ELEMENT;
1725 line = g_strjoinv("\n", attrlist);
1727 if (!line) {
1728 g_strfreev(attrlist);
1729 return gpg_error_from_errno(ENOMEM);
1732 error = assuan_send_data(ctx, line, strlen(line));
1733 g_free(line);
1734 g_strfreev(attrlist);
1735 return error;
1739 * req[0] - attribute
1740 * req[1] - element path
1742 static int attribute_delete(struct client_s *client, gchar **req)
1744 xmlAttrPtr a;
1745 xmlNodePtr n;
1746 gchar **path = NULL;
1747 gpg_error_t error;
1749 if (!req || !req[0] || !req[1])
1750 return EPWMD_COMMAND_SYNTAX;
1752 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1754 * The first argument may be only an account.
1756 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1757 return EPWMD_COMMAND_SYNTAX;
1761 * Don't remove the "name" attribute for the account element. To remove an
1762 * account use DELETE <account>.
1764 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1765 error = EPWMD_ATTR_SYNTAX;
1766 goto fail;
1769 n = find_account(client->doc, &path, &error, NULL, 0);
1771 if (!n)
1772 goto fail;
1774 if (path[1]) {
1775 n = find_elements(client->doc, n->children, path+1, &error,
1776 NULL, NULL, NULL, FALSE, 0, NULL);
1778 if (!n)
1779 goto fail;
1782 g_strfreev(path);
1784 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1785 return EPWMD_ATTR_NOT_FOUND;
1787 if (xmlRemoveProp(a) == -1)
1788 return EPWMD_LIBXML_ERROR;
1790 return 0;
1792 fail:
1793 g_strfreev(path);
1794 return error;
1798 * Creates a "target" attribute. When other commands encounter an element with
1799 * this attribute, the element path is modified to the target value. If the
1800 * source element path doesn't exist when using 'ATTR SET target', it is
1801 * created, but the destination element path must exist.
1803 * req[0] - source element path
1804 * req[1] - destination element path
1806 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1808 gchar **src, **dst, *line = NULL;
1809 gpg_error_t error;
1810 xmlNodePtr n;
1811 gchar **src_orig = NULL;
1813 if (!req || !req[0] || !req[1])
1814 return EPWMD_COMMAND_SYNTAX;
1816 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1818 * The first argument may be only an account.
1820 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1821 return EPWMD_COMMAND_SYNTAX;
1824 if (valid_element_path(src, FALSE) == FALSE) {
1825 g_strfreev(src);
1826 return EPWMD_INVALID_ELEMENT;
1829 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1831 * The first argument may be only an account.
1833 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1834 error = EPWMD_COMMAND_SYNTAX;
1835 goto fail;
1839 n = find_account(client->doc, &dst, &error, NULL, 0);
1842 * Make sure the destination element path exists.
1844 if (!n)
1845 goto fail;
1847 if (dst[1]) {
1848 n = find_elements(client->doc, n->children, dst+1, &error,
1849 NULL, NULL, NULL, FALSE, 0, NULL);
1851 if (!n)
1852 goto fail;
1855 again:
1856 src_orig = g_strdupv(src);
1857 n = find_account(client->doc, &src, &error, NULL, 0);
1859 if (!n) {
1860 if (error == EPWMD_ELEMENT_NOT_FOUND) {
1861 error = new_account(client->doc, src[0]);
1863 if (error)
1864 goto fail;
1866 goto again;
1868 else
1869 goto fail;
1872 if (src[1]) {
1873 if (!n->children)
1874 n = create_target_elements_cb(n, src+1, &error, NULL);
1875 else
1876 n = find_elements(client->doc, n->children, src+1, &error,
1877 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1879 if (!n)
1880 goto fail;
1883 * Reset the position of the element tree now that the elements
1884 * have been created.
1886 g_strfreev(src);
1887 src = src_orig;
1888 src_orig = NULL;
1889 n = find_account(client->doc, &src, &error, NULL, 0);
1891 if (!n)
1892 goto fail;
1894 n = find_elements(client->doc, n->children, src+1, &error,
1895 NULL, NULL, NULL, FALSE, 0, NULL);
1897 if (!n)
1898 goto fail;
1901 line = g_strjoinv("\t", dst);
1902 error = add_attribute(n, "target", line);
1904 fail:
1905 g_free(line);
1906 g_strfreev(src);
1907 g_strfreev(dst);
1908 g_strfreev(src_orig);
1909 return error;
1913 * req[0] - account name
1914 * req[1] - new name
1916 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1918 gpg_error_t error;
1919 gchar **tmp;
1920 xmlNodePtr n;
1922 tmp = g_strdupv(req);
1924 if (!tmp)
1925 return gpg_error_from_errno(ENOMEM);
1927 n = find_account(client->doc, &tmp, &error, NULL, 0);
1928 g_strfreev(tmp);
1930 if (!n)
1931 return error;
1933 if (g_utf8_collate(req[0], req[1]) == 0)
1934 return 0;
1937 * Will not overwrite an existing account.
1939 tmp = g_strdupv(req+1);
1941 if (!tmp)
1942 return gpg_error_from_errno(ENOMEM);
1944 n = find_account(client->doc, &tmp, &error, NULL, 0);
1945 g_strfreev(tmp);
1947 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1948 return error;
1950 if (n)
1951 return EPWMD_ACCOUNT_EXISTS;
1954 * Whitespace not allowed in account names.
1956 if (contains_whitespace(req[1]) == TRUE)
1957 return EPWMD_ATTR_SYNTAX;
1959 tmp = g_strdupv(req);
1961 if (!tmp)
1962 return gpg_error_from_errno(ENOMEM);
1964 n = find_account(client->doc, &tmp, &error, NULL, 0);
1965 g_strfreev(tmp);
1967 if (!n)
1968 return EPWMD_ELEMENT_NOT_FOUND;
1970 return add_attribute(n, "name", req[1]);
1974 * req[0] - attribute
1975 * req[1] - element path
1977 static int attribute_get(assuan_context_t ctx, gchar **req)
1979 struct client_s *client = assuan_get_pointer(ctx);
1980 xmlNodePtr n;
1981 xmlChar *a;
1982 gchar **path= NULL;
1983 gpg_error_t error;
1985 if (!req || !req[0] || !req[1])
1986 return EPWMD_COMMAND_SYNTAX;
1988 if (strchr(req[1], '\t')) {
1989 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1990 return EPWMD_COMMAND_SYNTAX;
1992 else {
1993 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1994 return EPWMD_COMMAND_SYNTAX;
1997 n = find_account(client->doc, &path, &error, NULL, 0);
1999 if (!n)
2000 goto fail;
2002 if (path[1]) {
2003 n = find_elements(client->doc, n->children, path+1, &error,
2004 NULL, NULL, NULL, FALSE, 0, NULL);
2006 if (!n)
2007 goto fail;
2010 g_strfreev(path);
2012 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2013 return EPWMD_ATTR_NOT_FOUND;
2015 error = assuan_send_data(ctx, a, xmlStrlen(a));
2016 xmlFree(a);
2017 return error;
2019 fail:
2020 g_strfreev(path);
2021 return error;
2025 * req[0] - attribute
2026 * req[1] - element path
2027 * req[2] - value
2029 static int attribute_set(struct client_s *client, gchar **req)
2031 gchar **path = NULL;
2032 gpg_error_t error;
2033 xmlNodePtr n;
2035 if (!req || !req[0] || !req[1] || !req[2])
2036 return EPWMD_COMMAND_SYNTAX;
2039 * Reserved attribute names.
2041 if (g_utf8_collate(req[0], "name") == 0) {
2043 * Only reserved for the account element. Not the rest of the
2044 * document.
2046 if (strchr(req[1], '\t') == NULL)
2047 return name_attribute(client, req + 1);
2049 else if (g_utf8_collate(req[0], "target") == 0)
2050 return target_attribute(client, req + 1);
2052 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2054 * The first argument may be only an account.
2056 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2057 return EPWMD_COMMAND_SYNTAX;
2060 n = find_account(client->doc, &path, &error, NULL, 0);
2062 if (!n)
2063 goto fail;
2065 if (path[1]) {
2066 n = find_elements(client->doc, n->children, path+1, &error,
2067 NULL, NULL, NULL, FALSE, 0, NULL);
2069 if (!n)
2070 goto fail;
2073 g_strfreev(path);
2074 return add_attribute(n, req[0], req[2]);
2076 fail:
2077 g_strfreev(path);
2078 return error;
2082 * req[0] - command
2083 * req[1] - attribute name or element path if command is LIST
2084 * req[2] - element path
2085 * req[2] - element path or value
2087 static int attr_command(assuan_context_t ctx, char *line)
2089 struct client_s *client = assuan_get_pointer(ctx);
2090 gchar **req = split_input_line(line, " ", 4);
2091 gpg_error_t error = 0;
2093 error = file_modified(client);
2095 if (error) {
2096 log_write("%s: %s", client->filename ? client->filename : "",
2097 pwmd_strerror(error));
2098 g_strfreev(req);
2099 return send_error(ctx, error);
2102 if (!req || !req[0] || !req[1]) {
2103 g_strfreev(req);
2104 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2107 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2108 error = attribute_set(client, req+1);
2109 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2110 error = attribute_get(ctx, req+1);
2111 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2112 error = attribute_delete(client, req+1);
2113 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2114 error = attribute_list(ctx, req+1);
2115 else
2116 error = EPWMD_COMMAND_SYNTAX;
2118 g_strfreev(req);
2119 return send_error(ctx, error);
2122 static int iscached_command(assuan_context_t ctx, char *line)
2124 gchar **req = split_input_line(line, " ", 0);
2125 guchar md5file[16];
2127 if (!req || !*req) {
2128 g_strfreev(req);
2129 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2132 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2133 g_strfreev(req);
2134 CACHE_LOCK(ctx);
2136 if (cache_iscached(md5file) == FALSE) {
2137 CACHE_UNLOCK;
2138 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2141 CACHE_UNLOCK;
2142 return send_error(ctx, 0);
2145 gpg_error_t send_cache_status(assuan_context_t ctx)
2147 gchar *tmp;
2148 struct client_s *client = assuan_get_pointer(ctx);
2150 CACHE_LOCK(client->ctx);
2151 tmp = print_fmt("%i %i",
2152 cache_file_count(),
2153 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2154 CACHE_UNLOCK;
2156 return assuan_write_status(ctx, "CACHE", tmp);
2159 static int clearcache_command(assuan_context_t ctx, char *line)
2161 struct client_s *client = assuan_get_pointer(ctx);
2162 gchar **req = split_input_line(line, " ", 0);
2163 guchar md5file[16];
2165 CACHE_LOCK(ctx);
2167 if (!req || !*req) {
2168 g_strfreev(req);
2169 cache_clear(client->md5file, 2);
2170 CACHE_UNLOCK;
2171 return send_error(ctx, 0);
2174 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2175 g_strfreev(req);
2177 if (cache_clear(md5file, 1) == FALSE) {
2178 CACHE_UNLOCK;
2179 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2182 CACHE_UNLOCK;
2183 return send_error(ctx, 0);
2186 static int cachetimeout_command(assuan_context_t ctx, char *line)
2188 guchar md5file[16];
2189 glong timeout;
2190 gchar **req = split_input_line(line, " ", 0);
2191 gchar *p;
2192 struct client_s *client = assuan_get_pointer(ctx);
2194 if (!req || !*req || !req[1]) {
2195 g_strfreev(req);
2196 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2199 errno = 0;
2200 timeout = strtol(req[0], &p, 10);
2202 if (errno != 0 || *p != 0) {
2203 g_strfreev(req);
2204 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2207 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2208 g_strfreev(req);
2209 CACHE_LOCK(client->ctx);
2211 if (cache_set_timeout(md5file, timeout) == FALSE) {
2212 CACHE_UNLOCK;
2213 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2216 CACHE_UNLOCK;
2217 return send_error(ctx, 0);
2220 static int dump_command(assuan_context_t ctx, char *line)
2222 xmlChar *xml;
2223 gssize len;
2224 struct client_s *client = assuan_get_pointer(ctx);
2225 gpg_error_t error;
2227 if (disable_list_and_dump == TRUE)
2228 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2230 error = file_modified(client);
2232 if (error) {
2233 log_write("%s: %s", client->filename ? client->filename : "",
2234 pwmd_strerror(error));
2235 return send_error(ctx, error);
2238 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2239 error = assuan_send_data(ctx, xml, len);
2240 xmlFree(xml);
2241 return send_error(ctx, error);
2244 static int getconfig_command(assuan_context_t ctx, gchar *line)
2246 struct client_s *client = assuan_get_pointer(ctx);
2247 gpg_error_t error = 0;
2248 gchar *p, *tmp;
2250 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2251 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2253 p = get_key_file_string(client->filename ? client->filename : "global", line);
2255 if (!p)
2256 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2258 tmp = expand_homedir(p);
2259 g_free(p);
2260 p = tmp;
2261 error = assuan_send_data(ctx, p, strlen(p));
2262 g_free(p);
2263 return send_error(ctx, error);
2266 void cleanup_assuan(assuan_context_t ctx)
2268 struct client_s *cl = assuan_get_pointer(ctx);
2270 cleanup_client(cl);
2273 static void reset_notify(assuan_context_t ctx)
2275 struct client_s *cl = assuan_get_pointer(ctx);
2277 cleanup_client(cl);
2280 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2282 gchar name[32] = {0}, value[256] = {0};
2283 pth_attr_t attr = pth_attr_of(pth_self());
2285 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2286 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2288 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2289 log_write("OPTION CLIENT %s", line);
2290 pth_attr_set(attr, PTH_ATTR_NAME, value);
2292 else
2293 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2295 return 0;
2298 static int option_handler(assuan_context_t ctx, const gchar *name,
2299 const gchar *value)
2301 #ifdef WITH_PINENTRY
2302 struct client_s *client = assuan_get_pointer(ctx);
2303 #endif
2305 if (!value || !*value)
2306 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2308 if (g_strcasecmp(name, (gchar *)"client") == 0)
2309 return parse_client_option(ctx, value);
2311 #ifdef WITH_PINENTRY
2312 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2313 g_free(client->pinentry->ttyname);
2314 client->pinentry->ttyname = g_strdup(value);
2316 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2317 g_free(client->pinentry->ttytype);
2318 client->pinentry->ttytype = g_strdup(value);
2320 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2321 g_free(client->pinentry->display);
2322 client->pinentry->display = g_strdup(value);
2324 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2325 g_free(client->pinentry->path);
2326 client->pinentry->path = g_strdup(value);
2328 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2329 g_free(client->pinentry->title);
2330 client->pinentry->title = g_strdup(value);
2332 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2333 g_free(client->pinentry->prompt);
2334 client->pinentry->prompt = g_strdup(value);
2336 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2337 g_free(client->pinentry->desc);
2338 client->pinentry->desc = g_strdup(value);
2340 #if 0
2341 /* Need to wait for pinentry to support a --timeout option so it can
2342 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2343 * execv() which replaces the pid of the fork()ed thread from
2344 * pinentry_fork(). So pinentry will become a real process after the
2345 * thread terminates and won't be able to be kill()ed from pwmd.
2347 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2348 gchar *p = NULL;
2349 gint n = strtol(value, &p, 10);
2351 if (*p || n < 0)
2352 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2354 client->pinentry->timeout = n;
2356 #endif
2357 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2358 gchar *p = NULL;
2359 gint n = strtol(value, &p, 10);
2361 if (*p || n < 0 || n > 1)
2362 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2364 g_key_file_set_boolean(keyfileh, client->filename ? client->filename : "global",
2365 "enable_pinentry", n == 0 ? FALSE : TRUE);
2367 else
2368 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2369 #else
2370 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2371 #endif
2373 log_write("OPTION %s=%s", name, value);
2374 return 0;
2377 gpg_error_t register_commands(assuan_context_t ctx)
2379 static struct {
2380 const char *name;
2381 int (*handler)(assuan_context_t, char *line);
2382 } table[] = {
2383 { "OPEN", open_command },
2384 { "SAVE", save_command },
2385 { "LIST", list_command },
2386 { "REALPATH", realpath_command },
2387 { "STORE", store_command },
2388 { "DELETE", delete_command },
2389 { "GET", get_command },
2390 { "ATTR", attr_command },
2391 { "ISCACHED", iscached_command },
2392 { "CLEARCACHE", clearcache_command },
2393 { "CACHETIMEOUT", cachetimeout_command },
2394 { "GETCONFIG", getconfig_command },
2395 { "DUMP", dump_command },
2396 { "INPUT", NULL },
2397 { "OUTPUT", NULL },
2398 { NULL, NULL }
2400 int i, rc;
2402 for (i=0; table[i].name; i++) {
2403 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2405 if (rc)
2406 return rc;
2409 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2410 if (rc)
2411 return rc;
2413 rc = assuan_register_option_handler(ctx, option_handler);
2414 if (rc)
2415 return rc;
2417 return assuan_register_reset_notify(ctx, reset_notify);
2420 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2421 guchar *key)
2423 guchar *iv;
2424 void *inbuf;
2425 gsize insize, len;
2426 guchar tkey[gcrykeysize];
2427 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2428 gcry_cipher_hd_t gh;
2429 guint iter = 0, n_iter = 0;
2430 gint iter_progress;
2431 void *outbuf = NULL;
2432 gint zerror = 0;
2433 glong outsize = 0;
2434 gpg_error_t error;
2435 file_header_t file_header;
2437 if (!ctx) {
2438 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2440 if (error)
2441 return error;
2443 else
2444 gh = client->gh;
2446 lseek(fd, 0, SEEK_SET);
2447 insize = st.st_size - sizeof(file_header_t);
2448 iv = gcry_malloc(gcryblocksize);
2450 if (!iv) {
2451 if (!ctx)
2452 gcry_cipher_close(gh);
2454 return gpg_error_from_errno(ENOMEM);
2457 len = pth_read(fd, &file_header, sizeof(file_header_t));
2459 if (len != sizeof(file_header_t)) {
2460 len = errno;
2462 if (!ctx)
2463 gcry_cipher_close(gh);
2465 gcry_free(iv);
2466 errno = len;
2467 return gpg_error_from_errno(errno);
2470 /* No encryption iterations. This is a plain (gzipped) file. */
2471 if (file_header.iter == -1) {
2473 * cache_file_count() needs both .used == TRUE and a valid key in
2474 * order for it to count as a used cache entry. Fixes CACHE status
2475 * messages.
2477 memset(key, '!', gcrykeysize);
2478 insize = st.st_size - sizeof(file_header_t);
2481 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2482 inbuf = gcry_malloc(insize);
2484 if (!inbuf) {
2485 if (!ctx)
2486 gcry_cipher_close(gh);
2488 gcry_free(iv);
2489 return gpg_error_from_errno(ENOMEM);
2492 len = pth_read(fd, inbuf, insize);
2494 if (len != insize) {
2495 len = errno;
2497 if (!ctx)
2498 gcry_cipher_close(gh);
2500 gcry_free(iv);
2501 errno = len;
2502 return gpg_error_from_errno(errno);
2505 if (file_header.iter == -1)
2506 goto decompress;
2508 memcpy(tkey, key, sizeof(tkey));
2509 tkey[0] ^= 1;
2511 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2512 if (!ctx) {
2513 gcry_cipher_close(gh);
2514 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2516 else
2517 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2519 gcry_free(inbuf);
2520 gcry_free(iv);
2521 return error;
2524 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2525 if (!ctx) {
2526 gcry_cipher_close(gh);
2527 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2529 else
2530 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2532 gcry_free(inbuf);
2533 gcry_free(iv);
2535 if (!ctx)
2536 gcry_cipher_close(gh);
2538 return error;
2541 iter_progress = get_key_file_integer("global", "iteration_progress");
2543 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2544 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2546 if (error) {
2547 gcry_free(inbuf);
2548 gcry_free(iv);
2549 return error;
2553 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2555 if (error) {
2556 gcry_free(inbuf);
2557 gcry_free(iv);
2558 return error;
2561 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2562 if (!ctx) {
2563 gcry_cipher_close(gh);
2564 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2566 else
2567 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2569 gcry_free(inbuf);
2570 gcry_free(iv);
2571 return error;
2574 while (iter < file_header.iter) {
2575 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2576 if (!(iter % iter_progress)) {
2577 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i",
2578 ++n_iter * iter_progress));
2580 if (error) {
2581 gcry_free(inbuf);
2582 gcry_free(iv);
2583 return error;
2588 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2589 if (!ctx) {
2590 gcry_cipher_close(gh);
2591 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2593 else
2594 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2596 gcry_free(inbuf);
2597 gcry_free(iv);
2598 return error;
2601 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2603 if (error) {
2604 if (!ctx) {
2605 gcry_cipher_close(gh);
2606 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2608 else
2609 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2611 gcry_free(inbuf);
2612 gcry_free(iv);
2613 return error;
2616 iter++;
2617 pth_yield(NULL);
2620 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2621 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i", file_header.iter));
2623 if (error) {
2624 gcry_free(inbuf);
2625 gcry_free(iv);
2626 return error;
2630 gcry_free(iv);
2632 decompress:
2633 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2635 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2637 if (zerror == Z_MEM_ERROR) {
2638 gcry_free(inbuf);
2639 return gpg_error_from_errno(ENOMEM);
2641 else if (zerror != Z_DATA_ERROR) {
2642 gcry_free(inbuf);
2644 if (!ctx)
2645 gcry_cipher_close(gh);
2647 return EPWMD_BADKEY;
2650 else {
2651 gcry_free(inbuf);
2652 inbuf = outbuf;
2653 insize = outsize;
2656 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2657 gcry_free(inbuf);
2659 if (!ctx)
2660 gcry_cipher_close(gh);
2662 return EPWMD_BADKEY;
2665 if (ctx) {
2666 client->xml = inbuf;
2667 client->len = insize;
2669 else {
2670 gcry_cipher_close(gh);
2671 gcry_free(inbuf);
2674 return 0;
2678 * This is called after every Assuan command.
2680 void command_finalize(assuan_context_t ctx, gint error)
2682 struct client_s *client = assuan_get_pointer(ctx);
2684 unlock_file_mutex(client);