IMPORT: make sure the element path is valid.
[pwmd.git] / src / commands.c
blob7f8cd85499ce01feb5133d3f84aa5a34e623156b
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2008 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <zlib.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #ifndef MEM_DEBUG
37 #include "mem.h"
38 #endif
40 #include "xml.h"
41 #include "common.h"
43 #ifdef WITH_PINENTRY
44 #include "pinentry.h"
45 #endif
47 #include "pwmd_error.h"
48 #include "cache.h"
49 #include "misc.h"
50 #include "commands.h"
52 static void *z_alloc(void *data, unsigned items, unsigned size)
54 #ifndef MEM_DEBUG
55 return gcry_calloc(items, size);
56 #else
57 return calloc(items, size);
58 #endif
61 static void z_free(void *data, void *p)
63 #ifndef MEM_DEBUG
64 gcry_free(p);
65 #else
66 free(p);
67 #endif
70 static gpg_error_t file_modified(struct client_s *client)
72 struct stat st;
74 if (client->state != STATE_OPEN)
75 return EPWMD_NO_FILE;
77 if (stat(client->filename, &st) == 0 && client->mtime) {
78 if (client->mtime != st.st_mtime)
79 return EPWMD_FILE_MODIFIED;
82 return 0;
85 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
86 void *inbuf, gsize insize)
88 gpg_error_t rc;
90 if ((rc = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
91 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
92 return FALSE;
95 return TRUE;
98 static gpg_error_t decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
99 void *inbuf, gsize insize)
101 gpg_error_t rc;
103 if ((rc = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize)))
104 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
106 return rc;
109 static gpg_error_t parse_xml(assuan_context_t ctx)
111 struct client_s *client = assuan_get_pointer(ctx);
113 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
115 if (!client->doc)
116 return EPWMD_LIBXML_ERROR;
118 return 0;
121 void unlock_file_mutex(struct client_s *client)
123 pth_mutex_t *m;
125 #ifdef WITH_PINENTRY
126 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
127 #else
128 if (client->has_lock == FALSE)
129 #endif
130 return;
132 CACHE_LOCK(client->ctx);
134 if (cache_get_mutex(client->md5file, &m) == FALSE) {
135 CACHE_UNLOCK;
136 return;
139 CACHE_UNLOCK;
140 pth_mutex_release(m);
141 client->has_lock = FALSE;
144 gpg_error_t lock_file_mutex(struct client_s *client)
146 pth_mutex_t *m;
148 if (client->has_lock == TRUE)
149 return 0;
151 CACHE_LOCK(client->ctx);
153 if (cache_get_mutex(client->md5file, &m) == FALSE) {
154 CACHE_UNLOCK;
155 return 0;
158 CACHE_UNLOCK;
160 if (pth_mutex_acquire(m, TRUE, NULL) == FALSE) {
161 if (errno == EBUSY) {
162 if (client->ctx)
163 assuan_write_status(client->ctx, "LOCKED", N_("Waiting for lock"));
165 pth_mutex_acquire(m, FALSE, NULL);
167 else {
168 gint e = errno;
169 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(errno));
170 return gpg_error_from_errno(e);
174 client->has_lock = TRUE;
175 return 0;
178 void free_client(struct client_s *client)
180 if (client->doc)
181 xmlFreeDoc(client->doc);
183 if (client->xml)
184 gcry_free(client->xml);
186 if (client->filename)
187 g_free(client->filename);
189 if (client->gh)
190 gcry_cipher_close(client->gh);
193 void cleanup_client(struct client_s *client)
195 assuan_context_t ctx = client->ctx;
196 #ifdef WITH_PINENTRY
197 struct pinentry_s *pin = client->pinentry;
198 #endif
200 unlock_file_mutex(client);
201 CACHE_LOCK(client->ctx);
202 cache_decr_refcount(client->md5file);
205 * This may be a new file so don't use a cache slot. save_command() will
206 * set this to FALSE on success.
208 if (client->new == TRUE)
209 cache_clear(client->md5file, 1);
211 free_client(client);
212 memset(client, 0, sizeof(struct client_s));
213 client->state = STATE_CONNECTED;
214 client->ctx = ctx;
215 client->freed = TRUE;
216 #ifdef WITH_PINENTRY
217 client->pinentry = pin;
218 #endif
219 CACHE_UNLOCK;
222 gboolean do_decompress(assuan_context_t ctx, gpointer in, gint insize,
223 gpointer *out, glong *outsize, gint *rc)
225 z_stream z;
226 gpointer pout;
227 gz_header h;
228 gchar buf[17];
229 gchar str[ASSUAN_LINELENGTH];
231 z.zalloc = z_alloc;
232 z.zfree = z_free;
233 z.next_in = in;
234 z.avail_in = insize;
235 z.avail_out = zlib_bufsize;
236 z.next_out = pout = g_malloc(zlib_bufsize);
238 if (!pout) {
239 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
240 *rc = Z_MEM_ERROR;
241 return FALSE;
244 *rc = inflateInit2(&z, 47);
246 if (*rc != Z_OK) {
247 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
248 g_free(pout);
249 return FALSE;
252 memset(&h, 0, sizeof(gz_header));
253 h.comment = (guchar *)buf;
254 h.comm_max = sizeof(buf);
255 *rc = inflateGetHeader(&z, &h);
257 if (*rc != Z_OK) {
258 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
259 g_free(pout);
260 inflateEnd(&z);
261 return FALSE;
264 *rc = inflate(&z, Z_BLOCK);
266 if (*rc != Z_OK) {
267 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
268 g_free(pout);
269 inflateEnd(&z);
270 return FALSE;
273 if (h.comment)
274 insize = atoi((gchar *)h.comment);
276 do {
277 gpointer p;
279 *rc = inflate(&z, Z_FINISH);
281 switch (*rc) {
282 case Z_OK:
283 break;
284 case Z_BUF_ERROR:
285 if (!z.avail_out) {
286 p = g_realloc(pout, z.total_out + zlib_bufsize);
288 if (!p) {
289 *rc = Z_MEM_ERROR;
290 goto fail;
293 pout = p;
294 z.next_out = pout + z.total_out;
295 z.avail_out = zlib_bufsize;
297 if (ctx) {
298 *rc = assuan_write_status(ctx, "DECOMPRESS",
299 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
301 if (*rc)
302 goto fail;
305 break;
306 case Z_STREAM_END:
307 break;
308 default:
309 goto fail;
310 break;
313 pth_yield(NULL);
314 } while (*rc != Z_STREAM_END);
316 if (ctx) {
317 *rc = assuan_write_status(ctx, "DECOMPRESS",
318 print_fmt(str, sizeof(str), "%i %i", z.total_out, insize));
320 if (*rc)
321 goto fail;
324 *out = pout;
325 *outsize = z.total_out;
326 inflateEnd(&z);
327 *rc = 0;
328 return TRUE;
330 fail:
331 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
332 g_free(pout);
333 inflateEnd(&z);
334 return FALSE;
337 gpg_error_t read_file_header(const gchar *filename, file_header_t *fh)
339 gint fd;
340 gsize len;
342 fd = open(filename, O_RDONLY);
344 if (fd == -1)
345 return gpg_error_from_errno(errno);
347 len = pth_read(fd, fh, sizeof(file_header_t));
348 close(fd);
350 if (len != sizeof(file_header_t))
351 return gpg_error_from_errno(errno);
353 return 0;
356 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar shakey[],
357 gboolean cached)
359 struct client_s *client = assuan_get_pointer(ctx);
360 gpg_error_t rc;
361 struct stat st;
362 gint fd;
363 gint timeout;
365 if ((fd = open_file(client->filename, &st)) == -1) {
366 /* New file. */
367 if (errno == ENOENT) {
368 if (shakey[0])
369 goto update_cache;
371 goto done;
374 rc = errno;
375 log_write("%s: %s", client->filename, strerror(errno));
376 cleanup_client(client);
377 memset(shakey, 0, sizeof(shakey));
378 return send_syserror(ctx, rc);
381 rc = try_xml_decrypt(ctx, fd, st, shakey);
382 close(fd);
384 if (rc) {
385 memset(shakey, 0, sizeof(shakey));
386 cleanup_client(client);
387 return send_error(ctx, rc);
390 update_cache:
391 CACHE_LOCK(client->ctx);
393 if (cached == FALSE) {
394 if (cache_update_key(client->md5file, shakey) == FALSE) {
395 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
396 cleanup_client(client);
397 CACHE_UNLOCK;
398 return send_error(ctx, EPWMD_MAX_SLOTS);
401 timeout = get_key_file_integer(client->filename, "cache_timeout");
402 cache_reset_timeout(client->md5file, timeout);
404 else
405 cache_set_timeout(client->md5file, -2);
407 CACHE_UNLOCK;
409 done:
410 memset(shakey, 0, sizeof(shakey));
411 rc = parse_xml(ctx);
413 if (client->xml) {
414 gcry_free(client->xml);
415 client->xml = NULL;
418 if (!rc) {
419 if (client->new == FALSE)
420 send_cache_status_all();
422 client->state = STATE_OPEN;
425 return send_error(ctx, rc);
428 static int open_command(assuan_context_t ctx, char *line)
430 struct stat st;
431 guchar shakey[gcrykeysize];
432 gboolean cached = FALSE;
433 gpg_error_t rc;
434 struct client_s *client = assuan_get_pointer(ctx);
435 gchar **req;
436 gchar *filename = NULL;
437 file_header_t file_header;
439 memset(shakey, 0, sizeof(shakey));
441 if ((req = split_input_line(line, " ", 2)) != NULL)
442 filename = req[0];
444 if (!filename || !*filename) {
445 g_strfreev(req);
446 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
449 if (valid_filename(filename) == FALSE) {
450 g_strfreev(req);
451 return send_error(ctx, EPWMD_INVALID_FILENAME);
454 if (client->state == STATE_OPEN)
455 cleanup_client(client);
457 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
458 CACHE_LOCK(client->ctx);
460 if (cache_has_file(client->md5file) == FALSE) {
461 if (cache_add_file(client->md5file, NULL) == FALSE) {
462 g_strfreev(req);
463 CACHE_UNLOCK;
464 return send_error(ctx, EPWMD_MAX_SLOTS);
468 cache_incr_refcount(client->md5file);
469 CACHE_UNLOCK;
470 rc = lock_file_mutex(client);
472 if (rc) {
473 g_strfreev(req);
474 return send_error(ctx, rc);
477 client->freed = FALSE;
479 if ((rc = gcry_cipher_open(&client->gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0))) {
480 g_strfreev(req);
481 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
482 cleanup_client(client);
483 return send_error(ctx, rc);
486 if (stat(filename, &st) == 0) {
487 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
488 log_write("%s: %s", filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
489 g_strfreev(req);
490 cleanup_client(client);
491 return send_error(ctx, EPWMD_INVALID_FILENAME);
494 client->mtime = st.st_mtime;
497 client->filename = g_strdup(filename);
499 if (!client->filename) {
500 memset(shakey, 0, sizeof(shakey));
501 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
502 cleanup_client(client);
503 g_strfreev(req);
504 return send_syserror(ctx, ENOMEM);
507 #ifdef WITH_PINENTRY
508 client->pinentry->filename = g_strdup(client->filename);
510 if (!client->pinentry->filename) {
511 memset(shakey, 0, sizeof(shakey));
512 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
513 cleanup_client(client);
514 g_strfreev(req);
515 return send_syserror(ctx, ENOMEM);
517 #endif
520 * New files don't need a key.
522 if (access(filename, R_OK) != 0) {
523 if (errno != ENOENT) {
524 rc = errno;
525 log_write("%s: %s", filename, strerror(errno));
526 g_strfreev(req);
527 cleanup_client(client);
528 return send_syserror(ctx, rc);
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 rc = read_file_header(filename, &file_header);
560 if (rc) {
561 g_strfreev(req);
562 cleanup_client(client);
563 return send_error(ctx, rc);
566 if (file_header.iter == -1)
567 goto done;
569 CACHE_LOCK(client->ctx);
570 cached = cache_get_key(client->md5file, shakey);
571 CACHE_UNLOCK;
573 if (cached == FALSE) {
575 * No key specified and no matching filename found in the cache. Use
576 * pinentry to retrieve the key. Cannot return assuan_process_done()
577 * here otherwise the command will be interrupted. The event loop in
578 * client_thread() will poll the file descriptor waiting for it to
579 * become ready to read a pinentry_key_s which will contain the
580 * entered key or rc. It will then call open_command_finalize() to
581 * to finish the command.
583 if (!req[1] || !*req[1]) {
584 #ifdef WITH_PINENTRY
585 if (get_key_file_boolean(filename, "enable_pinentry") == FALSE) {
586 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
587 goto done;
590 g_strfreev(req);
591 lock_pin_mutex(client);
592 client->pinentry->which = PINENTRY_OPEN;
593 rc = pinentry_fork(ctx);
595 if (rc) {
596 unlock_pin_mutex(client->pinentry);
597 cleanup_client(client);
598 return send_error(ctx, rc);
601 client->pinentry->cb = open_command_finalize;
602 client->pinentry->status = PINENTRY_INIT;
603 return 0;
604 #else
605 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
606 goto done;
607 #endif
610 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
613 done:
614 g_strfreev(req);
615 return open_command_finalize(ctx, shakey, cached);
618 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
619 gint size, gpointer *out, glong *outsize, gint *rc)
621 z_stream z;
622 gpointer pout, pin;
623 gz_header h;
624 gchar buf[17];
625 gint cmd = Z_NO_FLUSH;
626 gchar str[ASSUAN_LINELENGTH];
628 z.zalloc = z_alloc;
629 z.zfree = z_free;
630 z.next_in = pin = data;
631 z.avail_in = size < zlib_bufsize ? size : zlib_bufsize;
632 z.avail_out = zlib_bufsize;
633 z.next_out = pout = g_malloc(zlib_bufsize);
635 if (!pout) {
636 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
637 *rc = Z_MEM_ERROR;
638 return FALSE;
641 *rc = deflateInit2(&z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
643 if (*rc != Z_OK) {
644 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
645 g_free(pout);
646 return FALSE;
649 memset(&h, 0, sizeof(gz_header));
650 g_snprintf(buf, sizeof(buf), "%i", size);
651 h.comment = (guchar *)buf;
652 *rc = deflateSetHeader(&z, &h);
654 if (*rc != Z_OK) {
655 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
656 g_free(pout);
657 deflateEnd(&z);
658 return FALSE;
661 do {
662 gpointer p;
664 *rc = deflate(&z, cmd);
666 switch (*rc) {
667 case Z_OK:
668 break;
669 case Z_BUF_ERROR:
670 if (!z.avail_out) {
671 p = g_realloc(pout, z.total_out + zlib_bufsize);
673 if (!p) {
674 *rc = Z_MEM_ERROR;
675 goto fail;
678 pout = p;
679 z.next_out = pout + z.total_out;
680 z.avail_out = zlib_bufsize;
683 if (!z.avail_in && z.total_in < size) {
684 if (z.total_in + zlib_bufsize > size)
685 z.avail_in = size - z.total_in;
686 else
687 z.avail_in = zlib_bufsize;
689 if (ctx) {
690 *rc = assuan_write_status(ctx, "COMPRESS",
691 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
693 if (*rc)
694 goto fail;
698 if (z.total_in >= size)
699 cmd = Z_FINISH;
701 break;
702 case Z_STREAM_END:
703 break;
704 default:
705 goto fail;
708 pth_yield(NULL);
709 } while (*rc != Z_STREAM_END);
711 if (ctx) {
712 *rc = assuan_write_status(ctx, "COMPRESS",
713 print_fmt(str, sizeof(str), "%i %i", z.total_in, size));
715 if (*rc)
716 goto fail;
719 *out = pout;
720 *outsize = z.total_out;
721 deflateEnd(&z);
722 *rc = 0;
723 return TRUE;
725 fail:
726 log_write("%s(%i): %s", __FUNCTION__, __LINE__, z.msg);
727 g_free(pout);
728 deflateEnd(&z);
729 return FALSE;
732 gpg_error_t do_xml_encrypt(struct client_s *client, gcry_cipher_hd_t gh,
733 const gchar *filename, gpointer data, size_t insize, guchar *shakey,
734 gint iter)
736 gsize len = insize;
737 gint fd;
738 gpointer inbuf;
739 guchar tkey[gcrykeysize];
740 gchar *p;
741 gpg_error_t rc;
742 guint iter_progress = 0, n_iter = 0, xiter = 0;
743 gchar tmp[FILENAME_MAX];
744 struct stat st;
745 mode_t mode = 0;
746 file_header_t file_header;
747 gchar str[ASSUAN_LINELENGTH];
749 if (iter == -1) {
751 * cache_file_count() needs both .used == TRUE and a valid key in
752 * order for it to count as a used cache entry. Fixes CACHE status
753 * messages.
755 memset(shakey, '!', gcrykeysize);
756 inbuf = data;
757 file_header.iter = iter;
758 goto write_file;
761 if (insize / gcryblocksize) {
762 len = (insize / gcryblocksize) * gcryblocksize;
764 if (insize % gcryblocksize)
765 len += gcryblocksize;
769 * Resize the existing xml buffer to the block size required by gcrypt
770 * rather than duplicating it and wasting memory.
772 inbuf = gcry_realloc(data, len);
774 if (!inbuf)
775 return gpg_error_from_errno(ENOMEM);
777 insize = len;
778 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
779 memcpy(tkey, shakey, sizeof(tkey));
780 tkey[0] ^= 1;
782 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
783 gcry_free(inbuf);
784 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
785 return rc;
788 file_header.iter = iter;
790 if (client)
791 iter_progress = get_key_file_integer("global", "iteration_progress");
793 if (client && iter_progress && file_header.iter >= iter_progress) {
794 rc = assuan_write_status(client->ctx, "ENCRYPT", "0");
796 if (rc) {
797 gcry_free(inbuf);
798 return rc;
802 while (xiter < file_header.iter) {
803 if (client && iter_progress > 0 && xiter >= iter_progress) {
804 if (!(xiter % iter_progress)) {
805 rc = assuan_write_status(client->ctx, "ENCRYPT",
806 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
808 if (rc) {
809 gcry_free(inbuf);
810 return rc;
815 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
816 sizeof(file_header.iv)))) {
817 gcry_free(inbuf);
818 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
819 return rc;
822 if (encrypt_xml(gh, inbuf, insize, NULL, 0)
823 == FALSE) {
824 gcry_free(inbuf);
825 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
826 return rc;
829 xiter++;
830 pth_yield(NULL);
833 if ((rc = gcry_cipher_setiv(gh, file_header.iv,
834 sizeof(file_header.iv)))) {
835 gcry_free(inbuf);
836 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
837 return rc;
840 if ((rc = gcry_cipher_setkey(gh, shakey, gcrykeysize))) {
841 gcry_free(inbuf);
842 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
843 return rc;
846 if (encrypt_xml(gh, inbuf, insize, NULL, 0) == FALSE) {
847 gcry_free(inbuf);
848 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
849 return rc;
852 if (client && iter_progress && file_header.iter >= iter_progress) {
853 rc = assuan_write_status(client->ctx, "ENCRYPT",
854 print_fmt(str, sizeof(str), "%i", file_header.iter));
856 if (rc) {
857 gcry_free(inbuf);
858 return rc;
862 write_file:
863 if (filename) {
864 if (stat(filename, &st) == 0) {
865 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
868 * FIXME What if the file has an ACL?
870 if (!(mode & S_IWUSR)) {
871 gcry_free(inbuf);
872 return gpg_error_from_errno(EACCES);
875 else {
876 if (errno != ENOENT) {
877 rc = errno;
878 gcry_free(inbuf);
879 return gpg_error_from_errno(rc);
883 g_snprintf(tmp, sizeof(tmp), ".%s.tmp", filename);
885 if ((fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
886 rc = errno;
887 gcry_free(inbuf);
888 p = strrchr(tmp, '/');
889 p++;
890 log_write("%s: %s", p, strerror(rc));
891 return gpg_error_from_errno(rc);
894 else
896 * xml_import() from command line.
898 fd = STDOUT_FILENO;
900 len = pth_write(fd, &file_header, sizeof(file_header_t));
902 if (len != sizeof(file_header)) {
903 len = errno;
905 if (filename) {
906 close(fd);
907 unlink(tmp);
910 gcry_free(inbuf);
911 return gpg_error_from_errno(len);
914 len = pth_write(fd, inbuf, insize);
916 if (len != insize) {
917 len = errno;
919 if (filename) {
920 close(fd);
921 unlink(tmp);
924 gcry_free(inbuf);
925 return gpg_error_from_errno(len);
928 if (fsync(fd) == -1) {
929 len = errno;
931 if (filename) {
932 close(fd);
933 unlink(tmp);
936 gcry_free(inbuf);
937 return gpg_error_from_errno(len);
940 if (filename) {
941 close(fd);
943 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
944 gchar tmp2[FILENAME_MAX];
946 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
948 if (rename(filename, tmp2) == -1) {
949 unlink(tmp);
950 len = errno;
951 gcry_free(inbuf);
952 return gpg_error_from_errno(len);
956 if (rename(tmp, filename) == -1) {
957 len = errno;
958 unlink(tmp);
959 gcry_free(inbuf);
960 return gpg_error_from_errno(len);
963 if (mode)
964 chmod(filename, mode);
967 gcry_free(inbuf);
968 return 0;
971 static gpg_error_t save_command_finalize(assuan_context_t ctx,
972 guchar shakey[], gboolean cached)
974 struct client_s *client = assuan_get_pointer(ctx);
975 gpointer xmlbuf;
976 xmlChar *p;
977 gint len;
978 gint iter;
979 gint timeout;
980 gpointer outbuf;
981 glong outsize = 0;
982 gint zrc;
983 gpg_error_t rc;
984 struct stat st;
986 xmlDocDumpFormatMemory(client->doc, &p, &len, 0);
987 xmlbuf = p;
989 iter = get_key_file_integer(client->filename, "compression_level");
991 if (iter < 0)
992 iter = 0;
994 if (do_compress(ctx, iter, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
995 memset(shakey, 0, sizeof(shakey));
996 xmlFree(xmlbuf);
998 if (zrc == Z_MEM_ERROR) {
999 return send_syserror(ctx, ENOMEM);
1001 else
1002 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1004 else {
1005 gcry_free(xmlbuf);
1006 xmlbuf = outbuf;
1007 len = outsize;
1010 iter = get_key_file_integer(client->filename, "iterations");
1011 rc = do_xml_encrypt(client, client->gh, client->filename, xmlbuf, len, shakey, iter);
1013 if (rc) {
1014 memset(shakey, 0, sizeof(shakey));
1015 return send_error(ctx, rc);
1018 stat(client->filename, &st);
1019 client->mtime = st.st_mtime;
1020 timeout = get_key_file_integer(client->filename, "cache_timeout");
1021 CACHE_LOCK(client->ctx);
1023 if (cached) {
1024 memset(shakey, 0, sizeof(shakey));
1025 cache_reset_timeout(client->md5file, timeout);
1026 CACHE_UNLOCK;
1028 if (client->new == TRUE)
1029 send_cache_status_all();
1031 client->new = FALSE;
1032 return send_error(ctx, 0);
1035 if (cache_update_key(client->md5file, shakey) == FALSE) {
1036 memset(shakey, 0, sizeof(shakey));
1037 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(EPWMD_MAX_SLOTS));
1038 CACHE_UNLOCK;
1039 return send_error(ctx, EPWMD_MAX_SLOTS);
1042 client->new = FALSE;
1043 memset(shakey, 0, sizeof(shakey));
1044 cache_reset_timeout(client->md5file, timeout);
1045 CACHE_UNLOCK;
1046 send_cache_status_all();
1047 return send_error(ctx, 0);
1050 static int save_command(assuan_context_t ctx, char *line)
1052 gboolean cached = FALSE;
1053 guchar shakey[gcrykeysize];
1054 struct stat st;
1055 struct client_s *client = assuan_get_pointer(ctx);
1056 gpg_error_t rc;
1058 memset(shakey, 0, sizeof(shakey));
1059 rc = file_modified(client);
1061 if (rc) {
1062 log_write("%s: %s", client->filename ? client->filename : "",
1063 pwmd_strerror(rc));
1064 return send_error(ctx, rc);
1067 rc = lock_file_mutex(client);
1069 if (rc)
1070 return send_error(ctx, rc);
1072 if (stat(client->filename, &st) == -1 && errno != ENOENT)
1073 return send_syserror(ctx, errno);
1075 if (errno != ENOENT && !S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1076 log_write("%s: %s", client->filename, pwmd_strerror(EPWMD_INVALID_FILENAME));
1077 return send_error(ctx, EPWMD_INVALID_FILENAME);
1080 if (get_key_file_integer(client->filename, "iterations") == -1)
1081 goto done;
1083 if (!line || !*line) {
1084 guchar tmp[sizeof(shakey)];
1085 CACHE_LOCK(ctx);
1087 memset(tmp, '!', sizeof(tmp));
1089 if (cache_get_key(client->md5file, shakey) == FALSE ||
1090 memcmp(shakey, tmp, sizeof(shakey)) == 0) {
1091 CACHE_UNLOCK;
1092 #ifdef WITH_PINENTRY
1093 if (get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1094 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1095 goto done;
1098 lock_pin_mutex(client);
1099 client->pinentry->which = PINENTRY_SAVE;
1100 rc = pinentry_fork(ctx);
1102 if (rc) {
1103 unlock_pin_mutex(client->pinentry);
1104 return send_error(ctx, rc);
1107 client->pinentry->cb = save_command_finalize;
1108 client->pinentry->status = PINENTRY_INIT;
1109 return 0;
1110 #else
1111 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, "", 1);
1112 goto done;
1113 #endif
1115 else {
1116 CACHE_UNLOCK;
1117 cached = TRUE;
1120 else {
1121 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, line, strlen(line));
1122 memset(line, 0, strlen(line));
1125 done:
1126 return save_command_finalize(ctx, shakey, cached);
1129 static int delete_command(assuan_context_t ctx, char *line)
1131 struct client_s *client = assuan_get_pointer(ctx);
1132 gchar **req;
1133 gpg_error_t rc;
1134 xmlNodePtr n;
1136 rc = file_modified(client);
1138 if (rc) {
1139 log_write("%s: %s", client->filename ? client->filename : "",
1140 pwmd_strerror(rc));
1141 return send_error(ctx, rc);
1144 if (strchr(line, '\t'))
1145 req = split_input_line(line, "\t", -1);
1146 else
1147 req = split_input_line(line, " ", -1);
1149 if (!req || !*req)
1150 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1152 n = find_account(client->doc, &req, &rc, NULL, 0);
1154 if (!n) {
1155 g_strfreev(req);
1156 return send_error(ctx, rc);
1160 * No sub-node defined. Remove the entire node (account).
1162 if (!req[1]) {
1163 if (n) {
1164 xmlUnlinkNode(n);
1165 xmlFreeNode(n);
1168 g_strfreev(req);
1169 return send_error(ctx, 0);
1172 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1173 g_strfreev(req);
1175 if (!n)
1176 return send_error(ctx, rc);
1178 if (n) {
1179 xmlUnlinkNode(n);
1180 xmlFreeNode(n);
1183 return send_error(ctx, 0);
1187 * Don't return with assuan_process_done() here. This has been called from
1188 * assuan_process_next() and the command should be finished in
1189 * client_thread().
1191 static int store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1192 gsize len)
1194 assuan_context_t ctx = data;
1195 struct client_s *client = assuan_get_pointer(ctx);
1196 gchar **req;
1197 xmlNodePtr n;
1198 gpg_error_t rc = file_modified(client);
1200 if (assuan_rc || rc) {
1201 if (line)
1202 #ifndef MEM_DEBUG
1203 xfree(line);
1204 #else
1205 free(line);
1206 #endif
1207 return assuan_rc ? assuan_rc : rc;
1210 req = split_input_line((gchar *)line, "\t", 0);
1211 #ifndef MEM_DEBUG
1212 xfree(line);
1213 #else
1214 free(line);
1215 #endif
1217 if (!req || !*req)
1218 return EPWMD_COMMAND_SYNTAX;
1220 if (valid_xml_element((xmlChar *)*req) == FALSE) {
1221 g_strfreev(req);
1222 return EPWMD_INVALID_ELEMENT;
1225 if (valid_element_path(req+1, TRUE) == FALSE) {
1226 g_strfreev(req);
1227 return EPWMD_INVALID_ELEMENT;
1230 again:
1231 n = find_account(client->doc, &req, &rc, NULL, 0);
1233 if (rc && rc == EPWMD_ELEMENT_NOT_FOUND) {
1234 rc = new_account(client->doc, *req);
1236 if (rc) {
1237 g_strfreev(req);
1238 return rc;
1241 goto again;
1244 if (!n) {
1245 g_strfreev(req);
1246 return rc;
1249 if (req[1]) {
1250 if (!n->children)
1251 create_elements_cb(n, req+1, &rc, NULL);
1252 else
1253 find_elements(client->doc, n->children, req+1, &rc,
1254 NULL, NULL, create_elements_cb, FALSE, 0, NULL);
1257 g_strfreev(req);
1258 client->inquire_status = INQUIRE_DONE;
1259 return rc;
1262 static int store_command(assuan_context_t ctx, char *line)
1264 struct client_s *client = assuan_get_pointer(ctx);
1265 gpg_error_t rc = file_modified(client);
1267 if (rc) {
1268 log_write("%s: %s", client->filename ? client->filename : "",
1269 pwmd_strerror(rc));
1270 return send_error(ctx, rc);
1273 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1275 if (rc)
1276 return send_error(ctx, rc);
1278 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1279 client->inquire_status = INQUIRE_BUSY;
1280 return 0;
1283 static int get_command(assuan_context_t ctx, char *line)
1285 struct client_s *client = assuan_get_pointer(ctx);
1286 gchar **req;
1287 gpg_error_t rc;
1288 xmlNodePtr n;
1290 rc = file_modified(client);
1292 if (rc) {
1293 log_write("%s: %s", client->filename ? client->filename : "",
1294 pwmd_strerror(rc));
1295 return send_error(ctx, rc);
1298 req = split_input_line(line, "\t", -1);
1300 if (!req || !*req) {
1301 g_strfreev(req);
1302 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1305 n = find_account(client->doc, &req, &rc, NULL, 0);
1307 if (!n) {
1308 g_strfreev(req);
1309 return send_error(ctx, rc);
1312 if (req[1])
1313 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL);
1315 g_strfreev(req);
1317 if (rc)
1318 return send_error(ctx, rc);
1320 if (!n || !n->children)
1321 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1323 n = find_text_node(n->children);
1325 if (!n || !n->content || !*n->content)
1326 return send_error(ctx, EPWMD_EMPTY_ELEMENT);
1328 rc = assuan_send_data(ctx, n->content, xmlStrlen(n->content));
1329 return send_error(ctx, rc);
1332 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1333 gpg_error_t *rc, gchar **req_orig, void *data)
1335 gchar *path = *(gchar **)data;
1336 gchar *tmp = NULL, *result;
1338 if (path) {
1339 g_free(path);
1340 *(gchar **)data = NULL;
1343 path = g_strjoinv("\t", target);
1345 if (!path) {
1346 *rc = gpg_error_from_errno(ENOMEM);
1347 return NULL;
1350 if (req_orig) {
1351 tmp = g_strjoinv("\t", req_orig);
1353 if (!tmp) {
1354 g_free(path);
1355 *rc = gpg_error_from_errno(ENOMEM);
1356 return NULL;
1360 if (tmp && *tmp)
1361 result = g_strdup_printf("%s\t%s", path, tmp);
1362 else
1363 result = g_strdup(path);
1365 if (!result) {
1366 *rc = gpg_error_from_errno(ENOMEM);
1367 g_free(path);
1368 g_free(tmp);
1369 return NULL;
1372 g_free(path);
1373 g_free(tmp);
1374 *(gchar **)data = result;
1375 return node;
1378 static int realpath_command(assuan_context_t ctx, char *line)
1380 gpg_error_t rc;
1381 struct client_s *client = assuan_get_pointer(ctx);
1382 gchar **req;
1383 gchar *t;
1384 gint i;
1385 xmlNodePtr n;
1386 GString *string;
1387 gchar *rp = NULL;
1389 rc = file_modified(client);
1391 if (rc) {
1392 log_write("%s: %s", client->filename ? client->filename : "",
1393 pwmd_strerror(rc));
1394 return send_error(ctx, rc);
1397 if (strchr(line, '\t') != NULL) {
1398 if ((req = split_input_line(line, "\t", 0)) == NULL)
1399 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1401 else {
1402 if ((req = split_input_line(line, " ", 0)) == NULL)
1403 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
1406 n = find_account(client->doc, &req, &rc, NULL, 0);
1408 if (!n) {
1409 g_strfreev(req);
1410 return send_error(ctx, rc);
1413 rp = g_strjoinv("\t", req);
1415 if (!rp) {
1416 g_strfreev(req);
1417 return send_syserror(ctx, ENOMEM);
1420 if (req[1]) {
1421 n = find_elements(client->doc, n->children, req+1, &rc,
1422 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp);
1424 if (!n) {
1425 g_free(rp);
1426 g_strfreev(req);
1427 return send_error(ctx, rc);
1431 string = g_string_new(rp);
1432 g_free(rp);
1433 g_strfreev(req);
1435 if (!string)
1436 return send_syserror(ctx, ENOMEM);
1438 again:
1439 for (i = 0, t = string->str + i; *t; t++, i++) {
1440 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1441 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1442 goto again;
1446 rc = assuan_send_data(ctx, string->str, string->len);
1447 g_string_free(string, TRUE);
1448 return send_error(ctx, rc);
1451 static int list_command(assuan_context_t ctx, char *line)
1453 struct client_s *client = assuan_get_pointer(ctx);
1454 gpg_error_t rc;
1455 struct element_list_s *elements = NULL;
1456 gchar *tmp;
1458 if (disable_list_and_dump == TRUE)
1459 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
1461 rc = file_modified(client);
1463 if (rc) {
1464 log_write("%s: %s", client->filename, pwmd_strerror(rc));
1465 return send_error(ctx, rc);
1468 if (!*line) {
1469 GString *str;
1471 rc = list_accounts(client->doc, &str);
1473 if (rc)
1474 return send_error(ctx, rc);
1476 rc = assuan_send_data(ctx, str->str, str->len);
1477 g_string_free(str, TRUE);
1478 return send_error(ctx, rc);
1481 elements = g_malloc0(sizeof(struct element_list_s));
1483 if (!elements) {
1484 rc = gpg_err_code_from_errno(ENOMEM);
1485 goto fail;
1488 rc = create_path_list(client->doc, elements, line);
1490 if (rc)
1491 goto fail;
1493 if (elements) {
1494 gint total = g_slist_length(elements->list);
1495 gint i;
1496 GString *str;
1498 if (!total) {
1499 rc = EPWMD_EMPTY_ELEMENT;
1500 goto fail;
1503 str = g_string_new(NULL);
1505 if (!str) {
1506 rc = gpg_err_code_from_errno(ENOMEM);
1507 goto fail;
1510 for (i = 0; i < total; i++) {
1511 tmp = g_slist_nth_data(elements->list, i);
1512 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
1515 rc = assuan_send_data(ctx, str->str, str->len);
1516 g_string_free(str, TRUE);
1518 else
1519 rc = EPWMD_EMPTY_ELEMENT;
1521 fail:
1522 if (elements) {
1523 gint total = g_slist_length(elements->list);
1524 gint i;
1526 for (i = 0; i < total; i++) {
1527 tmp = g_slist_nth_data(elements->list, i);
1528 g_free(tmp);
1531 g_slist_free(elements->list);
1533 if (elements->prefix)
1534 g_free(elements->prefix);
1536 g_free(elements);
1539 return send_error(ctx, rc);
1542 static gpg_error_t add_attribute(xmlNodePtr node, const gchar *name,
1543 const gchar *value)
1545 xmlAttrPtr a;
1547 if ((a = xmlHasProp(node, (xmlChar *)name)) == NULL) {
1548 a = xmlNewProp(node, (xmlChar *)name, (xmlChar *)value);
1550 if (!a)
1551 return EPWMD_LIBXML_ERROR;
1553 else
1554 xmlNodeSetContent(a->children, (xmlChar *)value);
1556 return 0;
1560 * req[0] - element path
1562 static int attribute_list(assuan_context_t ctx, gchar **req)
1564 struct client_s *client = assuan_get_pointer(ctx);
1565 gchar **attrlist = NULL;
1566 gint i = 0;
1567 gchar **path = NULL;
1568 xmlAttrPtr a;
1569 xmlNodePtr n, an;
1570 gchar *line;
1571 gpg_error_t rc;
1573 if (!req || !req[0])
1574 return EPWMD_COMMAND_SYNTAX;
1576 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
1578 * The first argument may be only an account.
1580 if ((path = split_input_line(req[0], " ", 0)) == NULL)
1581 return EPWMD_COMMAND_SYNTAX;
1584 n = find_account(client->doc, &path, &rc, NULL, 0);
1586 if (!n) {
1587 g_strfreev(path);
1588 return rc;
1591 if (path[1]) {
1592 n = find_elements(client->doc, n->children, path+1, &rc,
1593 NULL, NULL, NULL, FALSE, 0, NULL);
1595 if (!n) {
1596 g_strfreev(path);
1597 return rc;
1601 g_strfreev(path);
1603 for (a = n->properties; a; a = a->next) {
1604 gchar **pa;
1606 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1607 if (attrlist)
1608 g_strfreev(attrlist);
1610 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1611 return gpg_error_from_errno(ENOMEM);
1614 attrlist = pa;
1615 an = a->children;
1616 attrlist[i] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1618 if (!attrlist[i]) {
1619 g_strfreev(attrlist);
1620 return gpg_error_from_errno(ENOMEM);
1623 attrlist[++i] = NULL;
1626 if (!attrlist)
1627 return EPWMD_EMPTY_ELEMENT;
1629 line = g_strjoinv("\n", attrlist);
1631 if (!line) {
1632 g_strfreev(attrlist);
1633 return gpg_error_from_errno(ENOMEM);
1636 rc = assuan_send_data(ctx, line, strlen(line));
1637 g_free(line);
1638 g_strfreev(attrlist);
1639 return rc;
1643 * req[0] - attribute
1644 * req[1] - element path
1646 static int attribute_delete(struct client_s *client, gchar **req)
1648 xmlAttrPtr a;
1649 xmlNodePtr n;
1650 gchar **path = NULL;
1651 gpg_error_t rc;
1653 if (!req || !req[0] || !req[1])
1654 return EPWMD_COMMAND_SYNTAX;
1656 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1658 * The first argument may be only an account.
1660 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1661 return EPWMD_COMMAND_SYNTAX;
1665 * Don't remove the "name" attribute for the account element. To remove an
1666 * account use DELETE <account>.
1668 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"name")) {
1669 rc = EPWMD_ATTR_SYNTAX;
1670 goto fail;
1673 n = find_account(client->doc, &path, &rc, NULL, 0);
1675 if (!n)
1676 goto fail;
1678 if (path[1]) {
1679 n = find_elements(client->doc, n->children, path+1, &rc,
1680 NULL, NULL, NULL, FALSE, 0, NULL);
1682 if (!n)
1683 goto fail;
1686 g_strfreev(path);
1688 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL)
1689 return EPWMD_ATTR_NOT_FOUND;
1691 if (xmlRemoveProp(a) == -1)
1692 return EPWMD_LIBXML_ERROR;
1694 return 0;
1696 fail:
1697 g_strfreev(path);
1698 return rc;
1701 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
1702 gpg_error_t *rc)
1704 gchar **src = *path;
1705 gchar **src_orig = g_strdupv(src);
1706 xmlNodePtr n = NULL;
1708 if (!src_orig) {
1709 *rc = gpg_error_from_errno(ENOMEM);
1710 goto fail;
1713 again:
1714 n = find_account(client->doc, &src, rc, NULL, 0);
1716 if (!n) {
1717 if (*rc == EPWMD_ELEMENT_NOT_FOUND) {
1718 *rc = new_account(client->doc, src[0]);
1720 if (*rc)
1721 goto fail;
1723 goto again;
1725 else
1726 goto fail;
1729 if (src[1]) {
1730 if (!n->children)
1731 n = create_target_elements_cb(n, src+1, rc, NULL);
1732 else
1733 n = find_elements(client->doc, n->children, src+1, rc,
1734 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL);
1736 if (!n)
1737 goto fail;
1740 * Reset the position of the element tree now that the elements
1741 * have been created.
1743 g_strfreev(src);
1744 src = src_orig;
1745 src_orig = NULL;
1746 n = find_account(client->doc, &src, rc, NULL, 0);
1748 if (!n)
1749 goto fail;
1751 n = find_elements(client->doc, n->children, src+1, rc,
1752 NULL, NULL, NULL, FALSE, 0, NULL);
1754 if (!n)
1755 goto fail;
1758 fail:
1759 if (src_orig)
1760 g_strfreev(src_orig);
1762 *path = src;
1763 return n;
1767 * Creates a "target" attribute. When other commands encounter an element with
1768 * this attribute, the element path is modified to the target value. If the
1769 * source element path doesn't exist when using 'ATTR SET target', it is
1770 * created, but the destination element path must exist.
1772 * req[0] - source element path
1773 * req[1] - destination element path
1775 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
1777 gchar **src, **dst, *line = NULL;
1778 gpg_error_t rc;
1779 xmlNodePtr n;
1781 if (!req || !req[0] || !req[1])
1782 return EPWMD_COMMAND_SYNTAX;
1784 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1786 * The first argument may be only an account.
1788 if ((src = split_input_line(req[0], " ", 0)) == NULL)
1789 return EPWMD_COMMAND_SYNTAX;
1792 if (valid_element_path(src, FALSE) == FALSE) {
1793 g_strfreev(src);
1794 return EPWMD_INVALID_ELEMENT;
1797 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1799 * The first argument may be only an account.
1801 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1802 rc = EPWMD_COMMAND_SYNTAX;
1803 goto fail;
1807 n = find_account(client->doc, &dst, &rc, NULL, 0);
1810 * Make sure the destination element path exists.
1812 if (!n)
1813 goto fail;
1815 if (dst[1]) {
1816 n = find_elements(client->doc, n->children, dst+1, &rc,
1817 NULL, NULL, NULL, FALSE, 0, NULL);
1819 if (!n)
1820 goto fail;
1823 n = create_element_path(client, &src, &rc);
1825 if (rc)
1826 goto fail;
1828 line = g_strjoinv("\t", dst);
1830 if (!line) {
1831 rc = gpg_error_from_errno(ENOMEM);
1832 goto fail;
1835 rc = add_attribute(n, "target", line);
1837 fail:
1838 g_free(line);
1839 g_strfreev(src);
1840 g_strfreev(dst);
1841 return rc;
1845 * req[0] - account name
1846 * req[1] - new name
1848 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
1850 gpg_error_t rc;
1851 gchar **tmp;
1852 xmlNodePtr n;
1854 tmp = g_strdupv(req);
1856 if (!tmp)
1857 return gpg_error_from_errno(ENOMEM);
1859 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1860 g_strfreev(tmp);
1862 if (!n)
1863 return rc;
1865 if (g_utf8_collate(req[0], req[1]) == 0)
1866 return 0;
1869 * Will not overwrite an existing account.
1871 tmp = g_strdupv(req+1);
1873 if (!tmp)
1874 return gpg_error_from_errno(ENOMEM);
1876 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1877 g_strfreev(tmp);
1879 if (rc && rc != EPWMD_ELEMENT_NOT_FOUND)
1880 return rc;
1882 if (n)
1883 return EPWMD_ACCOUNT_EXISTS;
1886 * Whitespace not allowed in account names.
1888 if (contains_whitespace(req[1]) == TRUE)
1889 return EPWMD_ATTR_SYNTAX;
1891 tmp = g_strdupv(req);
1893 if (!tmp)
1894 return gpg_error_from_errno(ENOMEM);
1896 n = find_account(client->doc, &tmp, &rc, NULL, 0);
1897 g_strfreev(tmp);
1899 if (!n)
1900 return EPWMD_ELEMENT_NOT_FOUND;
1902 return add_attribute(n, "name", req[1]);
1906 * req[0] - attribute
1907 * req[1] - element path
1909 static int attribute_get(assuan_context_t ctx, gchar **req)
1911 struct client_s *client = assuan_get_pointer(ctx);
1912 xmlNodePtr n;
1913 xmlChar *a;
1914 gchar **path= NULL;
1915 gpg_error_t rc;
1917 if (!req || !req[0] || !req[1])
1918 return EPWMD_COMMAND_SYNTAX;
1920 if (strchr(req[1], '\t')) {
1921 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
1922 return EPWMD_COMMAND_SYNTAX;
1924 else {
1925 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1926 return EPWMD_COMMAND_SYNTAX;
1929 n = find_account(client->doc, &path, &rc, NULL, 0);
1931 if (!n)
1932 goto fail;
1934 if (path[1]) {
1935 n = find_elements(client->doc, n->children, path+1, &rc,
1936 NULL, NULL, NULL, FALSE, 0, NULL);
1938 if (!n)
1939 goto fail;
1942 g_strfreev(path);
1944 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
1945 return EPWMD_ATTR_NOT_FOUND;
1947 rc = assuan_send_data(ctx, a, xmlStrlen(a));
1948 xmlFree(a);
1949 return rc;
1951 fail:
1952 g_strfreev(path);
1953 return rc;
1957 * req[0] - attribute
1958 * req[1] - element path
1959 * req[2] - value
1961 static int attribute_set(struct client_s *client, gchar **req)
1963 gchar **path = NULL;
1964 gpg_error_t rc;
1965 xmlNodePtr n;
1967 if (!req || !req[0] || !req[1] || !req[2])
1968 return EPWMD_COMMAND_SYNTAX;
1971 * Reserved attribute names.
1973 if (g_utf8_collate(req[0], "name") == 0) {
1975 * Only reserved for the account element. Not the rest of the
1976 * document.
1978 if (strchr(req[1], '\t') == NULL)
1979 return name_attribute(client, req + 1);
1981 else if (g_utf8_collate(req[0], "target") == 0)
1982 return target_attribute(client, req + 1);
1984 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
1986 * The first argument may be only an account.
1988 if ((path = split_input_line(req[1], " ", 0)) == NULL)
1989 return EPWMD_COMMAND_SYNTAX;
1992 n = find_account(client->doc, &path, &rc, NULL, 0);
1994 if (!n)
1995 goto fail;
1997 if (path[1]) {
1998 n = find_elements(client->doc, n->children, path+1, &rc,
1999 NULL, NULL, NULL, FALSE, 0, NULL);
2001 if (!n)
2002 goto fail;
2005 g_strfreev(path);
2006 return add_attribute(n, req[0], req[2]);
2008 fail:
2009 g_strfreev(path);
2010 return rc;
2014 * req[0] - command
2015 * req[1] - attribute name or element path if command is LIST
2016 * req[2] - element path
2017 * req[2] - element path or value
2019 static int attr_command(assuan_context_t ctx, char *line)
2021 struct client_s *client = assuan_get_pointer(ctx);
2022 gchar **req = split_input_line(line, " ", 4);
2023 gpg_error_t rc = 0;
2025 rc = file_modified(client);
2027 if (rc) {
2028 log_write("%s: %s", client->filename ? client->filename : "",
2029 pwmd_strerror(rc));
2030 g_strfreev(req);
2031 return send_error(ctx, rc);
2034 if (!req || !req[0] || !req[1]) {
2035 g_strfreev(req);
2036 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2039 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2040 rc = attribute_set(client, req+1);
2041 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2042 rc = attribute_get(ctx, req+1);
2043 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2044 rc = attribute_delete(client, req+1);
2045 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2046 rc = attribute_list(ctx, req+1);
2047 else
2048 rc = EPWMD_COMMAND_SYNTAX;
2050 g_strfreev(req);
2051 return send_error(ctx, rc);
2054 static int iscached_command(assuan_context_t ctx, char *line)
2056 gchar **req = split_input_line(line, " ", 0);
2057 guchar md5file[16];
2059 if (!req || !*req) {
2060 g_strfreev(req);
2061 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2064 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2065 g_strfreev(req);
2066 CACHE_LOCK(ctx);
2068 if (cache_iscached(md5file) == FALSE) {
2069 CACHE_UNLOCK;
2070 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2073 CACHE_UNLOCK;
2074 return send_error(ctx, 0);
2077 gpg_error_t send_cache_status(assuan_context_t ctx)
2079 gchar *tmp;
2080 struct client_s *client = assuan_get_pointer(ctx);
2081 gchar buf[ASSUAN_LINELENGTH];
2083 CACHE_LOCK(client->ctx);
2084 tmp = print_fmt(buf, sizeof(buf), "%i %i",
2085 cache_file_count(),
2086 (cache_size / sizeof(file_cache_t)) - cache_file_count());
2087 CACHE_UNLOCK;
2089 return assuan_write_status(ctx, "CACHE", buf);
2092 static int clearcache_command(assuan_context_t ctx, char *line)
2094 struct client_s *client = assuan_get_pointer(ctx);
2095 gchar **req = split_input_line(line, " ", 0);
2096 guchar md5file[16];
2098 CACHE_LOCK(ctx);
2100 if (!req || !*req) {
2101 g_strfreev(req);
2102 cache_clear(client->md5file, 2);
2103 CACHE_UNLOCK;
2104 return send_error(ctx, 0);
2107 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2108 g_strfreev(req);
2110 if (cache_clear(md5file, 1) == FALSE) {
2111 CACHE_UNLOCK;
2112 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2115 CACHE_UNLOCK;
2116 return send_error(ctx, 0);
2119 static int cachetimeout_command(assuan_context_t ctx, char *line)
2121 guchar md5file[16];
2122 glong timeout;
2123 gchar **req = split_input_line(line, " ", 0);
2124 gchar *p;
2125 struct client_s *client = assuan_get_pointer(ctx);
2127 if (!req || !*req || !req[1]) {
2128 g_strfreev(req);
2129 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2132 errno = 0;
2133 timeout = strtol(req[0], &p, 10);
2135 if (errno != 0 || *p != 0) {
2136 g_strfreev(req);
2137 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2140 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
2141 g_strfreev(req);
2142 CACHE_LOCK(client->ctx);
2144 if (cache_set_timeout(md5file, timeout) == FALSE) {
2145 CACHE_UNLOCK;
2146 return send_error(ctx, EPWMD_CACHE_NOT_FOUND);
2149 CACHE_UNLOCK;
2150 return send_error(ctx, 0);
2153 static int dump_command(assuan_context_t ctx, char *line)
2155 xmlChar *xml;
2156 gssize len;
2157 struct client_s *client = assuan_get_pointer(ctx);
2158 gpg_error_t rc;
2160 if (disable_list_and_dump == TRUE)
2161 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2163 rc = file_modified(client);
2165 if (rc) {
2166 log_write("%s: %s", client->filename ? client->filename : "",
2167 pwmd_strerror(rc));
2168 return send_error(ctx, rc);
2171 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2173 if (!xml)
2174 return send_syserror(ctx, ENOMEM);
2176 rc = assuan_send_data(ctx, xml, len);
2177 xmlFree(xml);
2178 return send_error(ctx, rc);
2181 static int getconfig_command(assuan_context_t ctx, gchar *line)
2183 struct client_s *client = assuan_get_pointer(ctx);
2184 gpg_error_t rc = 0;
2185 gchar *p, *tmp;
2187 if (strcmp(line, "key") == 0 || strcmp(line, "key_file") == 0)
2188 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2190 p = get_key_file_string(client->filename ? client->filename : "global", line);
2192 if (!p)
2193 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2195 tmp = expand_homedir(p);
2197 if (!tmp) {
2198 g_free(p);
2199 return send_syserror(ctx, ENOMEM);
2202 g_free(p);
2203 p = tmp;
2204 rc = assuan_send_data(ctx, p, strlen(p));
2205 g_free(p);
2206 return send_error(ctx, rc);
2209 static int xpath_command(assuan_context_t ctx, gchar *line)
2211 struct client_s *client = assuan_get_pointer(ctx);
2212 gpg_error_t rc;
2213 xmlXPathContextPtr xp;
2214 xmlXPathObjectPtr result;
2215 xmlBufferPtr buf = NULL;
2216 gchar **req = NULL;
2218 rc = file_modified(client);
2220 if (rc) {
2221 log_write("%s: %s", client->filename ? client->filename : "",
2222 pwmd_strerror(rc));
2223 return send_error(ctx, rc);
2226 if (!line || !*line)
2227 return send_error(ctx, EPWMD_COMMAND_SYNTAX);
2229 if ((req = split_input_line(line, "\t", 2)) == NULL) {
2230 if (strv_printf(&req, "%s", line) == FALSE)
2231 return send_syserror(ctx, ENOMEM);
2234 xp = xmlXPathNewContext(client->doc);
2236 if (!xp)
2237 return send_error(ctx, EPWMD_LIBXML_ERROR);
2239 result = xmlXPathEvalExpression((xmlChar *)req[0], xp);
2241 if (!result) {
2242 xmlXPathFreeContext(xp);
2243 return send_error(ctx, EPWMD_LIBXML_ERROR);
2246 if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
2247 rc = EPWMD_EMPTY_ELEMENT;
2248 goto fail;
2251 rc = recurse_xpath_nodeset(client->doc, result->nodesetval,
2252 (xmlChar *)req[1], &buf);
2254 if (rc)
2255 goto fail;
2256 else if (!req[1] && !xmlBufferLength(buf)) {
2257 rc = EPWMD_EMPTY_ELEMENT;
2258 goto fail;
2260 else if (req[1])
2261 goto fail;
2263 rc = assuan_send_data(ctx, xmlBufferContent(buf), xmlBufferLength(buf));
2265 fail:
2266 g_strfreev(req);
2268 if (buf)
2269 xmlBufferFree(buf);
2271 if (result)
2272 xmlXPathFreeObject(result);
2274 if (xp)
2275 xmlXPathFreeContext(xp);
2277 return send_error(ctx, rc);
2280 static int import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
2281 gsize len)
2283 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
2284 gpg_error_t rc = file_modified(client);
2285 gchar **req, **path = NULL, *content;
2286 xmlDocPtr doc;
2287 xmlNodePtr n, root, copy;
2289 if (assuan_rc || rc) {
2290 if (line)
2291 #ifndef MEM_DEBUG
2292 xfree(line);
2293 #else
2294 free(line);
2295 #endif
2296 return assuan_rc ? assuan_rc : rc;
2299 req = split_input_line((gchar *)line, " ", 2);
2300 #ifndef MEM_DEBUG
2301 xfree(line);
2302 #else
2303 free(line);
2304 #endif
2306 if (!req || !*req)
2307 return EPWMD_COMMAND_SYNTAX;
2309 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2310 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2311 return EPWMD_COMMAND_SYNTAX;
2314 content = req[1];
2316 if (!content || !*content) {
2317 rc = EPWMD_COMMAND_SYNTAX;
2318 goto fail;
2321 if (valid_xml_element((xmlChar *)*path) == FALSE) {
2322 rc = EPWMD_INVALID_ELEMENT;
2323 goto fail;
2326 if (valid_element_path(path+1, FALSE) == FALSE) {
2327 rc = EPWMD_INVALID_ELEMENT;
2328 goto fail;
2331 n = create_element_path(client, &path, &rc);
2333 if (rc)
2334 goto fail;
2336 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2338 if (!doc) {
2339 rc = EPWMD_LIBXML_ERROR;
2340 goto fail;
2343 root = xmlDocGetRootElement(doc);
2344 copy = xmlCopyNode(root, 1);
2345 n = xmlAddChild(n, copy);
2347 if (!n) {
2348 rc = EPWMD_LIBXML_ERROR;
2349 goto fail;
2352 xmlFreeDoc(doc);
2354 fail:
2355 g_strfreev(path);
2356 g_strfreev(req);
2357 client->inquire_status = INQUIRE_DONE;
2358 return rc;
2361 static int import_command(assuan_context_t ctx, gchar *line)
2363 gpg_error_t rc;
2364 struct client_s *client = assuan_get_pointer(ctx);
2366 rc = file_modified(client);
2368 if (rc) {
2369 log_write("%s: %s", client->filename ? client->filename : "",
2370 pwmd_strerror(rc));
2371 return send_error(ctx, rc);
2374 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
2376 if (rc)
2377 return send_error(ctx, rc);
2379 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2380 client->inquire_status = INQUIRE_BUSY;
2381 return 0;
2384 void cleanup_assuan(assuan_context_t ctx)
2386 struct client_s *cl = assuan_get_pointer(ctx);
2388 if (cl)
2389 cleanup_client(cl);
2392 static void reset_notify(assuan_context_t ctx)
2394 struct client_s *cl = assuan_get_pointer(ctx);
2396 if (cl)
2397 cleanup_client(cl);
2400 static gpg_error_t parse_client_option(assuan_context_t ctx, const gchar *line)
2402 gchar name[32] = {0}, value[256] = {0};
2404 if (sscanf(line, " %31[a-zA-Z] = %255c", name, value) != 2)
2405 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX);
2407 if (g_strcasecmp(name, (gchar *)"NAME") == 0) {
2408 pth_attr_t attr = pth_attr_of(pth_self());
2410 log_write("OPTION CLIENT %s", line);
2411 pth_attr_set(attr, PTH_ATTR_NAME, value);
2412 pth_attr_destroy(attr);
2414 else
2415 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2417 return 0;
2420 static int option_handler(assuan_context_t ctx, const gchar *name,
2421 const gchar *value)
2423 #ifdef WITH_PINENTRY
2424 struct client_s *client = assuan_get_pointer(ctx);
2425 #endif
2427 if (!value || !*value)
2428 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2430 if (g_strcasecmp(name, (gchar *)"client") == 0)
2431 return parse_client_option(ctx, value);
2433 #ifdef WITH_PINENTRY
2434 if (g_strcasecmp(name, (gchar *)"ttyname") == 0) {
2435 g_free(client->pinentry->ttyname);
2436 client->pinentry->ttyname = g_strdup(value);
2438 else if (g_strcasecmp(name, (gchar *)"ttytype") == 0) {
2439 g_free(client->pinentry->ttytype);
2440 client->pinentry->ttytype = g_strdup(value);
2442 else if (g_strcasecmp(name, (gchar *)"display") == 0) {
2443 g_free(client->pinentry->display);
2444 client->pinentry->display = g_strdup(value);
2446 else if (g_strcasecmp(name, (gchar *)"path") == 0) {
2447 g_free(client->pinentry->path);
2448 client->pinentry->path = g_strdup(value);
2450 else if (g_strcasecmp(name, (gchar *)"title") == 0) {
2451 g_free(client->pinentry->title);
2452 client->pinentry->title = g_strdup(value);
2454 else if (g_strcasecmp(name, (gchar *)"prompt") == 0) {
2455 g_free(client->pinentry->prompt);
2456 client->pinentry->prompt = g_strdup(value);
2458 else if (g_strcasecmp(name, (gchar *)"desc") == 0) {
2459 g_free(client->pinentry->desc);
2460 client->pinentry->desc = g_strdup(value);
2462 #if 0
2463 /* Need to wait for pinentry to support a --timeout option so it can
2464 * terminate itself. Cannot do it here because assuan_pipe_connect() calls
2465 * execv() which replaces the pid of the fork()ed thread from
2466 * pinentry_fork(). So pinentry will become a real process after the
2467 * thread terminates and won't be able to be kill()ed from pwmd.
2469 else if (g_strcasecmp(name, (gchar *)"timeout") == 0) {
2470 gchar *p = NULL;
2471 gint n = strtol(value, &p, 10);
2473 if (*p || n < 0)
2474 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2476 client->pinentry->timeout = n;
2478 #endif
2479 else if (g_strcasecmp(name, (gchar *)"pinentry") == 0) {
2480 gchar *p = NULL;
2481 gint n = strtol(value, &p, 10);
2483 if (*p || n < 0 || n > 1)
2484 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
2486 g_key_file_set_boolean(keyfileh, client->filename ? client->filename : "global",
2487 "enable_pinentry", n == 0 ? FALSE : TRUE);
2489 else
2490 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
2491 #else
2492 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
2493 #endif
2495 log_write("OPTION %s=%s", name, value);
2496 return 0;
2499 gpg_error_t register_commands(assuan_context_t ctx)
2501 static struct {
2502 const gchar *name;
2503 gint (*handler)(assuan_context_t, gchar *line);
2504 } table[] = {
2505 { "OPEN", open_command },
2506 { "SAVE", save_command },
2507 { "LIST", list_command },
2508 { "REALPATH", realpath_command },
2509 { "STORE", store_command },
2510 { "DELETE", delete_command },
2511 { "GET", get_command },
2512 { "ATTR", attr_command },
2513 { "ISCACHED", iscached_command },
2514 { "CLEARCACHE", clearcache_command },
2515 { "CACHETIMEOUT", cachetimeout_command },
2516 { "GETCONFIG", getconfig_command },
2517 { "DUMP", dump_command },
2518 { "XPATH", xpath_command },
2519 { "IMPORT", import_command },
2520 { "INPUT", NULL },
2521 { "OUTPUT", NULL },
2522 { NULL, NULL }
2524 gint i, rc;
2526 for (i=0; table[i].name; i++) {
2527 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
2529 if (rc)
2530 return rc;
2533 rc = assuan_register_bye_notify(ctx, cleanup_assuan);
2535 if (rc)
2536 return rc;
2538 rc = assuan_register_option_handler(ctx, option_handler);
2540 if (rc)
2541 return rc;
2543 return assuan_register_reset_notify(ctx, reset_notify);
2546 gpg_error_t try_xml_decrypt(assuan_context_t ctx, gint fd, struct stat st,
2547 guchar *key)
2549 guchar *iv;
2550 void *inbuf;
2551 gsize insize, len;
2552 guchar tkey[gcrykeysize];
2553 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
2554 gcry_cipher_hd_t gh;
2555 guint iter = 0, n_iter = 0;
2556 gint iter_progress;
2557 void *outbuf = NULL;
2558 gint zrc = 0;
2559 glong outsize = 0;
2560 gpg_error_t rc;
2561 file_header_t file_header;
2562 gchar str[ASSUAN_LINELENGTH];
2564 if (!ctx) {
2565 rc = gcry_cipher_open(&gh, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
2567 if (rc)
2568 return rc;
2570 else
2571 gh = client->gh;
2573 lseek(fd, 0, SEEK_SET);
2574 insize = st.st_size - sizeof(file_header_t);
2575 iv = gcry_malloc(gcryblocksize);
2577 if (!iv) {
2578 if (!ctx)
2579 gcry_cipher_close(gh);
2581 return gpg_error_from_errno(ENOMEM);
2584 len = pth_read(fd, &file_header, sizeof(file_header_t));
2586 if (len != sizeof(file_header_t)) {
2587 len = errno;
2589 if (!ctx)
2590 gcry_cipher_close(gh);
2592 gcry_free(iv);
2593 errno = len;
2594 return gpg_error_from_errno(errno);
2597 /* No encryption iterations. This is a plain (gzipped) file. */
2598 if (file_header.iter == -1) {
2600 * cache_file_count() needs both .used == TRUE and a valid key in
2601 * order for it to count as a used cache entry. Fixes CACHE status
2602 * messages.
2604 memset(key, '!', gcrykeysize);
2605 insize = st.st_size - sizeof(file_header_t);
2608 memcpy(iv, &file_header.iv, sizeof(file_header.iv));
2609 inbuf = gcry_malloc(insize);
2611 if (!inbuf) {
2612 if (!ctx)
2613 gcry_cipher_close(gh);
2615 gcry_free(iv);
2616 return gpg_error_from_errno(ENOMEM);
2619 len = pth_read(fd, inbuf, insize);
2621 if (len != insize) {
2622 len = errno;
2624 if (!ctx)
2625 gcry_cipher_close(gh);
2627 gcry_free(iv);
2628 errno = len;
2629 return gpg_error_from_errno(errno);
2632 if (file_header.iter == -1)
2633 goto decompress;
2635 memcpy(tkey, key, sizeof(tkey));
2636 tkey[0] ^= 1;
2638 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2639 if (!ctx) {
2640 gcry_cipher_close(gh);
2641 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2643 else
2644 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2646 gcry_free(inbuf);
2647 gcry_free(iv);
2648 return rc;
2651 if ((rc = gcry_cipher_setkey(gh, key, gcrykeysize))) {
2652 if (!ctx) {
2653 gcry_cipher_close(gh);
2654 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2656 else
2657 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2659 gcry_free(inbuf);
2660 gcry_free(iv);
2662 if (!ctx)
2663 gcry_cipher_close(gh);
2665 return rc;
2668 iter_progress = get_key_file_integer("global", "iteration_progress");
2670 if (ctx && iter_progress > 0 && file_header.iter >= iter_progress) {
2671 rc = assuan_write_status(client->ctx, "DECRYPT", "0");
2673 if (rc) {
2674 gcry_free(inbuf);
2675 gcry_free(iv);
2676 return rc;
2680 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2682 if (rc) {
2683 gcry_free(inbuf);
2684 gcry_free(iv);
2685 return rc;
2688 if ((rc = gcry_cipher_setkey(gh, tkey, gcrykeysize))) {
2689 if (!ctx) {
2690 gcry_cipher_close(gh);
2691 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2693 else
2694 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2696 gcry_free(inbuf);
2697 gcry_free(iv);
2698 return rc;
2701 while (iter < file_header.iter) {
2702 if (ctx && iter_progress > 0 && iter >= iter_progress) {
2703 if (!(iter % iter_progress)) {
2704 rc = assuan_write_status(ctx, "DECRYPT",
2705 print_fmt(str, sizeof(str), "%i", ++n_iter * iter_progress));
2707 if (rc) {
2708 gcry_free(inbuf);
2709 gcry_free(iv);
2710 return rc;
2715 if ((rc = gcry_cipher_setiv(gh, iv, gcryblocksize))) {
2716 if (!ctx) {
2717 gcry_cipher_close(gh);
2718 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2720 else
2721 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2723 gcry_free(inbuf);
2724 gcry_free(iv);
2725 return rc;
2728 rc = decrypt_xml(gh, inbuf, insize, NULL, 0);
2730 if (rc) {
2731 if (!ctx) {
2732 gcry_cipher_close(gh);
2733 warnx("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2735 else
2736 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(rc));
2738 gcry_free(inbuf);
2739 gcry_free(iv);
2740 return rc;
2743 iter++;
2744 pth_yield(NULL);
2747 if (ctx && iter_progress && file_header.iter >= iter_progress) {
2748 rc = assuan_write_status(ctx, "DECRYPT",
2749 print_fmt(str, sizeof(str), "%i", file_header.iter));
2751 if (rc) {
2752 gcry_free(inbuf);
2753 gcry_free(iv);
2754 return rc;
2758 gcry_free(iv);
2760 decompress:
2761 if (do_decompress(ctx, inbuf, insize, &outbuf, &outsize, &zrc) == FALSE) {
2763 * Z_DATA_ERROR may be returned if this file hasn't been compressed yet.
2765 if (zrc == Z_MEM_ERROR) {
2766 gcry_free(inbuf);
2767 return gpg_error_from_errno(ENOMEM);
2769 else if (zrc != Z_DATA_ERROR) {
2770 gcry_free(inbuf);
2772 if (!ctx)
2773 gcry_cipher_close(gh);
2775 return EPWMD_BADKEY;
2778 else {
2779 gcry_free(inbuf);
2780 inbuf = outbuf;
2781 insize = outsize;
2784 if (g_strncasecmp(inbuf, "<?xml version=\"1.0\"?>", 21) != 0) {
2785 gcry_free(inbuf);
2787 if (!ctx)
2788 gcry_cipher_close(gh);
2790 return EPWMD_BADKEY;
2793 if (ctx) {
2794 client->xml = inbuf;
2795 client->len = insize;
2797 else {
2798 gcry_cipher_close(gh);
2799 gcry_free(inbuf);
2802 return 0;
2806 * This is called after every Assuan command.
2808 void command_finalize(assuan_context_t ctx, gint rc)
2810 struct client_s *client = assuan_get_pointer(ctx);
2812 unlock_file_mutex(client);