Don't require a key when iterations == -1.
[pwmd.git] / src / commands.c
blobd3d3d827db8db4ed1c974d06e331dd26db30cb5e
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_NONE)
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 read_file_header(const gchar *filename, file_header_t *fh)
373 gint fd;
374 gsize len;
376 fd = open(filename, O_RDONLY);
378 if (fd == -1)
379 return gpg_error_from_errno(errno);
381 len = pth_read(fd, fh, sizeof(file_header_t));
382 close(fd);
384 if (len != sizeof(file_header_t))
385 return gpg_error_from_errno(errno);
387 return 0;
390 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
391 gboolean cached)
393 struct client_s *client = assuan_get_pointer(ctx);
394 gpg_error_t error;
395 struct stat st;
396 gint fd;
397 gint timeout;
399 if ((fd = open_file(client->filename, &st)) == -1) {
400 /* New file. */
401 if (errno == ENOENT) {
402 if (shakey[0])
403 goto update_cache;
405 goto done;
408 error = errno;
409 log_write("%s: %s", client->filename, strerror(errno));
410 cleanup_client(client);
411 memset(shakey, 0, sizeof(shakey));
412 return send_syserror(ctx, error);
415 error = try_xml_decrypt(ctx, fd, st, shakey);
416 close(fd);
418 if (error) {
419 memset(shakey, 0, sizeof(shakey));
420 cleanup_client(client);
421 return send_error(ctx, error);
424 update_cache:
425 CACHE_LOCK(client->ctx);
427 if (cached == FALSE) {
428 if (cache_update_key(client->md5file, shakey) == FALSE) {
429 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
430 cleanup_client(client);
431 CACHE_UNLOCK;
432 return send_error(ctx, EPWMD_MAX_SLOTS);
435 timeout = get_key_file_integer(client->filename, "cache_timeout");
436 cache_reset_timeout(client->md5file, timeout);
438 else
439 cache_set_timeout(client->md5file, -2);
441 CACHE_UNLOCK;
443 done:
444 memset(shakey, 0, sizeof(shakey));
445 error = parse_xml(ctx);
447 if (client->xml) {
448 gcry_free(client->xml);
449 client->xml = NULL;
452 if (!error) {
453 if (client->new == FALSE)
454 send_cache_status_all();
456 client->state = STATE_OPEN;
459 return send_error(ctx, error);
462 static int open_command(assuan_context_t ctx, char *line)
464 struct stat st;
465 guchar shakey[gcrykeysize];
466 gboolean cached = FALSE;
467 gpg_error_t error;
468 struct client_s *client = assuan_get_pointer(ctx);
469 gchar **req;
470 gchar *filename = NULL;
471 file_header_t file_header;
473 memset(shakey, 0, sizeof(shakey));
475 if ((req = split_input_line(line, " ", 2)) != NULL)
476 filename = req[0];
478 if (!filename || !*filename) {
479 g_strfreev(req);
480 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
483 if (valid_filename(filename) == FALSE) {
484 g_strfreev(req);
485 return send_error(ctx, EPWMD_INVALID_FILENAME);
488 if (client->state == STATE_OPEN)
489 cleanup_client(client);
491 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
492 CACHE_LOCK(client->ctx);
494 if (cache_has_file(client->md5file) == FALSE) {
495 if (cache_add_file(client->md5file, NULL) == FALSE) {
496 g_strfreev(req);
497 CACHE_UNLOCK;
498 return send_error(ctx, EPWMD_MAX_SLOTS);
502 cache_incr_refcount(client->md5file);
503 CACHE_UNLOCK;
504 error = lock_file_mutex(client);
506 if (error) {
507 g_strfreev(req);
508 return send_error(ctx, error);
511 client->freed = FALSE;
513 if ((error = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
514 g_strfreev(req);
515 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
516 cleanup_client(client);
517 return send_error(ctx, error);
520 if (stat(filename, &st) == 0) {
521 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
522 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
523 g_strfreev(req);
524 cleanup_client(client);
525 return send_error(ctx, EPWMD_INVALID_FILENAME);
528 client->mtime = st.st_mtime;
531 client->pinentry->filename = client->filename = g_strdup(filename);
533 if (!client->filename) {
534 memset(shakey, 0, sizeof(shakey));
535 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
536 cleanup_client(client);
537 g_strfreev(req);
538 return send_syserror(ctx, ENOMEM);
542 * New files don't need a key.
544 if (access(filename, R_OK|W_OK) != 0) {
545 if (errno != ENOENT) {
546 error = errno;
547 log_write("%s: %s", filename, strerror(errno));
548 g_strfreev(req);
549 cleanup_client(client);
550 return send_syserror(ctx, error);
553 if ((client->xml = new_document()) == NULL) {
554 log_write("%s", strerror(ENOMEM));
555 g_strfreev(req);
556 cleanup_client(client);
557 return send_syserror(ctx, ENOMEM);
560 client->len = xmlStrlen(client->xml);
561 client->new = TRUE;
562 client->filename = g_strdup(filename);
564 if (!client->filename) {
565 g_strfreev(req);
566 cleanup_client(client);
567 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
568 return send_syserror(ctx, ENOMEM);
571 memset(shakey, 0, sizeof(shakey));
573 if (req[1] && *req[1])
574 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
576 g_strfreev(req);
577 return open_command_finalize(ctx, shakey, cached);
580 error = read_file_header(filename, &file_header);
582 if (error) {
583 g_strfreev(req);
584 cleanup_client(client);
585 return send_error(ctx, error);
588 if (file_header.iter == -1)
589 goto done;
591 CACHE_LOCK(client->ctx);
592 cached = cache_get_key(client->md5file, shakey);
593 CACHE_UNLOCK;
595 if (cached == FALSE) {
597 * No key specified and no matching filename found in the cache. Use
598 * pinentry to retrieve the key. Cannot return assuan_process_done()
599 * here otherwise the command will be interrupted. The event loop in
600 * client_thread() will poll the file descriptor waiting for it to
601 * become ready to read a pinentry_key_s which will contain the
602 * entered key or error. It will then call open_command_finalize() to
603 * to finish the command.
605 if (!req[1] || !*req[1]) {
606 #ifdef WITH_PINENTRY
607 if (client->pinentry->use == FALSE) {
608 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
609 goto done;
612 g_strfreev(req);
613 client->pinentry->which = PINENTRY_OPEN;
614 error = pinentry_fork(ctx);
616 if (error) {
617 cleanup_client(client);
618 return send_error(ctx, error);
621 client->pinentry->cb = open_command_finalize;
622 client->pinentry->status = PINENTRY_INIT;
623 return 0;
624 #else
625 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
626 goto done;
627 #endif
630 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
633 done:
634 g_strfreev(req);
635 return open_command_finalize(ctx, shakey, cached);
638 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
639 gint size, gpointer *out, glong *outsize, gint *error)
641 z_stream z;
642 gpointer pout, pin;
643 gint ret;
644 gz_header h;
645 gchar buf[17];
646 gint cmd = Z_NO_FLUSH;
647 gpg_error_t rc;
649 z.zalloc = z_alloc;
650 z.zfree = z_free;
651 z.next_in = pin = data;
652 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
653 z.avail_out = zlib_bufsize;
654 z.next_out = pout = g_malloc(zlib_bufsize);
656 if (!pout) {
657 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
658 *error = Z_MEM_ERROR;
659 return FALSE;
662 ret = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
664 if (ret != Z_OK) {
665 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
666 *error = ret;
667 g_free(pout);
668 return FALSE;
671 memset(&h, 0, sizeof(gz_header));
672 snprintf(buf, sizeof(buf), "%i", size);
673 h.comment = (guchar *)buf;
674 ret = deflateSetHeader(&z, &h);
676 if (ret != Z_OK) {
677 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
678 *error = ret;
679 g_free(pout);
680 deflateEnd(&z);
681 return FALSE;
684 do {
685 gpointer p;
687 ret = deflate(&z, cmd);
689 switch (ret) {
690 case Z_OK:
691 break;
692 case Z_BUF_ERROR:
693 if (!z.avail_out) {
694 p = g_realloc(pout, z.total_out + zlib_bufsize);
696 if (!p) {
697 ret = Z_MEM_ERROR;
698 goto fail;
701 pout = p;
702 z.next_out = pout + z.total_out;
703 z.avail_out = zlib_bufsize;
706 if (!z.avail_in && z.total_in < size) {
707 if (z.total_in + zlib_bufsize > size)
708 z.avail_in = size - z.total_in;
709 else
710 z.avail_in = zlib_bufsize;
712 if (ctx) {
713 rc = assuan_write_status(ctx, "COMPRESS",
714 print_fmt("%i %i", z.total_in, size));
716 if (rc) {
717 ret = rc;
718 goto fail;
723 if (z.total_in >= size)
724 cmd = Z_FINISH;
726 break;
727 case Z_STREAM_END:
728 break;
729 default:
730 goto fail;
733 pth_yield(NULL);
734 } while (ret != Z_STREAM_END);
736 if (ctx) {
737 rc = assuan_write_status(ctx, "COMPRESS",
738 print_fmt("%i %i", z.total_in, size));
740 if (rc) {
741 ret = rc;
742 goto fail;
746 *out = pout;
747 *outsize = z.total_out;
748 deflateEnd(&z);
749 return TRUE;
751 fail:
752 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
753 *error = ret;
754 g_free(pout);
755 deflateEnd(&z);
756 return FALSE;
759 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
760 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
761 gint iter)
763 gsize len = insize;
764 gint fd;
765 gpointer inbuf;
766 guchar tkey[gcrykeysize];
767 gchar *p;
768 gint error;
769 gpg_error_t rc;
770 guint iter_progress = 0, n_iter = 0, xiter = 0;
771 gchar tmp[FILENAME_MAX];
772 file_header_t file_header;
774 if (iter == -1) {
776 * cache_file_count() needs both .used == TRUE and a valid key in
777 * order for it to count as a used cache entry. Fixes CACHE status
778 * messages.
780 memset(shakey, '!', gcrykeysize);
781 inbuf = data;
782 file_header.iter = iter;
783 goto write_file;
786 if (insize / gcryblocksize) {
787 len = (insize / gcryblocksize) * gcryblocksize;
789 if (insize % gcryblocksize)
790 len += gcryblocksize;
794 * Resize the existing xml buffer to the block size required by gcrypt
795 * rather than duplicating it and wasting memory.
797 inbuf = gcry_realloc(data, len);
799 if (!inbuf)
800 return gpg_error_from_errno(ENOMEM);
802 insize = len;
803 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
804 memcpy(tkey, shakey, sizeof(tkey));
805 tkey[0] ^= 1;
807 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
808 gcry_free(inbuf);
809 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
810 return rc;
813 file_header.iter = iter;
815 if (client)
816 iter_progress = get_key_file_integer("default", "iteration_progress");
818 if (client && iter_progress && file_header.iter >= iter_progress) {
819 error = assuan_write_status(client->ctx, "ENCRYPT", "0");
821 if (error) {
822 gcry_free(inbuf);
823 return error;
827 while (xiter < file_header.iter) {
828 if (client && iter_progress > 0 && xiter >= iter_progress) {
829 if (!(xiter % iter_progress)) {
830 error = assuan_write_status(client->ctx, "ENCRYPT", print_fmt("%i",
831 ++n_iter * iter_progress));
833 if (error) {
834 gcry_free(inbuf);
835 return error;
840 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
841 sizeof(file_header.iv)))) {
842 gcry_free(inbuf);
843 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
844 return rc;
847 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
848 == FALSE) {
849 gcry_free(inbuf);
850 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
851 return rc;
854 xiter++;
855 pth_yield(NULL);
858 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
859 sizeof(file_header.iv)))) {
860 gcry_free(inbuf);
861 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
862 return rc;
865 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
866 gcry_free(inbuf);
867 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
868 return rc;
871 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
872 gcry_free(inbuf);
873 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
874 return rc;
877 if (client && iter_progress && file_header.iter >= iter_progress) {
878 error = assuan_write_status(client->ctx, "ENCRYPT",
879 print_fmt("%i", file_header.iter));
881 if (error) {
882 gcry_free(inbuf);
883 return error;
887 write_file:
888 if (filename) {
889 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
891 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
892 error = errno;
893 gcry_free(inbuf);
894 p = strrchr(tmp, '/');
895 p++;
896 log_write("%s: %s", p, strerror(errno));
897 return gpg_error_from_errno(error);
900 else
902 * xml_import() from command line.
904 fd = STDOUT_FILENO;
906 len = pth_write(fd, &file_header, sizeof(file_header_t));
908 if (len != sizeof(file_header)) {
909 len = errno;
911 if (filename)
912 close(fd);
914 gcry_free(inbuf);
915 return gpg_error_from_errno(len);
918 len = pth_write(fd, inbuf, insize);
920 if (len != insize) {
921 len = errno;
923 if (filename)
924 close(fd);
926 gcry_free(inbuf);
927 return gpg_error_from_errno(len);
930 if (fsync(fd) == -1) {
931 len = errno;
932 close(fd);
933 gcry_free(inbuf);
934 return gpg_error_from_errno(len);
937 if (filename) {
938 struct stat st;
939 mode_t mode = 0;
941 close(fd);
943 if (stat(filename, &st) == 0)
944 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
946 if (rename(tmp, filename) == -1) {
947 len = errno;
948 gcry_free(inbuf);
949 return gpg_error_from_errno(len);
952 if (mode)
953 chmod(filename, mode);
956 gcry_free(inbuf);
957 return 0;
960 static gpg_error_t save_command_finalize(assuan_context_t ctx,
961 guchar shakey[], gboolean cached)
963 struct client_s *client = assuan_get_pointer(ctx);
964 gpointer xmlbuf;
965 xmlChar *p;
966 gint len;
967 gint iter;
968 gint timeout;
969 gpointer outbuf;
970 glong outsize = 0;
971 gint zerror;
972 gpg_error_t error;
973 struct stat st;
975 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
976 xmlbuf = p;
978 iter = get_key_file_integer(client->filename, "compression_level");
980 if (iter < 0)
981 iter = 0;
983 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zerror) == FALSE) {
984 memset(shakey, 0, sizeof(shakey));
985 xmlFree(xmlbuf);
987 if (zerror == Z_MEM_ERROR) {
988 return send_syserror(ctx, ENOMEM);
990 else
991 return send_error(ctx, GPG_ERR_COMPR_ALGO);
993 else {
994 gcry_free(xmlbuf);
995 xmlbuf = outbuf;
996 len = outsize;
999 iter = get_key_file_integer(client->filename, "iterations");
1000 error = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1002 if (error) {
1003 memset(shakey, 0, sizeof(shakey));
1004 return send_error(ctx, error);
1007 stat(client->filename, &st);
1008 client->mtime = st.st_mtime;
1009 timeout = get_key_file_integer(client->filename, "cache_timeout");
1010 CACHE_LOCK(client->ctx);
1012 if (cached) {
1013 memset(shakey, 0, sizeof(shakey));
1014 cache_reset_timeout(client->md5file, timeout);
1015 CACHE_UNLOCK;
1017 if (client->new == TRUE)
1018 send_cache_status_all();
1020 client->new = FALSE;
1021 return send_error(ctx, 0);
1024 if (cache_update_key(client->md5file, shakey) == FALSE) {
1025 memset(shakey, 0, sizeof(shakey));
1026 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1027 CACHE_UNLOCK;
1028 return send_error(ctx, EPWMD_MAX_SLOTS);
1031 client->new = FALSE;
1032 memset(shakey, 0, sizeof(shakey));
1033 cache_reset_timeout(client->md5file, timeout);
1034 CACHE_UNLOCK;
1035 send_cache_status_all();
1036 return send_error(ctx, 0);
1039 static int save_command(assuan_context_t ctx, char *line)
1041 gboolean cached = FALSE;
1042 guchar shakey[gcrykeysize];
1043 struct stat st;
1044 struct client_s *client = assuan_get_pointer(ctx);
1045 gpg_error_t error;
1047 memset(shakey, 0, sizeof(shakey));
1048 error = file_modified(client);
1050 if (error) {
1051 log_write("%s: %s", client->filename ? client->filename : "",
1052 pwmd_strerror(error));
1053 return send_error(ctx, error);
1056 error = lock_file_mutex(client);
1058 if (error)
1059 return send_error(ctx, error);
1061 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1062 return send_syserror(ctx, errno);
1064 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1065 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1066 return send_error(ctx, EPWMD_INVALID_FILENAME);
1069 if (get_key_file_integer(client->filename, "iterations") == -1)
1070 goto done;
1072 if (!line || !*line) {
1073 guchar tmp[sizeof(shakey)];
1074 CACHE_LOCK(ctx);
1076 memset(tmp, '!', sizeof(tmp));
1078 if (cache_get_key(client->md5file, shakey) == FALSE ||
1079 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1080 CACHE_UNLOCK;
1081 #ifdef WITH_PINENTRY
1082 if (client->pinentry->use == FALSE) {
1083 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1084 goto done;
1087 client->pinentry->which = PINENTRY_SAVE;
1088 error = pinentry_fork(ctx);
1090 if (error)
1091 return send_error(ctx, error);
1093 client->pinentry->cb = save_command_finalize;
1094 client->pinentry->status = PINENTRY_INIT;
1095 return 0;
1096 #else
1097 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1098 goto done;
1099 #endif
1101 else {
1102 CACHE_UNLOCK;
1103 cached = TRUE;
1106 else {
1107 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1108 memset(line, 0, strlen(line));
1111 done:
1112 return save_command_finalize(ctx, shakey, cached);
1115 static gboolean contains_whitespace(const gchar *str)
1117 const gchar *p = str;
1118 gunichar c;
1119 glong len;
1121 len = g_utf8_strlen(p++, -1) -1;
1123 while (len--) {
1124 c = g_utf8_get_char(p++);
1126 if (g_unichar_isspace(c))
1127 return TRUE;
1130 return FALSE;
1133 static int delete_command(assuan_context_t ctx, char *line)
1135 struct client_s *client = assuan_get_pointer(ctx);
1136 gchar **req;
1137 gpg_error_t error;
1138 xmlNodePtr n;
1140 error = file_modified(client);
1142 if (error) {
1143 log_write("%s: %s", client->filename ? client->filename : "",
1144 pwmd_strerror(error));
1145 return send_error(ctx, error);
1148 if (strchr(line, '\t'))
1149 req = split_input_line(line, "\t", -1);
1150 else
1151 req = split_input_line(line, " ", -1);
1153 if (!req || !*req)
1154 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1156 n = find_account(client->doc, &req, &error, NULL, 0);
1158 if (!n) {
1159 g_strfreev(req);
1160 return send_error(ctx, error);
1164 * No sub-node defined. Remove the entire node (account).
1166 if (!req[1]) {
1167 if (n) {
1168 xmlUnlinkNode(n);
1169 xmlFreeNode(n);
1172 g_strfreev(req);
1173 return send_error(ctx, 0);
1176 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1177 g_strfreev(req);
1179 if (!n)
1180 return send_error(ctx, error);
1182 if (n) {
1183 xmlUnlinkNode(n);
1184 xmlFreeNode(n);
1187 return send_error(ctx, 0);
1191 * Don't return with assuan_process_done() here. This has been called from
1192 * assuan_process_next() and the command should be finished in
1193 * client_thread().
1195 static int store_command_finalize(gpointer data, gint rc, guchar *line,
1196 gsize len)
1198 assuan_context_t ctx = data;
1199 struct client_s *client = assuan_get_pointer(ctx);
1200 gchar **req;
1201 guchar *result = line;
1202 xmlNodePtr n;
1203 gpg_error_t error = file_modified(client);
1205 if (rc) {
1206 if (line)
1207 #ifndef MEM_DEBUG
1208 xfree(line);
1209 #else
1210 free(line);
1211 #endif
1212 return rc;
1215 req = split_input_line((gchar *)result, "\t", 0);
1216 #ifndef MEM_DEBUG
1217 xfree(line);
1218 #else
1219 free(line);
1220 #endif
1222 if (rc) {
1223 if (req)
1224 g_strfreev(req);
1226 return rc;
1229 if (!req || !*req)
1230 return EPWMD_COMMAND_SYNTAX;
1232 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1233 g_strfreev(req);
1234 return EPWMD_INVALID_ELEMENT;
1237 if (valid_element_path(req+1, TRUE) == FALSE) {
1238 g_strfreev(req);
1239 return EPWMD_INVALID_ELEMENT;
1242 again:
1243 n = find_account(client->doc, &req, &error, NULL, 0);
1245 if (error && error == EPWMD_ELEMENT_NOT_FOUND) {
1246 error = new_account(client->doc, *req);
1248 if (error) {
1249 g_strfreev(req);
1250 return error;
1253 goto again;
1256 if (!n) {
1257 g_strfreev(req);
1258 return error;
1261 if (req[1]) {
1262 if (!n->children)
1263 create_elements_cb(n, req+1, &error, NULL);
1264 else
1265 find_elements(client->doc, n->children, req+1, &error,
1266 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1269 g_strfreev(req);
1270 client->inquire_status = INQUIRE_DONE;
1271 return error;
1274 static int store_command(assuan_context_t ctx, char *line)
1276 struct client_s *client = assuan_get_pointer(ctx);
1277 gpg_error_t error = file_modified(client);
1279 if (error) {
1280 log_write("%s: %s", client->filename ? client->filename : "",
1281 pwmd_strerror(error));
1282 return send_error(ctx, error);
1285 error = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1287 if (error)
1288 return send_error(ctx, error);
1290 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1291 client->inquire_status = INQUIRE_BUSY;
1292 return 0;
1295 static int get_command(assuan_context_t ctx, char *line)
1297 struct client_s *client = assuan_get_pointer(ctx);
1298 gchar **req;
1299 gpg_error_t error;
1300 xmlNodePtr n;
1302 error = file_modified(client);
1304 if (error) {
1305 log_write("%s: %s", client->filename ? client->filename : "",
1306 pwmd_strerror(error));
1307 return send_error(ctx, error);
1310 req = split_input_line(line, "\t", -1);
1312 if (!req || !*req) {
1313 g_strfreev(req);
1314 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1317 n = find_account(client->doc, &req, &error, NULL, 0);
1319 if (!n) {
1320 g_strfreev(req);
1321 return send_error(ctx, error);
1324 if (req[1])
1325 n = find_elements(client->doc, n->children, req+1, &error, NULL, NULL, NULL, FALSE, 0, NULL);
1327 g_strfreev(req);
1329 if (error)
1330 return send_error(ctx, error);
1332 if (!n || !n->children)
1333 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1335 n = n->children;
1337 if (!n || !n->content || !*n->content)
1338 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1340 error = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1341 return send_error(ctx, error);
1344 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
1346 xmlChar *p = path;
1347 gint n;
1348 gchar *buf;
1350 if (!p)
1351 return NULL;
1353 for (n = 0; *p && n < 3; p++) {
1354 if (*p == '/')
1355 n++;
1358 if (strstr((gchar *)p, "text()") != NULL)
1359 p[xmlStrlen(p) - 7] = 0;
1361 for (n = 0; p[n]; n++) {
1362 if (p[n] == '/')
1363 p[n] = '\t';
1366 buf = g_strdup_printf("%s\t%s", account, p);
1367 p = (xmlChar *)buf + strlen(buf) - 1;
1369 while (isspace(*p))
1370 *p-- = 0;
1372 return buf;
1375 gboolean strv_printf(gchar ***array, const gchar *fmt, ...)
1377 gchar **a;
1378 va_list ap;
1379 gchar *buf;
1380 gint len = *array ? g_strv_length(*array) : 0;
1381 gint ret;
1383 if (!fmt)
1384 return FALSE;
1386 if ((a = g_realloc(*array, (len + 2) * sizeof(gchar *))) == NULL)
1387 return FALSE;
1389 va_start(ap, fmt);
1390 ret = g_vasprintf(&buf, fmt, ap);
1391 va_end(ap);
1393 if (ret == -1)
1394 return FALSE;
1396 a[len++] = buf;
1397 a[len] = NULL;
1398 *array = a;
1399 return TRUE;
1402 struct realpath_s {
1403 gchar *account;
1406 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **req,
1407 gpg_error_t *error, void *data)
1409 struct realpath_s *rp = data;
1411 if (rp->account)
1412 g_free(rp->account);
1414 rp->account = g_strdup(req[0]);
1416 if (!rp->account) {
1417 *error = gpg_error_from_errno(ENOMEM);
1418 return NULL;
1421 return node;
1424 static int realpath_command(assuan_context_t ctx, char *line)
1426 gpg_error_t error;
1427 struct client_s *client = assuan_get_pointer(ctx);
1428 xmlChar *p;
1429 gchar **req;
1430 gchar *result, *t;
1431 gint i;
1432 xmlNodePtr n;
1433 struct realpath_s *rp;
1434 GString *string;
1436 error = file_modified(client);
1438 if (error) {
1439 log_write("%s: %s", client->filename ? client->filename : "",
1440 pwmd_strerror(error));
1441 return send_error(ctx, error);
1444 if (strchr(line, '\t') != NULL) {
1445 if ((req = split_input_line(line, "\t", 0)) == NULL)
1446 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1448 else {
1449 if ((req = split_input_line(line, " ", 0)) == NULL)
1450 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1453 n = find_account(client->doc, &req, &error, NULL, 0);
1455 if (!n) {
1456 g_strfreev(req);
1457 return send_error(ctx, error);
1460 rp = g_malloc(sizeof(struct realpath_s));
1462 if (!rp) {
1463 g_strfreev(req);
1464 return send_syserror(ctx, ENOMEM);
1467 rp->account = g_strdup(req[0]);
1469 if (!rp->account) {
1470 g_strfreev(req);
1471 return send_syserror(ctx, ENOMEM);
1474 if (req[1]) {
1475 n = find_elements(client->doc, n->children, req+1, &error,
1476 NULL, realpath_elements_cb, NULL, FALSE, 0, rp);
1478 if (!n) {
1479 g_free(rp->account);
1480 g_free(rp);
1481 g_strfreev(req);
1482 return send_error(ctx, error);
1486 p = xmlGetNodePath(n);
1487 result = element_path_to_req(rp->account, p);
1489 if (!result) {
1490 g_free(result);
1491 g_free(rp->account);
1492 g_free(rp);
1493 g_strfreev(req);
1494 xmlFree(p);
1495 return send_syserror(ctx, ENOMEM);
1498 string = g_string_new(result);
1499 g_free(result);
1500 g_free(rp->account);
1501 g_free(rp);
1502 g_strfreev(req);
1503 xmlFree(p);
1504 i = 0;
1506 again:
1507 for (t = string->str + i; *t; t++, i++) {
1508 if ((!i && *t != '!') || *t == '\t') {
1509 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1510 goto again;
1514 error = assuan_send_data(ctx, string->str, string->len);
1515 g_string_free(string, TRUE);
1516 return send_error(ctx, error);
1519 struct list_element_s {
1520 GSList *list;
1521 gchar **elements;
1524 static gboolean append_to_element_list(struct list_element_s *elements)
1526 gchar *tmp;
1527 gint i, total;
1528 gchar *a;
1529 GSList *list;
1531 if (!elements || !elements->elements)
1532 return TRUE;
1534 tmp = g_strjoinv("\t", elements->elements);
1536 if (!tmp)
1537 return FALSE;
1539 g_strfreev(elements->elements);
1540 elements->elements = NULL;
1541 total = g_slist_length(elements->list);
1542 a = g_utf8_collate_key(tmp, -1);
1544 if (!a) {
1545 g_free(tmp);
1546 return FALSE;
1550 * Removes duplicate element paths from the list. This is needed when
1551 * appending an element tree from list_command(). The glib docs recommend
1552 * using g_utf8_collate_key() for a large number of strings.
1554 for (i = 0; i < total; i++) {
1555 gchar *p = g_slist_nth_data(elements->list, i);
1556 gchar *b = g_utf8_collate_key(p, -1);
1558 if (!b) {
1559 g_free(a);
1560 g_free(tmp);
1561 return FALSE;
1564 if (strcmp(a, b) == 0) {
1565 g_free(a);
1566 g_free(b);
1567 g_free(tmp);
1568 return TRUE;
1571 g_free(b);
1574 g_free(a);
1575 list = g_slist_append(elements->list, tmp);
1577 if (!list)
1578 return FALSE;
1580 elements->list = list;
1581 return TRUE;
1584 static gpg_error_t do_list_recurse(xmlDocPtr doc, xmlNodePtr node,
1585 struct list_element_s *elements, gchar *prefix)
1587 xmlNodePtr n;
1588 gpg_error_t error;
1590 if (append_to_element_list(elements) == FALSE)
1591 return gpg_error_from_errno(ENOMEM);
1593 for (n = node; n; n = n->next) {
1594 if (n->type == XML_ELEMENT_NODE) {
1595 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
1596 gchar *tmp;
1598 if (content) {
1599 if (strv_printf(&elements->elements, "%s\t%s", prefix, n->name) == FALSE)
1600 return gpg_error_from_errno(ENOMEM);
1602 if (append_to_element_list(elements) == FALSE)
1603 return gpg_error_from_errno(ENOMEM);
1606 tmp = g_strdup_printf("%s\t!%s", prefix, n->name);
1608 if (!tmp)
1609 return gpg_error_from_errno(ENOMEM);
1611 if (strv_printf(&elements->elements, "%s", tmp) == FALSE) {
1612 g_free(tmp);
1613 return gpg_error_from_errno(ENOMEM);
1616 if (n->children) {
1617 error = do_list_recurse(doc, n->children, elements, tmp);
1618 g_free(tmp);
1620 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1621 return error;
1623 else
1624 g_free(tmp);
1626 if (append_to_element_list(elements) == FALSE)
1627 return gpg_error_from_errno(ENOMEM);
1631 return 0;
1634 static gpg_error_t do_list_command(assuan_context_t ctx, xmlDocPtr doc,
1635 struct list_element_s *elements, char *line)
1637 gchar *prefix = NULL, *account;
1638 gchar **req = NULL, **oreq = NULL, *tmp;
1639 xmlNodePtr n;
1640 gboolean account_is_literal, account_has_target = FALSE;
1641 gint which = 0;
1642 gchar **p;
1643 gpg_error_t error;
1645 if ((req = split_input_line(line, "\t", 0)) == NULL) {
1646 if ((req = split_input_line(line, " ", 0)) == NULL)
1647 return EPWMD_COMMAND_SYNTAX;
1650 prefix = g_strdup(*req);
1652 if (!prefix) {
1653 g_strfreev(req);
1654 return gpg_error_from_errno(ENOMEM);
1657 account = g_strdup(*req);
1659 if (!account) {
1660 g_free(prefix);
1661 g_strfreev(req);
1662 return gpg_error_from_errno(ENOMEM);
1665 oreq = g_strdupv(req);
1667 if (!oreq) {
1668 g_free(prefix);
1669 g_free(account);
1670 g_strfreev(req);
1671 return gpg_error_from_errno(ENOMEM);
1674 p = req;
1675 again:
1676 account_has_target = FALSE;
1677 account_is_literal = is_literal_element_str(prefix);
1678 n = find_account(doc, &p, &error, &account_has_target, 0);
1680 if (which)
1681 oreq = p;
1682 else
1683 req = p;
1685 if (!n)
1686 goto fail;
1688 if (!which && account_is_literal == FALSE && account_has_target == FALSE) {
1689 tmp = g_strdup_printf("!%s", prefix);
1691 if (!tmp) {
1692 error = gpg_error_from_errno(ENOMEM);
1693 goto fail;
1696 g_free(prefix);
1697 prefix = tmp;
1700 if (*(p+1)) {
1701 gchar *t;
1703 n = find_elements(doc, n->children, p+1, &error, NULL, NULL, NULL,
1704 TRUE, 0, NULL);
1706 if (error)
1707 goto fail;
1709 tmp = g_strjoinv("\t", p+1);
1710 if (!tmp) {
1711 error = gpg_error_from_errno(ENOMEM);
1712 goto fail;
1715 t = g_strdup_printf("%s\t%s", prefix, tmp);
1716 if (!t) {
1717 error = gpg_error_from_errno(ENOMEM);
1718 goto fail;
1721 g_free(prefix);
1722 prefix = t;
1723 g_free(tmp);
1726 if (strv_printf(&elements->elements, "%s", prefix) == FALSE) {
1727 error = gpg_error_from_errno(ENOMEM);
1728 goto fail;
1731 if (node_has_child_element(n->children) == FALSE) {
1732 if (append_to_element_list(elements) == FALSE) {
1733 error = gpg_error_from_errno(ENOMEM);
1734 goto fail;
1737 else
1738 error = do_list_recurse(doc, n->children, elements, prefix);
1740 if (error)
1741 goto fail;
1743 if (!which++ && !*(p+1) && account_is_literal == FALSE && account_has_target == TRUE) {
1744 g_free(*oreq);
1745 *oreq = g_strdup_printf("!%s", account);
1747 if (!*oreq) {
1748 error = gpg_error_from_errno(ENOMEM);
1749 goto fail;
1752 p = oreq;
1753 g_free(prefix);
1754 prefix = g_strdup(*oreq);
1756 if (!prefix) {
1757 error = gpg_error_from_errno(ENOMEM);
1758 goto fail;
1761 goto again;
1764 fail:
1765 g_free(prefix);
1766 g_free(account);
1767 g_strfreev(req);
1769 if (oreq)
1770 g_strfreev(oreq);
1772 return error;
1776 * This could be faster especially when finding "target" attributes.
1778 static int list_command(assuan_context_t ctx, char *line)
1780 struct client_s *client = assuan_get_pointer(ctx);
1781 gpg_error_t error;
1782 struct list_element_s *elements = NULL;
1783 GString *string;
1784 gchar *tmp;
1785 gint i, total;
1787 if (disable_list_and_dump == TRUE)
1788 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1790 error = file_modified(client);
1792 if (error) {
1793 log_write("%s: %s", client->filename, pwmd_strerror(error));
1794 return send_error(ctx, error);
1797 if (!*line) {
1798 GString *str;
1800 error = list_accounts(client->doc, &str);
1802 if (error)
1803 return send_error(ctx, error);
1805 error = assuan_send_data(ctx, str->str, str->len);
1806 g_string_free(str, TRUE);
1807 return send_error(ctx, error);
1810 elements = g_malloc0(sizeof(struct list_element_s));
1812 if (!elements) {
1813 error = gpg_error_from_errno(ENOMEM);
1814 goto fail;
1817 error = do_list_command(ctx, client->doc, elements, line);
1819 if (error)
1820 goto fail;
1822 if (!error) {
1823 total = g_slist_length(elements->list);
1825 if (!total) {
1826 error = EPWMD_EMPTY_ELEMENT;
1827 goto fail;
1831 * Find element paths with a target and append those element trees to
1832 * the list.
1834 for (i = 0; i < total; i++) {
1835 gchar **req;
1837 tmp = g_slist_nth_data(elements->list, i);
1838 req = split_input_line(tmp, "\t", 0);
1840 if (!req) {
1841 if (g_str_has_prefix(tmp, "!") == TRUE) {
1842 g_strfreev(req);
1843 continue;
1846 else {
1847 gchar **p;
1849 for (p = req; *p; p++) {
1850 if (g_str_has_prefix(*p, "!") == FALSE)
1851 break;
1854 if (!*p) {
1855 g_strfreev(req);
1856 continue;
1860 g_strfreev(req);
1861 error = do_list_command(ctx, client->doc, elements, tmp);
1863 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
1864 goto fail;
1866 total = g_slist_length(elements->list);
1870 string = g_string_new(NULL);
1872 for (i = 0; i < total; i++) {
1873 tmp = g_slist_nth_data(elements->list, i);
1874 g_string_append_printf(string, "%s\n", tmp);
1875 g_free(tmp);
1878 string = g_string_truncate(string, string->len - 1);
1879 error = assuan_send_data(ctx, string->str, string->len);
1880 g_string_free(string, TRUE);
1882 fail:
1883 if (elements) {
1884 if (elements->list)
1885 g_slist_free(elements->list);
1887 if (elements->elements)
1888 g_strfreev(elements->elements);
1890 g_free(elements);
1893 return send_error(ctx, error);
1896 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1897 const gchar *value)
1899 xmlAttrPtr a;
1901 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1902 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1904 if (!a)
1905 return EPWMD_LIBXML_ERROR;
1907 else
1908 xmlNodeSetContent(a->children, (xmlChar *)value);
1910 return 0;
1914 * req[0] - element path
1916 static int attribute_list(assuan_context_t ctx, gchar **req)
1918 struct client_s *client = assuan_get_pointer(ctx);
1919 gchar **attrlist = NULL;
1920 gint i = 0;
1921 gchar **path = NULL;
1922 xmlAttrPtr a;
1923 xmlNodePtr n, an;
1924 gchar *line;
1925 gpg_error_t error;
1927 if (!req || !req[0])
1928 return EPWMD_COMMAND_SYNTAX;
1930 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1932 * The first argument may be only an account.
1934 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1935 return EPWMD_COMMAND_SYNTAX;
1938 n = find_account(client->doc, &path, &error, NULL, 0);
1940 if (!n) {
1941 g_strfreev(path);
1942 return error;
1945 if (path[1]) {
1946 n = find_elements(client->doc, n->children, path+1, &error,
1947 NULL, NULL, NULL, FALSE, 0, NULL);
1949 if (!n) {
1950 g_strfreev(path);
1951 return error;
1955 g_strfreev(path);
1957 for (a = n->properties; a; a = a->next) {
1958 gchar **pa;
1960 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1961 if (attrlist)
1962 g_strfreev(attrlist);
1964 error = errno;
1965 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(errno));
1966 return gpg_error_from_errno(error);
1969 attrlist = pa;
1970 an = a->children;
1971 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1973 if (!attrlist[i]) {
1974 g_strfreev(attrlist);
1975 return gpg_error_from_errno(ENOMEM);
1978 attrlist[++i] = NULL;
1981 if (!attrlist)
1982 return EPWMD_EMPTY_ELEMENT;
1984 line = g_strjoinv("\n", attrlist);
1986 if (!line) {
1987 g_strfreev(attrlist);
1988 return gpg_error_from_errno(ENOMEM);
1991 error = assuan_send_data(ctx, line, strlen(line));
1992 g_free(line);
1993 g_strfreev(attrlist);
1994 return error;
1998 * req[0] - attribute
1999 * req[1] - element path
2001 static int attribute_delete(struct client_s *client, gchar **req)
2003 xmlAttrPtr a;
2004 xmlNodePtr n;
2005 gchar **path = NULL;
2006 gpg_error_t error;
2008 if (!req || !req[0] || !req[1])
2009 return EPWMD_COMMAND_SYNTAX;
2011 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2013 * The first argument may be only an account.
2015 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2016 return EPWMD_COMMAND_SYNTAX;
2020 * Don't remove the "name" attribute for the account element. To remove an
2021 * account use DELETE <account>.
2023 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
2024 error = EPWMD_ATTR_SYNTAX;
2025 goto fail;
2028 n = find_account(client->doc, &path, &error, NULL, 0);
2030 if (!n)
2031 goto fail;
2033 if (path[1]) {
2034 n = find_elements(client->doc, n->children, path+1, &error,
2035 NULL, NULL, NULL, FALSE, 0, NULL);
2037 if (!n)
2038 goto fail;
2041 g_strfreev(path);
2043 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
2044 return EPWMD_ATTR_NOT_FOUND;
2046 if (xmlRemoveProp(a) == -1)
2047 return EPWMD_LIBXML_ERROR;
2049 return 0;
2051 fail:
2052 g_strfreev(path);
2053 return error;
2057 * Creates a "target" attribute. When other commands encounter an element with
2058 * this attribute, the element path is modified to the target value. If the
2059 * source element path doesn't exist when using 'ATTR SET target', it is
2060 * created, but the destination element path must exist.
2062 * req[0] - source element path
2063 * req[1] - destination element path
2065 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2067 gchar **src, **dst, *line = NULL;
2068 gpg_error_t error;
2069 xmlNodePtr n;
2071 if (!req || !req[0] || !req[1])
2072 return EPWMD_COMMAND_SYNTAX;
2074 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2076 * The first argument may be only an account.
2078 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2079 return EPWMD_COMMAND_SYNTAX;
2082 if (valid_element_path(src, FALSE) == FALSE) {
2083 g_strfreev(src);
2084 return EPWMD_INVALID_ELEMENT;
2087 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2089 * The first argument may be only an account.
2091 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2092 error = EPWMD_COMMAND_SYNTAX;
2093 goto fail;
2097 n = find_account(client->doc, &dst, &error, NULL, 0);
2100 * Make sure the destination element path exists.
2102 if (!n)
2103 goto fail;
2105 if (dst[1]) {
2106 n = find_elements(client->doc, n->children, dst+1, &error,
2107 NULL, NULL, NULL, FALSE, 0, NULL);
2109 if (!n)
2110 goto fail;
2113 again:
2114 n = find_account(client->doc, &src, &error, NULL, 0);
2116 if (!n) {
2117 if (error == EPWMD_ELEMENT_NOT_FOUND) {
2118 error = new_account(client->doc, src[0]);
2120 if (error)
2121 goto fail;
2123 goto again;
2125 else
2126 goto fail;
2129 if (src[1]) {
2130 if (!n->children)
2131 n = create_target_elements_cb(n, src+1, &error, NULL);
2132 else
2133 n = find_elements(client->doc, n->children, src+1, &error,
2134 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
2136 if (!n)
2137 goto fail;
2140 * Reset the position of the element tree now that the elements
2141 * have been created.
2143 n = find_account(client->doc, &src, &error, NULL, 0);
2145 if (!n)
2146 goto fail;
2148 n = find_elements(client->doc, n->children, src+1, &error,
2149 NULL, NULL, NULL, FALSE, 0, NULL);
2151 if (!n)
2152 goto fail;
2155 line = g_strjoinv("\t", dst);
2156 error = add_attribute(n, "target", line);
2158 fail:
2159 g_free(line);
2160 g_strfreev(src);
2161 g_strfreev(dst);
2162 return error;
2166 * req[0] - account name
2167 * req[1] - new name
2169 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2171 gpg_error_t error;
2172 gchar **tmp;
2173 xmlNodePtr n;
2175 tmp = g_strdupv(req);
2177 if (!tmp)
2178 return gpg_error_from_errno(ENOMEM);
2180 n = find_account(client->doc, &tmp, &error, NULL, 0);
2181 g_strfreev(tmp);
2183 if (!n)
2184 return error;
2186 if (g_utf8_collate(req[0], req[1]) == 0)
2187 return 0;
2190 * Will not overwrite an existing account.
2192 tmp = g_strdupv(req+1);
2194 if (!tmp)
2195 return gpg_error_from_errno(ENOMEM);
2197 n = find_account(client->doc, &tmp, &error, NULL, 0);
2198 g_strfreev(tmp);
2200 if (error && error != EPWMD_ELEMENT_NOT_FOUND)
2201 return error;
2203 if (n)
2204 return EPWMD_ACCOUNT_EXISTS;
2207 * Whitespace not allowed in account names.
2209 if (contains_whitespace(req[1]) == TRUE)
2210 return EPWMD_ATTR_SYNTAX;
2212 tmp = g_strdupv(req);
2214 if (!tmp)
2215 return gpg_error_from_errno(ENOMEM);
2217 n = find_account(client->doc, &tmp, &error, NULL, 0);
2218 g_strfreev(tmp);
2220 if (!n)
2221 return EPWMD_ELEMENT_NOT_FOUND;
2223 return add_attribute(n, "name", req[1]);
2227 * req[0] - attribute
2228 * req[1] - element path
2230 static int attribute_get(assuan_context_t ctx, gchar **req)
2232 struct client_s *client = assuan_get_pointer(ctx);
2233 xmlNodePtr n;
2234 xmlChar *a;
2235 gchar **path= NULL;
2236 gpg_error_t error;
2238 if (!req || !req[0] || !req[1])
2239 return EPWMD_COMMAND_SYNTAX;
2241 if (strchr(req[1], '\t')) {
2242 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2243 return EPWMD_COMMAND_SYNTAX;
2245 else {
2246 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2247 return EPWMD_COMMAND_SYNTAX;
2250 n = find_account(client->doc, &path, &error, NULL, 0);
2252 if (!n)
2253 goto fail;
2255 if (path[1]) {
2256 n = find_elements(client->doc, n->children, path+1, &error,
2257 NULL, NULL, NULL, FALSE, 0, NULL);
2259 if (!n)
2260 goto fail;
2263 g_strfreev(path);
2265 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2266 return EPWMD_ATTR_NOT_FOUND;
2268 error = assuan_send_data(ctx, a, xmlStrlen(a));
2269 xmlFree(a);
2270 return error;
2272 fail:
2273 g_strfreev(path);
2274 return error;
2278 * req[0] - attribute
2279 * req[1] - element path
2280 * req[2] - value
2282 static int attribute_set(struct client_s *client, gchar **req)
2284 gchar **path = NULL;
2285 gpg_error_t error;
2286 xmlNodePtr n;
2288 if (!req || !req[0] || !req[1] || !req[2])
2289 return EPWMD_COMMAND_SYNTAX;
2292 * Reserved attribute names.
2294 if (g_utf8_collate(req[0], "name") == 0) {
2296 * Only reserved for the account element. Not the rest of the
2297 * document.
2299 if (strchr(req[1], '\t') == NULL)
2300 return name_attribute(client, req + 1);
2302 else if (g_utf8_collate(req[0], "target") == 0)
2303 return target_attribute(client, req + 1);
2305 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2307 * The first argument may be only an account.
2309 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2310 return EPWMD_COMMAND_SYNTAX;
2313 n = find_account(client->doc, &path, &error, NULL, 0);
2315 if (!n)
2316 goto fail;
2318 if (path[1]) {
2319 n = find_elements(client->doc, n->children, path+1, &error,
2320 NULL, NULL, NULL, FALSE, 0, NULL);
2322 if (!n)
2323 goto fail;
2326 g_strfreev(path);
2327 return add_attribute(n, req[0], req[2]);
2329 fail:
2330 g_strfreev(path);
2331 return error;
2335 * req[0] - command
2336 * req[1] - attribute name or element path if command is LIST
2337 * req[2] - element path
2338 * req[2] - element path or value
2340 static int attr_command(assuan_context_t ctx, char *line)
2342 struct client_s *client = assuan_get_pointer(ctx);
2343 gchar **req = split_input_line(line, " ", 4);
2344 gpg_error_t error = 0;
2346 error = file_modified(client);
2348 if (error) {
2349 log_write("%s: %s", client->filename ? client->filename : "",
2350 pwmd_strerror(error));
2351 g_strfreev(req);
2352 return send_error(ctx, error);
2355 if (!req || !req[0] || !req[1]) {
2356 g_strfreev(req);
2357 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2360 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2361 error = attribute_set(client, req+1);
2362 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2363 error = attribute_get(ctx, req+1);
2364 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2365 error = attribute_delete(client, req+1);
2366 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2367 error = attribute_list(ctx, req+1);
2368 else
2369 error = EPWMD_COMMAND_SYNTAX;
2371 g_strfreev(req);
2372 return send_error(ctx, error);
2375 static int iscached_command(assuan_context_t ctx, char *line)
2377 gchar **req = split_input_line(line, " ", 0);
2378 guchar md5file[16];
2380 if (!req || !*req) {
2381 g_strfreev(req);
2382 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2385 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2386 g_strfreev(req);
2387 CACHE_LOCK(ctx);
2389 if (cache_iscached(md5file) == FALSE) {
2390 CACHE_UNLOCK;
2391 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2394 CACHE_UNLOCK;
2395 return send_error(ctx, 0);
2398 gpg_error_t send_cache_status(assuan_context_t ctx)
2400 gchar *tmp;
2401 struct client_s *client = assuan_get_pointer(ctx);
2403 CACHE_LOCK(client->ctx);
2404 tmp = print_fmt("%i %i",
2405 cache_file_count(),
2406 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2407 CACHE_UNLOCK;
2409 return assuan_write_status(ctx, "CACHE", tmp);
2412 static int clearcache_command(assuan_context_t ctx, char *line)
2414 struct client_s *client = assuan_get_pointer(ctx);
2415 gchar **req = split_input_line(line, " ", 0);
2416 guchar md5file[16];
2418 CACHE_LOCK(ctx);
2420 if (!req || !*req) {
2421 g_strfreev(req);
2422 cache_clear(client->md5file, 2);
2423 CACHE_UNLOCK;
2424 return send_error(ctx, 0);
2427 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2428 g_strfreev(req);
2430 if (cache_clear(md5file, 1) == FALSE) {
2431 CACHE_UNLOCK;
2432 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2435 CACHE_UNLOCK;
2436 return send_error(ctx, 0);
2439 static int cachetimeout_command(assuan_context_t ctx, char *line)
2441 guchar md5file[16];
2442 glong timeout;
2443 gchar **req = split_input_line(line, " ", 0);
2444 gchar *p;
2445 struct client_s *client = assuan_get_pointer(ctx);
2447 if (!req || !*req || !req[1]) {
2448 g_strfreev(req);
2449 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2452 errno = 0;
2453 timeout = strtol(req[0], &p, 10);
2455 if (errno != 0 || *p != 0) {
2456 g_strfreev(req);
2457 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2460 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2461 g_strfreev(req);
2462 CACHE_LOCK(client->ctx);
2464 if (cache_set_timeout(md5file, timeout) == FALSE) {
2465 CACHE_UNLOCK;
2466 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2469 CACHE_UNLOCK;
2470 send_cache_status_all();
2471 return send_error(ctx, 0);
2474 static int dump_command(assuan_context_t ctx, char *line)
2476 xmlChar *xml;
2477 gssize len;
2478 struct client_s *client = assuan_get_pointer(ctx);
2479 gpg_error_t error;
2481 if (disable_list_and_dump == TRUE)
2482 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2484 error = file_modified(client);
2486 if (error) {
2487 log_write("%s: %s", client->filename ? client->filename : "",
2488 pwmd_strerror(error));
2489 return send_error(ctx, error);
2492 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2493 error = assuan_send_data(ctx, xml, len);
2494 xmlFree(xml);
2495 return send_error(ctx, error);
2498 static int getconfig_command(assuan_context_t ctx, gchar *line)
2500 struct client_s *client = assuan_get_pointer(ctx);
2501 gpg_error_t error = 0;
2502 gchar *p, *tmp;
2504 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2505 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2507 p = get_key_file_string(client->filename ? client->filename : "default", line);
2509 if (!p)
2510 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2512 tmp = expand_homedir(p);
2513 g_free(p);
2514 p = tmp;
2515 error = assuan_send_data(ctx, p, strlen(p));
2516 g_free(p);
2517 return send_error(ctx, error);
2520 void cleanup_assuan(assuan_context_t ctx)
2522 struct client_s *cl = assuan_get_pointer(ctx);
2524 cleanup_client(cl);
2527 static void reset_notify(assuan_context_t ctx)
2529 struct client_s *cl = assuan_get_pointer(ctx);
2531 cleanup_client(cl);
2534 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2536 gchar name[32] = {0}, value[256] = {0};
2537 pth_attr_t attr = pth_attr_of(pth_self());
2539 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2540 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_SYNTAX);
2542 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2543 log_write("OPTION CLIENT %s", line);
2544 pth_attr_set(attr, PTH_ATTR_NAME, value);
2546 else
2547 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2549 return 0;
2552 static int option_handler(assuan_context_t ctx, const gchar *name,
2553 const gchar *value)
2555 struct client_s *client = assuan_get_pointer(ctx);
2557 if (!value || !*value)
2558 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2560 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2561 g_free(client->pinentry->ttyname);
2562 client->pinentry->ttyname = g_strdup(value);
2564 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2565 g_free(client->pinentry->ttytype);
2566 client->pinentry->ttytype = g_strdup(value);
2568 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2569 g_free(client->pinentry->display);
2570 client->pinentry->display = g_strdup(value);
2572 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2573 g_free(client->pinentry->path);
2574 client->pinentry->path = g_strdup(value);
2576 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2577 g_free(client->pinentry->title);
2578 client->pinentry->title = g_strdup(value);
2580 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2581 g_free(client->pinentry->prompt);
2582 client->pinentry->prompt = g_strdup(value);
2584 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2585 g_free(client->pinentry->desc);
2586 client->pinentry->desc = g_strdup(value);
2588 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2589 gchar *p = NULL;
2590 gint n = strtol(value, &p, 10);
2592 if (*p || n < 0)
2593 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2595 client->pinentry->timeout = n;
2597 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2598 gchar *p = NULL;
2599 gint n = strtol(value, &p, 10);
2601 if (*p || n < 0 || n > 1)
2602 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_INV_VALUE);
2604 client->pinentry->use = n == 0 ? FALSE : TRUE;
2606 else if (g_strcasecmp(name, (gchar *)"client") == 0)
2607 return parse_client_option(ctx, value);
2608 else
2609 return gpg_err_make(GPG_ERR_SOURCE_USER_1, GPG_ERR_UNKNOWN_OPTION);
2611 log_write("OPTION %s=%s", name, value);
2612 return 0;
2615 gpg_error_t register_commands(assuan_context_t ctx)
2617 static struct {
2618 const char *name;
2619 int (*handler)(assuan_context_t, char *line);
2620 } table[] = {
2621 { "OPEN", open_command },
2622 { "SAVE", save_command },
2623 { "LIST", list_command },
2624 { "REALPATH", realpath_command },
2625 { "STORE", store_command },
2626 { "DELETE", delete_command },
2627 { "GET", get_command },
2628 { "ATTR", attr_command },
2629 { "ISCACHED", iscached_command },
2630 { "CLEARCACHE", clearcache_command },
2631 { "CACHETIMEOUT", cachetimeout_command },
2632 { "GETCONFIG", getconfig_command },
2633 { "DUMP", dump_command },
2634 { "INPUT", NULL },
2635 { "OUTPUT", NULL },
2636 { NULL, NULL }
2638 int i, rc;
2640 for (i=0; table[i].name; i++) {
2641 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2643 if (rc)
2644 return rc;
2647 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2648 if (rc)
2649 return rc;
2651 rc = assuan_register_option_handler(ctx, option_handler);
2652 if (rc)
2653 return rc;
2655 return assuan_register_reset_notify(ctx, reset_notify);
2658 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2659 guchar *key)
2661 guchar *iv;
2662 void *inbuf;
2663 gsize insize, len;
2664 guchar tkey[gcrykeysize];
2665 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2666 gcry_cipher_hd_t gh;
2667 guint iter = 0, n_iter = 0;
2668 gint iter_progress;
2669 void *outbuf = NULL;
2670 gint zerror = 0;
2671 glong outsize = 0;
2672 gpg_error_t error;
2673 file_header_t file_header;
2675 if (!ctx) {
2676 error = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2678 if (error)
2679 return error;
2681 else
2682 gh = client->gh;
2684 lseek(fd, 0, SEEK_SET);
2685 insize = st.st_size - sizeof(file_header_t);
2686 iv = gcry_malloc(gcryblocksize);
2688 if (!iv) {
2689 if (!ctx)
2690 gcry_cipher_close(gh);
2692 return gpg_error_from_errno(ENOMEM);
2695 len = pth_read(fd, &file_header, sizeof(file_header_t));
2697 if (len != sizeof(file_header_t)) {
2698 len = errno;
2700 if (!ctx)
2701 gcry_cipher_close(gh);
2703 gcry_free(iv);
2704 errno = len;
2705 return gpg_error_from_errno(errno);
2708 /* No encryption iterations. This is a plain (gzipped) file. */
2709 if (file_header.iter == -1) {
2711 * cache_file_count() needs both .used == TRUE and a valid key in
2712 * order for it to count as a used cache entry. Fixes CACHE status
2713 * messages.
2715 memset(key, '!', gcrykeysize);
2716 insize = st.st_size - sizeof(file_header_t);
2719 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2720 inbuf = gcry_malloc(insize);
2722 if (!inbuf) {
2723 if (!ctx)
2724 gcry_cipher_close(gh);
2726 gcry_free(iv);
2727 return gpg_error_from_errno(ENOMEM);
2730 len = pth_read(fd, inbuf, insize);
2732 if (len != insize) {
2733 len = errno;
2735 if (!ctx)
2736 gcry_cipher_close(gh);
2738 gcry_free(iv);
2739 errno = len;
2740 return gpg_error_from_errno(errno);
2743 if (file_header.iter == -1)
2744 goto decompress;
2746 memcpy(tkey, key, sizeof(tkey));
2747 tkey[0] ^= 1;
2749 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2750 if (!ctx) {
2751 gcry_cipher_close(gh);
2752 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2754 else
2755 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2757 gcry_free(inbuf);
2758 gcry_free(iv);
2759 return error;
2762 if ((error = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2763 if (!ctx) {
2764 gcry_cipher_close(gh);
2765 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2767 else
2768 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2770 gcry_free(inbuf);
2771 gcry_free(iv);
2773 if (!ctx)
2774 gcry_cipher_close(gh);
2776 return error;
2779 iter_progress = get_key_file_integer("default", "iteration_progress");
2781 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2782 error = assuan_write_status(client->ctx, "DECRYPT", "0");
2784 if (error) {
2785 gcry_free(inbuf);
2786 gcry_free(iv);
2787 return error;
2791 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2793 if (error) {
2794 gcry_free(inbuf);
2795 gcry_free(iv);
2796 return error;
2799 if ((error = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2800 if (!ctx) {
2801 gcry_cipher_close(gh);
2802 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2804 else
2805 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2807 gcry_free(inbuf);
2808 gcry_free(iv);
2809 return error;
2812 while (iter < file_header.iter) {
2813 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2814 if (!(iter % iter_progress)) {
2815 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i",
2816 ++n_iter * iter_progress));
2818 if (error) {
2819 gcry_free(inbuf);
2820 gcry_free(iv);
2821 return error;
2826 if ((error = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2827 if (!ctx) {
2828 gcry_cipher_close(gh);
2829 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2831 else
2832 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2834 gcry_free(inbuf);
2835 gcry_free(iv);
2836 return error;
2839 error = decrypt_xml(gh, inbuf, insize, NULL, 0);
2841 if (error) {
2842 if (!ctx) {
2843 gcry_cipher_close(gh);
2844 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2846 else
2847 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(error));
2849 gcry_free(inbuf);
2850 gcry_free(iv);
2851 return error;
2854 iter++;
2855 pth_yield(NULL);
2858 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2859 error = assuan_write_status(ctx, "DECRYPT", print_fmt("%i", file_header.iter));
2861 if (error) {
2862 gcry_free(inbuf);
2863 gcry_free(iv);
2864 return error;
2868 gcry_free(iv);
2870 decompress:
2871 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zerror) == FALSE) {
2873 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2875 if (zerror == Z_MEM_ERROR) {
2876 gcry_free(inbuf);
2877 return gpg_error_from_errno(ENOMEM);
2879 else if (zerror != Z_DATA_ERROR) {
2880 gcry_free(inbuf);
2882 if (!ctx)
2883 gcry_cipher_close(gh);
2885 return EPWMD_BADKEY;
2888 else {
2889 gcry_free(inbuf);
2890 inbuf = outbuf;
2891 insize = outsize;
2894 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2895 gcry_free(inbuf);
2897 if (!ctx)
2898 gcry_cipher_close(gh);
2900 return EPWMD_BADKEY;
2903 if (ctx) {
2904 client->xml = inbuf;
2905 client->len = insize;
2907 else {
2908 gcry_cipher_close(gh);
2909 gcry_free(inbuf);
2912 return 0;
2916 * This is called after every Assuan command.
2918 void command_finalize(assuan_context_t ctx, gint error)
2920 struct client_s *client = assuan_get_pointer(ctx);
2922 unlock_file_mutex(client);