Don't call assuan_process_done() in client_thread() again after the
[pwmd.git] / src / commands.c
blobe39cb05dc3bad265b844d5e869ebc40f7f4e1875
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 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"
43 #include "pinentry.h"
44 #include "pwmd_error.h"
45 #include "cache.h"
46 #include "commands.h"
48 static void *z_alloc(void *data, unsigned items, unsigned size)
50 #ifndef MEM_DEBUG
51 return gcry_calloc(items, size);
52 #else
53 return calloc(items, size);
54 #endif
57 static void z_free(void *data, void *p)
59 #ifndef MEM_DEBUG
60 gcry_free(p);
61 #else
62 free(p);
63 #endif
66 static gpg_error_t file_modified(struct client_s *client)
68 struct stat st;
70 if (client->state != STATE_OPEN)
71 return EPWMD_NO_FILE;
73 if (stat(client->filename, &st) == 0 && client->mtime) {
74 if (client->mtime != st.st_mtime)
75 return EPWMD_FILE_MODIFIED;
78 return 0;
81 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
82 void *inbuf, gsize insize)
84 gpg_error_t rc;
86 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
87 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
88 return FALSE;
91 return TRUE;
94 gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
95 void *inbuf, gsize insize)
97 gpg_error_t rc;
99 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
100 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
102 return rc;
105 static gpg_error_t parse_xml(assuan_context_t ctx)
107 struct client_s *client = assuan_get_pointer(ctx);
109 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
111 if (!client->doc)
112 return EPWMD_LIBXML_ERROR;
114 return 0;
117 gboolean valid_filename(const gchar *filename)
119 const gchar *p;
121 if (!filename || !*filename)
122 return FALSE;
124 for (p = filename; *p; p++) {
125 if (g_ascii_isalnum(*p) == FALSE && *p != '-' && *p != '_' && *p != '.')
126 return FALSE;
129 return TRUE;
132 gint open_file(const gchar *filename, struct stat *st)
134 gint fd;
136 if ((fd = open(filename, O_RDONLY)) == -1)
137 return -1;
139 if (stat(filename, st) == -1) {
140 close(fd);
141 return -1;
144 return fd;
147 void unlock_file_mutex(struct client_s *client)
149 pth_mutex_t *m;
151 if (client->has_lock == FALSE || client->pinentry->status == PINENTRY_INIT)
152 return;
154 CACHE_LOCK(client->ctx);
156 if (cache_get_mutex(client->md5file, &m) == FALSE) {
157 CACHE_UNLOCK;
158 return;
161 CACHE_UNLOCK;
162 pth_mutex_release(m);
163 client->has_lock = FALSE;
166 gpg_error_t lock_file_mutex(struct client_s *client)
168 pth_mutex_t *m;
170 if (client->has_lock == TRUE)
171 return 0;
173 CACHE_LOCK(client->ctx);
175 if (cache_get_mutex(client->md5file, &m) == FALSE) {
176 CACHE_UNLOCK;
177 return 0;
180 CACHE_UNLOCK;
182 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
183 if (errno == EBUSY) {
184 if (client->ctx)
185 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
187 pth_mutex_acquire(m, FALSE, NULL);
189 else {
190 gint e = errno;
191 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
192 return gpg_error_from_errno(e);
196 client->has_lock = TRUE;
197 return 0;
200 void free_client(struct client_s *client)
202 if (client->doc)
203 xmlFreeDoc(client->doc);
205 if (client->xml)
206 gcry_free(client->xml);
208 if (client->filename)
209 g_free(client->filename);
211 if (client->gh)
212 gcry_cipher_close(client->gh);
215 static void cleanup_client(struct client_s *client)
217 assuan_context_t ctx = client->ctx;
218 struct pinentry_s *pin = client->pinentry;
220 unlock_file_mutex(client);
221 CACHE_LOCK(client->ctx);
222 cache_decr_refcount(client->md5file);
225 * This may be a new file so don't use a cache slot. save_command() will
226 * set this to FALSE on success.
228 if (client->new == TRUE)
229 cache_clear(client->md5file, 1);
231 free_client(client);
232 memset(client, 0, sizeof(struct client_s));
233 client->state = STATE_CONNECTED;
234 client->ctx = ctx;
235 client->freed = TRUE;
236 client->pinentry = pin;
237 CACHE_UNLOCK;
240 static gchar *print_fmt(const char *fmt, ...)
242 va_list ap;
243 static gchar buf[ASSUAN_LINELENGTH] = {0};
245 va_start(ap, fmt);
246 vsnprintf(buf, sizeof(buf), fmt, ap);
247 va_end(ap);
248 return buf;
251 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
252 gpointer *out, glong *outsize, gint *error)
254 z_stream z;
255 gint ret;
256 gpointer pout;
257 gz_header h;
258 gchar buf[17];
259 gpg_error_t rc;
261 z.zalloc = z_alloc;
262 z.zfree = z_free;
263 z.next_in = in;
264 z.avail_in = insize;
265 z.avail_out = zlib_bufsize;
266 z.next_out = pout = g_malloc(zlib_bufsize);
268 if (!pout) {
269 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
270 *error = Z_MEM_ERROR;
271 return FALSE;
274 ret = inflateInit2(&z, 47);
276 if (ret != Z_OK) {
277 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
278 g_free(pout);
279 return FALSE;
282 memset(&h, 0, sizeof(gz_header));
283 h.comment = (guchar *)buf;
284 h.comm_max = sizeof(buf);
285 ret = inflateGetHeader(&z, &h);
287 if (ret != Z_OK) {
288 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
289 g_free(pout);
290 inflateEnd(&z);
291 return FALSE;
294 ret = inflate(&z, Z_BLOCK);
296 if (ret != Z_OK) {
297 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
298 g_free(pout);
299 inflateEnd(&z);
300 return FALSE;
303 if (h.comment)
304 insize = atoi((gchar *)h.comment);
306 do {
307 gpointer p;
309 ret = inflate(&z, Z_FINISH);
311 switch (ret) {
312 case Z_OK:
313 break;
314 case Z_BUF_ERROR:
315 if (!z.avail_out) {
316 p = g_realloc(pout, z.total_out + zlib_bufsize);
318 if (!p) {
319 ret = Z_MEM_ERROR;
320 goto fail;
323 pout = p;
324 z.next_out = pout + z.total_out;
325 z.avail_out = zlib_bufsize;
327 if (ctx) {
328 rc = assuan_write_status(ctx, "DECOMPRESS",
329 print_fmt("%i %i", z.total_out, insize));
331 if (rc) {
332 ret = rc;
333 goto fail;
337 break;
338 case Z_STREAM_END:
339 break;
340 default:
341 goto fail;
342 break;
345 pth_yield(NULL);
346 } while (ret != Z_STREAM_END);
348 if (ctx) {
349 rc = assuan_write_status(ctx, "DECOMPRESS",
350 print_fmt("%i %i", z.total_out, insize));
352 if (rc) {
353 ret = rc;
354 goto fail;
358 *out = pout;
359 *outsize = z.total_out;
360 inflateEnd(&z);
361 return TRUE;
363 fail:
364 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
365 *error = ret;
366 g_free(pout);
367 inflateEnd(&z);
368 return FALSE;
371 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
372 gboolean cached)
374 struct client_s *client = assuan_get_pointer(ctx);
375 gpg_error_t error;
376 struct stat st;
377 gint fd;
378 gint timeout;
380 if ((fd = open_file(client->filename, &st)) == -1) {
381 /* New file. */
382 if (errno == ENOENT) {
383 if (shakey[0])
384 goto update_cache;
386 goto done;
389 error = errno;
390 log_write("%s: %s", client->filename, strerror(errno));
391 cleanup_client(client);
392 memset(shakey, 0, sizeof(shakey));
393 return send_syserror(ctx, error);
396 error = try_xml_decrypt(ctx, fd, st, shakey);
397 close(fd);
399 if (error) {
400 memset(shakey, 0, sizeof(shakey));
401 cleanup_client(client);
402 return send_error(ctx, error);
405 update_cache:
406 CACHE_LOCK(client->ctx);
408 if (cached == FALSE && shakey[0]) {
409 if (cache_update_key(client->md5file, shakey) == FALSE) {
410 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
411 cleanup_client(client);
412 CACHE_UNLOCK;
413 return send_error(ctx, EPWMD_MAX_SLOTS);
416 timeout = get_key_file_integer(client->filename, "cache_timeout");
417 cache_reset_timeout(client->md5file, timeout);
419 else
420 cache_set_timeout(client->md5file, -2);
422 CACHE_UNLOCK;
424 done:
425 memset(shakey, 0, sizeof(shakey));
426 error = parse_xml(ctx);
428 if (client->xml) {
429 gcry_free(client->xml);
430 client->xml = NULL;
433 if (!error) {
434 if (client->new == FALSE)
435 send_cache_status_all();
437 client->state = STATE_OPEN;
440 return send_error(ctx, error);
443 static int open_command(assuan_context_t ctx, char *line)
445 struct stat st;
446 guchar shakey[gcrykeysize];
447 gboolean cached = FALSE;
448 gpg_error_t error;
449 struct client_s *client = assuan_get_pointer(ctx);
450 gchar **req;
451 gchar *filename = NULL;
453 if ((req = split_input_line(line, " ", 2)) != NULL)
454 filename = req[0];
456 if (!filename || !*filename) {
457 g_strfreev(req);
458 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
461 if (valid_filename(filename) == FALSE) {
462 g_strfreev(req);
463 return send_error(ctx, EPWMD_INVALID_FILENAME);
466 if (client->state == STATE_OPEN)
467 cleanup_client(client);
469 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
470 CACHE_LOCK(client->ctx);
472 if (cache_has_file(client->md5file) == FALSE) {
473 if (cache_add_file(client->md5file, NULL) == FALSE) {
474 g_strfreev(req);
475 CACHE_UNLOCK;
476 return send_error(ctx, EPWMD_MAX_SLOTS);
480 cache_incr_refcount(client->md5file);
481 CACHE_UNLOCK;
482 error = lock_file_mutex(client);
484 if (error) {
485 g_strfreev(req);
486 return send_error(ctx, error);
489 client->freed = FALSE;
491 if ((error = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
492 g_strfreev(req);
493 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
494 cleanup_client(client);
495 return send_error(ctx, error);
498 if (stat(filename, &st) == 0) {
499 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
500 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
501 g_strfreev(req);
502 cleanup_client(client);
503 return send_error(ctx, EPWMD_INVALID_FILENAME);
506 client->mtime = st.st_mtime;
509 client->filename = g_strdup(filename);
511 if (!client->filename) {
512 memset(shakey, 0, sizeof(shakey));
513 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
514 cleanup_client(client);
515 g_strfreev(req);
516 return send_syserror(ctx, ENOMEM);
520 * New files don't need a key.
522 if (access(filename, R_OK|W_OK) != 0) {
523 if (errno != ENOENT) {
524 error = errno;
525 log_write("%s: %s", filename, strerror(errno));
526 g_strfreev(req);
527 cleanup_client(client);
528 return send_syserror(ctx, error);
531 if ((client->xml = new_document()) == NULL) {
532 log_write("%s", strerror(ENOMEM));
533 g_strfreev(req);
534 cleanup_client(client);
535 return send_syserror(ctx, ENOMEM);
538 client->len = xmlStrlen(client->xml);
539 client->new = TRUE;
540 client->filename = g_strdup(filename);
542 if (!client->filename) {
543 g_strfreev(req);
544 cleanup_client(client);
545 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
546 return send_syserror(ctx, ENOMEM);
549 memset(shakey, 0, sizeof(shakey));
551 if (req[1] && *req[1])
552 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
554 g_strfreev(req);
555 return open_command_finalize(ctx, shakey, cached);
558 CACHE_LOCK(client->ctx);
559 cached = cache_get_key(client->md5file, shakey);
560 CACHE_UNLOCK;
562 if (cached == FALSE) {
564 * No key specified and no matching filename found in the cache. Use
565 * pinentry to retrieve the key. Cannot return assuan_process_done()
566 * here otherwise the command will be interrupted. The event loop in
567 * client_thread() will poll the file descriptor waiting for it to
568 * become ready to read a pinentry_key_s which will contain the
569 * entered key or error. It will then call open_command_finalize() to
570 * to finish the command.
572 if (!req[1] || !*req[1]) {
573 g_strfreev(req);
574 #ifdef WITH_PINENTRY
575 if (client->pinentry->use == FALSE) {
576 cleanup_client(client);
577 return send_error(ctx, EPWMD_KEY);
580 client->pinentry->filename = client->filename;
581 client->pinentry->which = PINENTRY_OPEN;
582 error = pinentry_fork(ctx);
584 if (error) {
585 cleanup_client(client);
586 return send_error(ctx, error);
589 client->pinentry->cb = open_command_finalize;
590 client->pinentry->status = PINENTRY_INIT;
591 return 0;
592 #else
593 cleanup_client(client);
594 return send_error(ctx, EPWMD_KEY);
595 #endif
598 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
601 g_strfreev(req);
602 return open_command_finalize(ctx, shakey, cached);
605 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
606 gint size, gpointer *out, glong *outsize, gint *error)
608 z_stream z;
609 gpointer pout, pin;
610 gint ret;
611 gz_header h;
612 gchar buf[17];
613 gint cmd = Z_NO_FLUSH;
614 gpg_error_t rc;
616 z.zalloc = z_alloc;
617 z.zfree = z_free;
618 z.next_in = pin = data;
619 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
620 z.avail_out = zlib_bufsize;
621 z.next_out = pout = g_malloc(zlib_bufsize);
623 if (!pout) {
624 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
625 *error = Z_MEM_ERROR;
626 return FALSE;
629 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
631 if (ret != Z_OK) {
632 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
633 *error = ret;
634 g_free(pout);
635 return FALSE;
638 memset(&h, 0, sizeof(gz_header));
639 snprintf(buf, sizeof(buf), "%i", size);
640 h.comment = (guchar *)buf;
641 ret = deflateSetHeader(&z, &h);
643 if (ret != Z_OK) {
644 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
645 *error = ret;
646 g_free(pout);
647 deflateEnd(&z);
648 return FALSE;
651 do {
652 gpointer p;
654 ret = deflate(&z, cmd);
656 switch (ret) {
657 case Z_OK:
658 break;
659 case Z_BUF_ERROR:
660 if (!z.avail_out) {
661 p = g_realloc(pout, z.total_out + zlib_bufsize);
663 if (!p) {
664 ret = Z_MEM_ERROR;
665 goto fail;
668 pout = p;
669 z.next_out = pout + z.total_out;
670 z.avail_out = zlib_bufsize;
673 if (!z.avail_in && z.total_in < size) {
674 if (z.total_in + zlib_bufsize > size)
675 z.avail_in = size - z.total_in;
676 else
677 z.avail_in = zlib_bufsize;
679 if (ctx) {
680 rc = assuan_write_status(ctx, "COMPRESS",
681 print_fmt("%i %i", z.total_in, size));
683 if (rc) {
684 ret = rc;
685 goto fail;
690 if (z.total_in >= size)
691 cmd = Z_FINISH;
693 break;
694 case Z_STREAM_END:
695 break;
696 default:
697 goto fail;
700 pth_yield(NULL);
701 } while (ret != Z_STREAM_END);
703 if (ctx) {
704 rc = assuan_write_status(ctx, "COMPRESS",
705 print_fmt("%i %i", z.total_in, size));
707 if (rc) {
708 ret = rc;
709 goto fail;
713 *out = pout;
714 *outsize = z.total_out;
715 deflateEnd(&z);
716 return TRUE;
718 fail:
719 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
720 *error = ret;
721 g_free(pout);
722 deflateEnd(&z);
723 return FALSE;
726 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
727 const gchar *filename, gpointer data, size_t insize,
728 const guchar *shakey, guint iter)
730 gsize len = insize;
731 gint fd;
732 gpointer inbuf;
733 guchar tkey[gcrykeysize];
734 gchar *p;
735 gint error;
736 gpg_error_t rc;
737 guint iter_progress = 0, n_iter = 0, xiter = 0;
738 gchar tmp[FILENAME_MAX];
739 struct file_header_s {
740 guint iter;
741 guchar iv[gcryblocksize];
742 } file_header;
744 if (iter == -1) {
745 inbuf = data;
746 file_header.iter = iter;
747 goto write_file;
750 if (insize / gcryblocksize) {
751 len = (insize / gcryblocksize) * gcryblocksize;
753 if (insize % gcryblocksize)
754 len += gcryblocksize;
758 * Resize the existing xml buffer to the block size required by gcrypt
759 * rather than duplicating it and wasting memory.
761 inbuf = gcry_realloc(data, len);
763 if (!inbuf)
764 return gpg_error_from_errno(ENOMEM);
766 insize = len;
767 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
768 memcpy(tkey, shakey, sizeof(tkey));
769 tkey[0] ^= 1;
771 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
772 gcry_free(inbuf);
773 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
774 return rc;
777 file_header.iter = iter;
779 if (client)
780 iter_progress = get_key_file_integer("default", "iteration_progress");
782 if (client && iter_progress && file_header.iter >= iter_progress) {
783 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
785 if (error) {
786 gcry_free(inbuf);
787 return error;
791 while (xiter < file_header.iter) {
792 if (client && iter_progress > 0 && xiter >= iter_progress) {
793 if (!(xiter % iter_progress)) {
794 error = assuan_write_status(client->ctx, "ENCRYPT", print_fmt("%i",
795 ++n_iter * iter_progress));
797 if (error) {
798 gcry_free(inbuf);
799 return error;
804 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
805 sizeof(file_header.iv)))) {
806 gcry_free(inbuf);
807 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
808 return rc;
811 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
812 == FALSE) {
813 gcry_free(inbuf);
814 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
815 return rc;
818 xiter++;
819 pth_yield(NULL);
822 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
823 sizeof(file_header.iv)))) {
824 gcry_free(inbuf);
825 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
826 return rc;
829 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
830 gcry_free(inbuf);
831 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
832 return rc;
835 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
836 gcry_free(inbuf);
837 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
838 return rc;
841 if (client && iter_progress && file_header.iter >= iter_progress) {
842 error = assuan_write_status(client->ctx, "ENCRYPT",
843 print_fmt("%i", file_header.iter));
845 if (error) {
846 gcry_free(inbuf);
847 return error;
851 write_file:
852 if (filename) {
853 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
855 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
856 error = errno;
857 gcry_free(inbuf);
858 p = strrchr(tmp, '/');
859 p++;
860 log_write("%s: %s", p, strerror(errno));
861 return gpg_error_from_errno(error);
864 else
866 * xml_import() from command line.
868 fd = STDOUT_FILENO;
870 len = pth_write(fd, &file_header, sizeof(struct file_header_s));
872 if (len != sizeof(file_header)) {
873 len = errno;
875 if (filename)
876 close(fd);
878 gcry_free(inbuf);
879 return gpg_error_from_errno(len);
882 len = pth_write(fd, inbuf, insize);
884 if (len != insize) {
885 len = errno;
887 if (filename)
888 close(fd);
890 gcry_free(inbuf);
891 return gpg_error_from_errno(len);
894 if (fsync(fd) == -1) {
895 len = errno;
896 close(fd);
897 gcry_free(inbuf);
898 return gpg_error_from_errno(len);
901 if (filename) {
902 struct stat st;
903 mode_t mode = 0;
905 close(fd);
907 if (stat(filename, &st) == 0)
908 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
910 if (rename(tmp, filename) == -1) {
911 len = errno;
912 gcry_free(inbuf);
913 return gpg_error_from_errno(len);
916 if (mode)
917 chmod(filename, mode);
920 gcry_free(inbuf);
921 return 0;
924 static gpg_error_t save_command_finalize(assuan_context_t ctx,
925 guchar shakey[], gboolean cached)
927 struct client_s *client = assuan_get_pointer(ctx);
928 gpointer xmlbuf;
929 xmlChar *p;
930 gint len;
931 gint iter;
932 gint timeout;
933 gpointer outbuf;
934 glong outsize = 0;
935 gint zerror;
936 gpg_error_t error;
937 struct stat st;
939 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
940 xmlbuf = p;
942 iter = get_key_file_integer(client->filename, "compression_level");
944 if (iter < 0)
945 iter = 0;
947 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
948 memset(shakey, 0, sizeof(shakey));
949 xmlFree(xmlbuf);
951 if (zerror == Z_MEM_ERROR) {
952 return send_syserror(ctx, ENOMEM);
954 else
955 return send_error(ctx, GPG_ERR_COMPR_ALGO);
957 else {
958 gcry_free(xmlbuf);
959 xmlbuf = outbuf;
960 len = outsize;
963 iter = get_key_file_integer(client->filename, "iterations");
964 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
966 if (error) {
967 memset(shakey, 0, sizeof(shakey));
968 return send_error(ctx, error);
971 stat(client->filename, &st);
972 client->mtime = st.st_mtime;
973 timeout = get_key_file_integer(client->filename, "cache_timeout");
974 CACHE_LOCK(client->ctx);
976 if (cached) {
977 memset(shakey, 0, sizeof(shakey));
978 cache_reset_timeout(client->md5file, timeout);
979 CACHE_UNLOCK;
981 if (client->new == TRUE)
982 send_cache_status_all();
984 client->new = FALSE;
985 return send_error(ctx, 0);
988 if (cache_update_key(client->md5file, shakey) == FALSE) {
989 memset(shakey, 0, sizeof(shakey));
990 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
991 CACHE_UNLOCK;
992 return send_error(ctx, EPWMD_MAX_SLOTS);
995 client->new = FALSE;
996 memset(shakey, 0, sizeof(shakey));
997 cache_reset_timeout(client->md5file, timeout);
998 CACHE_UNLOCK;
999 send_cache_status_all();
1000 return send_error(ctx, 0);
1003 static int save_command(assuan_context_t ctx, char *line)
1005 gboolean cached = FALSE;
1006 guchar shakey[gcrykeysize];
1007 struct stat st;
1008 struct client_s *client = assuan_get_pointer(ctx);
1009 gpg_error_t error;
1011 error = file_modified(client);
1013 if (error) {
1014 log_write("%s: %s", client->filename ? client->filename : "",
1015 pwmd_strerror(error));
1016 return send_error(ctx, error);
1019 error = lock_file_mutex(client);
1021 if (error)
1022 return send_error(ctx, error);
1024 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1025 return send_syserror(ctx, errno);
1027 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1028 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1029 return send_error(ctx, EPWMD_INVALID_FILENAME);
1032 if (!line || !*line) {
1033 CACHE_LOCK(ctx);
1035 if (cache_get_key(client->md5file, shakey) == FALSE) {
1036 CACHE_UNLOCK;
1037 #ifdef WITH_PINENTRY
1038 if (client->pinentry->use == FALSE)
1039 return send_error(ctx, EPWMD_KEY);
1041 client->pinentry->which = PINENTRY_SAVE;
1042 error = pinentry_fork(ctx);
1044 if (error)
1045 return send_error(ctx, error);
1047 client->pinentry->cb = save_command_finalize;
1048 client->pinentry->status = PINENTRY_INIT;
1049 return 0;
1050 #else
1051 return send_error(ctx, EPWMD_KEY);
1052 #endif
1055 CACHE_UNLOCK;
1056 cached = TRUE;
1058 else {
1059 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1060 memset(line, 0, strlen(line));
1063 return save_command_finalize(ctx, shakey, cached);
1066 static gboolean contains_whitespace(const gchar *str)
1068 const gchar *p = str;
1069 gunichar c;
1070 glong len;
1072 len = g_utf8_strlen(p++, -1) -1;
1074 while (len--) {
1075 c = g_utf8_get_char(p++);
1077 if (g_unichar_isspace(c))
1078 return TRUE;
1081 return FALSE;
1084 static int delete_command(assuan_context_t ctx, char *line)
1086 struct client_s *client = assuan_get_pointer(ctx);
1087 gchar **req;
1088 gpg_error_t error;
1089 xmlNodePtr n;
1091 error = file_modified(client);
1093 if (error) {
1094 log_write("%s: %s", client->filename ? client->filename : "",
1095 pwmd_strerror(error));
1096 return send_error(ctx, error);
1099 if (strchr(line, '\t'))
1100 req = split_input_line(line, "\t", -1);
1101 else
1102 req = split_input_line(line, " ", -1);
1104 if (!req || !*req)
1105 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1107 n = find_account(client->doc, &req, &error, NULL, 0);
1109 if (!n) {
1110 g_strfreev(req);
1111 return send_error(ctx, error);
1115 * No sub-node defined. Remove the entire node (account).
1117 if (!req[1]) {
1118 if (n) {
1119 xmlUnlinkNode(n);
1120 xmlFreeNode(n);
1123 g_strfreev(req);
1124 return send_error(ctx, 0);
1127 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1128 g_strfreev(req);
1130 if (!n)
1131 return send_error(ctx, error);
1133 if (n) {
1134 xmlUnlinkNode(n);
1135 xmlFreeNode(n);
1138 return send_error(ctx, 0);
1142 * Don't return with assuan_process_done() here. This has been called from
1143 * assuan_process_next() and the command should be finished in
1144 * client_thread().
1146 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1147 gsize len)
1149 assuan_context_t ctx = data;
1150 struct client_s *client = assuan_get_pointer(ctx);
1151 gchar **req;
1152 guchar *result = line;
1153 xmlNodePtr n;
1154 gpg_error_t error = file_modified(client);
1156 if (rc) {
1157 if (line)
1158 #ifndef MEM_DEBUG
1159 xfree(line);
1160 #else
1161 free(line);
1162 #endif
1163 return rc;
1166 req = split_input_line((gchar *)result, "\t", 0);
1167 #ifndef MEM_DEBUG
1168 xfree(line);
1169 #else
1170 free(line);
1171 #endif
1173 if (rc) {
1174 if (req)
1175 g_strfreev(req);
1177 return rc;
1180 if (!req || !*req)
1181 return EPWMD_COMMAND_SYNTAX;
1183 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1184 g_strfreev(req);
1185 return EPWMD_INVALID_ELEMENT;
1188 if (valid_element_path(req+1, TRUE) == FALSE) {
1189 g_strfreev(req);
1190 return EPWMD_INVALID_ELEMENT;
1193 again:
1194 n = find_account(client->doc, &req, &error, NULL, 0);
1196 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1197 error = new_account(client->doc, *req);
1199 if (error) {
1200 g_strfreev(req);
1201 return error;
1204 goto again;
1207 if (!n) {
1208 g_strfreev(req);
1209 return error;
1212 if (req[1]) {
1213 if (!n->children)
1214 create_elements_cb(n, req+1, &error, NULL);
1215 else
1216 find_elements(client->doc, n->children, req+1, &error,
1217 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1220 g_strfreev(req);
1221 client->inquire_status = INQUIRE_DONE;
1222 return error;
1225 static int store_command(assuan_context_t ctx, char *line)
1227 struct client_s *client = assuan_get_pointer(ctx);
1228 gpg_error_t error = file_modified(client);
1230 if (error) {
1231 log_write("%s: %s", client->filename ? client->filename : "",
1232 pwmd_strerror(error));
1233 return send_error(ctx, error);
1236 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1238 if (error)
1239 return send_error(ctx, error);
1241 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1242 client->inquire_status = INQUIRE_BUSY;
1243 return 0;
1246 static int get_command(assuan_context_t ctx, char *line)
1248 struct client_s *client = assuan_get_pointer(ctx);
1249 gchar **req;
1250 gpg_error_t error;
1251 xmlNodePtr n;
1253 error = file_modified(client);
1255 if (error) {
1256 log_write("%s: %s", client->filename ? client->filename : "",
1257 pwmd_strerror(error));
1258 return send_error(ctx, error);
1261 req = split_input_line(line, "\t", -1);
1263 if (!req || !*req) {
1264 g_strfreev(req);
1265 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1268 n = find_account(client->doc, &req, &error, NULL, 0);
1270 if (!n) {
1271 g_strfreev(req);
1272 return send_error(ctx, error);
1275 if (req[1])
1276 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1278 g_strfreev(req);
1280 if (error)
1281 return send_error(ctx, error);
1283 if (!n || !n->children)
1284 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1286 n = n->children;
1288 if (!n || !n->content || !*n->content)
1289 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1291 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1292 return send_error(ctx, error);
1295 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
1297 xmlChar *p = path;
1298 gint n;
1299 gchar *buf;
1301 if (!p)
1302 return NULL;
1304 for (n = 0; *p && n < 3; p++) {
1305 if (*p == '/')
1306 n++;
1309 if (strstr((gchar *)p, "text()") != NULL)
1310 p[xmlStrlen(p) - 7] = 0;
1312 for (n = 0; p[n]; n++) {
1313 if (p[n] == '/')
1314 p[n] = '\t';
1317 buf = g_strdup_printf("%s\t%s", account, p);
1318 p = (xmlChar *)buf + strlen(buf) - 1;
1320 while (isspace(*p))
1321 *p-- = 0;
1323 return buf;
1326 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
1328 gchar **a;
1329 va_list ap;
1330 gchar *buf;
1331 gint len = *array ? g_strv_length(*array) : 0;
1332 gint ret;
1334 if (!fmt)
1335 return FALSE;
1337 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL)
1338 return FALSE;
1340 va_start(ap, fmt);
1341 ret = g_vasprintf(&buf, fmt, ap);
1342 va_end(ap);
1344 if (ret == -1)
1345 return FALSE;
1347 a[len++] = buf;
1348 a[len] = NULL;
1349 *array = a;
1350 return TRUE;
1353 struct realpath_s {
1354 gchar *account;
1357 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **req,
1358 gpg_error_t *error, void *data)
1360 struct realpath_s *rp = data;
1362 if (rp->account)
1363 g_free(rp->account);
1365 rp->account = g_strdup(req[0]);
1367 if (!rp->account) {
1368 *error = gpg_error_from_errno(ENOMEM);
1369 return NULL;
1372 return node;
1375 static int realpath_command(assuan_context_t ctx, char *line)
1377 gpg_error_t error;
1378 struct client_s *client = assuan_get_pointer(ctx);
1379 xmlChar *p;
1380 gchar **req;
1381 gchar *result, *t;
1382 gint i;
1383 xmlNodePtr n;
1384 struct realpath_s *rp;
1385 GString *string;
1387 error = file_modified(client);
1389 if (error) {
1390 log_write("%s: %s", client->filename ? client->filename : "",
1391 pwmd_strerror(error));
1392 return send_error(ctx, error);
1395 if (strchr(line, '\t') != NULL) {
1396 if ((req = split_input_line(line, "\t", 0)) == NULL)
1397 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1399 else {
1400 if ((req = split_input_line(line, " ", 0)) == NULL)
1401 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1404 n = find_account(client->doc, &req, &error, NULL, 0);
1406 if (!n) {
1407 g_strfreev(req);
1408 return send_error(ctx, error);
1411 rp = g_malloc(sizeof(struct realpath_s));
1413 if (!rp) {
1414 g_strfreev(req);
1415 return send_syserror(ctx, ENOMEM);
1418 rp->account = g_strdup(req[0]);
1420 if (!rp->account) {
1421 g_strfreev(req);
1422 return send_syserror(ctx, ENOMEM);
1425 if (req[1]) {
1426 n = find_elements(client->doc, n->children, req+1, &error,
1427 NULL, realpath_elements_cb, NULL, FALSE, 0, rp);
1429 if (!n) {
1430 g_free(rp->account);
1431 g_free(rp);
1432 g_strfreev(req);
1433 return send_error(ctx, error);
1437 p = xmlGetNodePath(n);
1438 result = element_path_to_req(rp->account, p);
1440 if (!result) {
1441 g_free(result);
1442 g_free(rp->account);
1443 g_free(rp);
1444 g_strfreev(req);
1445 xmlFree(p);
1446 return send_syserror(ctx, ENOMEM);
1449 string = g_string_new(result);
1450 g_free(result);
1451 g_free(rp->account);
1452 g_free(rp);
1453 g_strfreev(req);
1454 xmlFree(p);
1455 i = 0;
1457 again:
1458 for (t = string->str + i; *t; t++, i++) {
1459 if ((!i && *t != '!') || *t == '\t') {
1460 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1461 goto again;
1465 error = assuan_send_data(ctx, string->str, string->len);
1466 g_string_free(string, TRUE);
1467 return send_error(ctx, error);
1470 struct list_element_s {
1471 GSList *list;
1472 gchar **elements;
1475 static gboolean append_to_element_list(struct list_element_s *elements)
1477 gchar *tmp;
1478 gint i, total;
1479 gchar *a;
1480 GSList *list;
1482 if (!elements || !elements->elements)
1483 return TRUE;
1485 tmp = g_strjoinv("\t", elements->elements);
1487 if (!tmp)
1488 return FALSE;
1490 g_strfreev(elements->elements);
1491 elements->elements = NULL;
1492 total = g_slist_length(elements->list);
1493 a = g_utf8_collate_key(tmp, -1);
1495 if (!a) {
1496 g_free(tmp);
1497 return FALSE;
1501 * Removes duplicate element paths from the list. This is needed when
1502 * appending an element tree from list_command(). The glib docs recommend
1503 * using g_utf8_collate_key() for a large number of strings.
1505 for (i = 0; i < total; i++) {
1506 gchar *p = g_slist_nth_data(elements->list, i);
1507 gchar *b = g_utf8_collate_key(p, -1);
1509 if (!b) {
1510 g_free(a);
1511 g_free(tmp);
1512 return FALSE;
1515 if (strcmp(a, b) == 0) {
1516 g_free(a);
1517 g_free(b);
1518 g_free(tmp);
1519 return TRUE;
1522 g_free(b);
1525 g_free(a);
1526 list = g_slist_append(elements->list, tmp);
1528 if (!list)
1529 return FALSE;
1531 elements->list = list;
1532 return TRUE;
1535 static gpg_error_t do_list_recurse(xmlDocPtr doc, xmlNodePtr node,
1536 struct list_element_s *elements, gchar *prefix)
1538 xmlNodePtr n;
1539 gpg_error_t error;
1541 if (append_to_element_list(elements) == FALSE)
1542 return gpg_error_from_errno(ENOMEM);
1544 for (n = node; n; n = n->next) {
1545 if (n->type == XML_ELEMENT_NODE) {
1546 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
1547 gchar *tmp;
1549 if (content) {
1550 if (strv_printf(&elements->elements, "%s\t%s", prefix, n->name) == FALSE)
1551 return gpg_error_from_errno(ENOMEM);
1553 if (append_to_element_list(elements) == FALSE)
1554 return gpg_error_from_errno(ENOMEM);
1557 tmp = g_strdup_printf("%s\t!%s", prefix, n->name);
1559 if (!tmp)
1560 return gpg_error_from_errno(ENOMEM);
1562 if (strv_printf(&elements->elements, "%s", tmp) == FALSE) {
1563 g_free(tmp);
1564 return gpg_error_from_errno(ENOMEM);
1567 if (n->children) {
1568 error = do_list_recurse(doc, n->children, elements, tmp);
1569 g_free(tmp);
1571 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1572 return error;
1574 else
1575 g_free(tmp);
1577 if (append_to_element_list(elements) == FALSE)
1578 return gpg_error_from_errno(ENOMEM);
1582 return 0;
1585 static gpg_error_t do_list_command(assuan_context_t ctx, xmlDocPtr doc,
1586 struct list_element_s *elements, char *line)
1588 gchar *prefix = NULL, *account;
1589 gchar **req = NULL, **oreq = NULL, *tmp;
1590 xmlNodePtr n;
1591 gboolean account_is_literal, account_has_target = FALSE;
1592 gint which = 0;
1593 gchar **p;
1594 gpg_error_t error;
1596 if ((req = split_input_line(line, "\t", 0)) == NULL) {
1597 if ((req = split_input_line(line, " ", 0)) == NULL)
1598 return EPWMD_COMMAND_SYNTAX;
1601 prefix = g_strdup(*req);
1603 if (!prefix) {
1604 g_strfreev(req);
1605 return gpg_error_from_errno(ENOMEM);
1608 account = g_strdup(*req);
1610 if (!account) {
1611 g_free(prefix);
1612 g_strfreev(req);
1613 return gpg_error_from_errno(ENOMEM);
1616 oreq = g_strdupv(req);
1618 if (!oreq) {
1619 g_free(prefix);
1620 g_free(account);
1621 g_strfreev(req);
1622 return gpg_error_from_errno(ENOMEM);
1625 p = req;
1626 again:
1627 account_has_target = FALSE;
1628 account_is_literal = is_literal_element_str(prefix);
1629 n = find_account(doc, &p, &error, &account_has_target, 0);
1631 if (which)
1632 oreq = p;
1633 else
1634 req = p;
1636 if (!n)
1637 goto fail;
1639 if (!which && account_is_literal == FALSE && account_has_target == FALSE) {
1640 tmp = g_strdup_printf("!%s", prefix);
1642 if (!tmp) {
1643 error = gpg_error_from_errno(ENOMEM);
1644 goto fail;
1647 g_free(prefix);
1648 prefix = tmp;
1651 if (*(p+1)) {
1652 gchar *t;
1654 n = find_elements(doc, n->children, p+1, &error, NULL, NULL, NULL,
1655 TRUE, 0, NULL);
1657 if (error)
1658 goto fail;
1660 tmp = g_strjoinv("\t", p+1);
1661 if (!tmp) {
1662 error = gpg_error_from_errno(ENOMEM);
1663 goto fail;
1666 t = g_strdup_printf("%s\t%s", prefix, tmp);
1667 if (!t) {
1668 error = gpg_error_from_errno(ENOMEM);
1669 goto fail;
1672 g_free(prefix);
1673 prefix = t;
1674 g_free(tmp);
1677 if (strv_printf(&elements->elements, "%s", prefix) == FALSE) {
1678 error = gpg_error_from_errno(ENOMEM);
1679 goto fail;
1682 if (node_has_child_element(n->children) == FALSE) {
1683 if (append_to_element_list(elements) == FALSE) {
1684 error = gpg_error_from_errno(ENOMEM);
1685 goto fail;
1688 else
1689 error = do_list_recurse(doc, n->children, elements, prefix);
1691 if (error)
1692 goto fail;
1694 if (!which++ && !*(p+1) && account_is_literal == FALSE && account_has_target == TRUE) {
1695 g_free(*oreq);
1696 *oreq = g_strdup_printf("!%s", account);
1698 if (!*oreq) {
1699 error = gpg_error_from_errno(ENOMEM);
1700 goto fail;
1703 p = oreq;
1704 g_free(prefix);
1705 prefix = g_strdup(*oreq);
1707 if (!prefix) {
1708 error = gpg_error_from_errno(ENOMEM);
1709 goto fail;
1712 goto again;
1715 fail:
1716 g_free(prefix);
1717 g_free(account);
1718 g_strfreev(req);
1720 if (oreq)
1721 g_strfreev(oreq);
1723 return error;
1727 * This could be faster especially when finding "target" attributes.
1729 static int list_command(assuan_context_t ctx, char *line)
1731 struct client_s *client = assuan_get_pointer(ctx);
1732 gpg_error_t error;
1733 struct list_element_s *elements = NULL;
1734 GString *string;
1735 gchar *tmp;
1736 gint i, total;
1738 if (disable_list_and_dump == TRUE)
1739 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1741 error = file_modified(client);
1743 if (error) {
1744 log_write("%s: %s", client->filename, pwmd_strerror(error));
1745 return send_error(ctx, error);
1748 if (!*line) {
1749 GString *str;
1751 error = list_accounts(client->doc, &str);
1753 if (error)
1754 return send_error(ctx, error);
1756 error = assuan_send_data(ctx, str->str, str->len);
1757 g_string_free(str, TRUE);
1758 return send_error(ctx, error);
1761 elements = g_malloc0(sizeof(struct list_element_s));
1763 if (!elements) {
1764 error = gpg_error_from_errno(ENOMEM);
1765 goto fail;
1768 error = do_list_command(ctx, client->doc, elements, line);
1770 if (error)
1771 goto fail;
1773 if (!error) {
1774 total = g_slist_length(elements->list);
1776 if (!total) {
1777 error = EPWMD_EMPTY_ELEMENT;
1778 goto fail;
1782 * Find element paths with a target and append those element trees to
1783 * the list.
1785 for (i = 0; i < total; i++) {
1786 gchar **req;
1788 tmp = g_slist_nth_data(elements->list, i);
1789 req = split_input_line(tmp, "\t", 0);
1791 if (!req) {
1792 if (g_str_has_prefix(tmp, "!") == TRUE) {
1793 g_strfreev(req);
1794 continue;
1797 else {
1798 gchar **p;
1800 for (p = req; *p; p++) {
1801 if (g_str_has_prefix(*p, "!") == FALSE)
1802 break;
1805 if (!*p) {
1806 g_strfreev(req);
1807 continue;
1811 g_strfreev(req);
1812 error = do_list_command(ctx, client->doc, elements, tmp);
1814 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1815 goto fail;
1817 total = g_slist_length(elements->list);
1821 string = g_string_new(NULL);
1823 for (i = 0; i < total; i++) {
1824 tmp = g_slist_nth_data(elements->list, i);
1825 g_string_append_printf(string, "%s\n", tmp);
1826 g_free(tmp);
1829 string = g_string_truncate(string, string->len - 1);
1830 error = assuan_send_data(ctx, string->str, string->len);
1831 g_string_free(string, TRUE);
1833 fail:
1834 if (elements) {
1835 if (elements->list)
1836 g_slist_free(elements->list);
1838 if (elements->elements)
1839 g_strfreev(elements->elements);
1841 g_free(elements);
1844 return send_error(ctx, error);
1847 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1848 const gchar *value)
1850 xmlAttrPtr a;
1852 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1853 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1855 if (!a)
1856 return EPWMD_LIBXML_ERROR;
1858 else
1859 xmlNodeSetContent(a->children, (xmlChar *)value);
1861 return 0;
1865 * req[0] - element path
1867 static int attribute_list(assuan_context_t ctx, gchar **req)
1869 struct client_s *client = assuan_get_pointer(ctx);
1870 gchar **attrlist = NULL;
1871 gint i = 0;
1872 gchar **path = NULL;
1873 xmlAttrPtr a;
1874 xmlNodePtr n, an;
1875 gchar *line;
1876 gpg_error_t error;
1878 if (!req || !req[0])
1879 return EPWMD_COMMAND_SYNTAX;
1881 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1883 * The first argument may be only an account.
1885 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1886 return EPWMD_COMMAND_SYNTAX;
1889 n = find_account(client->doc, &path, &error, NULL, 0);
1891 if (!n) {
1892 g_strfreev(path);
1893 return error;
1896 if (path[1]) {
1897 n = find_elements(client->doc, n->children, path+1, &error,
1898 NULL, NULL, NULL, FALSE, 0, NULL);
1900 if (!n) {
1901 g_strfreev(path);
1902 return error;
1906 g_strfreev(path);
1908 for (a = n->properties; a; a = a->next) {
1909 gchar **pa;
1911 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1912 if (attrlist)
1913 g_strfreev(attrlist);
1915 error = errno;
1916 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
1917 return gpg_error_from_errno(error);
1920 attrlist = pa;
1921 an = a->children;
1922 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1924 if (!attrlist[i]) {
1925 g_strfreev(attrlist);
1926 return gpg_error_from_errno(ENOMEM);
1929 attrlist[++i] = NULL;
1932 if (!attrlist)
1933 return EPWMD_EMPTY_ELEMENT;
1935 line = g_strjoinv("\n", attrlist);
1937 if (!line) {
1938 g_strfreev(attrlist);
1939 return gpg_error_from_errno(ENOMEM);
1942 error = assuan_send_data(ctx, line, strlen(line));
1943 g_free(line);
1944 g_strfreev(attrlist);
1945 return error;
1949 * req[0] - attribute
1950 * req[1] - element path
1952 static int attribute_delete(struct client_s *client, gchar **req)
1954 xmlAttrPtr a;
1955 xmlNodePtr n;
1956 gchar **path = NULL;
1957 gpg_error_t error;
1959 if (!req || !req[0] || !req[1])
1960 return EPWMD_COMMAND_SYNTAX;
1962 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1964 * The first argument may be only an account.
1966 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1967 return EPWMD_COMMAND_SYNTAX;
1971 * Don't remove the "name" attribute for the account element. To remove an
1972 * account use DELETE <account>.
1974 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1975 error = EPWMD_ATTR_SYNTAX;
1976 goto fail;
1979 n = find_account(client->doc, &path, &error, NULL, 0);
1981 if (!n)
1982 goto fail;
1984 if (path[1]) {
1985 n = find_elements(client->doc, n->children, path+1, &error,
1986 NULL, NULL, NULL, FALSE, 0, NULL);
1988 if (!n)
1989 goto fail;
1992 g_strfreev(path);
1994 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1995 return EPWMD_ATTR_NOT_FOUND;
1997 if (xmlRemoveProp(a) == -1)
1998 return EPWMD_LIBXML_ERROR;
2000 return 0;
2002 fail:
2003 g_strfreev(path);
2004 return error;
2008 * Creates a "target" attribute. When other commands encounter an element with
2009 * this attribute, the element path is modified to the target value. If the
2010 * source element path doesn't exist when using 'ATTR SET target', it is
2011 * created, but the destination element path must exist.
2013 * req[0] - source element path
2014 * req[1] - destination element path
2016 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2018 gchar **src, **dst, *line = NULL;
2019 gpg_error_t error;
2020 xmlNodePtr n;
2022 if (!req || !req[0] || !req[1])
2023 return EPWMD_COMMAND_SYNTAX;
2025 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2027 * The first argument may be only an account.
2029 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2030 return EPWMD_COMMAND_SYNTAX;
2033 if (valid_element_path(src, FALSE) == FALSE) {
2034 g_strfreev(src);
2035 return EPWMD_INVALID_ELEMENT;
2038 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2040 * The first argument may be only an account.
2042 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2043 error = EPWMD_COMMAND_SYNTAX;
2044 goto fail;
2048 n = find_account(client->doc, &dst, &error, NULL, 0);
2051 * Make sure the destination element path exists.
2053 if (!n)
2054 goto fail;
2056 if (dst[1]) {
2057 n = find_elements(client->doc, n->children, dst+1, &error,
2058 NULL, NULL, NULL, FALSE, 0, NULL);
2060 if (!n)
2061 goto fail;
2064 again:
2065 n = find_account(client->doc, &src, &error, NULL, 0);
2067 if (!n) {
2068 if (error == EPWMD_ELEMENT_NOT_FOUND) {
2069 error = new_account(client->doc, src[0]);
2071 if (error)
2072 goto fail;
2074 goto again;
2076 else
2077 goto fail;
2080 if (src[1]) {
2081 if (!n->children)
2082 n = create_target_elements_cb(n, src+1, &error, NULL);
2083 else
2084 n = find_elements(client->doc, n->children, src+1, &error,
2085 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2087 if (!n)
2088 goto fail;
2091 * Reset the position of the element tree now that the elements
2092 * have been created.
2094 n = find_account(client->doc, &src, &error, NULL, 0);
2096 if (!n)
2097 goto fail;
2099 n = find_elements(client->doc, n->children, src+1, &error,
2100 NULL, NULL, NULL, FALSE, 0, NULL);
2102 if (!n)
2103 goto fail;
2106 line = g_strjoinv("\t", dst);
2107 error = add_attribute(n, "target", line);
2109 fail:
2110 g_free(line);
2111 g_strfreev(src);
2112 g_strfreev(dst);
2113 return error;
2117 * req[0] - account name
2118 * req[1] - new name
2120 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2122 gpg_error_t error;
2123 gchar **tmp;
2124 xmlNodePtr n;
2126 tmp = g_strdupv(req);
2128 if (!tmp)
2129 return gpg_error_from_errno(ENOMEM);
2131 n = find_account(client->doc, &tmp, &error, NULL, 0);
2132 g_strfreev(tmp);
2134 if (!n)
2135 return error;
2137 if (g_utf8_collate(req[0], req[1]) == 0)
2138 return 0;
2141 * Will not overwrite an existing account.
2143 tmp = g_strdupv(req+1);
2145 if (!tmp)
2146 return gpg_error_from_errno(ENOMEM);
2148 n = find_account(client->doc, &tmp, &error, NULL, 0);
2149 g_strfreev(tmp);
2151 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
2152 return error;
2154 if (n)
2155 return EPWMD_ACCOUNT_EXISTS;
2158 * Whitespace not allowed in account names.
2160 if (contains_whitespace(req[1]) == TRUE)
2161 return EPWMD_ATTR_SYNTAX;
2163 tmp = g_strdupv(req);
2165 if (!tmp)
2166 return gpg_error_from_errno(ENOMEM);
2168 n = find_account(client->doc, &tmp, &error, NULL, 0);
2169 g_strfreev(tmp);
2171 if (!n)
2172 return EPWMD_ELEMENT_NOT_FOUND;
2174 return add_attribute(n, "name", req[1]);
2178 * req[0] - attribute
2179 * req[1] - element path
2181 static int attribute_get(assuan_context_t ctx, gchar **req)
2183 struct client_s *client = assuan_get_pointer(ctx);
2184 xmlNodePtr n;
2185 xmlChar *a;
2186 gchar **path= NULL;
2187 gpg_error_t error;
2189 if (!req || !req[0] || !req[1])
2190 return EPWMD_COMMAND_SYNTAX;
2192 if (strchr(req[1], '\t')) {
2193 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2194 return EPWMD_COMMAND_SYNTAX;
2196 else {
2197 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2198 return EPWMD_COMMAND_SYNTAX;
2201 n = find_account(client->doc, &path, &error, NULL, 0);
2203 if (!n)
2204 goto fail;
2206 if (path[1]) {
2207 n = find_elements(client->doc, n->children, path+1, &error,
2208 NULL, NULL, NULL, FALSE, 0, NULL);
2210 if (!n)
2211 goto fail;
2214 g_strfreev(path);
2216 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2217 return EPWMD_ATTR_NOT_FOUND;
2219 error = assuan_send_data(ctx, a, xmlStrlen(a));
2220 xmlFree(a);
2221 return error;
2223 fail:
2224 g_strfreev(path);
2225 return error;
2229 * req[0] - attribute
2230 * req[1] - element path
2231 * req[2] - value
2233 static int attribute_set(struct client_s *client, gchar **req)
2235 gchar **path = NULL;
2236 gpg_error_t error;
2237 xmlNodePtr n;
2239 if (!req || !req[0] || !req[1] || !req[2])
2240 return EPWMD_COMMAND_SYNTAX;
2243 * Reserved attribute names.
2245 if (g_utf8_collate(req[0], "name") == 0) {
2247 * Only reserved for the account element. Not the rest of the
2248 * document.
2250 if (strchr(req[1], '\t') == NULL)
2251 return name_attribute(client, req + 1);
2253 else if (g_utf8_collate(req[0], "target") == 0)
2254 return target_attribute(client, req + 1);
2256 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2258 * The first argument may be only an account.
2260 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2261 return EPWMD_COMMAND_SYNTAX;
2264 n = find_account(client->doc, &path, &error, NULL, 0);
2266 if (!n)
2267 goto fail;
2269 if (path[1]) {
2270 n = find_elements(client->doc, n->children, path+1, &error,
2271 NULL, NULL, NULL, FALSE, 0, NULL);
2273 if (!n)
2274 goto fail;
2277 g_strfreev(path);
2278 return add_attribute(n, req[0], req[2]);
2280 fail:
2281 g_strfreev(path);
2282 return error;
2286 * req[0] - command
2287 * req[1] - attribute name or element path if command is LIST
2288 * req[2] - element path
2289 * req[2] - element path or value
2291 static int attr_command(assuan_context_t ctx, char *line)
2293 struct client_s *client = assuan_get_pointer(ctx);
2294 gchar **req = split_input_line(line, " ", 4);
2295 gpg_error_t error = 0;
2297 error = file_modified(client);
2299 if (error) {
2300 log_write("%s: %s", client->filename ? client->filename : "",
2301 pwmd_strerror(error));
2302 g_strfreev(req);
2303 return send_error(ctx, error);
2306 if (!req || !req[0] || !req[1]) {
2307 g_strfreev(req);
2308 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2311 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2312 error = attribute_set(client, req+1);
2313 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2314 error = attribute_get(ctx, req+1);
2315 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2316 error = attribute_delete(client, req+1);
2317 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2318 error = attribute_list(ctx, req+1);
2319 else
2320 error = EPWMD_COMMAND_SYNTAX;
2322 g_strfreev(req);
2323 return send_error(ctx, error);
2326 static int iscached_command(assuan_context_t ctx, char *line)
2328 gchar **req = split_input_line(line, " ", 0);
2329 guchar md5file[16];
2331 if (!req || !*req) {
2332 g_strfreev(req);
2333 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2336 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2337 g_strfreev(req);
2338 CACHE_LOCK(ctx);
2340 if (cache_iscached(md5file) == FALSE) {
2341 CACHE_UNLOCK;
2342 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2345 CACHE_UNLOCK;
2346 return send_error(ctx, 0);
2349 gpg_error_t send_cache_status(assuan_context_t ctx)
2351 gchar *tmp;
2352 struct client_s *client = assuan_get_pointer(ctx);
2354 CACHE_LOCK(client->ctx);
2355 tmp = print_fmt("%i %i",
2356 cache_file_count(),
2357 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2358 CACHE_UNLOCK;
2360 return assuan_write_status(ctx, "CACHE", tmp);
2363 static int clearcache_command(assuan_context_t ctx, char *line)
2365 struct client_s *client = assuan_get_pointer(ctx);
2366 gchar **req = split_input_line(line, " ", 0);
2367 guchar md5file[16];
2369 CACHE_LOCK(ctx);
2371 if (!req || !*req) {
2372 g_strfreev(req);
2373 cache_clear(client->md5file, 2);
2374 CACHE_UNLOCK;
2375 return send_error(ctx, 0);
2378 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2379 g_strfreev(req);
2381 if (cache_clear(md5file, 1) == FALSE) {
2382 CACHE_UNLOCK;
2383 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2386 CACHE_UNLOCK;
2387 return send_error(ctx, 0);
2390 static int cachetimeout_command(assuan_context_t ctx, char *line)
2392 guchar md5file[16];
2393 glong timeout;
2394 gchar **req = split_input_line(line, " ", 0);
2395 gchar *p;
2396 struct client_s *client = assuan_get_pointer(ctx);
2398 if (!req || !*req || !req[1]) {
2399 g_strfreev(req);
2400 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2403 errno = 0;
2404 timeout = strtol(req[0], &p, 10);
2406 if (errno != 0 || *p != 0) {
2407 g_strfreev(req);
2408 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2411 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2412 g_strfreev(req);
2413 CACHE_LOCK(client->ctx);
2415 if (cache_set_timeout(md5file, timeout) == FALSE) {
2416 CACHE_UNLOCK;
2417 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2420 CACHE_UNLOCK;
2421 send_cache_status_all();
2422 return send_error(ctx, 0);
2425 static int dump_command(assuan_context_t ctx, char *line)
2427 xmlChar *xml;
2428 gssize len;
2429 struct client_s *client = assuan_get_pointer(ctx);
2430 gpg_error_t error;
2432 if (disable_list_and_dump == TRUE)
2433 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2435 error = file_modified(client);
2437 if (error) {
2438 log_write("%s: %s", client->filename ? client->filename : "",
2439 pwmd_strerror(error));
2440 return send_error(ctx, error);
2443 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2444 error = assuan_send_data(ctx, xml, len);
2445 xmlFree(xml);
2446 return send_error(ctx, error);
2449 static int getconfig_command(assuan_context_t ctx, gchar *line)
2451 struct client_s *client = assuan_get_pointer(ctx);
2452 gpg_error_t error = 0;
2453 gchar *p, *tmp;
2455 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2456 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2458 p = get_key_file_string(client->filename ? client->filename : "default", line);
2460 if (!p)
2461 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2463 tmp = expand_homedir(p);
2464 g_free(p);
2465 p = tmp;
2466 error = assuan_send_data(ctx, p, strlen(p));
2467 g_free(p);
2468 return send_error(ctx, error);
2471 void cleanup_assuan(assuan_context_t ctx)
2473 struct client_s *cl = assuan_get_pointer(ctx);
2475 cleanup_client(cl);
2478 static void reset_notify(assuan_context_t ctx)
2480 struct client_s *cl = assuan_get_pointer(ctx);
2482 cleanup_client(cl);
2485 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2487 gchar name[32] = {0}, value[256] = {0};
2488 pth_attr_t attr = pth_attr_of(pth_self());
2490 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2491 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_SYNTAX);
2493 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2494 log_write("OPTION CLIENT %s", line);
2495 pth_attr_set(attr, PTH_ATTR_NAME, value);
2497 else
2498 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2500 return 0;
2503 static int option_handler(assuan_context_t ctx, const gchar *name,
2504 const gchar *value)
2506 struct client_s *client = assuan_get_pointer(ctx);
2508 if (!value || !*value)
2509 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2511 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2512 g_free(client->pinentry->ttyname);
2513 client->pinentry->ttyname = g_strdup(value);
2515 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2516 g_free(client->pinentry->ttytype);
2517 client->pinentry->ttytype = g_strdup(value);
2519 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2520 g_free(client->pinentry->display);
2521 client->pinentry->display = g_strdup(value);
2523 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2524 g_free(client->pinentry->path);
2525 client->pinentry->path = g_strdup(value);
2527 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2528 g_free(client->pinentry->title);
2529 client->pinentry->title = g_strdup(value);
2531 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2532 g_free(client->pinentry->prompt);
2533 client->pinentry->prompt = g_strdup(value);
2535 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2536 g_free(client->pinentry->desc);
2537 client->pinentry->desc = g_strdup(value);
2539 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2540 gchar *p = NULL;
2541 gint n = strtol(value, &p, 10);
2543 if (*p || n < 0)
2544 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2546 client->pinentry->timeout = n;
2548 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2549 gchar *p = NULL;
2550 gint n = strtol(value, &p, 10);
2552 if (*p || n < 0 || n > 1)
2553 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2555 client->pinentry->use = n == 0 ? FALSE : TRUE;
2557 else if (g_strcasecmp(name, (gchar *)"client") == 0)
2558 return parse_client_option(ctx, value);
2559 else
2560 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2562 log_write("OPTION %s=%s", name, value);
2563 return 0;
2566 gpg_error_t register_commands(assuan_context_t ctx)
2568 static struct {
2569 const char *name;
2570 int (*handler)(assuan_context_t, char *line);
2571 } table[] = {
2572 { "OPEN", open_command },
2573 { "SAVE", save_command },
2574 { "LIST", list_command },
2575 { "REALPATH", realpath_command },
2576 { "STORE", store_command },
2577 { "DELETE", delete_command },
2578 { "GET", get_command },
2579 { "ATTR", attr_command },
2580 { "ISCACHED", iscached_command },
2581 { "CLEARCACHE", clearcache_command },
2582 { "CACHETIMEOUT", cachetimeout_command },
2583 { "GETCONFIG", getconfig_command },
2584 { "DUMP", dump_command },
2585 { "INPUT", NULL },
2586 { "OUTPUT", NULL },
2587 { NULL, NULL }
2589 int i, rc;
2591 for (i=0; table[i].name; i++) {
2592 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2594 if (rc)
2595 return rc;
2598 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2599 if (rc)
2600 return rc;
2602 rc = assuan_register_option_handler(ctx, option_handler);
2603 if (rc)
2604 return rc;
2606 return assuan_register_reset_notify(ctx, reset_notify);
2609 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2610 guchar *key)
2612 guchar *iv;
2613 void *inbuf;
2614 gsize insize, len;
2615 guchar tkey[gcrykeysize];
2616 struct file_header_s {
2617 guint iter;
2618 guchar iv[gcryblocksize];
2619 } file_header;
2620 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2621 gcry_cipher_hd_t gh;
2622 guint iter = 0, n_iter = 0;
2623 gint iter_progress;
2624 void *outbuf = NULL;
2625 gint zerror = 0;
2626 glong outsize = 0;
2627 gpg_error_t error;
2629 if (!ctx) {
2630 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2632 if (error)
2633 return error;
2635 else
2636 gh = client->gh;
2638 lseek(fd, 0, SEEK_SET);
2639 insize = st.st_size - sizeof(struct file_header_s);
2640 iv = gcry_malloc(gcryblocksize);
2642 if (!iv) {
2643 if (!ctx)
2644 gcry_cipher_close(gh);
2646 return gpg_error_from_errno(ENOMEM);
2649 len = pth_read(fd, &file_header, sizeof(struct file_header_s));
2651 if (len != sizeof(file_header)) {
2652 len = errno;
2654 if (!ctx)
2655 gcry_cipher_close(gh);
2657 gcry_free(iv);
2658 errno = len;
2659 return gpg_error_from_errno(errno);
2662 /* No encryption iterations. This is a plain (gzipped) file. */
2663 if (file_header.iter == -1)
2664 insize = st.st_size - sizeof(struct file_header_s);
2666 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2667 inbuf = gcry_malloc(insize);
2669 if (!inbuf) {
2670 if (!ctx)
2671 gcry_cipher_close(gh);
2673 gcry_free(iv);
2674 return gpg_error_from_errno(ENOMEM);
2677 len = pth_read(fd, inbuf, insize);
2679 if (len != insize) {
2680 len = errno;
2682 if (!ctx)
2683 gcry_cipher_close(gh);
2685 gcry_free(iv);
2686 errno = len;
2687 return gpg_error_from_errno(errno);
2690 if (file_header.iter == -1)
2691 goto decompress;
2693 memcpy(tkey, key, sizeof(tkey));
2694 tkey[0] ^= 1;
2696 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2697 if (!ctx) {
2698 gcry_cipher_close(gh);
2699 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2701 else
2702 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2704 gcry_free(inbuf);
2705 gcry_free(iv);
2706 return error;
2709 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2710 if (!ctx) {
2711 gcry_cipher_close(gh);
2712 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2714 else
2715 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2717 gcry_free(inbuf);
2718 gcry_free(iv);
2720 if (!ctx)
2721 gcry_cipher_close(gh);
2723 return error;
2726 iter_progress = get_key_file_integer("default", "iteration_progress");
2728 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2729 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2731 if (error) {
2732 gcry_free(inbuf);
2733 gcry_free(iv);
2734 return error;
2738 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2740 if (error) {
2741 gcry_free(inbuf);
2742 gcry_free(iv);
2743 return error;
2746 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2747 if (!ctx) {
2748 gcry_cipher_close(gh);
2749 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2751 else
2752 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2754 gcry_free(inbuf);
2755 gcry_free(iv);
2756 return error;
2759 while (iter < file_header.iter) {
2760 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2761 if (!(iter % iter_progress)) {
2762 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i",
2763 ++n_iter * iter_progress));
2765 if (error) {
2766 gcry_free(inbuf);
2767 gcry_free(iv);
2768 return error;
2773 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2774 if (!ctx) {
2775 gcry_cipher_close(gh);
2776 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2778 else
2779 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2781 gcry_free(inbuf);
2782 gcry_free(iv);
2783 return error;
2786 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2788 if (error) {
2789 if (!ctx) {
2790 gcry_cipher_close(gh);
2791 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2793 else
2794 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2796 gcry_free(inbuf);
2797 gcry_free(iv);
2798 return error;
2801 iter++;
2802 pth_yield(NULL);
2805 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2806 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i", file_header.iter));
2808 if (error) {
2809 gcry_free(inbuf);
2810 gcry_free(iv);
2811 return error;
2815 gcry_free(iv);
2817 decompress:
2818 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2820 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2822 if (zerror == Z_MEM_ERROR) {
2823 gcry_free(inbuf);
2824 return gpg_error_from_errno(ENOMEM);
2826 else if (zerror != Z_DATA_ERROR) {
2827 gcry_free(inbuf);
2829 if (!ctx)
2830 gcry_cipher_close(gh);
2832 return EPWMD_BADKEY;
2835 else {
2836 gcry_free(inbuf);
2837 inbuf = outbuf;
2838 insize = outsize;
2841 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2842 gcry_free(inbuf);
2844 if (!ctx)
2845 gcry_cipher_close(gh);
2847 return EPWMD_BADKEY;
2850 if (ctx) {
2851 client->xml = inbuf;
2852 client->len = insize;
2854 else {
2855 gcry_cipher_close(gh);
2856 gcry_free(inbuf);
2859 return 0;
2863 * This is called after every Assuan command.
2865 void command_finalize(assuan_context_t ctx, gint error)
2867 struct client_s *client = assuan_get_pointer(ctx);
2869 unlock_file_mutex(client);