When the pwmd client process does with SIGTERM, set the pinentry error
[pwmd.git] / src / commands.c
blobb7f9b7d73cc748ca60d00c1d78f4e550506e9341
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 error = pinentry_fork(ctx);
582 if (error) {
583 cleanup_client(client);
584 return error;
587 client->pinentry->cb = open_command_finalize;
588 client->pinentry->status = PINENTRY_INIT;
589 return 0;
590 #else
591 cleanup_client(client);
592 return send_error(ctx, EPWMD_KEY);
593 #endif
596 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
599 g_strfreev(req);
600 return open_command_finalize(ctx, shakey, cached);
603 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
604 gint size, gpointer *out, glong *outsize, gint *error)
606 z_stream z;
607 gpointer pout, pin;
608 gint ret;
609 gz_header h;
610 gchar buf[17];
611 gint cmd = Z_NO_FLUSH;
612 gpg_error_t rc;
614 z.zalloc = z_alloc;
615 z.zfree = z_free;
616 z.next_in = pin = data;
617 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
618 z.avail_out = zlib_bufsize;
619 z.next_out = pout = g_malloc(zlib_bufsize);
621 if (!pout) {
622 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
623 *error = Z_MEM_ERROR;
624 return FALSE;
627 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
629 if (ret != Z_OK) {
630 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
631 *error = ret;
632 g_free(pout);
633 return FALSE;
636 memset(&h, 0, sizeof(gz_header));
637 snprintf(buf, sizeof(buf), "%i", size);
638 h.comment = (guchar *)buf;
639 ret = deflateSetHeader(&z, &h);
641 if (ret != Z_OK) {
642 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
643 *error = ret;
644 g_free(pout);
645 deflateEnd(&z);
646 return FALSE;
649 do {
650 gpointer p;
652 ret = deflate(&z, cmd);
654 switch (ret) {
655 case Z_OK:
656 break;
657 case Z_BUF_ERROR:
658 if (!z.avail_out) {
659 p = g_realloc(pout, z.total_out + zlib_bufsize);
661 if (!p) {
662 ret = Z_MEM_ERROR;
663 goto fail;
666 pout = p;
667 z.next_out = pout + z.total_out;
668 z.avail_out = zlib_bufsize;
671 if (!z.avail_in && z.total_in < size) {
672 if (z.total_in + zlib_bufsize > size)
673 z.avail_in = size - z.total_in;
674 else
675 z.avail_in = zlib_bufsize;
677 if (ctx) {
678 rc = assuan_write_status(ctx, "COMPRESS",
679 print_fmt("%i %i", z.total_in, size));
681 if (rc) {
682 ret = rc;
683 goto fail;
688 if (z.total_in >= size)
689 cmd = Z_FINISH;
691 break;
692 case Z_STREAM_END:
693 break;
694 default:
695 goto fail;
698 pth_yield(NULL);
699 } while (ret != Z_STREAM_END);
701 if (ctx) {
702 rc = assuan_write_status(ctx, "COMPRESS",
703 print_fmt("%i %i", z.total_in, size));
705 if (rc) {
706 ret = rc;
707 goto fail;
711 *out = pout;
712 *outsize = z.total_out;
713 deflateEnd(&z);
714 return TRUE;
716 fail:
717 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
718 *error = ret;
719 g_free(pout);
720 deflateEnd(&z);
721 return FALSE;
724 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
725 const gchar *filename, gpointer data, size_t insize,
726 const guchar *shakey, guint iter)
728 gsize len = insize;
729 gint fd;
730 gpointer inbuf;
731 guchar tkey[gcrykeysize];
732 gchar *p;
733 gint error;
734 gpg_error_t rc;
735 guint iter_progress = 0, n_iter = 0, xiter = 0;
736 gchar tmp[FILENAME_MAX];
737 struct file_header_s {
738 guint iter;
739 guchar iv[gcryblocksize];
740 } file_header;
742 if (iter == -1) {
743 inbuf = data;
744 file_header.iter = iter;
745 goto write_file;
748 if (insize / gcryblocksize) {
749 len = (insize / gcryblocksize) * gcryblocksize;
751 if (insize % gcryblocksize)
752 len += gcryblocksize;
756 * Resize the existing xml buffer to the block size required by gcrypt
757 * rather than duplicating it and wasting memory.
759 inbuf = gcry_realloc(data, len);
761 if (!inbuf)
762 return gpg_error_from_errno(ENOMEM);
764 insize = len;
765 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
766 memcpy(tkey, shakey, sizeof(tkey));
767 tkey[0] ^= 1;
769 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
770 gcry_free(inbuf);
771 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
772 return rc;
775 file_header.iter = iter;
777 if (client)
778 iter_progress = get_key_file_integer("default", "iteration_progress");
780 if (client && iter_progress && file_header.iter >= iter_progress) {
781 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
783 if (error) {
784 gcry_free(inbuf);
785 return error;
789 while (xiter < file_header.iter) {
790 if (client && iter_progress > 0 && xiter >= iter_progress) {
791 if (!(xiter % iter_progress)) {
792 error = assuan_write_status(client->ctx, "ENCRYPT", print_fmt("%i",
793 ++n_iter * iter_progress));
795 if (error) {
796 gcry_free(inbuf);
797 return error;
802 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
803 sizeof(file_header.iv)))) {
804 gcry_free(inbuf);
805 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
806 return rc;
809 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
810 == FALSE) {
811 gcry_free(inbuf);
812 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
813 return rc;
816 xiter++;
817 pth_yield(NULL);
820 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
821 sizeof(file_header.iv)))) {
822 gcry_free(inbuf);
823 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
824 return rc;
827 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
828 gcry_free(inbuf);
829 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
830 return rc;
833 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
834 gcry_free(inbuf);
835 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
836 return rc;
839 if (client && iter_progress && file_header.iter >= iter_progress) {
840 error = assuan_write_status(client->ctx, "ENCRYPT",
841 print_fmt("%i", file_header.iter));
843 if (error) {
844 gcry_free(inbuf);
845 return error;
849 write_file:
850 if (filename) {
851 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
853 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
854 error = errno;
855 gcry_free(inbuf);
856 p = strrchr(tmp, '/');
857 p++;
858 log_write("%s: %s", p, strerror(errno));
859 return gpg_error_from_errno(error);
862 else
864 * xml_import() from command line.
866 fd = STDOUT_FILENO;
868 len = pth_write(fd, &file_header, sizeof(struct file_header_s));
870 if (len != sizeof(file_header)) {
871 len = errno;
873 if (filename)
874 close(fd);
876 gcry_free(inbuf);
877 return gpg_error_from_errno(len);
880 len = pth_write(fd, inbuf, insize);
882 if (len != insize) {
883 len = errno;
885 if (filename)
886 close(fd);
888 gcry_free(inbuf);
889 return gpg_error_from_errno(len);
892 if (fsync(fd) == -1) {
893 len = errno;
894 close(fd);
895 gcry_free(inbuf);
896 return gpg_error_from_errno(len);
899 if (filename) {
900 struct stat st;
901 mode_t mode = 0;
903 close(fd);
905 if (stat(filename, &st) == 0)
906 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
908 if (rename(tmp, filename) == -1) {
909 len = errno;
910 gcry_free(inbuf);
911 return gpg_error_from_errno(len);
914 if (mode)
915 chmod(filename, mode);
918 gcry_free(inbuf);
919 return 0;
922 static gpg_error_t save_command_finalize(assuan_context_t ctx,
923 guchar shakey[], gboolean cached)
925 struct client_s *client = assuan_get_pointer(ctx);
926 gpointer xmlbuf;
927 xmlChar *p;
928 gint len;
929 gint iter;
930 gint timeout;
931 gpointer outbuf;
932 glong outsize = 0;
933 gint zerror;
934 gpg_error_t error;
935 struct stat st;
937 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
938 xmlbuf = p;
940 iter = get_key_file_integer(client->filename, "compression_level");
942 if (iter < 0)
943 iter = 0;
945 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
946 memset(shakey, 0, sizeof(shakey));
947 xmlFree(xmlbuf);
949 if (zerror == Z_MEM_ERROR) {
950 return send_syserror(ctx, ENOMEM);
952 else
953 return send_error(ctx, GPG_ERR_COMPR_ALGO);
955 else {
956 gcry_free(xmlbuf);
957 xmlbuf = outbuf;
958 len = outsize;
961 iter = get_key_file_integer(client->filename, "iterations");
962 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
964 if (error) {
965 memset(shakey, 0, sizeof(shakey));
966 return send_error(ctx, error);
969 stat(client->filename, &st);
970 client->mtime = st.st_mtime;
971 timeout = get_key_file_integer(client->filename, "cache_timeout");
972 CACHE_LOCK(client->ctx);
974 if (cached) {
975 memset(shakey, 0, sizeof(shakey));
976 cache_reset_timeout(client->md5file, timeout);
977 CACHE_UNLOCK;
979 if (client->new == TRUE)
980 send_cache_status_all();
982 client->new = FALSE;
983 return send_error(ctx, 0);
986 if (cache_update_key(client->md5file, shakey) == FALSE) {
987 memset(shakey, 0, sizeof(shakey));
988 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
989 CACHE_UNLOCK;
990 return send_error(ctx, EPWMD_MAX_SLOTS);
993 client->new = FALSE;
994 memset(shakey, 0, sizeof(shakey));
995 cache_reset_timeout(client->md5file, timeout);
996 CACHE_UNLOCK;
997 send_cache_status_all();
998 return send_error(ctx, 0);
1001 static int save_command(assuan_context_t ctx, char *line)
1003 gboolean cached = FALSE;
1004 guchar shakey[gcrykeysize];
1005 struct stat st;
1006 struct client_s *client = assuan_get_pointer(ctx);
1007 gpg_error_t error;
1009 error = file_modified(client);
1011 if (error) {
1012 log_write("%s: %s", client->filename ? client->filename : "",
1013 pwmd_strerror(error));
1014 return send_error(ctx, error);
1017 error = lock_file_mutex(client);
1019 if (error)
1020 return send_error(ctx, error);
1022 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1023 return send_syserror(ctx, errno);
1025 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1026 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1027 return send_error(ctx, EPWMD_INVALID_FILENAME);
1030 if (!line || !*line) {
1031 CACHE_LOCK(ctx);
1033 if (cache_get_key(client->md5file, shakey) == FALSE) {
1034 CACHE_UNLOCK;
1035 #ifdef WITH_PINENTRY
1036 if (client->pinentry->use == FALSE)
1037 return send_error(ctx, EPWMD_KEY);
1039 error = pinentry_fork(ctx);
1041 if (error)
1042 return send_error(ctx, error);
1044 client->pinentry->cb = save_command_finalize;
1045 client->pinentry->status = PINENTRY_INIT;
1046 return 0;
1047 #else
1048 return send_error(ctx, EPWMD_KEY);
1049 #endif
1052 CACHE_UNLOCK;
1053 cached = TRUE;
1055 else {
1056 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1057 memset(line, 0, strlen(line));
1060 return save_command_finalize(ctx, shakey, cached);
1063 static gboolean contains_whitespace(const gchar *str)
1065 const gchar *p = str;
1066 gunichar c;
1067 glong len;
1069 len = g_utf8_strlen(p++, -1) -1;
1071 while (len--) {
1072 c = g_utf8_get_char(p++);
1074 if (g_unichar_isspace(c))
1075 return TRUE;
1078 return FALSE;
1081 static int delete_command(assuan_context_t ctx, char *line)
1083 struct client_s *client = assuan_get_pointer(ctx);
1084 gchar **req;
1085 gpg_error_t error;
1086 xmlNodePtr n;
1088 error = file_modified(client);
1090 if (error) {
1091 log_write("%s: %s", client->filename ? client->filename : "",
1092 pwmd_strerror(error));
1093 return send_error(ctx, error);
1096 if (strchr(line, '\t'))
1097 req = split_input_line(line, "\t", -1);
1098 else
1099 req = split_input_line(line, " ", -1);
1101 if (!req || !*req)
1102 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1104 n = find_account(client->doc, &req, &error, NULL, 0);
1106 if (!n) {
1107 g_strfreev(req);
1108 return send_error(ctx, error);
1112 * No sub-node defined. Remove the entire node (account).
1114 if (!req[1]) {
1115 if (n) {
1116 xmlUnlinkNode(n);
1117 xmlFreeNode(n);
1120 g_strfreev(req);
1121 return send_error(ctx, 0);
1124 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1125 g_strfreev(req);
1127 if (!n)
1128 return send_error(ctx, error);
1130 if (n) {
1131 xmlUnlinkNode(n);
1132 xmlFreeNode(n);
1135 return send_error(ctx, 0);
1139 * Don't return with assuan_process_done() here. This has been called from
1140 * assuan_process_next() and the command should be finished in
1141 * client_thread().
1143 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1144 gsize len)
1146 assuan_context_t ctx = data;
1147 struct client_s *client = assuan_get_pointer(ctx);
1148 gchar **req;
1149 guchar *result = line;
1150 xmlNodePtr n;
1151 gpg_error_t error = file_modified(client);
1153 if (rc) {
1154 if (line)
1155 #ifndef MEM_DEBUG
1156 xfree(line);
1157 #else
1158 free(line);
1159 #endif
1160 return rc;
1163 req = split_input_line((gchar *)result, "\t", 0);
1164 #ifndef MEM_DEBUG
1165 xfree(line);
1166 #else
1167 free(line);
1168 #endif
1170 if (rc) {
1171 if (req)
1172 g_strfreev(req);
1174 return rc;
1177 if (!req || !*req)
1178 return EPWMD_COMMAND_SYNTAX;
1180 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1181 g_strfreev(req);
1182 return EPWMD_INVALID_ELEMENT;
1185 if (valid_element_path(req+1, TRUE) == FALSE) {
1186 g_strfreev(req);
1187 return EPWMD_INVALID_ELEMENT;
1190 again:
1191 n = find_account(client->doc, &req, &error, NULL, 0);
1193 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1194 error = new_account(client->doc, *req);
1196 if (error) {
1197 g_strfreev(req);
1198 return error;
1201 goto again;
1204 if (!n) {
1205 g_strfreev(req);
1206 return error;
1209 if (req[1]) {
1210 if (!n->children)
1211 create_elements_cb(n, req+1, &error, NULL);
1212 else
1213 find_elements(client->doc, n->children, req+1, &error,
1214 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1217 g_strfreev(req);
1218 client->inquire_status = INQUIRE_DONE;
1219 return error;
1222 static int store_command(assuan_context_t ctx, char *line)
1224 struct client_s *client = assuan_get_pointer(ctx);
1225 gpg_error_t error = file_modified(client);
1227 if (error) {
1228 log_write("%s: %s", client->filename ? client->filename : "",
1229 pwmd_strerror(error));
1230 return send_error(ctx, error);
1233 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1235 if (error)
1236 return send_error(ctx, error);
1238 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1239 client->inquire_status = INQUIRE_BUSY;
1240 return 0;
1243 static int get_command(assuan_context_t ctx, char *line)
1245 struct client_s *client = assuan_get_pointer(ctx);
1246 gchar **req;
1247 gpg_error_t error;
1248 xmlNodePtr n;
1250 error = file_modified(client);
1252 if (error) {
1253 log_write("%s: %s", client->filename ? client->filename : "",
1254 pwmd_strerror(error));
1255 return send_error(ctx, error);
1258 req = split_input_line(line, "\t", -1);
1260 if (!req || !*req) {
1261 g_strfreev(req);
1262 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1265 n = find_account(client->doc, &req, &error, NULL, 0);
1267 if (!n) {
1268 g_strfreev(req);
1269 return send_error(ctx, error);
1272 if (req[1])
1273 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1275 g_strfreev(req);
1277 if (error)
1278 return send_error(ctx, error);
1280 if (!n || !n->children)
1281 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1283 n = n->children;
1285 if (!n || !n->content || !*n->content)
1286 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1288 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1289 return send_error(ctx, error);
1292 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
1294 xmlChar *p = path;
1295 gint n;
1296 gchar *buf;
1298 if (!p)
1299 return NULL;
1301 for (n = 0; *p && n < 3; p++) {
1302 if (*p == '/')
1303 n++;
1306 if (strstr((gchar *)p, "text()") != NULL)
1307 p[xmlStrlen(p) - 7] = 0;
1309 for (n = 0; p[n]; n++) {
1310 if (p[n] == '/')
1311 p[n] = '\t';
1314 buf = g_strdup_printf("%s\t%s", account, p);
1315 p = (xmlChar *)buf + strlen(buf) - 1;
1317 while (isspace(*p))
1318 *p-- = 0;
1320 return buf;
1323 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
1325 gchar **a;
1326 va_list ap;
1327 gchar *buf;
1328 gint len = *array ? g_strv_length(*array) : 0;
1329 gint ret;
1331 if (!fmt)
1332 return FALSE;
1334 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL)
1335 return FALSE;
1337 va_start(ap, fmt);
1338 ret = g_vasprintf(&buf, fmt, ap);
1339 va_end(ap);
1341 if (ret == -1)
1342 return FALSE;
1344 a[len++] = buf;
1345 a[len] = NULL;
1346 *array = a;
1347 return TRUE;
1350 struct realpath_s {
1351 gchar *account;
1354 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **req,
1355 gpg_error_t *error, void *data)
1357 struct realpath_s *rp = data;
1359 if (rp->account)
1360 g_free(rp->account);
1362 rp->account = g_strdup(req[0]);
1364 if (!rp->account) {
1365 *error = gpg_error_from_errno(ENOMEM);
1366 return NULL;
1369 return node;
1372 static int realpath_command(assuan_context_t ctx, char *line)
1374 gpg_error_t error;
1375 struct client_s *client = assuan_get_pointer(ctx);
1376 xmlChar *p;
1377 gchar **req;
1378 gchar *result, *t;
1379 gint i;
1380 xmlNodePtr n;
1381 struct realpath_s *rp;
1382 GString *string;
1384 error = file_modified(client);
1386 if (error) {
1387 log_write("%s: %s", client->filename ? client->filename : "",
1388 pwmd_strerror(error));
1389 return send_error(ctx, error);
1392 if (strchr(line, '\t') != NULL) {
1393 if ((req = split_input_line(line, "\t", 0)) == NULL)
1394 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1396 else {
1397 if ((req = split_input_line(line, " ", 0)) == NULL)
1398 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1401 n = find_account(client->doc, &req, &error, NULL, 0);
1403 if (!n) {
1404 g_strfreev(req);
1405 return send_error(ctx, error);
1408 rp = g_malloc(sizeof(struct realpath_s));
1410 if (!rp) {
1411 g_strfreev(req);
1412 return send_syserror(ctx, ENOMEM);
1415 rp->account = g_strdup(req[0]);
1417 if (!rp->account) {
1418 g_strfreev(req);
1419 return send_syserror(ctx, ENOMEM);
1422 if (req[1]) {
1423 n = find_elements(client->doc, n->children, req+1, &error,
1424 NULL, realpath_elements_cb, NULL, FALSE, 0, rp);
1426 if (!n) {
1427 g_free(rp->account);
1428 g_free(rp);
1429 g_strfreev(req);
1430 return send_error(ctx, error);
1434 p = xmlGetNodePath(n);
1435 result = element_path_to_req(rp->account, p);
1437 if (!result) {
1438 g_free(result);
1439 g_free(rp->account);
1440 g_free(rp);
1441 g_strfreev(req);
1442 xmlFree(p);
1443 return send_syserror(ctx, ENOMEM);
1446 string = g_string_new(result);
1447 g_free(result);
1448 g_free(rp->account);
1449 g_free(rp);
1450 g_strfreev(req);
1451 xmlFree(p);
1452 i = 0;
1454 again:
1455 for (t = string->str + i; *t; t++, i++) {
1456 if ((!i && *t != '!') || *t == '\t') {
1457 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1458 goto again;
1462 error = assuan_send_data(ctx, string->str, string->len);
1463 g_string_free(string, TRUE);
1464 return send_error(ctx, error);
1467 struct list_element_s {
1468 GSList *list;
1469 gchar **elements;
1472 static gboolean append_to_element_list(struct list_element_s *elements)
1474 gchar *tmp;
1475 gint i, total;
1476 gchar *a;
1477 GSList *list;
1479 if (!elements || !elements->elements)
1480 return TRUE;
1482 tmp = g_strjoinv("\t", elements->elements);
1484 if (!tmp)
1485 return FALSE;
1487 g_strfreev(elements->elements);
1488 elements->elements = NULL;
1489 total = g_slist_length(elements->list);
1490 a = g_utf8_collate_key(tmp, -1);
1492 if (!a) {
1493 g_free(tmp);
1494 return FALSE;
1498 * Removes duplicate element paths from the list. This is needed when
1499 * appending an element tree from list_command(). The glib docs recommend
1500 * using g_utf8_collate_key() for a large number of strings.
1502 for (i = 0; i < total; i++) {
1503 gchar *p = g_slist_nth_data(elements->list, i);
1504 gchar *b = g_utf8_collate_key(p, -1);
1506 if (!b) {
1507 g_free(a);
1508 g_free(tmp);
1509 return FALSE;
1512 if (strcmp(a, b) == 0) {
1513 g_free(a);
1514 g_free(b);
1515 g_free(tmp);
1516 return TRUE;
1519 g_free(b);
1522 g_free(a);
1523 list = g_slist_append(elements->list, tmp);
1525 if (!list)
1526 return FALSE;
1528 elements->list = list;
1529 return TRUE;
1532 static gpg_error_t do_list_recurse(xmlDocPtr doc, xmlNodePtr node,
1533 struct list_element_s *elements, gchar *prefix)
1535 xmlNodePtr n;
1536 gpg_error_t error;
1538 if (append_to_element_list(elements) == FALSE)
1539 return gpg_error_from_errno(ENOMEM);
1541 for (n = node; n; n = n->next) {
1542 if (n->type == XML_ELEMENT_NODE) {
1543 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
1544 gchar *tmp;
1546 if (content) {
1547 if (strv_printf(&elements->elements, "%s\t%s", prefix, n->name) == FALSE)
1548 return gpg_error_from_errno(ENOMEM);
1550 if (append_to_element_list(elements) == FALSE)
1551 return gpg_error_from_errno(ENOMEM);
1554 tmp = g_strdup_printf("%s\t!%s", prefix, n->name);
1556 if (!tmp)
1557 return gpg_error_from_errno(ENOMEM);
1559 if (strv_printf(&elements->elements, "%s", tmp) == FALSE) {
1560 g_free(tmp);
1561 return gpg_error_from_errno(ENOMEM);
1564 if (n->children) {
1565 error = do_list_recurse(doc, n->children, elements, tmp);
1566 g_free(tmp);
1568 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1569 return error;
1571 else
1572 g_free(tmp);
1574 if (append_to_element_list(elements) == FALSE)
1575 return gpg_error_from_errno(ENOMEM);
1579 return 0;
1582 static gpg_error_t do_list_command(assuan_context_t ctx, xmlDocPtr doc,
1583 struct list_element_s *elements, char *line)
1585 gchar *prefix = NULL, *account;
1586 gchar **req = NULL, **oreq = NULL, *tmp;
1587 xmlNodePtr n;
1588 gboolean account_is_literal, account_has_target = FALSE;
1589 gint which = 0;
1590 gchar **p;
1591 gpg_error_t error;
1593 if ((req = split_input_line(line, "\t", 0)) == NULL) {
1594 if ((req = split_input_line(line, " ", 0)) == NULL)
1595 return EPWMD_COMMAND_SYNTAX;
1598 prefix = g_strdup(*req);
1600 if (!prefix) {
1601 g_strfreev(req);
1602 return gpg_error_from_errno(ENOMEM);
1605 account = g_strdup(*req);
1607 if (!account) {
1608 g_free(prefix);
1609 g_strfreev(req);
1610 return gpg_error_from_errno(ENOMEM);
1613 oreq = g_strdupv(req);
1615 if (!oreq) {
1616 g_free(prefix);
1617 g_free(account);
1618 g_strfreev(req);
1619 return gpg_error_from_errno(ENOMEM);
1622 p = req;
1623 again:
1624 account_has_target = FALSE;
1625 account_is_literal = is_literal_element_str(prefix);
1626 n = find_account(doc, &p, &error, &account_has_target, 0);
1628 if (which)
1629 oreq = p;
1630 else
1631 req = p;
1633 if (!n)
1634 goto fail;
1636 if (!which && account_is_literal == FALSE && account_has_target == FALSE) {
1637 tmp = g_strdup_printf("!%s", prefix);
1639 if (!tmp) {
1640 error = gpg_error_from_errno(ENOMEM);
1641 goto fail;
1644 g_free(prefix);
1645 prefix = tmp;
1648 if (*(p+1)) {
1649 gchar *t;
1651 n = find_elements(doc, n->children, p+1, &error, NULL, NULL, NULL,
1652 TRUE, 0, NULL);
1654 if (error)
1655 goto fail;
1657 tmp = g_strjoinv("\t", p+1);
1658 if (!tmp) {
1659 error = gpg_error_from_errno(ENOMEM);
1660 goto fail;
1663 t = g_strdup_printf("%s\t%s", prefix, tmp);
1664 if (!t) {
1665 error = gpg_error_from_errno(ENOMEM);
1666 goto fail;
1669 g_free(prefix);
1670 prefix = t;
1671 g_free(tmp);
1674 if (strv_printf(&elements->elements, "%s", prefix) == FALSE) {
1675 error = gpg_error_from_errno(ENOMEM);
1676 goto fail;
1679 if (node_has_child_element(n->children) == FALSE) {
1680 if (append_to_element_list(elements) == FALSE) {
1681 error = gpg_error_from_errno(ENOMEM);
1682 goto fail;
1685 else
1686 error = do_list_recurse(doc, n->children, elements, prefix);
1688 if (error)
1689 goto fail;
1691 if (!which++ && !*(p+1) && account_is_literal == FALSE && account_has_target == TRUE) {
1692 g_free(*oreq);
1693 *oreq = g_strdup_printf("!%s", account);
1695 if (!*oreq) {
1696 error = gpg_error_from_errno(ENOMEM);
1697 goto fail;
1700 p = oreq;
1701 g_free(prefix);
1702 prefix = g_strdup(*oreq);
1704 if (!prefix) {
1705 error = gpg_error_from_errno(ENOMEM);
1706 goto fail;
1709 goto again;
1712 fail:
1713 g_free(prefix);
1714 g_free(account);
1715 g_strfreev(req);
1717 if (oreq)
1718 g_strfreev(oreq);
1720 return error;
1724 * This could be faster especially when finding "target" attributes.
1726 static int list_command(assuan_context_t ctx, char *line)
1728 struct client_s *client = assuan_get_pointer(ctx);
1729 gpg_error_t error;
1730 struct list_element_s *elements = NULL;
1731 GString *string;
1732 gchar *tmp;
1733 gint i, total;
1735 if (disable_list_and_dump == TRUE)
1736 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1738 error = file_modified(client);
1740 if (error) {
1741 log_write("%s: %s", client->filename, pwmd_strerror(error));
1742 return send_error(ctx, error);
1745 if (!*line) {
1746 GString *str;
1748 error = list_accounts(client->doc, &str);
1750 if (error)
1751 return send_error(ctx, error);
1753 error = assuan_send_data(ctx, str->str, str->len);
1754 g_string_free(str, TRUE);
1755 return send_error(ctx, error);
1758 elements = g_malloc0(sizeof(struct list_element_s));
1760 if (!elements) {
1761 error = gpg_error_from_errno(ENOMEM);
1762 goto fail;
1765 error = do_list_command(ctx, client->doc, elements, line);
1767 if (error)
1768 goto fail;
1770 if (!error) {
1771 total = g_slist_length(elements->list);
1773 if (!total) {
1774 error = EPWMD_EMPTY_ELEMENT;
1775 goto fail;
1779 * Find element paths with a target and append those element trees to
1780 * the list.
1782 for (i = 0; i < total; i++) {
1783 gchar **req;
1785 tmp = g_slist_nth_data(elements->list, i);
1786 req = split_input_line(tmp, "\t", 0);
1788 if (!req) {
1789 if (g_str_has_prefix(tmp, "!") == TRUE) {
1790 g_strfreev(req);
1791 continue;
1794 else {
1795 gchar **p;
1797 for (p = req; *p; p++) {
1798 if (g_str_has_prefix(*p, "!") == FALSE)
1799 break;
1802 if (!*p) {
1803 g_strfreev(req);
1804 continue;
1808 g_strfreev(req);
1809 error = do_list_command(ctx, client->doc, elements, tmp);
1811 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1812 goto fail;
1814 total = g_slist_length(elements->list);
1818 string = g_string_new(NULL);
1820 for (i = 0; i < total; i++) {
1821 tmp = g_slist_nth_data(elements->list, i);
1822 g_string_append_printf(string, "%s\n", tmp);
1823 g_free(tmp);
1826 string = g_string_truncate(string, string->len - 1);
1827 error = assuan_send_data(ctx, string->str, string->len);
1828 g_string_free(string, TRUE);
1830 fail:
1831 if (elements) {
1832 if (elements->list)
1833 g_slist_free(elements->list);
1835 if (elements->elements)
1836 g_strfreev(elements->elements);
1838 g_free(elements);
1841 return send_error(ctx, error);
1844 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1845 const gchar *value)
1847 xmlAttrPtr a;
1849 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1850 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1852 if (!a)
1853 return EPWMD_LIBXML_ERROR;
1855 else
1856 xmlNodeSetContent(a->children, (xmlChar *)value);
1858 return 0;
1862 * req[0] - element path
1864 static int attribute_list(assuan_context_t ctx, gchar **req)
1866 struct client_s *client = assuan_get_pointer(ctx);
1867 gchar **attrlist = NULL;
1868 gint i = 0;
1869 gchar **path = NULL;
1870 xmlAttrPtr a;
1871 xmlNodePtr n, an;
1872 gchar *line;
1873 gpg_error_t error;
1875 if (!req || !req[0])
1876 return EPWMD_COMMAND_SYNTAX;
1878 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1880 * The first argument may be only an account.
1882 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1883 return EPWMD_COMMAND_SYNTAX;
1886 n = find_account(client->doc, &path, &error, NULL, 0);
1888 if (!n) {
1889 g_strfreev(path);
1890 return error;
1893 if (path[1]) {
1894 n = find_elements(client->doc, n->children, path+1, &error,
1895 NULL, NULL, NULL, FALSE, 0, NULL);
1897 if (!n) {
1898 g_strfreev(path);
1899 return error;
1903 g_strfreev(path);
1905 for (a = n->properties; a; a = a->next) {
1906 gchar **pa;
1908 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1909 if (attrlist)
1910 g_strfreev(attrlist);
1912 error = errno;
1913 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
1914 return gpg_error_from_errno(error);
1917 attrlist = pa;
1918 an = a->children;
1919 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1921 if (!attrlist[i]) {
1922 g_strfreev(attrlist);
1923 return gpg_error_from_errno(ENOMEM);
1926 attrlist[++i] = NULL;
1929 if (!attrlist)
1930 return EPWMD_EMPTY_ELEMENT;
1932 line = g_strjoinv("\n", attrlist);
1934 if (!line) {
1935 g_strfreev(attrlist);
1936 return gpg_error_from_errno(ENOMEM);
1939 error = assuan_send_data(ctx, line, strlen(line));
1940 g_free(line);
1941 g_strfreev(attrlist);
1942 return error;
1946 * req[0] - attribute
1947 * req[1] - element path
1949 static int attribute_delete(struct client_s *client, gchar **req)
1951 xmlAttrPtr a;
1952 xmlNodePtr n;
1953 gchar **path = NULL;
1954 gpg_error_t error;
1956 if (!req || !req[0] || !req[1])
1957 return EPWMD_COMMAND_SYNTAX;
1959 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1961 * The first argument may be only an account.
1963 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1964 return EPWMD_COMMAND_SYNTAX;
1968 * Don't remove the "name" attribute for the account element. To remove an
1969 * account use DELETE <account>.
1971 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1972 error = EPWMD_ATTR_SYNTAX;
1973 goto fail;
1976 n = find_account(client->doc, &path, &error, NULL, 0);
1978 if (!n)
1979 goto fail;
1981 if (path[1]) {
1982 n = find_elements(client->doc, n->children, path+1, &error,
1983 NULL, NULL, NULL, FALSE, 0, NULL);
1985 if (!n)
1986 goto fail;
1989 g_strfreev(path);
1991 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1992 return EPWMD_ATTR_NOT_FOUND;
1994 if (xmlRemoveProp(a) == -1)
1995 return EPWMD_LIBXML_ERROR;
1997 return 0;
1999 fail:
2000 g_strfreev(path);
2001 return error;
2005 * Creates a "target" attribute. When other commands encounter an element with
2006 * this attribute, the element path is modified to the target value. If the
2007 * source element path doesn't exist when using 'ATTR SET target', it is
2008 * created, but the destination element path must exist.
2010 * req[0] - source element path
2011 * req[1] - destination element path
2013 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2015 gchar **src, **dst, *line = NULL;
2016 gpg_error_t error;
2017 xmlNodePtr n;
2019 if (!req || !req[0] || !req[1])
2020 return EPWMD_COMMAND_SYNTAX;
2022 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2024 * The first argument may be only an account.
2026 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2027 return EPWMD_COMMAND_SYNTAX;
2030 if (valid_element_path(src, FALSE) == FALSE) {
2031 g_strfreev(src);
2032 return EPWMD_INVALID_ELEMENT;
2035 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2037 * The first argument may be only an account.
2039 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2040 error = EPWMD_COMMAND_SYNTAX;
2041 goto fail;
2045 n = find_account(client->doc, &dst, &error, NULL, 0);
2048 * Make sure the destination element path exists.
2050 if (!n)
2051 goto fail;
2053 if (dst[1]) {
2054 n = find_elements(client->doc, n->children, dst+1, &error,
2055 NULL, NULL, NULL, FALSE, 0, NULL);
2057 if (!n)
2058 goto fail;
2061 again:
2062 n = find_account(client->doc, &src, &error, NULL, 0);
2064 if (!n) {
2065 if (error == EPWMD_ELEMENT_NOT_FOUND) {
2066 error = new_account(client->doc, src[0]);
2068 if (error)
2069 goto fail;
2071 goto again;
2073 else
2074 goto fail;
2077 if (src[1]) {
2078 if (!n->children)
2079 n = create_target_elements_cb(n, src+1, &error, NULL);
2080 else
2081 n = find_elements(client->doc, n->children, src+1, &error,
2082 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2084 if (!n)
2085 goto fail;
2088 * Reset the position of the element tree now that the elements
2089 * have been created.
2091 n = find_account(client->doc, &src, &error, NULL, 0);
2093 if (!n)
2094 goto fail;
2096 n = find_elements(client->doc, n->children, src+1, &error,
2097 NULL, NULL, NULL, FALSE, 0, NULL);
2099 if (!n)
2100 goto fail;
2103 line = g_strjoinv("\t", dst);
2104 error = add_attribute(n, "target", line);
2106 fail:
2107 g_free(line);
2108 g_strfreev(src);
2109 g_strfreev(dst);
2110 return error;
2114 * req[0] - account name
2115 * req[1] - new name
2117 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2119 gpg_error_t error;
2120 gchar **tmp;
2121 xmlNodePtr n;
2123 tmp = g_strdupv(req);
2125 if (!tmp)
2126 return gpg_error_from_errno(ENOMEM);
2128 n = find_account(client->doc, &tmp, &error, NULL, 0);
2129 g_strfreev(tmp);
2131 if (!n)
2132 return error;
2134 if (g_utf8_collate(req[0], req[1]) == 0)
2135 return 0;
2138 * Will not overwrite an existing account.
2140 tmp = g_strdupv(req+1);
2142 if (!tmp)
2143 return gpg_error_from_errno(ENOMEM);
2145 n = find_account(client->doc, &tmp, &error, NULL, 0);
2146 g_strfreev(tmp);
2148 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
2149 return error;
2151 if (n)
2152 return EPWMD_ACCOUNT_EXISTS;
2155 * Whitespace not allowed in account names.
2157 if (contains_whitespace(req[1]) == TRUE)
2158 return EPWMD_ATTR_SYNTAX;
2160 tmp = g_strdupv(req);
2162 if (!tmp)
2163 return gpg_error_from_errno(ENOMEM);
2165 n = find_account(client->doc, &tmp, &error, NULL, 0);
2166 g_strfreev(tmp);
2168 if (!n)
2169 return EPWMD_ELEMENT_NOT_FOUND;
2171 return add_attribute(n, "name", req[1]);
2175 * req[0] - attribute
2176 * req[1] - element path
2178 static int attribute_get(assuan_context_t ctx, gchar **req)
2180 struct client_s *client = assuan_get_pointer(ctx);
2181 xmlNodePtr n;
2182 xmlChar *a;
2183 gchar **path= NULL;
2184 gpg_error_t error;
2186 if (!req || !req[0] || !req[1])
2187 return EPWMD_COMMAND_SYNTAX;
2189 if (strchr(req[1], '\t')) {
2190 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2191 return EPWMD_COMMAND_SYNTAX;
2193 else {
2194 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2195 return EPWMD_COMMAND_SYNTAX;
2198 n = find_account(client->doc, &path, &error, NULL, 0);
2200 if (!n)
2201 goto fail;
2203 if (path[1]) {
2204 n = find_elements(client->doc, n->children, path+1, &error,
2205 NULL, NULL, NULL, FALSE, 0, NULL);
2207 if (!n)
2208 goto fail;
2211 g_strfreev(path);
2213 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2214 return EPWMD_ATTR_NOT_FOUND;
2216 error = assuan_send_data(ctx, a, xmlStrlen(a));
2217 xmlFree(a);
2218 return error;
2220 fail:
2221 g_strfreev(path);
2222 return error;
2226 * req[0] - attribute
2227 * req[1] - element path
2228 * req[2] - value
2230 static int attribute_set(struct client_s *client, gchar **req)
2232 gchar **path = NULL;
2233 gpg_error_t error;
2234 xmlNodePtr n;
2236 if (!req || !req[0] || !req[1] || !req[2])
2237 return EPWMD_COMMAND_SYNTAX;
2240 * Reserved attribute names.
2242 if (g_utf8_collate(req[0], "name") == 0) {
2244 * Only reserved for the account element. Not the rest of the
2245 * document.
2247 if (strchr(req[1], '\t') == NULL)
2248 return name_attribute(client, req + 1);
2250 else if (g_utf8_collate(req[0], "target") == 0)
2251 return target_attribute(client, req + 1);
2253 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2255 * The first argument may be only an account.
2257 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2258 return EPWMD_COMMAND_SYNTAX;
2261 n = find_account(client->doc, &path, &error, NULL, 0);
2263 if (!n)
2264 goto fail;
2266 if (path[1]) {
2267 n = find_elements(client->doc, n->children, path+1, &error,
2268 NULL, NULL, NULL, FALSE, 0, NULL);
2270 if (!n)
2271 goto fail;
2274 g_strfreev(path);
2275 return add_attribute(n, req[0], req[2]);
2277 fail:
2278 g_strfreev(path);
2279 return error;
2283 * req[0] - command
2284 * req[1] - attribute name or element path if command is LIST
2285 * req[2] - element path
2286 * req[2] - element path or value
2288 static int attr_command(assuan_context_t ctx, char *line)
2290 struct client_s *client = assuan_get_pointer(ctx);
2291 gchar **req = split_input_line(line, " ", 4);
2292 gpg_error_t error = 0;
2294 error = file_modified(client);
2296 if (error) {
2297 log_write("%s: %s", client->filename ? client->filename : "",
2298 pwmd_strerror(error));
2299 g_strfreev(req);
2300 return send_error(ctx, error);
2303 if (!req || !req[0] || !req[1]) {
2304 g_strfreev(req);
2305 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2308 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2309 error = attribute_set(client, req+1);
2310 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2311 error = attribute_get(ctx, req+1);
2312 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2313 error = attribute_delete(client, req+1);
2314 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2315 error = attribute_list(ctx, req+1);
2316 else
2317 error = EPWMD_COMMAND_SYNTAX;
2319 g_strfreev(req);
2320 return send_error(ctx, error);
2323 static int iscached_command(assuan_context_t ctx, char *line)
2325 gchar **req = split_input_line(line, " ", 0);
2326 guchar md5file[16];
2328 if (!req || !*req) {
2329 g_strfreev(req);
2330 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2333 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2334 g_strfreev(req);
2335 CACHE_LOCK(ctx);
2337 if (cache_iscached(md5file) == FALSE) {
2338 CACHE_UNLOCK;
2339 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2342 CACHE_UNLOCK;
2343 return send_error(ctx, 0);
2346 gpg_error_t send_cache_status(assuan_context_t ctx)
2348 gchar *tmp;
2349 struct client_s *client = assuan_get_pointer(ctx);
2351 CACHE_LOCK(client->ctx);
2352 tmp = print_fmt("%i %i",
2353 cache_file_count(),
2354 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2355 CACHE_UNLOCK;
2357 return assuan_write_status(ctx, "CACHE", tmp);
2360 static int clearcache_command(assuan_context_t ctx, char *line)
2362 struct client_s *client = assuan_get_pointer(ctx);
2363 gchar **req = split_input_line(line, " ", 0);
2364 guchar md5file[16];
2366 CACHE_LOCK(ctx);
2368 if (!req || !*req) {
2369 g_strfreev(req);
2370 cache_clear(client->md5file, 2);
2371 CACHE_UNLOCK;
2372 return send_error(ctx, 0);
2375 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2376 g_strfreev(req);
2378 if (cache_clear(md5file, 1) == FALSE) {
2379 CACHE_UNLOCK;
2380 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2383 CACHE_UNLOCK;
2384 return send_error(ctx, 0);
2387 static int cachetimeout_command(assuan_context_t ctx, char *line)
2389 guchar md5file[16];
2390 glong timeout;
2391 gchar **req = split_input_line(line, " ", 0);
2392 gchar *p;
2393 struct client_s *client = assuan_get_pointer(ctx);
2395 if (!req || !*req || !req[1]) {
2396 g_strfreev(req);
2397 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2400 errno = 0;
2401 timeout = strtol(req[0], &p, 10);
2403 if (errno != 0 || *p != 0) {
2404 g_strfreev(req);
2405 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2408 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2409 g_strfreev(req);
2410 CACHE_LOCK(client->ctx);
2412 if (cache_set_timeout(md5file, timeout) == FALSE) {
2413 CACHE_UNLOCK;
2414 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2417 CACHE_UNLOCK;
2418 send_cache_status_all();
2419 return send_error(ctx, 0);
2422 static int dump_command(assuan_context_t ctx, char *line)
2424 xmlChar *xml;
2425 gssize len;
2426 struct client_s *client = assuan_get_pointer(ctx);
2427 gpg_error_t error;
2429 if (disable_list_and_dump == TRUE)
2430 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2432 error = file_modified(client);
2434 if (error) {
2435 log_write("%s: %s", client->filename ? client->filename : "",
2436 pwmd_strerror(error));
2437 return send_error(ctx, error);
2440 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2441 error = assuan_send_data(ctx, xml, len);
2442 xmlFree(xml);
2443 return send_error(ctx, error);
2446 static int getconfig_command(assuan_context_t ctx, gchar *line)
2448 struct client_s *client = assuan_get_pointer(ctx);
2449 gpg_error_t error = 0;
2450 gchar *p, *tmp;
2452 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2453 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2455 p = get_key_file_string(client->filename ? client->filename : "default", line);
2457 if (!p)
2458 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2460 tmp = expand_homedir(p);
2461 g_free(p);
2462 p = tmp;
2463 error = assuan_send_data(ctx, p, strlen(p));
2464 g_free(p);
2465 return send_error(ctx, error);
2468 void cleanup_assuan(assuan_context_t ctx)
2470 struct client_s *cl = assuan_get_pointer(ctx);
2472 cleanup_client(cl);
2475 static void reset_notify(assuan_context_t ctx)
2477 struct client_s *cl = assuan_get_pointer(ctx);
2479 cleanup_client(cl);
2482 static int option_handler(assuan_context_t ctx, const gchar *name,
2483 const gchar *value)
2485 struct client_s *client = assuan_get_pointer(ctx);
2487 if (!value || !*value)
2488 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2490 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2491 if (client->pinentry->ttyname)
2492 xfree(client->pinentry->ttyname);
2493 client->pinentry->ttyname = xstrdup(value);
2495 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2496 if (client->pinentry->ttytype)
2497 xfree(client->pinentry->ttytype);
2498 client->pinentry->ttytype = xstrdup(value);
2500 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2501 if (client->pinentry->display)
2502 xfree(client->pinentry->display);
2503 client->pinentry->display = xstrdup(value);
2505 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2506 if (client->pinentry->path)
2507 xfree(client->pinentry->path);
2508 client->pinentry->path = xstrdup(value);
2510 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2511 if (client->pinentry->title)
2512 xfree(client->pinentry->title);
2513 client->pinentry->title = xstrdup(value);
2515 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2516 if (client->pinentry->prompt)
2517 xfree(client->pinentry->prompt);
2518 client->pinentry->prompt = xstrdup(value);
2520 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2521 if (client->pinentry->desc)
2522 xfree(client->pinentry->desc);
2523 client->pinentry->desc = xstrdup(value);
2525 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2526 gchar *p = NULL;
2527 gint n = strtol(value, &p, 10);
2529 if (*p || n < 0)
2530 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2532 client->pinentry->timeout = n;
2534 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2535 gchar *p = NULL;
2536 gint n = strtol(value, &p, 10);
2538 if (*p || n < 0 || n > 1)
2539 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2541 client->pinentry->use = n == 0 ? FALSE : TRUE;
2543 else
2544 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2546 return 0;
2549 gpg_error_t register_commands(assuan_context_t ctx)
2551 static struct {
2552 const char *name;
2553 int (*handler)(assuan_context_t, char *line);
2554 } table[] = {
2555 { "OPEN", open_command },
2556 { "SAVE", save_command },
2557 { "LIST", list_command },
2558 { "REALPATH", realpath_command },
2559 { "STORE", store_command },
2560 { "DELETE", delete_command },
2561 { "GET", get_command },
2562 { "ATTR", attr_command },
2563 { "ISCACHED", iscached_command },
2564 { "CLEARCACHE", clearcache_command },
2565 { "CACHETIMEOUT", cachetimeout_command },
2566 { "GETCONFIG", getconfig_command },
2567 { "DUMP", dump_command },
2568 { "INPUT", NULL },
2569 { "OUTPUT", NULL },
2570 { NULL, NULL }
2572 int i, rc;
2574 for (i=0; table[i].name; i++) {
2575 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2577 if (rc)
2578 return rc;
2581 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2582 if (rc)
2583 return rc;
2585 rc = assuan_register_option_handler(ctx, option_handler);
2586 if (rc)
2587 return rc;
2589 return assuan_register_reset_notify(ctx, reset_notify);
2592 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2593 guchar *key)
2595 guchar *iv;
2596 void *inbuf;
2597 gsize insize, len;
2598 guchar tkey[gcrykeysize];
2599 struct file_header_s {
2600 guint iter;
2601 guchar iv[gcryblocksize];
2602 } file_header;
2603 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2604 gcry_cipher_hd_t gh;
2605 guint iter = 0, n_iter = 0;
2606 gint iter_progress;
2607 void *outbuf = NULL;
2608 gint zerror = 0;
2609 glong outsize = 0;
2610 gpg_error_t error;
2612 if (!ctx) {
2613 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2615 if (error)
2616 return error;
2618 else
2619 gh = client->gh;
2621 lseek(fd, 0, SEEK_SET);
2622 insize = st.st_size - sizeof(struct file_header_s);
2623 iv = gcry_malloc(gcryblocksize);
2625 if (!iv) {
2626 if (!ctx)
2627 gcry_cipher_close(gh);
2629 return gpg_error_from_errno(ENOMEM);
2632 len = pth_read(fd, &file_header, sizeof(struct file_header_s));
2634 if (len != sizeof(file_header)) {
2635 len = errno;
2637 if (!ctx)
2638 gcry_cipher_close(gh);
2640 gcry_free(iv);
2641 errno = len;
2642 return gpg_error_from_errno(errno);
2645 /* No encryption iterations. This is a plain (gzipped) file. */
2646 if (file_header.iter == -1)
2647 insize = st.st_size - sizeof(struct file_header_s);
2649 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2650 inbuf = gcry_malloc(insize);
2652 if (!inbuf) {
2653 if (!ctx)
2654 gcry_cipher_close(gh);
2656 gcry_free(iv);
2657 return gpg_error_from_errno(ENOMEM);
2660 len = pth_read(fd, inbuf, insize);
2662 if (len != insize) {
2663 len = errno;
2665 if (!ctx)
2666 gcry_cipher_close(gh);
2668 gcry_free(iv);
2669 errno = len;
2670 return gpg_error_from_errno(errno);
2673 if (file_header.iter == -1)
2674 goto decompress;
2676 memcpy(tkey, key, sizeof(tkey));
2677 tkey[0] ^= 1;
2679 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2680 if (!ctx) {
2681 gcry_cipher_close(gh);
2682 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2684 else
2685 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2687 gcry_free(inbuf);
2688 gcry_free(iv);
2689 return error;
2692 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2693 if (!ctx) {
2694 gcry_cipher_close(gh);
2695 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2697 else
2698 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2700 gcry_free(inbuf);
2701 gcry_free(iv);
2703 if (!ctx)
2704 gcry_cipher_close(gh);
2706 return error;
2709 iter_progress = get_key_file_integer("default", "iteration_progress");
2711 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2712 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2714 if (error) {
2715 gcry_free(inbuf);
2716 gcry_free(iv);
2717 return error;
2721 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2723 if (error) {
2724 gcry_free(inbuf);
2725 gcry_free(iv);
2726 return error;
2729 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2730 if (!ctx) {
2731 gcry_cipher_close(gh);
2732 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2734 else
2735 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2737 gcry_free(inbuf);
2738 gcry_free(iv);
2739 return error;
2742 while (iter < file_header.iter) {
2743 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2744 if (!(iter % iter_progress)) {
2745 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i",
2746 ++n_iter * iter_progress));
2748 if (error) {
2749 gcry_free(inbuf);
2750 gcry_free(iv);
2751 return error;
2756 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2757 if (!ctx) {
2758 gcry_cipher_close(gh);
2759 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2761 else
2762 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2764 gcry_free(inbuf);
2765 gcry_free(iv);
2766 return error;
2769 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2771 if (error) {
2772 if (!ctx) {
2773 gcry_cipher_close(gh);
2774 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2776 else
2777 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2779 gcry_free(inbuf);
2780 gcry_free(iv);
2781 return error;
2784 iter++;
2785 pth_yield(NULL);
2788 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2789 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i", file_header.iter));
2791 if (error) {
2792 gcry_free(inbuf);
2793 gcry_free(iv);
2794 return error;
2798 gcry_free(iv);
2800 decompress:
2801 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2803 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2805 if (zerror == Z_MEM_ERROR) {
2806 gcry_free(inbuf);
2807 return gpg_error_from_errno(ENOMEM);
2809 else if (zerror != Z_DATA_ERROR) {
2810 gcry_free(inbuf);
2812 if (!ctx)
2813 gcry_cipher_close(gh);
2815 return EPWMD_BADKEY;
2818 else {
2819 gcry_free(inbuf);
2820 inbuf = outbuf;
2821 insize = outsize;
2824 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2825 gcry_free(inbuf);
2827 if (!ctx)
2828 gcry_cipher_close(gh);
2830 return EPWMD_BADKEY;
2833 if (ctx) {
2834 client->xml = inbuf;
2835 client->len = insize;
2837 else {
2838 gcry_cipher_close(gh);
2839 gcry_free(inbuf);
2842 return 0;
2846 * This is called after every Assuan command.
2848 void command_finalize(assuan_context_t ctx, gint error)
2850 struct client_s *client = assuan_get_pointer(ctx);
2852 unlock_file_mutex(client);