Let the COPY command update the _mtime of the destination element path.
[pwmd.git] / src / commands.c
blob4ec9c3a1c8a699d7b687aa9896b327e5342a4627
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2010 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 02110-1301 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>
31 #include <dirent.h>
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
37 #ifdef WITH_LIBACL
38 #include <sys/acl.h>
39 #endif
41 #include "mem.h"
42 #include "xml.h"
43 #include "common.h"
45 #ifdef WITH_PINENTRY
46 #include "pinentry.h"
47 #endif
49 #include "pwmd_error.h"
50 #include "cache.h"
51 #include "misc.h"
52 #include "commands.h"
53 #include "lock.h"
55 struct gz_s {
56 z_stream z;
57 gpointer out;
58 gboolean done;
59 status_msg_t which;
62 static gpg_error_t do_lock_command(struct client_s *client);
64 static void *z_alloc(void *data, unsigned items, unsigned size)
66 return gcry_calloc(items, size);
69 static void z_free(void *data, void *p)
71 gcry_free(p);
74 static gpg_error_t file_modified(struct client_s *client)
76 struct stat st;
77 gpg_error_t rc;
79 if (client->state != STATE_OPEN)
80 return EPWMD_NO_FILE;
82 rc = lock_file_mutex(client);
84 if (rc)
85 return rc;
87 if (lstat(client->filename, &st) == 0 && client->mtime) {
88 if (client->mtime != st.st_mtime)
89 return EPWMD_FILE_MODIFIED;
92 pth_cancel_point();
93 return 0;
96 static gpg_error_t parse_xml(assuan_context_t ctx)
98 struct client_s *client = assuan_get_pointer(ctx);
100 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
102 if (!client->doc)
103 return EPWMD_LIBXML_ERROR;
105 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
106 return 0;
108 return convert_elements(client->doc);
111 void unlock_file_mutex(struct client_s *client)
113 pth_mutex_t *m;
115 #ifdef WITH_PINENTRY
116 if (client->has_lock == FALSE || client->pinentry->status != PINENTRY_NONE)
117 #else
118 if (client->has_lock == FALSE)
119 #endif
120 return;
122 CACHE_LOCK(client->ctx);
124 if (cache_get_mutex(client->md5file, &m) == FALSE) {
125 CACHE_UNLOCK;
126 return;
129 CACHE_UNLOCK;
130 MUTEX_UNLOCK(m);
131 client->has_lock = client->is_lock_cmd = FALSE;
134 gpg_error_t lock_file_mutex(struct client_s *client)
136 pth_mutex_t *m;
137 gpg_error_t rc = 0;
139 if (client->has_lock == TRUE)
140 return 0;
142 CACHE_LOCK(client->ctx);
144 if (cache_get_mutex(client->md5file, &m) == FALSE) {
145 CACHE_UNLOCK;
146 return 0;
149 CACHE_UNLOCK;
151 if (client->rc_on_locked) {
152 if (!pth_mutex_acquire(m, TRUE, NULL))
153 return GPG_ERR_LOCKED;
154 #ifdef DEBUG
155 MUTEX_LOCK_DEBUG(m);
156 #endif
158 else
159 MUTEX_TRYLOCK(client, m, rc);
161 if (!rc)
162 client->has_lock = TRUE;
164 return rc;
167 void free_client(struct client_s *client)
169 if (client->doc)
170 xmlFreeDoc(client->doc);
172 if (client->xml)
173 gcry_free(client->xml);
175 if (client->filename)
176 g_free(client->filename);
178 if (client->crypto)
179 cleanup_crypto(&client->crypto);
181 if (client->xml_error)
182 xmlResetError(client->xml_error);
185 void cleanup_client(struct client_s *client)
187 assuan_context_t ctx = client->ctx;
188 struct client_thread_s *thd = client->thd;
189 gboolean rc_on_locked = client->rc_on_locked;
190 gboolean lock_on_open = client->lock_on_open;
191 #ifdef WITH_PINENTRY
192 struct pinentry_s *pin = client->pinentry;
193 #endif
195 unlock_file_mutex(client);
196 CACHE_LOCK(client->ctx);
197 cache_decr_refcount(client->md5file);
200 * This may be a new file so don't use a cache slot. save_command() will
201 * set this to FALSE on success.
203 if (client->new == TRUE)
204 cache_clear(client->md5file, 1);
206 CACHE_UNLOCK;
207 free_client(client);
208 memset(client, 0, sizeof(struct client_s));
209 client->state = STATE_CONNECTED;
210 client->ctx = ctx;
211 client->thd = thd;
212 client->freed = TRUE;
213 #ifdef WITH_PINENTRY
214 client->pinentry = pin;
215 #endif
216 client->rc_on_locked = rc_on_locked;
217 client->lock_on_open = lock_on_open;
220 static void gz_cleanup(void *arg)
222 struct gz_s **gz = (struct gz_s **)arg;
224 if (!gz)
225 return;
227 if (!(*gz)->done && (*gz)->out)
228 gcry_free((*gz)->out);
230 if ((*gz)->which == STATUS_COMPRESS) {
231 if ((*gz)->z.zalloc)
232 deflateEnd(&(*gz)->z);
234 else {
235 if ((*gz)->z.zalloc)
236 inflateEnd(&(*gz)->z);
239 g_free(*gz);
240 *gz = NULL;
243 gboolean do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
244 gpointer *out, gulong *outsize, gint *rc)
246 struct gz_s *gz;
247 gz_header h;
248 gchar buf[17];
250 gz = g_malloc0(sizeof(struct gz_s));
252 if (!gz) {
253 *rc = gpg_error_from_errno(ENOMEM);
254 return FALSE;
257 pth_cleanup_push(gz_cleanup, &gz);
258 gz->which = STATUS_DECOMPRESS;
259 gz->z.zalloc = z_alloc;
260 gz->z.zfree = z_free;
261 gz->z.next_in = in;
262 gz->z.avail_in = (uInt)insize;
263 gz->z.avail_out = zlib_bufsize;
264 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
266 if (!gz->out) {
267 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
268 *rc = Z_MEM_ERROR;
269 pth_cleanup_pop(1);
270 return FALSE;
273 *rc = inflateInit2(&gz->z, 47);
275 if (*rc != Z_OK) {
276 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
277 pth_cleanup_pop(1);
278 return FALSE;
281 memset(&h, 0, sizeof(gz_header));
282 h.comment = (guchar *)buf;
283 h.comm_max = sizeof(buf);
284 *rc = inflateGetHeader(&gz->z, &h);
286 if (*rc != Z_OK) {
287 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
288 pth_cleanup_pop(1);
289 return FALSE;
292 *rc = inflate(&gz->z, Z_BLOCK);
294 if (*rc != Z_OK) {
295 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
296 pth_cleanup_pop(1);
297 return FALSE;
300 if (h.comment)
301 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
303 do {
304 gpointer p;
306 *rc = inflate(&gz->z, Z_FINISH);
308 switch (*rc) {
309 case Z_OK:
310 break;
311 case Z_BUF_ERROR:
312 if (!gz->z.avail_out) {
313 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
315 if (!p) {
316 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
317 *rc = Z_MEM_ERROR;
318 goto fail;
321 gz->out = p;
322 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
323 gz->z.avail_out = zlib_bufsize;
324 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
325 gz->z.total_out, insize);
327 if (*rc)
328 goto fail;
330 break;
331 case Z_STREAM_END:
332 break;
333 default:
334 goto fail;
335 break;
337 } while (*rc != Z_STREAM_END);
339 *rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
340 insize);
342 if (*rc)
343 goto fail;
345 *out = gz->out;
346 *outsize = gz->z.total_out;
347 gz->done = TRUE;
348 pth_cleanup_pop(1);
349 *rc = 0;
350 return TRUE;
352 fail:
353 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
354 pth_cleanup_pop(1);
355 return FALSE;
358 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
359 gpg_error_t *rc)
361 gint fd;
362 gsize len;
363 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
364 gsize fh_size;
365 gpointer p;
367 *rc = 0;
369 if (!fh) {
370 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
371 *rc = gpg_error_from_errno(ENOMEM);
372 return NULL;
375 pth_cleanup_push(g_free, fh);
376 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
378 if (lstat(filename, &fh->st) == -1) {
379 *rc = gpg_error_from_syserror();
380 pth_cleanup_pop(1);
381 return NULL;
384 if (!S_ISREG(fh->st.st_mode)) {
385 *rc = GPG_ERR_ENOANO;
386 pth_cleanup_pop(1);
387 return NULL;
390 fd = open(filename, O_RDONLY);
392 if (fd == -1) {
393 *rc = gpg_error_from_errno(errno);
394 pth_cleanup_pop(1);
395 return NULL;
398 pth_cleanup_push(cleanup_fd_cb, &fd);
399 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
400 len = pth_read(fd, p, fh_size);
402 if (len != fh_size) {
403 gint n = errno;
404 pth_cleanup_pop(1);
405 pth_cleanup_pop(1);
406 *rc = gpg_error_from_errno(n);
407 return NULL;
410 fh->v1 = v1;
411 fh->fd = fd;
412 pth_cleanup_pop(0);
413 pth_cleanup_pop(0);
414 return fh;
417 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
418 gboolean cached)
420 struct client_s *client = assuan_get_pointer(ctx);
421 gpg_error_t rc;
422 gint timeout;
423 guchar *key = client->crypto->key;
425 /* New file. */
426 if (!client->crypto->fh) {
427 if (key[0])
428 goto update_cache;
430 goto done;
433 rc = init_client_crypto2(client->filename, client->crypto);
435 if (rc) {
436 cleanup_client(client);
437 return send_error(ctx, rc);
440 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
442 if (rc) {
443 cleanup_client(client);
444 return send_error(ctx, rc);
447 update_cache:
448 CACHE_LOCK(client->ctx);
450 if (cached == FALSE) {
451 if (cache_update_key(client->md5file, key) == FALSE) {
452 cleanup_client(client);
453 CACHE_UNLOCK;
454 return send_syserror(ctx, ENOMEM);
457 timeout = get_key_file_integer(client->filename, "cache_timeout");
458 cache_reset_timeout(client->md5file, timeout);
460 else
461 cache_set_timeout(client->md5file, -2);
463 CACHE_UNLOCK;
465 done:
466 rc = parse_xml(ctx);
468 if (client->xml) {
469 gcry_free(client->xml);
470 client->xml = NULL;
473 if (!rc) {
474 if (client->new == FALSE)
475 send_status_all(STATUS_CACHE);
477 client->state = STATE_OPEN;
480 if (!rc && client->new == FALSE &&
481 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
482 MUTEX_LOCK(&rcfile_mutex);
483 g_key_file_set_double(keyfileh, client->filename, "iterations",
484 client->crypto->fh->ver.fh2.iter);
485 MUTEX_UNLOCK(&rcfile_mutex);
486 send_status_all(STATUS_CONFIG);
489 cleanup_crypto(&client->crypto);
491 if (!rc && client->lock_on_open)
492 return do_lock_command(client);
494 return send_error(ctx, rc);
497 static void req_cleanup(void *arg)
499 if (!arg)
500 return;
502 g_strfreev((gchar **)arg);
505 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
507 struct client_s *client = data;
509 client->lock_on_open = TRUE;
510 return 0;
513 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
515 #ifdef WITH_PINENTRY
516 struct client_s *client = data;
517 gchar *p = NULL;
518 gchar *str = value;
519 gint n;
521 if (!str || !*str) {
522 client->pinentry->enable = -1;
523 client->opts &= ~(OPT_PINENTRY);
524 return 0;
527 n = strtol(str, &p, 10);
529 if (*p || n < 0 || n > 1)
530 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
532 client->pinentry->enable = n == 0 ? FALSE : TRUE;
533 client->opts |= OPT_PINENTRY;
534 log_write1("enable_pinentry=%i", n);
535 #endif
536 return 0;
539 static gint open_command(assuan_context_t ctx, gchar *line)
541 gboolean cached = FALSE;
542 gpg_error_t rc;
543 struct client_s *client = assuan_get_pointer(ctx);
544 gchar **req;
545 gchar *filename = NULL;
546 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
547 struct argv_s *args[] = {
548 &(struct argv_s) { "lock", OPT_NOARG, parse_open_opt_lock },
549 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry},
550 NULL
553 if (client->state == STATE_OPEN)
554 cleanup_client(client);
556 client->lock_on_open = FALSE;
557 rc = parse_options(&line, args, client);
559 if (rc)
560 return send_error(ctx, rc);
562 if ((req = split_input_line(line, " ", 2)) != NULL)
563 filename = req[0];
565 pth_cleanup_push(req_cleanup, req);
567 if (!filename || !*filename) {
568 pth_cleanup_pop(1);
569 return send_error(ctx, GPG_ERR_SYNTAX);
572 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
574 if (valid_filename(filename) == FALSE) {
575 pth_cleanup_pop(1);
576 return send_error(ctx, GPG_ERR_INV_VALUE);
579 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
580 CACHE_LOCK(client->ctx);
582 if (cache_has_file(client->md5file) == FALSE) {
583 if (cache_add_file(client->md5file, NULL) == FALSE) {
584 pth_cleanup_pop(1);
585 CACHE_UNLOCK;
586 return send_syserror(ctx, ENOMEM);
590 cache_incr_refcount(client->md5file);
591 CACHE_UNLOCK;
592 rc = lock_file_mutex(client);
594 if (rc) {
595 pth_cleanup_pop(1);
596 return send_error(ctx, rc);
599 client->freed = FALSE;
600 client->crypto = init_client_crypto();
602 if (!client->crypto) {
603 pth_cleanup_pop(1);
604 cleanup_client(client);
605 return send_syserror(ctx, ENOMEM);
608 client->crypto->key = gcry_malloc(hashlen);
610 if (!client->crypto->key) {
611 pth_cleanup_pop(1);
612 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
613 gpg_error_from_errno(ENOMEM));
614 cleanup_client(client);
615 return send_syserror(ctx, ENOMEM);
618 memset(client->crypto->key, 0, hashlen);
619 client->crypto->fh = read_file_header(filename, FALSE, &rc);
621 if (!client->crypto->fh) {
622 if (gpg_err_code_to_errno(rc) != ENOENT) {
623 log_write("%s: %s", filename, pwmd_strerror(rc));
624 pth_cleanup_pop(1);
625 cleanup_client(client);
626 return send_error(ctx, rc);
630 * New files don't need a key.
632 if ((client->xml = new_document()) == NULL) {
633 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
634 pth_cleanup_pop(1);
635 cleanup_client(client);
636 return send_syserror(ctx, ENOMEM);
639 client->len = xmlStrlen(client->xml);
640 client->new = TRUE;
641 client->filename = g_strdup(filename);
643 if (!client->filename) {
644 pth_cleanup_pop(1);
645 cleanup_client(client);
646 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
647 return send_syserror(ctx, ENOMEM);
650 if (req[1] && *req[1])
651 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
652 strlen(req[1]));
654 pth_cleanup_pop(1);
655 #ifdef WITH_PINENTRY
656 client->pinentry->filename = g_strdup(client->filename);
658 if (!client->pinentry->filename) {
659 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
660 cleanup_client(client);
661 return send_syserror(ctx, ENOMEM);
663 #endif
664 return open_command_finalize(ctx, NULL, cached);
666 else
667 client->mtime = client->crypto->fh->st.st_mtime;
669 client->filename = g_strdup(filename);
671 if (!client->filename) {
672 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
673 pth_cleanup_pop(1);
674 cleanup_client(client);
675 return send_syserror(ctx, ENOMEM);
678 #ifdef WITH_PINENTRY
679 if (client->pinentry->filename)
680 g_free(client->pinentry->filename);
682 client->pinentry->filename = g_strdup(client->filename);
684 if (!client->pinentry->filename) {
685 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
686 pth_cleanup_pop(1);
687 cleanup_client(client);
688 return send_syserror(ctx, ENOMEM);
690 #endif
692 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
693 goto done;
695 CACHE_LOCK(client->ctx);
696 cached = cache_get_key(client->md5file, client->crypto->key);
697 CACHE_UNLOCK;
699 if (cached == FALSE) {
700 gchar *tmp = get_key_file_string(filename, "key_file");
702 if (tmp) {
703 g_free(tmp);
704 pth_cleanup_pop(1);
705 cleanup_client(client);
706 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
710 * No key specified and no matching filename found in the cache. Use
711 * pinentry to retrieve the key. Cannot return assuan_process_done()
712 * here otherwise the command will be interrupted. The event loop in
713 * client_thread() will poll the file descriptor waiting for it to
714 * become ready to read a pinentry_key_s which will contain the
715 * entered key or an error code. It will then call
716 * open_command_finalize() to to finish the command.
718 if (!req[1] || !*req[1]) {
719 #ifdef WITH_PINENTRY
720 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
722 /* From set_pinentry_defaults(). */
723 if (client->pinentry->enable == FALSE ||
724 (client->pinentry->enable == -1 && b == FALSE)) {
725 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
726 goto done;
729 pth_cleanup_pop(1);
730 rc = lock_pin_mutex(client);
732 if (rc) {
733 unlock_pin_mutex(client->pinentry);
734 cleanup_client(client);
735 return send_error(ctx, rc);
738 client->pinentry->which = PINENTRY_OPEN;
739 rc = pinentry_fork(ctx);
741 if (rc) {
742 unlock_pin_mutex(client->pinentry);
743 cleanup_client(client);
744 return send_error(ctx, rc);
747 // Called from pinentry iterate.
748 client->pinentry->cb = open_command_finalize;
749 client->pinentry->status = PINENTRY_INIT;
750 return 0;
751 #else
752 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
753 goto done;
754 #endif
757 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
758 strlen(req[1]));
760 else if (req && req[1] && *req[1]) {
761 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
762 strlen(req[1]) ? strlen(req[1]) : 1);
765 done:
766 pth_cleanup_pop(1);
767 return open_command_finalize(ctx, NULL, cached);
770 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
771 guint size, gpointer *out, gulong *outsize, gint *rc)
773 struct gz_s *gz;
774 gz_header h;
775 gchar buf[17];
776 gint cmd = Z_NO_FLUSH;
778 gz = g_malloc0(sizeof(struct gz_s));
780 if (!gz) {
781 *rc = gpg_error_from_errno(ENOMEM);
782 return FALSE;
785 pth_cleanup_push(gz_cleanup, &gz);
786 gz->which = STATUS_COMPRESS;
787 gz->z.zalloc = z_alloc;
788 gz->z.zfree = z_free;
789 gz->z.next_in = data;
790 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
791 gz->z.avail_out = (uInt)zlib_bufsize;
792 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
794 if (!gz->out) {
795 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
796 *rc = Z_MEM_ERROR;
797 pth_cleanup_pop(1);
798 return FALSE;
801 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
803 if (*rc != Z_OK) {
804 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
805 pth_cleanup_pop(1);
806 return FALSE;
809 /* Rather than store the size of the uncompressed data in the file header,
810 * store it in the comment field of the gzip header. Don't give anyone too
811 * much information. Not sure why really, but it seems the right way. :)
813 memset(&h, 0, sizeof(gz_header));
814 g_snprintf(buf, sizeof(buf), "%u", size);
815 h.comment = (guchar *)buf;
816 *rc = deflateSetHeader(&gz->z, &h);
818 if (*rc != Z_OK) {
819 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
820 pth_cleanup_pop(1);
821 return FALSE;
824 do {
825 gpointer p;
827 *rc = deflate(&gz->z, cmd);
829 switch (*rc) {
830 case Z_OK:
831 break;
832 case Z_BUF_ERROR:
833 if (!gz->z.avail_out) {
834 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
836 if (!p) {
837 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
838 *rc = Z_MEM_ERROR;
839 goto fail;
842 gz->out = p;
843 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
844 gz->z.avail_out = zlib_bufsize;
847 if (!gz->z.avail_in && gz->z.total_in < size) {
848 if (gz->z.total_in + zlib_bufsize > size)
849 gz->z.avail_in = size - gz->z.total_in;
850 else
851 gz->z.avail_in = zlib_bufsize;
853 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
854 gz->z.total_in, size);
856 if (*rc)
857 goto fail;
860 if (gz->z.total_in >= size)
861 cmd = Z_FINISH;
863 break;
864 case Z_STREAM_END:
865 break;
866 default:
867 goto fail;
869 } while (*rc != Z_STREAM_END);
871 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
873 if (*rc)
874 goto fail;
876 *out = gz->out;
877 *outsize = gz->z.total_out;
878 *rc = 0;
879 gz->done = TRUE;
880 pth_cleanup_pop(1);
881 return TRUE;
883 fail:
884 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
885 pth_cleanup_pop(1);
886 return FALSE;
889 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
892 * Useful for a large amount of data. Rather than doing all of the data in one
893 * iteration do it in chunks. This lets the command be cancelable rather than
894 * waiting for it to complete.
896 static gpg_error_t iterate_crypto_once(struct client_s *client,
897 struct crypto_s *crypto, status_msg_t which)
899 gpg_error_t rc = 0;
900 goffset len = CRYPTO_BLOCKSIZE(crypto);
901 gpointer p = gcry_malloc(len);
902 goffset total = 0;
903 gpointer inbuf;
905 if (!p)
906 return gpg_err_code_from_errno(ENOMEM);
908 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
909 len = crypto->insize;
911 pth_cleanup_push(gcry_free, p);
913 for (;;) {
914 inbuf = (guchar *)crypto->inbuf + total;
915 guchar *tmp;
917 if (len + total > crypto->insize)
918 len = crypto->blocksize;
920 if (which == STATUS_ENCRYPT)
921 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
922 else
923 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
925 if (rc)
926 goto done;
928 tmp = (guchar *)crypto->inbuf + total;
929 memmove(tmp, p, len);
930 total += len;
932 if (total >= crypto->insize)
933 break;
935 pth_cancel_point();
938 done:
939 pth_cleanup_pop(1);
940 return rc;
943 /* The crypto struct must be setup for iterations and .key. */
944 gpg_error_t do_xml_encrypt(struct client_s *client,
945 struct crypto_s *crypto, const gchar *filename)
947 goffset len = crypto->insize;
948 gpointer inbuf;
949 gchar *p;
950 gpg_error_t rc;
951 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
952 gchar tmp[FILENAME_MAX];
953 struct stat st;
954 mode_t mode = 0;
955 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
957 if (!crypto->fh->ver.fh2.iter) {
959 * cache_file_count() needs both .used == TRUE and a valid key in
960 * order for it to count as a used cache entry. Fixes CACHE status
961 * messages.
963 memset(crypto->key, '!', hashlen);
964 goto write_file;
968 * Resize the existing xml buffer to the block size required by gcrypt
969 * rather than duplicating it and wasting memory.
971 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
973 if (crypto->insize % crypto->blocksize)
974 len += crypto->blocksize;
976 inbuf = gcry_realloc(crypto->inbuf, len);
978 if (!inbuf) {
979 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
980 return gpg_error_from_errno(ENOMEM);
983 crypto->inbuf = inbuf;
984 crypto->insize = len;
985 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
987 if (crypto->tkey)
988 gcry_free(crypto->tkey);
990 crypto->tkey = gcry_malloc(hashlen);
992 if (!crypto->tkey) {
993 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
994 return gpg_error_from_errno(ENOMEM);
997 memcpy(crypto->tkey, crypto->key, hashlen);
998 guchar *tkey = crypto->tkey;
999 tkey[0] ^= 1;
1001 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1002 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1003 return rc;
1006 iter_progress = (guint64)get_key_file_double(
1007 client ? client->filename : "global", "iteration_progress");
1009 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1010 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1011 "0 %llu", crypto->fh->ver.fh2.iter);
1013 if (rc)
1014 return rc;
1017 while (xiter < crypto->fh->ver.fh2.iter-1) {
1018 if (iter_progress > 0ULL && xiter >= iter_progress) {
1019 if (!(xiter % iter_progress)) {
1020 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1021 "%llu %llu", ++n_iter * iter_progress,
1022 crypto->fh->ver.fh2.iter);
1024 if (rc)
1025 return rc;
1029 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1030 crypto->blocksize))) {
1031 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1032 return rc;
1035 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1037 if (rc) {
1038 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1039 return rc;
1042 xiter++;
1045 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1046 crypto->blocksize))) {
1047 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1048 return rc;
1051 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1052 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1053 return rc;
1056 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1058 if (rc)
1059 return rc;
1061 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1062 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1063 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1065 if (rc)
1066 return rc;
1069 write_file:
1070 tmp[0] = 0;
1072 if (filename) {
1073 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1074 crypto->fh->fd = STDOUT_FILENO;
1075 goto do_write_file;
1078 if (lstat(filename, &st) == 0) {
1079 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1081 if (!(mode & S_IWUSR))
1082 return gpg_error_from_errno(EACCES);
1084 else if (errno != ENOENT)
1085 return gpg_error_from_errno(errno);
1087 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1088 crypto->fh->fd = mkstemp(tmp);
1090 if (crypto->fh->fd == -1) {
1091 rc = errno;
1092 p = strrchr(tmp, '/');
1093 p++;
1094 log_write("%s: %s", p, strerror(rc));
1095 return gpg_error_from_errno(rc);
1098 pth_cleanup_push(cleanup_unlink_cb, tmp);
1100 else
1102 * xml_import() or convert_file() from command line.
1104 crypto->fh->fd = STDOUT_FILENO;
1106 do_write_file:
1107 crypto->fh->ver.fh2.magic[0] = '\177';
1108 crypto->fh->ver.fh2.magic[1] = 'P';
1109 crypto->fh->ver.fh2.magic[2] = 'W';
1110 crypto->fh->ver.fh2.magic[3] = 'M';
1111 crypto->fh->ver.fh2.magic[4] = 'D';
1112 crypto->fh->ver.fh2.version = VERSION_HEX;
1113 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1115 if (len != sizeof(crypto->fh->ver.fh2)) {
1116 len = errno;
1118 if (tmp[0])
1119 pth_cleanup_pop(1);
1121 return gpg_error_from_errno(len);
1124 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1126 if (len != crypto->insize) {
1127 len = errno;
1129 if (tmp[0])
1130 pth_cleanup_pop(1);
1132 return gpg_error_from_errno(len);
1135 if (fsync(crypto->fh->fd) == -1) {
1136 len = errno;
1138 if (tmp[0])
1139 pth_cleanup_pop(1);
1141 return gpg_error_from_errno(len);
1144 if (tmp[0]) {
1145 #ifdef WITH_LIBACL
1146 acl_t acl;
1147 #endif
1148 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1149 gchar tmp2[FILENAME_MAX];
1151 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1152 #ifdef WITH_LIBACL
1153 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1155 if (!acl)
1156 log_write("ACL: %s: %s", filename, strerror(errno));
1157 #endif
1159 if (rename(filename, tmp2) == -1) {
1160 len = errno;
1161 pth_cleanup_pop(1);
1162 #ifdef WITH_LIBACL
1163 if (acl)
1164 acl_free(acl);
1165 #endif
1166 return gpg_error_from_errno(len);
1169 #ifdef WITH_LIBACL
1170 else {
1171 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1173 if (!acl)
1174 log_write("ACL: %s: %s", filename, strerror(errno));
1176 #endif
1178 if (rename(tmp, filename) == -1) {
1179 len = errno;
1180 pth_cleanup_pop(1);
1181 #ifdef WITH_LIBACL
1182 if (acl)
1183 acl_free(acl);
1184 #endif
1185 return gpg_error_from_errno(len);
1188 pth_cleanup_pop(0);
1190 if (mode)
1191 chmod(filename, mode);
1193 #ifdef WITH_LIBACL
1194 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1195 log_write("ACL: %s: %s", filename, strerror(errno));
1197 if (acl)
1198 acl_free(acl);
1199 #endif
1202 if (client && lstat(filename, &st) == 0)
1203 client->mtime = st.st_mtime;
1205 return 0;
1208 gpg_error_t update_save_flags(const gchar *filename,
1209 struct crypto_s *crypto)
1211 gpg_error_t rc;
1212 guint64 iter;
1214 /* New file? */
1215 if (!crypto->fh) {
1216 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1218 if (!crypto->fh)
1219 return GPG_ERR_ENOMEM;
1222 rc = init_client_crypto2(filename, crypto);
1224 if (rc)
1225 return rc;
1227 if (filename && !crypto->fh->v1) {
1228 iter = (guint64)get_key_file_double(filename, "iterations");
1229 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1232 return 0;
1235 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1236 gboolean cached)
1238 struct client_s *client = assuan_get_pointer(ctx);
1239 gpointer xmlbuf;
1240 gulong outsize = 0;
1241 guint len;
1242 gint clevel;
1243 gint timeout;
1244 gpointer outbuf;
1245 gint zrc;
1246 gpg_error_t rc;
1248 if (client->crypto->key && client->crypto->key != key)
1249 gcry_free(client->crypto->key);
1251 client->crypto->key = key;
1252 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1254 if (rc)
1255 return send_error(ctx, rc);
1257 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1258 pth_cleanup_push(xmlFree, xmlbuf);
1259 clevel = get_key_file_integer(client->filename, "compression_level");
1261 if (clevel < 0)
1262 clevel = 0;
1264 if (do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1265 pth_cleanup_pop(1);
1266 cleanup_crypto(&client->crypto);
1268 if (zrc == Z_MEM_ERROR)
1269 return send_syserror(ctx, ENOMEM);
1270 else
1271 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1273 else {
1274 pth_cleanup_pop(1);
1275 xmlbuf = outbuf;
1276 len = outsize;
1279 client->crypto->inbuf = xmlbuf;
1280 client->crypto->insize = len;
1281 rc = update_save_flags(client->filename, client->crypto);
1283 if (rc) {
1284 cleanup_crypto(&client->crypto);
1285 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1286 return send_error(ctx, rc);
1289 rc = do_xml_encrypt(client, client->crypto, client->filename);
1291 if (rc) {
1292 cleanup_crypto(&client->crypto);
1293 return send_error(ctx, rc);
1296 timeout = get_key_file_integer(client->filename, "cache_timeout");
1297 CACHE_LOCK(client->ctx);
1299 if (cached) {
1300 cache_reset_timeout(client->md5file, timeout);
1301 CACHE_UNLOCK;
1303 if (client->new == TRUE)
1304 send_status_all(STATUS_CACHE);
1306 client->new = FALSE;
1307 cleanup_crypto(&client->crypto);
1308 return send_error(ctx, 0);
1311 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1312 CACHE_UNLOCK;
1313 cleanup_crypto(&client->crypto);
1314 return send_syserror(ctx, ENOMEM);
1317 client->new = FALSE;
1318 cache_reset_timeout(client->md5file, timeout);
1319 CACHE_UNLOCK;
1320 send_status_all(STATUS_CACHE);
1321 cleanup_crypto(&client->crypto);
1322 return send_error(ctx, 0);
1325 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1327 struct client_s *client = data;
1328 guint64 n;
1329 gchar *value = v;
1330 gchar *p = NULL;
1332 if (!client->filename)
1333 return EPWMD_NO_FILE;
1335 if (!value || !*value)
1336 return 0;
1338 errno = 0;
1339 n = strtoul(value, &p, 10);
1341 if (errno || (p && *p) || n == G_MAXULONG)
1342 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1344 MUTEX_LOCK(&rcfile_mutex);
1345 g_key_file_set_double(keyfileh,
1346 client->filename ? client->filename : "global", "iterations", n);
1347 MUTEX_UNLOCK(&rcfile_mutex);
1349 if (client->filename)
1350 client->opts |= OPT_ITERATIONS;
1352 log_write1("iterations=%lu", n);
1353 return 0;
1356 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1358 struct client_s *client = data;
1359 const gchar *p = value;
1360 guint64 flags;
1362 if (!client->filename)
1363 return EPWMD_NO_FILE;
1365 if (!p || !*p)
1366 return 0;
1368 flags = pwmd_cipher_str_to_cipher(p);
1370 if (!flags)
1371 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1373 MUTEX_LOCK(&rcfile_mutex);
1374 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1375 MUTEX_UNLOCK(&rcfile_mutex);
1376 log_write1("cipher=%s", p);
1378 if (!value)
1379 g_free((gchar *)p);
1381 return 0;
1384 static gpg_error_t parse_save_opt_force(gpointer data, gpointer value)
1386 struct client_s *client = data;
1388 CACHE_LOCK(client->ctx);
1389 cache_clear(client->md5file, 1);
1390 CACHE_UNLOCK;
1391 return 0;
1394 static gint save_command(assuan_context_t ctx, gchar *line)
1396 gboolean cached = FALSE;
1397 struct stat st;
1398 struct client_s *client = assuan_get_pointer(ctx);
1399 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1400 gpg_error_t rc;
1401 struct argv_s *args[] = {
1402 &(struct argv_s) { "iterations", OPT_OPTARG, parse_save_opt_iterations },
1403 &(struct argv_s) { "cipher", OPT_OPTARG, parse_save_opt_cipher },
1404 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry},
1405 &(struct argv_s) { "force", OPT_NOARG, parse_save_opt_force},
1406 NULL
1409 rc = parse_options(&line, args, client);
1411 if (rc)
1412 return send_error(ctx, rc);
1414 if (line && *line)
1415 log_write2("ARGS=%s", "<passphrase>");
1417 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1418 return send_syserror(ctx, errno);
1420 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1421 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1422 return send_error(ctx, GPG_ERR_ENOANO);
1425 CACHE_LOCK(ctx);
1426 cached = cache_iscached(client->md5file);
1427 CACHE_UNLOCK;
1430 * If a cache entry doesn't exist for this file and the file has a
1431 * "key_file" or "key" parameter, then it's an error. The reason is that
1432 * cache expiration would be useless.
1434 if (cached == FALSE) {
1435 gchar *tmp = get_key_file_string(client->filename, "key_file");
1437 if (tmp) {
1438 g_free(tmp);
1439 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1443 cached = FALSE;
1445 /* New file? */
1446 if (!client->crypto) {
1447 client->crypto = init_client_crypto();
1449 if (!client->crypto) {
1450 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1451 return send_syserror(ctx, ENOMEM);
1455 client->crypto->key = gcry_malloc(hashlen);
1457 if (!client->crypto->key) {
1458 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1459 cleanup_crypto(&client->crypto);
1460 return send_syserror(ctx, ENOMEM);
1463 memset(client->crypto->key, '!', hashlen);
1465 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1466 (!line || !*line))
1467 goto done;
1469 if (!line || !*line) {
1470 client->crypto->tkey = gcry_malloc(hashlen);
1472 if (!client->crypto->tkey) {
1473 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1474 cleanup_crypto(&client->crypto);
1475 return send_syserror(ctx, ENOMEM);
1478 memset(client->crypto->tkey, '!', hashlen);
1479 CACHE_LOCK(ctx);
1481 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1482 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1483 CACHE_UNLOCK;
1485 #ifdef WITH_PINENTRY
1486 gpg_error_t rc;
1488 if (client->pinentry->enable == FALSE ||
1489 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1490 /* Empty keys are allowed. */
1491 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1492 goto done;
1495 lock_pin_mutex(client);
1496 client->pinentry->which = PINENTRY_SAVE;
1497 rc = pinentry_fork(ctx);
1499 if (rc) {
1500 unlock_pin_mutex(client->pinentry);
1501 cleanup_crypto(&client->crypto);
1502 return send_error(ctx, rc);
1505 client->pinentry->cb = save_command_finalize;
1506 client->pinentry->status = PINENTRY_INIT;
1507 return 0;
1508 #else
1509 /* Empty keys are allowed. */
1510 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1511 goto done;
1512 #endif
1514 else {
1515 CACHE_UNLOCK;
1516 cached = TRUE;
1519 else {
1520 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1521 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1523 if (iter <= 0L)
1524 iter = 1;
1526 MUTEX_LOCK(&rcfile_mutex);
1527 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1528 MUTEX_UNLOCK(&rcfile_mutex);
1529 client->opts |= OPT_ITERATIONS;
1530 gpg_error_t rc = send_status(ctx, STATUS_CONFIG, NULL);
1532 if (rc)
1533 return send_error(ctx, rc);
1536 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1537 strlen(line));
1540 done:
1541 return save_command_finalize(ctx, client->crypto->key, cached);
1544 static gint delete_command(assuan_context_t ctx, gchar *line)
1546 struct client_s *client = assuan_get_pointer(ctx);
1547 gchar **req;
1548 gpg_error_t rc;
1549 xmlNodePtr n;
1551 log_write2("ARGS=\"%s\"", line);
1553 if (strchr(line, '\t'))
1554 req = split_input_line(line, "\t", -1);
1555 else
1556 req = split_input_line(line, " ", -1);
1558 if (!req || !*req)
1559 return send_error(ctx, GPG_ERR_SYNTAX);
1561 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1563 if (!n) {
1564 g_strfreev(req);
1565 return send_error(ctx, rc);
1569 * No sub-node defined. Remove the entire node (root element).
1571 if (!req[1]) {
1572 if (n) {
1573 rc = unlink_node(n);
1574 xmlFreeNode(n);
1577 g_strfreev(req);
1578 return send_error(ctx, rc);
1581 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1582 g_strfreev(req);
1584 if (!n)
1585 return send_error(ctx, rc);
1587 if (n) {
1588 rc = unlink_node(n);
1589 xmlFreeNode(n);
1592 return send_error(ctx, rc);
1596 * Don't return with assuan_process_done() here. This has been called from
1597 * assuan_process_next() and the command should be finished in
1598 * client_thread().
1600 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1601 gsize len)
1603 assuan_context_t ctx = data;
1604 struct client_s *client = assuan_get_pointer(ctx);
1605 gchar **req;
1606 xmlNodePtr n;
1607 gpg_error_t rc = file_modified(client);
1609 if (assuan_rc || rc) {
1610 if (line)
1611 xfree(line);
1612 return assuan_rc ? assuan_rc : rc;
1615 req = split_input_line((gchar *)line, "\t", 0);
1616 xfree(line);
1618 if (!req || !*req)
1619 return GPG_ERR_SYNTAX;
1621 again:
1622 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1624 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1625 rc = new_root_element(client->doc, *req);
1627 if (rc) {
1628 g_strfreev(req);
1629 return rc;
1632 goto again;
1635 if (!n) {
1636 g_strfreev(req);
1637 return rc;
1640 if (req[1]) {
1641 if (!n->children)
1642 n = create_elements_cb(n, req+1, &rc, NULL);
1643 else
1644 n = find_elements(client->doc, n->children, req+1, &rc,
1645 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1648 g_strfreev(req);
1649 client->inquire_status = INQUIRE_DONE;
1651 if (!rc)
1652 rc = update_element_mtime(n);
1654 return rc;
1657 static gint store_command(assuan_context_t ctx, gchar *line)
1659 struct client_s *client = assuan_get_pointer(ctx);
1660 gpg_error_t rc;
1662 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1664 if (rc)
1665 return send_error(ctx, rc);
1667 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1668 client->inquire_status = INQUIRE_BUSY;
1669 return 0;
1672 static void *send_data_cb(void *arg)
1674 struct assuan_cmd_s *data = arg;
1675 gint old;
1676 gpg_error_t *rc;
1678 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1679 rc = g_malloc(sizeof(gpg_error_t));
1680 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1681 pth_cancel_state(old, NULL);
1682 pth_exit(rc);
1683 return NULL;
1686 /* For every assuan command that needs to be sent to the client, a timeout is
1687 * needed to determine if the client lost the connection. The timeout is the
1688 * same as the "keepalive" configuration parameter or a default if unset.
1690 gpg_error_t do_assuan_command(assuan_context_t ctx,
1691 void *(*cb)(void *data), void *data)
1693 pth_attr_t attr = pth_attr_new();
1694 pth_t tid;
1695 gint n;
1696 gint to = get_key_file_integer("global", "keepalive");
1697 pth_event_t ev, tev;
1698 pth_status_t st;
1699 gpg_error_t rc = 0;
1700 void *p;
1702 pth_attr_init(attr);
1703 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1704 tid = pth_spawn(attr, cb, data);
1705 n = errno;
1706 pth_attr_destroy(attr);
1708 if (!tid) {
1709 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1710 _gpg_strerror(gpg_error_from_errno(n)));
1711 return gpg_error_from_errno(n);
1714 pth_cleanup_push(cleanup_cancel_cb, tid);
1715 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1716 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1717 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1718 ev = pth_event_concat(ev, tev, NULL);
1719 pth_cleanup_push(cleanup_ev_cb, ev);
1720 pth_yield(tid);
1721 pth_wait(ev);
1723 if (tev) {
1724 st = pth_event_status(tev);
1726 if (st == PTH_STATUS_OCCURRED) {
1727 pth_cleanup_pop(1);
1728 pth_cleanup_pop(1);
1729 return GPG_ERR_TIMEOUT;
1733 st = pth_event_status(ev);
1735 if (st == PTH_STATUS_FAILED) {
1736 pth_cancel(tid);
1737 pth_join(tid, &p);
1738 g_free(p);
1739 rc = GPG_ERR_ASS_WRITE_ERROR;
1741 else if (st == PTH_STATUS_OCCURRED) {
1742 pth_join(tid, &p);
1743 rc = *(gpg_error_t *)p;
1744 g_free(p);
1747 pth_cleanup_pop(1);
1748 pth_cleanup_pop(0);
1749 return rc;
1752 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1753 gint total)
1755 gint to_send;
1756 gint sent = 0;
1757 gpg_error_t rc;
1758 struct assuan_cmd_s data;
1759 gint progress = get_key_file_integer("global", "xfer_progress");
1760 gint flush = 0;
1762 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1763 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1764 data.ctx = ctx;
1765 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1767 if (rc)
1768 return rc;
1770 again:
1771 do {
1772 if (sent + to_send > total)
1773 to_send = total - sent;
1775 data.line = flush ? NULL : (gchar *)line+sent;
1776 data.line_len = flush ? 0 : to_send;
1777 rc = do_assuan_command(ctx, send_data_cb, &data);
1779 if (!rc) {
1780 sent += flush ? 0 : to_send;
1782 if ((progress && !(sent % progress) && sent != total) ||
1783 (sent == total && flush))
1784 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1786 if (!flush && !rc && sent == total) {
1787 flush = 1;
1788 goto again;
1791 } while (!rc && sent < total);
1793 return rc;
1796 static gint get_command(assuan_context_t ctx, gchar *line)
1798 struct client_s *client = assuan_get_pointer(ctx);
1799 gchar **req;
1800 gpg_error_t rc;
1801 xmlNodePtr n;
1803 log_write2("ARGS=\"%s\"", line);
1804 req = split_input_line(line, "\t", -1);
1806 if (!req || !*req) {
1807 g_strfreev(req);
1808 return send_error(ctx, GPG_ERR_SYNTAX);
1811 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1813 if (!n) {
1814 g_strfreev(req);
1815 return send_error(ctx, rc);
1818 if (req[1])
1819 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1821 g_strfreev(req);
1823 if (rc)
1824 return send_error(ctx, rc);
1826 if (!n || !n->children)
1827 return send_error(ctx, GPG_ERR_NO_VALUE);
1829 n = find_text_node(n->children);
1831 if (!n || !n->content || !*n->content)
1832 return send_error(ctx, GPG_ERR_NO_VALUE);
1834 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1835 return send_error(ctx, rc);
1838 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1839 gpg_error_t *rc, gchar **req_orig, void *data)
1841 gchar *path = *(gchar **)data;
1842 gchar *tmp = NULL, *result;
1844 if (path) {
1845 g_free(path);
1846 *(gchar **)data = NULL;
1849 path = g_strjoinv("\t", target);
1851 if (!path) {
1852 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1853 *rc = gpg_error_from_errno(ENOMEM);
1854 return NULL;
1857 if (req_orig) {
1858 tmp = g_strjoinv("\t", req_orig);
1860 if (!tmp) {
1861 g_free(path);
1862 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1863 *rc = gpg_error_from_errno(ENOMEM);
1864 return NULL;
1868 if (tmp && *tmp)
1869 result = g_strdup_printf("%s\t%s", path, tmp);
1870 else
1871 result = g_strdup(path);
1873 if (!result) {
1874 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1875 *rc = gpg_error_from_errno(ENOMEM);
1876 g_free(path);
1877 g_free(tmp);
1878 return NULL;
1881 g_free(path);
1882 g_free(tmp);
1883 *(gchar **)data = result;
1884 return node;
1887 static void list_command_cleanup1(void *arg);
1888 static gint realpath_command(assuan_context_t ctx, gchar *line)
1890 gpg_error_t rc;
1891 struct client_s *client = assuan_get_pointer(ctx);
1892 gchar **req;
1893 gchar *t;
1894 gint i;
1895 xmlNodePtr n;
1896 GString *string;
1897 gchar *rp = NULL;
1899 log_write2("ARGS=\"%s\"", line);
1901 if (strchr(line, '\t') != NULL) {
1902 if ((req = split_input_line(line, "\t", 0)) == NULL)
1903 return send_error(ctx, GPG_ERR_SYNTAX);
1905 else {
1906 if ((req = split_input_line(line, " ", 0)) == NULL)
1907 return send_error(ctx, GPG_ERR_SYNTAX);
1910 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1912 if (!n) {
1913 g_strfreev(req);
1914 return send_error(ctx, rc);
1917 rp = g_strjoinv("\t", req);
1919 if (!rp) {
1920 g_strfreev(req);
1921 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1922 return send_syserror(ctx, ENOMEM);
1925 if (req[1]) {
1926 n = find_elements(client->doc, n->children, req+1, &rc,
1927 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
1929 if (!n) {
1930 g_free(rp);
1931 g_strfreev(req);
1932 return send_error(ctx, rc);
1936 string = g_string_new(rp);
1937 g_free(rp);
1938 g_strfreev(req);
1940 if (!string) {
1941 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1942 return send_syserror(ctx, ENOMEM);
1945 again:
1946 for (i = 0, t = string->str + i; *t; t++, i++) {
1947 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1948 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1949 goto again;
1953 pth_cleanup_push(list_command_cleanup1, string);
1954 rc = xfer_data(ctx, string->str, string->len);
1955 pth_cleanup_pop(1);
1956 return send_error(ctx, rc);
1959 static void list_command_cleanup1(void *arg)
1961 g_string_free((GString *)arg, TRUE);
1964 static void list_command_cleanup2(void *arg)
1966 struct element_list_s *elements = arg;
1968 if (elements) {
1969 if (elements->list) {
1970 gint total = g_slist_length(elements->list);
1971 gint i;
1973 for (i = 0; i < total; i++) {
1974 gchar *tmp = g_slist_nth_data(elements->list, i);
1975 g_free(tmp);
1978 g_slist_free(elements->list);
1981 if (elements->prefix)
1982 g_free(elements->prefix);
1984 if (elements->req)
1985 g_strfreev(elements->req);
1987 g_free(elements);
1991 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
1993 struct element_list_s *elements = data;
1995 elements->recurse = FALSE;
1996 return 0;
1999 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2001 struct element_list_s *elements = data;
2003 elements->verbose = TRUE;
2004 return 0;
2007 static gint list_command(assuan_context_t ctx, gchar *line)
2009 struct client_s *client = assuan_get_pointer(ctx);
2010 gpg_error_t rc;
2011 struct element_list_s *elements = NULL;
2012 gchar *tmp;
2013 struct argv_s *args[] = {
2014 &(struct argv_s) { "no-recurse", OPT_NOARG, parse_list_opt_norecurse },
2015 &(struct argv_s) { "verbose", OPT_NOARG, parse_list_opt_verbose },
2016 NULL
2019 if (disable_list_and_dump == TRUE)
2020 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2022 elements = g_malloc0(sizeof(struct element_list_s));
2024 if (!elements) {
2025 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2026 return gpg_err_code_from_errno(ENOMEM);
2029 elements->recurse = TRUE; // default
2030 pth_cleanup_push(list_command_cleanup2, elements);
2031 rc = parse_options(&line, args, elements);
2033 if (rc)
2034 goto fail;
2036 if (!*line) {
2037 GString *str;
2039 rc = list_root_elements(client->doc, &str, elements->verbose);
2041 if (rc) {
2042 pth_cleanup_pop(1);
2043 return send_error(ctx, rc);
2046 pth_cleanup_push(list_command_cleanup1, str);
2047 rc = xfer_data(ctx, str->str, str->len);
2048 pth_cleanup_pop(1);
2049 pth_cleanup_pop(1);
2050 return send_error(ctx, rc);
2053 elements->req = split_input_line(line, " ", 0);
2055 if (!elements->req)
2056 strv_printf(&elements->req, "%s", line);
2058 rc = create_path_list(client->doc, elements, *elements->req);
2060 if (rc)
2061 goto fail;
2063 if (elements) {
2064 gint total = g_slist_length(elements->list);
2065 gint i;
2066 GString *str;
2068 if (!total) {
2069 rc = GPG_ERR_NO_VALUE;
2070 goto fail;
2073 str = g_string_new(NULL);
2075 if (!str) {
2076 rc = gpg_err_code_from_errno(ENOMEM);
2077 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2078 goto fail;
2081 for (i = 0; i < total; i++) {
2082 tmp = g_slist_nth_data(elements->list, i);
2083 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2086 pth_cleanup_push(list_command_cleanup1, str);
2087 rc = xfer_data(ctx, str->str, str->len);
2088 pth_cleanup_pop(1);
2090 else
2091 rc = GPG_ERR_NO_VALUE;
2093 fail:
2094 pth_cleanup_pop(1);
2095 return send_error(ctx, rc);
2099 * req[0] - element path
2101 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2103 struct client_s *client = assuan_get_pointer(ctx);
2104 gchar **attrlist = NULL;
2105 gint i = 0;
2106 gchar **path = NULL;
2107 xmlAttrPtr a;
2108 xmlNodePtr n, an;
2109 gchar *line;
2110 gpg_error_t rc;
2112 if (!req || !req[0])
2113 return GPG_ERR_SYNTAX;
2115 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2117 * The first argument may be only a root element.
2119 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2120 return GPG_ERR_SYNTAX;
2123 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2125 if (!n) {
2126 g_strfreev(path);
2127 return rc;
2130 if (path[1]) {
2131 n = find_elements(client->doc, n->children, path+1, &rc,
2132 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2134 if (!n) {
2135 g_strfreev(path);
2136 return rc;
2140 g_strfreev(path);
2142 for (a = n->properties; a; a = a->next) {
2143 gchar **pa;
2145 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2146 if (attrlist)
2147 g_strfreev(attrlist);
2149 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2150 return gpg_error_from_errno(ENOMEM);
2153 attrlist = pa;
2154 an = a->children;
2155 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2156 an && an->content ? (gchar *)an->content : "");
2158 if (!attrlist[i]) {
2159 g_strfreev(attrlist);
2160 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2161 return gpg_error_from_errno(ENOMEM);
2164 attrlist[++i] = NULL;
2167 if (!attrlist)
2168 return GPG_ERR_NO_VALUE;
2170 line = g_strjoinv("\n", attrlist);
2172 if (!line) {
2173 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2174 g_strfreev(attrlist);
2175 return gpg_error_from_errno(ENOMEM);
2178 pth_cleanup_push(g_free, line);
2179 pth_cleanup_push(req_cleanup, attrlist);
2180 rc = xfer_data(ctx, line, strlen(line));
2181 pth_cleanup_pop(1);
2182 pth_cleanup_pop(1);
2183 return rc;
2187 * req[0] - attribute
2188 * req[1] - element path
2190 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2192 xmlNodePtr n;
2193 gchar **path = NULL;
2194 gpg_error_t rc;
2196 if (!req || !req[0] || !req[1])
2197 return GPG_ERR_SYNTAX;
2199 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2201 * The first argument may be only a root element.
2203 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2204 return GPG_ERR_SYNTAX;
2208 * Don't remove the "_name" attribute for the root element. To remove an
2209 * root element use DELETE <name>.
2211 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2212 rc = GPG_ERR_SYNTAX;
2213 goto fail;
2216 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2218 if (!n)
2219 goto fail;
2221 if (path[1]) {
2222 n = find_elements(client->doc, n->children, path+1, &rc,
2223 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2225 if (!n)
2226 goto fail;
2229 rc = delete_attribute(n, (xmlChar *)req[0]);
2231 fail:
2232 g_strfreev(path);
2233 return rc;
2236 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2237 gpg_error_t *rc)
2239 gchar **src = *path;
2240 gchar **src_orig = g_strdupv(src);
2241 xmlNodePtr n = NULL;
2243 *rc = 0;
2245 if (!src_orig) {
2246 *rc = gpg_error_from_errno(ENOMEM);
2247 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2248 goto fail;
2251 again:
2252 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2254 if (!n) {
2255 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2256 *rc = new_root_element(client->doc, src[0]);
2258 if (*rc)
2259 goto fail;
2261 goto again;
2263 else
2264 goto fail;
2267 if (src[1]) {
2268 if (!n->children)
2269 n = create_target_elements_cb(n, src+1, rc, NULL);
2270 else
2271 n = find_elements(client->doc, n->children, src+1, rc,
2272 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2274 if (!n)
2275 goto fail;
2278 * Reset the position of the element tree now that the elements
2279 * have been created.
2281 g_strfreev(src);
2282 src = src_orig;
2283 src_orig = NULL;
2284 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2286 if (!n)
2287 goto fail;
2289 n = find_elements(client->doc, n->children, src+1, rc,
2290 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2292 if (!n)
2293 goto fail;
2296 fail:
2297 if (src_orig)
2298 g_strfreev(src_orig);
2300 *path = src;
2301 return n;
2305 * Creates a "target" attribute. When other commands encounter an element with
2306 * this attribute, the element path is modified to the target value. If the
2307 * source element path doesn't exist when using 'ATTR SET target', it is
2308 * created, but the destination element path must exist.
2310 * req[0] - source element path
2311 * req[1] - destination element path
2313 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2315 gchar **src, **dst, *line = NULL, **odst = NULL;
2316 gpg_error_t rc;
2317 xmlNodePtr n;
2319 if (!req || !req[0] || !req[1])
2320 return GPG_ERR_SYNTAX;
2322 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2324 * The first argument may be only a root element.
2326 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2327 return GPG_ERR_SYNTAX;
2330 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2332 * The first argument may be only a root element.
2334 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2335 rc = GPG_ERR_SYNTAX;
2336 goto fail;
2340 odst = g_strdupv(dst);
2342 if (!odst) {
2343 rc = gpg_error_from_errno(ENOMEM);
2344 goto fail;
2347 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2350 * Make sure the destination element path exists.
2352 if (!n)
2353 goto fail;
2355 if (dst[1]) {
2356 n = find_elements(client->doc, n->children, dst+1, &rc,
2357 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2359 if (!n)
2360 goto fail;
2363 n = create_element_path(client, &src, &rc);
2365 if (rc)
2366 goto fail;
2368 line = g_strjoinv("\t", odst);
2370 if (!line) {
2371 rc = gpg_error_from_errno(ENOMEM);
2372 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2373 goto fail;
2376 rc = add_attribute(n, "target", line);
2378 fail:
2379 g_free(line);
2380 g_strfreev(src);
2381 g_strfreev(dst);
2382 g_strfreev(odst);
2383 return rc;
2387 * req[0] - name
2388 * req[1] - new name
2390 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2392 gpg_error_t rc;
2393 gchar **tmp;
2394 xmlNodePtr n;
2396 tmp = g_strdupv(req);
2398 if (!tmp) {
2399 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2400 return gpg_error_from_errno(ENOMEM);
2403 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2404 g_strfreev(tmp);
2406 if (!n)
2407 return rc;
2409 if (g_utf8_collate(req[0], req[1]) == 0)
2410 return 0;
2413 * Will not overwrite an existing root.
2415 tmp = g_strdupv(req+1);
2417 if (!tmp) {
2418 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2419 return gpg_error_from_errno(ENOMEM);
2422 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2423 g_strfreev(tmp);
2425 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2426 return rc;
2428 if (n)
2429 return GPG_ERR_AMBIGUOUS_NAME;
2432 * Whitespace not allowed in root names.
2434 if (contains_whitespace(req[1]) == TRUE)
2435 return GPG_ERR_SYNTAX;
2437 tmp = g_strdupv(req);
2439 if (!tmp) {
2440 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2441 return gpg_error_from_errno(ENOMEM);
2444 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2445 g_strfreev(tmp);
2447 if (!n)
2448 return GPG_ERR_ELEMENT_NOT_FOUND;
2450 return add_attribute(n, "_name", req[1]);
2454 * req[0] - attribute
2455 * req[1] - element path
2457 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2459 struct client_s *client = assuan_get_pointer(ctx);
2460 xmlNodePtr n;
2461 xmlChar *a;
2462 gchar **path= NULL;
2463 gpg_error_t rc;
2465 if (!req || !req[0] || !req[1])
2466 return GPG_ERR_SYNTAX;
2468 if (strchr(req[1], '\t')) {
2469 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2470 return GPG_ERR_SYNTAX;
2472 else {
2473 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2474 return GPG_ERR_SYNTAX;
2477 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2479 if (!n)
2480 goto fail;
2482 if (path[1]) {
2483 n = find_elements(client->doc, n->children, path+1, &rc,
2484 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2486 if (!n)
2487 goto fail;
2490 g_strfreev(path);
2492 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2493 return GPG_ERR_NOT_FOUND;
2495 pth_cleanup_push(xmlFree, a);
2497 if (*a)
2498 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2499 else
2500 rc = GPG_ERR_NO_VALUE;
2502 pth_cleanup_pop(1);
2503 return rc;
2505 fail:
2506 g_strfreev(path);
2507 return rc;
2511 * req[0] - attribute
2512 * req[1] - element path
2513 * req[2] - value
2515 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2517 gchar **path = NULL;
2518 gpg_error_t rc;
2519 xmlNodePtr n;
2521 if (!req || !req[0] || !req[1])
2522 return GPG_ERR_SYNTAX;
2525 * Reserved attribute names.
2527 if (!strcmp(req[0], "_name")) {
2529 * Only reserved for the root element. Not the rest of the
2530 * document.
2532 if (strchr(req[1], '\t') == NULL)
2533 return name_attribute(client, req + 1);
2535 else if (!strcmp(req[0], "target"))
2536 return target_attribute(client, req + 1);
2538 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2540 * The first argument may be only a root element.
2542 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2543 return GPG_ERR_SYNTAX;
2546 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2548 if (!n)
2549 goto fail;
2551 if (path[1]) {
2552 n = find_elements(client->doc, n->children, path+1, &rc,
2553 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2555 if (!n)
2556 goto fail;
2559 rc = add_attribute(n, req[0], req[2]);
2561 fail:
2562 g_strfreev(path);
2563 return rc;
2567 * req[0] - command
2568 * req[1] - attribute name or element path if command is LIST
2569 * req[2] - element path
2570 * req[2] - element path or value
2572 static gint attr_command(assuan_context_t ctx, gchar *line)
2574 struct client_s *client = assuan_get_pointer(ctx);
2575 gchar **req;
2576 gpg_error_t rc = 0;
2578 log_write2("ARGS=\"%s\"", line);
2579 req = split_input_line(line, " ", 4);
2581 if (!req || !req[0] || !req[1]) {
2582 g_strfreev(req);
2583 return send_error(ctx, GPG_ERR_SYNTAX);
2586 pth_cleanup_push(req_cleanup, req);
2588 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2589 rc = attribute_set(client, req+1);
2590 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2591 rc = attribute_get(ctx, req+1);
2592 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2593 rc = attribute_delete(client, req+1);
2594 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2595 rc = attribute_list(ctx, req+1);
2596 else
2597 rc = GPG_ERR_SYNTAX;
2599 pth_cleanup_pop(1);
2600 return send_error(ctx, rc);
2603 static gint iscached_command(assuan_context_t ctx, gchar *line)
2605 gchar **req = split_input_line(line, " ", 0);
2606 guchar md5file[16];
2607 gchar *path, *tmp;
2609 if (!req || !*req) {
2610 g_strfreev(req);
2611 return send_error(ctx, GPG_ERR_SYNTAX);
2614 log_write2("ARGS=\"%s\"", line);
2616 if (!valid_filename(req[0])) {
2617 g_strfreev(req);
2618 return GPG_ERR_INV_VALUE;
2621 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2622 CACHE_LOCK(ctx);
2624 if (cache_iscached(md5file)) {
2625 g_strfreev(req);
2626 CACHE_UNLOCK;
2627 return send_error(ctx, 0);
2630 CACHE_UNLOCK;
2631 tmp = get_key_file_string("global", "data_directory");
2633 if (!tmp) {
2634 g_strfreev(req);
2635 return gpg_error_from_errno(ENOMEM);
2638 path = expand_homedir(tmp);
2640 if (!path) {
2641 g_strfreev(req);
2642 g_free(tmp);
2643 return gpg_error_from_errno(ENOMEM);
2646 g_free(tmp);
2647 tmp = path;
2648 path = g_strdup_printf("%s/%s", tmp, req[0]);
2649 g_free(tmp);
2651 if (!path) {
2652 g_strfreev(req);
2653 return gpg_error_from_errno(ENOMEM);
2656 if (access(path, R_OK) == -1) {
2657 gpg_error_t rc = gpg_error_from_syserror();
2659 g_free(path);
2660 g_strfreev(req);
2661 return send_error(ctx, rc);
2664 g_free(path);
2665 return send_error(ctx, GPG_ERR_NOT_FOUND);
2668 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2670 struct client_s *client = assuan_get_pointer(ctx);
2671 gchar **req = split_input_line(line, " ", 0);
2672 guchar md5file[16];
2674 log_write2("ARGS=\"%s\"", line);
2675 CACHE_LOCK(ctx);
2677 if (!req || !*req) {
2678 g_strfreev(req);
2679 cache_clear(client->md5file, 2);
2680 CACHE_UNLOCK;
2681 return send_error(ctx, 0);
2684 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2685 g_strfreev(req);
2687 if (cache_clear(md5file, 1) == FALSE) {
2688 CACHE_UNLOCK;
2689 return send_error(ctx, GPG_ERR_NOT_FOUND);
2692 CACHE_UNLOCK;
2693 return send_error(ctx, 0);
2696 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2698 guchar md5file[16];
2699 glong timeout;
2700 gchar **req = split_input_line(line, " ", 0);
2701 gchar *p;
2703 if (!req || !*req || !req[1]) {
2704 g_strfreev(req);
2705 return send_error(ctx, GPG_ERR_SYNTAX);
2708 errno = 0;
2709 timeout = strtol(req[1], &p, 10);
2711 if (errno != 0 || *p != 0 || timeout < -1) {
2712 g_strfreev(req);
2713 return send_error(ctx, GPG_ERR_SYNTAX);
2716 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2717 CACHE_LOCK(client->ctx);
2719 if (cache_set_timeout(md5file, timeout) == FALSE) {
2720 CACHE_UNLOCK;
2721 return send_error(ctx, GPG_ERR_NOT_FOUND);
2724 CACHE_UNLOCK;
2725 return send_error(ctx, 0);
2728 static gint dump_command(assuan_context_t ctx, gchar *line)
2730 xmlChar *xml;
2731 gint len;
2732 struct client_s *client = assuan_get_pointer(ctx);
2733 gpg_error_t rc;
2735 if (disable_list_and_dump == TRUE)
2736 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2738 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2740 if (!xml) {
2741 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2742 return send_syserror(ctx, ENOMEM);
2745 pth_cleanup_push(xmlFree, xml);
2746 rc = xfer_data(ctx, (gchar *)xml, len);
2747 pth_cleanup_pop(1);
2748 return send_error(ctx, rc);
2751 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2753 struct client_s *client = assuan_get_pointer(ctx);
2754 gpg_error_t rc = 0;
2755 gchar filename[255]={0}, param[747]={0};
2756 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2758 log_write2("ARGS=\"%s\"", line);
2760 if (strchr(line, ' ')) {
2761 sscanf(line, " %254[^ ] %746c", filename, param);
2762 paramp = param;
2763 fp = filename;
2766 if (fp && !valid_filename(fp))
2767 return send_error(ctx, GPG_ERR_INV_VALUE);
2769 paramp = g_ascii_strdown(paramp, -1);
2771 if (!paramp) {
2772 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2773 return send_syserror(ctx, ENOMEM);
2776 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2777 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2778 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2780 if (!fh && rc != GPG_ERR_ENOENT)
2781 return send_error(ctx, rc);
2783 if (!rc) {
2784 g_free(paramp);
2785 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2786 close_file_header(fh);
2788 if (!p) {
2789 log_write("%s(%i): %s", __FILE__, __LINE__,
2790 strerror(ENOMEM));
2791 return send_syserror(ctx, ENOMEM);
2794 goto done;
2798 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2799 #ifdef WITH_PINENTRY
2800 gboolean n;
2802 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2803 n = client->pinentry->enable;
2804 else
2805 n = get_key_file_boolean(fp, "enable_pinentry");
2807 p = g_strdup_printf("%s", n ? "true" : "false");
2809 if (!p) {
2810 log_write("%s(%i): %s", __FILE__, __LINE__,
2811 strerror(ENOMEM));
2812 return send_syserror(ctx, ENOMEM);
2815 goto done;
2816 #else
2817 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2818 #endif
2820 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2821 #ifdef WITH_PINENTRY
2822 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
2824 if (!p) {
2825 log_write("%s(%i): %s", __FILE__, __LINE__,
2826 strerror(ENOMEM));
2827 return send_syserror(ctx, ENOMEM);
2830 goto done;
2831 #else
2832 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2833 #endif
2836 p = get_key_file_string(fp ? fp : "global", paramp);
2837 g_free(paramp);
2839 if (!p)
2840 return send_error(ctx, GPG_ERR_NO_VALUE);
2842 tmp = expand_homedir(p);
2843 g_free(p);
2845 if (!tmp) {
2846 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2847 return send_syserror(ctx, ENOMEM);
2850 p = tmp;
2851 done:
2852 pth_cleanup_push(g_free, p);
2853 rc = xfer_data(ctx, p, strlen(p));
2854 pth_cleanup_pop(1);
2855 return send_error(ctx, rc);
2858 struct xpath_s {
2859 xmlXPathContextPtr xp;
2860 xmlXPathObjectPtr result;
2861 xmlBufferPtr buf;
2862 gchar **req;
2865 static void xpath_command_cleanup(void *arg)
2867 struct xpath_s *xpath = arg;
2869 req_cleanup(xpath->req);
2871 if (xpath->buf)
2872 xmlBufferFree(xpath->buf);
2874 if (xpath->result)
2875 xmlXPathFreeObject(xpath->result);
2877 if (xpath->xp)
2878 xmlXPathFreeContext(xpath->xp);
2881 static gint xpath_command(assuan_context_t ctx, gchar *line)
2883 struct client_s *client = assuan_get_pointer(ctx);
2884 gpg_error_t rc;
2885 struct xpath_s xpath;
2887 log_write2("ARGS=\"%s\"", line);
2889 if (disable_list_and_dump == TRUE)
2890 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2892 if (!line || !*line)
2893 return send_error(ctx, GPG_ERR_SYNTAX);
2895 memset(&xpath, 0, sizeof(struct xpath_s));
2897 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2898 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2899 return send_syserror(ctx, ENOMEM);
2902 xpath.xp = xmlXPathNewContext(client->doc);
2904 if (!xpath.xp) {
2905 xpath_command_cleanup(&xpath);
2906 return send_error(ctx, EPWMD_LIBXML_ERROR);
2909 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2911 if (!xpath.result) {
2912 xpath_command_cleanup(&xpath);
2913 return send_error(ctx, EPWMD_LIBXML_ERROR);
2916 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2917 rc = GPG_ERR_ELEMENT_NOT_FOUND;
2918 goto fail;
2921 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2922 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
2924 if (rc)
2925 goto fail;
2926 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2927 rc = GPG_ERR_NO_VALUE;
2928 goto fail;
2930 else if (xpath.req[1])
2931 goto fail;
2933 pth_cleanup_push(xpath_command_cleanup, &xpath);
2934 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2935 xmlBufferLength(xpath.buf));
2936 pth_cleanup_pop(0);
2938 fail:
2939 xpath_command_cleanup(&xpath);
2940 return send_error(ctx, rc);
2943 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2944 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
2946 struct client_s *client = assuan_get_pointer(ctx);
2947 gpg_error_t rc;
2948 struct xpath_s xpath;
2949 gchar **req = NULL;
2950 gboolean cmd = FALSE; //SET
2952 log_write2("ARGS=\"%s\"", line);
2954 if (disable_list_and_dump == TRUE)
2955 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2957 if (!line || !*line)
2958 return send_error(ctx, GPG_ERR_SYNTAX);
2960 memset(&xpath, 0, sizeof(struct xpath_s));
2962 if ((req = split_input_line(line, " ", 3)) == NULL)
2963 return send_syserror(ctx, ENOMEM);
2965 if (!req[0]) {
2966 rc = GPG_ERR_SYNTAX;
2967 goto fail;
2970 if (!g_ascii_strcasecmp(req[0], "SET"))
2971 cmd = FALSE;
2972 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
2973 cmd = TRUE;
2974 else {
2975 rc = GPG_ERR_SYNTAX;
2976 goto fail;
2979 if (!req[1] || !req[2]) {
2980 rc = GPG_ERR_SYNTAX;
2981 goto fail;
2984 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
2985 rc = gpg_err_code_from_errno(ENOMEM);
2986 goto fail;
2989 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
2990 rc = GPG_ERR_SYNTAX;
2991 goto fail;
2994 xpath.xp = xmlXPathNewContext(client->doc);
2996 if (!xpath.xp) {
2997 rc = EPWMD_LIBXML_ERROR;
2998 goto fail;
3001 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3003 if (!xpath.result) {
3004 rc = EPWMD_LIBXML_ERROR;
3005 goto fail;
3008 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3009 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3010 goto fail;
3013 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3014 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3016 fail:
3017 g_strfreev(req);
3018 xpath_command_cleanup(&xpath);
3019 return send_error(ctx, rc);
3022 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3023 gsize len)
3025 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3026 gpg_error_t rc = file_modified(client);
3027 gchar **req, **path = NULL, **path_orig = NULL, *content;
3028 xmlDocPtr doc = NULL;
3029 xmlNodePtr n, root, copy;
3031 if (assuan_rc || rc) {
3032 if (line)
3033 xfree(line);
3034 return assuan_rc ? assuan_rc : rc;
3037 req = split_input_line((gchar *)line, "\t", 2);
3038 xfree(line);
3040 if (!req || !*req)
3041 return GPG_ERR_SYNTAX;
3043 content = req[0];
3044 path = split_input_line(req[1], "\t", 0);
3046 if (!content || !*content) {
3047 rc = GPG_ERR_SYNTAX;
3048 goto fail;
3051 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3053 if (!doc) {
3054 rc = EPWMD_LIBXML_ERROR;
3055 goto fail;
3058 root = xmlDocGetRootElement(doc);
3059 rc = validate_import(root);
3061 if (rc)
3062 goto fail;
3064 if (path) {
3065 path_orig = g_strdupv(path);
3067 if (!path_orig) {
3068 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3069 rc = gpg_error_from_errno(ENOMEM);
3070 goto fail;
3073 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3075 if (!a) {
3076 g_strfreev(path_orig);
3077 rc = gpg_error_from_errno(ENOMEM);
3078 goto fail;
3081 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3082 xmlFree(a);
3083 g_strfreev(path_orig);
3084 rc = gpg_error_from_errno(ENOMEM);
3085 goto fail;
3088 xmlFree(a);
3089 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3091 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3092 g_strfreev(path_orig);
3093 goto fail;
3096 if (!rc) {
3097 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3099 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3100 g_strfreev(path_orig);
3101 goto fail;
3103 else if (!rc) {
3104 xmlNodePtr parent = n->parent;
3106 xmlUnlinkNode(n);
3107 xmlFreeNode(n);
3108 n = parent;
3112 g_strfreev(path);
3113 path = path_orig;
3115 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3116 n = create_element_path(client, &path, &rc);
3118 if (rc)
3119 goto fail;
3122 copy = xmlCopyNodeList(root);
3123 n = xmlAddChildList(n, copy);
3125 if (!n)
3126 rc = EPWMD_LIBXML_ERROR;
3128 else {
3129 /* Check if the content root element can create a DTD root element. */
3130 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3131 rc = GPG_ERR_SYNTAX;
3132 goto fail;
3135 xmlChar *a;
3137 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3138 rc = GPG_ERR_SYNTAX;
3139 goto fail;
3142 gchar *tmp = g_strdup((gchar *)a);
3143 xmlFree(a);
3144 gboolean literal = is_literal_element(&tmp);
3146 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3147 g_free(tmp);
3148 rc = GPG_ERR_INV_VALUE;
3149 goto fail;
3152 if (strv_printf(&path, "%s", tmp) == FALSE) {
3153 g_free(tmp);
3154 rc = gpg_error_from_errno(ENOMEM);
3155 goto fail;
3158 g_free(tmp);
3159 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3161 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3162 rc = EPWMD_LIBXML_ERROR;
3163 goto fail;
3166 /* Overwriting the existing tree. */
3167 if (!rc) {
3168 xmlUnlinkNode(n);
3169 xmlFreeNodeList(n);
3172 rc = 0;
3173 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3174 n = xmlCopyNode(root, 1);
3175 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3178 if (n && !rc)
3179 rc = update_element_mtime(n->parent);
3181 fail:
3182 if (doc)
3183 xmlFreeDoc(doc);
3185 if (path)
3186 g_strfreev(path);
3188 g_strfreev(req);
3189 client->inquire_status = INQUIRE_DONE;
3190 return rc;
3193 static gint import_command(assuan_context_t ctx, gchar *line)
3195 gpg_error_t rc;
3196 struct client_s *client = assuan_get_pointer(ctx);
3198 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3200 if (rc)
3201 return send_error(ctx, rc);
3203 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3204 client->inquire_status = INQUIRE_BUSY;
3205 return 0;
3208 static gpg_error_t do_lock_command(struct client_s *client)
3210 gpg_error_t rc = lock_file_mutex(client);
3212 if (!rc)
3213 client->is_lock_cmd = TRUE;
3215 return send_error(client->ctx, rc);
3218 static gint lock_command(assuan_context_t ctx, gchar *line)
3220 struct client_s *client = assuan_get_pointer(ctx);
3222 return do_lock_command(client);
3225 static gint unlock_command(assuan_context_t ctx, gchar *line)
3227 struct client_s *client = assuan_get_pointer(ctx);
3229 unlock_file_mutex(client);
3230 return send_error(ctx, 0);
3233 static gint getpid_command(assuan_context_t ctx, gchar *line)
3235 gpg_error_t rc;
3236 gchar buf[32];
3237 pid_t pid = getpid();
3239 print_fmt(buf, sizeof(buf), "%i", pid);
3240 rc = xfer_data(ctx, buf, strlen(buf));
3241 return send_error(ctx, rc);
3244 static gint version_command(assuan_context_t ctx, gchar *line)
3246 gpg_error_t rc;
3247 gchar buf[32];
3249 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3250 rc = xfer_data(ctx, buf, strlen(buf));
3251 return send_error(ctx, rc);
3254 #ifdef WITH_PINENTRY
3255 static void set_option_value(gchar **opt, const gchar *value)
3257 if (opt)
3258 g_free(*opt);
3260 *opt = NULL;
3262 if (value)
3263 *opt = g_strdup(value);
3265 #endif
3267 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3268 const gchar *value)
3270 struct client_s *client = assuan_get_pointer(ctx);
3272 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3273 glong l = 0;
3275 if (value) {
3276 l = strtol(value, NULL, 10);
3278 if (l < 0 || l > 2)
3279 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3282 log_write1("log_level=%li", l);
3283 MUTEX_LOCK(&rcfile_mutex);
3284 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3285 MUTEX_UNLOCK(&rcfile_mutex);
3286 goto done;
3288 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3289 glong l = 0;
3291 if (value) {
3292 l = strtol(value, NULL, 10);
3294 if (l < 0 || l > 1)
3295 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3298 log_write1("rc_on_locked=%li", l);
3299 client->rc_on_locked = l ? TRUE : FALSE;
3300 goto done;
3302 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3303 pth_attr_t attr = pth_attr_of(pth_self());
3304 gchar buf[41];
3306 if (!value) {
3307 pth_attr_destroy(attr);
3308 goto done;
3311 print_fmt(buf, sizeof(buf), "%s", value);
3312 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3313 pth_attr_destroy(attr);
3314 log_write1("name=%s", buf);
3315 #ifdef WITH_PINENTRY
3316 if (client->pinentry->name)
3317 g_free(client->pinentry->name);
3319 client->pinentry->name = g_strdup(buf);
3321 if (!client->pinentry->name)
3322 return gpg_error_from_errno(ENOMEM);
3323 #endif
3325 goto done;
3327 #ifdef WITH_PINENTRY
3328 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3329 set_option_value(&client->pinentry->lcmessages, value);
3330 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3331 set_option_value(&client->pinentry->lcctype, value);
3332 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3333 set_option_value(&client->pinentry->ttyname, value);
3334 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3335 set_option_value(&client->pinentry->ttytype, value);
3336 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3337 set_option_value(&client->pinentry->display, value);
3338 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3339 set_option_value(&client->pinentry->path, value);
3340 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3341 set_option_value(&client->pinentry->title, value);
3342 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3343 set_option_value(&client->pinentry->prompt, value);
3344 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3345 set_option_value(&client->pinentry->desc, value);
3346 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3347 gchar *p = NULL;
3348 gint n;
3350 if (!value)
3351 goto done;
3353 n = strtol(value, &p, 10);
3355 if (*p || n < 0)
3356 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3358 MUTEX_LOCK(&rcfile_mutex);
3359 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3360 "global", "pinentry_timeout", n);
3361 MUTEX_UNLOCK(&rcfile_mutex);
3362 log_write1("pinentry_timeout=%i", n);
3363 goto done;
3365 #endif
3366 else
3367 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3369 log_write1("%s=%s", name, value ? value : "");
3371 done:
3372 return 0;
3375 static gint unset_command(assuan_context_t ctx, gchar *line)
3377 log_write2("ARGS=\"%s\"", line);
3378 return send_error(ctx, set_unset_common(ctx, line, NULL));
3381 static gint set_command(assuan_context_t ctx, gchar *line)
3383 gchar name[64] = {0}, value[256] = {0};
3385 log_write2("ARGS=\"%s\"", line);
3387 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3388 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3390 return send_error(ctx, set_unset_common(ctx, name, value));
3393 static gint rename_command(assuan_context_t ctx, gchar *line)
3395 struct client_s *client = assuan_get_pointer(ctx);
3396 gpg_error_t rc;
3397 gchar **req, **src, *dst;
3398 xmlNodePtr n, ndst;
3400 log_write2("ARGS=\"%s\"", line);
3401 req = split_input_line(line, " ", -1);
3403 if (!req || !req[0] || !req[1]) {
3404 g_strfreev(req);
3405 return send_error(ctx, GPG_ERR_SYNTAX);
3408 dst = req[1];
3409 is_literal_element(&dst);
3411 if (!valid_xml_element((xmlChar *)dst)) {
3412 g_strfreev(req);
3413 return GPG_ERR_INV_VALUE;
3416 if (strchr(req[0], '\t'))
3417 src = split_input_line(req[0], "\t", -1);
3418 else
3419 src = split_input_line(req[0], " ", -1);
3421 if (!src || !*src) {
3422 rc = GPG_ERR_SYNTAX;
3423 goto fail;
3426 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3428 if (src[1] && n)
3429 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3430 NULL, FALSE, 0, NULL, FALSE);
3432 if (!n)
3433 goto fail;
3436 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3438 if (!a) {
3439 rc = gpg_error_from_errno(ENOMEM);
3440 goto fail;
3443 /* To prevent unwanted effects:
3445 * <root name="a"><b/></root>
3447 * RENAME a<TAB>b b
3449 if (xmlStrEqual(a, (xmlChar *)dst)) {
3450 xmlFree(a);
3451 rc = GPG_ERR_AMBIGUOUS_NAME;
3452 goto fail;
3455 xmlFree(a);
3456 gchar **tmp = NULL;
3458 if (src[1]) {
3459 gchar **p;
3461 for (p = src; *p; p++) {
3462 if (!*(p+1))
3463 break;
3465 strv_printf(&tmp, "%s", *p);
3469 strv_printf(&tmp, "!%s", dst);
3470 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3472 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3473 g_strfreev(tmp);
3474 goto fail;
3477 if (tmp[1] && ndst)
3478 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3479 NULL, NULL, FALSE, 0, NULL, FALSE);
3481 g_strfreev(tmp);
3483 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3484 goto fail;
3486 rc = 0;
3488 /* Target may exist:
3490 * <root name="a"/>
3491 * <root name="b" target="a"/>
3493 * RENAME b a
3495 * Would need to do:
3496 * RENAME !b a
3498 if (ndst == n) {
3499 rc = GPG_ERR_AMBIGUOUS_NAME;
3500 goto fail;
3503 if (ndst) {
3504 unlink_node(ndst);
3505 xmlFreeNodeList(ndst);
3508 rc = add_attribute(n, "_name", dst);
3510 fail:
3511 g_strfreev(req);
3512 g_strfreev(src);
3513 return send_error(ctx, rc);
3516 static gint copy_command(assuan_context_t ctx, gchar *line)
3518 struct client_s *client = assuan_get_pointer(ctx);
3519 gpg_error_t rc;
3520 gchar **req, **src = NULL, **dst = NULL;
3521 xmlNodePtr nsrc, ndst, new;
3523 log_write2("ARGS=\"%s\"", line);
3524 req = split_input_line(line, " ", -1);
3526 if (!req || !req[0] || !req[1]) {
3527 g_strfreev(req);
3528 return send_error(ctx, GPG_ERR_SYNTAX);
3531 if (strchr(req[0], '\t'))
3532 src = split_input_line(req[0], "\t", -1);
3533 else
3534 src = split_input_line(req[0], " ", -1);
3536 if (!src || !*src) {
3537 rc = GPG_ERR_SYNTAX;
3538 goto fail;
3541 if (strchr(req[1], '\t'))
3542 dst = split_input_line(req[1], "\t", -1);
3543 else
3544 dst = split_input_line(req[1], " ", -1);
3546 if (!dst || !*dst) {
3547 rc = GPG_ERR_SYNTAX;
3548 goto fail;
3551 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3553 if (nsrc && src[1])
3554 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3555 NULL, NULL, FALSE, 0, NULL, FALSE);
3557 if (!nsrc)
3558 goto fail;
3560 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3562 if (ndst && dst[1])
3563 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3564 NULL, NULL, FALSE, 0, NULL, FALSE);
3566 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3567 goto fail;
3569 new = xmlCopyNodeList(nsrc);
3571 if (!new) {
3572 rc = GPG_ERR_ENOMEM;
3573 goto fail;
3576 if (!ndst)
3577 ndst = create_element_path(client, &dst, &rc);
3579 if (!ndst) {
3580 xmlUnlinkNode(new);
3581 xmlFreeNodeList(new);
3582 goto fail;
3585 /* Merge any attributes from the src node to the initial dst node. */
3586 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3587 if ((!src[1] || !dst[1]) && xmlStrEqual(attr->name, (xmlChar *)"_name"))
3588 continue;
3590 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3592 if (a)
3593 xmlRemoveProp(a);
3595 xmlChar *tmp = xmlNodeGetContent(attr->children);
3596 xmlNewProp(ndst, attr->name, tmp);
3597 xmlFree(tmp);
3600 xmlNodePtr n = ndst->children;
3601 xmlUnlinkNode(n);
3602 xmlFreeNodeList(n);
3603 ndst->children = NULL;
3605 if (!new->children) {
3606 xmlUnlinkNode(new);
3607 xmlFreeNodeList(new);
3608 goto fail;
3611 n = xmlCopyNodeList(new->children);
3613 if (!n) {
3614 rc = GPG_ERR_ENOMEM;
3615 goto fail;
3618 xmlUnlinkNode(new);
3619 xmlFreeNodeList(new);
3620 n = xmlAddChildList(ndst, n);
3622 if (!n) {
3623 rc = GPG_ERR_ENOMEM;
3624 goto fail;
3627 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3629 fail:
3630 if (req)
3631 g_strfreev(req);
3633 if (src)
3634 g_strfreev(src);
3636 if (dst)
3637 g_strfreev(dst);
3639 return send_error(ctx, rc);
3642 static gint move_command(assuan_context_t ctx, gchar *line)
3644 struct client_s *client = assuan_get_pointer(ctx);
3645 gpg_error_t rc;
3646 gchar **req, **src = NULL, **dst = NULL;
3647 xmlNodePtr nsrc, ndst = NULL;
3649 log_write2("ARGS=\"%s\"", line);
3650 req = split_input_line(line, " ", -1);
3652 if (!req || !req[0] || !req[1]) {
3653 g_strfreev(req);
3654 return send_error(ctx, GPG_ERR_SYNTAX);
3657 if (strchr(req[0], '\t'))
3658 src = split_input_line(req[0], "\t", -1);
3659 else
3660 src = split_input_line(req[0], " ", -1);
3662 if (!src || !*src) {
3663 rc = GPG_ERR_SYNTAX;
3664 goto fail;
3667 if (strchr(req[1], '\t'))
3668 dst = split_input_line(req[1], "\t", -1);
3669 else
3670 dst = split_input_line(req[1], " ", -1);
3672 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3674 if (nsrc && src[1])
3675 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3676 NULL, NULL, FALSE, 0, NULL, FALSE);
3678 if (!nsrc)
3679 goto fail;
3681 if (dst) {
3682 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3684 if (ndst && dst[1])
3685 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3686 NULL, NULL, FALSE, 0, NULL, FALSE);
3688 else
3689 ndst = xmlDocGetRootElement(client->doc);
3691 for (xmlNodePtr n = ndst; n; n = n->parent) {
3692 if (n == nsrc) {
3693 rc = GPG_ERR_CONFLICT;
3694 goto fail;
3698 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3699 goto fail;
3701 rc = 0;
3703 if (ndst) {
3704 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3705 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3707 xmlFree(a);
3709 if (dup) {
3710 if (dup == nsrc)
3711 goto fail;
3713 if (ndst == xmlDocGetRootElement(client->doc)) {
3714 xmlNodePtr n = nsrc;
3715 gboolean match = FALSE;
3717 while (n->parent && n->parent != ndst)
3718 n = n->parent;
3720 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3721 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3723 if (xmlStrEqual(a, b)) {
3724 match = TRUE;
3725 xmlUnlinkNode(nsrc);
3726 xmlUnlinkNode(n);
3727 xmlFreeNodeList(n);
3730 xmlFree(a);
3731 xmlFree(b);
3733 if (!match) {
3734 xmlUnlinkNode(dup);
3735 xmlFreeNodeList(dup);
3738 else
3739 xmlUnlinkNode(dup);
3743 if (!ndst && dst)
3744 ndst = create_element_path(client, &dst, &rc);
3746 if (!ndst)
3747 goto fail;
3749 xmlUnlinkNode(nsrc);
3750 ndst = xmlAddChildList(ndst, nsrc);
3752 if (!ndst)
3753 rc = GPG_ERR_ENOMEM;
3755 fail:
3756 if (req)
3757 g_strfreev(req);
3759 if (src)
3760 g_strfreev(src);
3762 if (dst)
3763 g_strfreev(dst);
3765 return send_error(ctx, rc);
3768 static int ls_command(assuan_context_t ctx, gchar *line)
3770 log_write2("ARGS=\"%s\"", line);
3771 gpg_error_t rc;
3772 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3773 gchar *dir = expand_homedir(tmp);
3774 DIR *d = opendir(dir);
3775 gint n = errno;
3777 g_free(tmp);
3779 if (!d) {
3780 g_free(dir);
3781 return send_syserror(ctx, n);
3784 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
3785 struct dirent *p = g_malloc(len), *cur = NULL;
3786 gchar *list = NULL;
3788 g_free(dir);
3789 rc = 0;
3791 while (!readdir_r(d, p, &cur) && cur) {
3792 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
3793 continue;
3794 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
3795 continue;
3797 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
3799 if (!tmp) {
3800 if (list)
3801 g_free(list);
3803 rc = GPG_ERR_ENOMEM;
3804 break;
3807 g_free(list);
3808 list = tmp;
3811 closedir(d);
3812 g_free(p);
3814 if (rc)
3815 return send_error(ctx, rc);
3817 if (!list)
3818 return send_error(ctx, GPG_ERR_NO_VALUE);
3820 list[strlen(list)-1] = 0;
3821 rc = xfer_data(ctx, list, strlen(list));
3822 g_free(list);
3823 return send_error(ctx, rc);
3826 static void bye_notify(assuan_context_t ctx)
3828 struct client_s *cl = assuan_get_pointer(ctx);
3830 /* This will let assuan_process_next() return. */
3831 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3834 static void reset_notify(assuan_context_t ctx)
3836 struct client_s *cl = assuan_get_pointer(ctx);
3838 if (cl)
3839 cleanup_client(cl);
3843 * This is called before every Assuan command.
3845 gint command_startup(assuan_context_t ctx, const gchar *name)
3847 struct client_s *cl = assuan_get_pointer(ctx);
3848 gpg_error_t rc;
3850 log_write1("%s", name);
3852 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
3853 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
3854 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
3855 !g_ascii_strcasecmp(name, "GETCONFIG") ||
3856 !g_ascii_strcasecmp(name, "GETPID") ||
3857 !g_ascii_strcasecmp(name, "VERSION") ||
3858 !g_ascii_strcasecmp(name, "SET") ||
3859 !g_ascii_strcasecmp(name, "BYE") ||
3860 !g_ascii_strcasecmp(name, "NOP") ||
3861 !g_ascii_strcasecmp(name, "CANCEL") ||
3862 !g_ascii_strcasecmp(name, "RESET") ||
3863 !g_ascii_strcasecmp(name, "END") ||
3864 !g_ascii_strcasecmp(name, "HELP") ||
3865 !g_ascii_strcasecmp(name, "OPTION") ||
3866 !g_ascii_strcasecmp(name, "INPUT") ||
3867 !g_ascii_strcasecmp(name, "OUTPUT") ||
3868 !g_ascii_strcasecmp(name, "LS") ||
3869 !g_ascii_strcasecmp(name, "UNSET"))
3870 return 0;
3872 #ifdef WITH_PINENTRY
3873 reset_pin_defaults(cl->pinentry);
3874 #endif
3876 cl->last_rc = rc = file_modified(cl);
3878 if (rc) {
3879 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3880 !g_ascii_strcasecmp(name, "OPEN"))
3881 rc = 0;
3884 return rc;
3888 * This is called after every Assuan command.
3890 void command_finalize(assuan_context_t ctx, gint rc)
3892 struct client_s *client = assuan_get_pointer(ctx);
3894 if (!client->is_lock_cmd)
3895 unlock_file_mutex(client);
3897 log_write1(N_("command completed (rc=%u)"), client->last_rc);
3900 gpg_error_t register_commands(assuan_context_t ctx)
3902 static struct {
3903 const gchar *name;
3904 gint (*handler)(assuan_context_t, gchar *line);
3905 } table[] = {
3906 { "OPEN", open_command },
3907 { "SAVE", save_command },
3908 { "LIST", list_command },
3909 { "REALPATH", realpath_command },
3910 { "STORE", store_command },
3911 { "DELETE", delete_command },
3912 { "GET", get_command },
3913 { "ATTR", attr_command },
3914 { "ISCACHED", iscached_command },
3915 { "CLEARCACHE", clearcache_command },
3916 { "CACHETIMEOUT", cachetimeout_command },
3917 { "GETCONFIG", getconfig_command },
3918 { "DUMP", dump_command },
3919 { "XPATH", xpath_command },
3920 { "XPATHATTR", xpathattr_command },
3921 { "IMPORT", import_command },
3922 { "LOCK", lock_command },
3923 { "UNLOCK", unlock_command },
3924 { "GETPID", getpid_command },
3925 { "VERSION", version_command },
3926 { "SET", set_command },
3927 { "UNSET", unset_command },
3928 { "RENAME", rename_command },
3929 { "COPY", copy_command },
3930 { "LS", ls_command },
3931 { "MOVE", move_command },
3932 { "INPUT", NULL },
3933 { "OUTPUT", NULL },
3934 { NULL, NULL }
3936 gint i, rc;
3938 for (i=0; table[i].name; i++) {
3939 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3941 if (rc)
3942 return rc;
3945 rc = assuan_register_bye_notify(ctx, bye_notify);
3947 if (rc)
3948 return rc;
3950 rc = assuan_register_reset_notify(ctx, reset_notify);
3952 if (rc)
3953 return rc;
3955 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
3957 if (rc)
3958 return rc;
3960 return assuan_register_post_cmd_notify(ctx, command_finalize);
3963 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
3964 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
3966 goffset insize, len;
3967 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3968 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
3969 gint zrc = 0;
3970 gulong outsize = 0;
3971 gpg_error_t rc;
3972 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
3973 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
3974 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
3976 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3977 insize = crypto->fh->st.st_size - fh_size;
3978 crypto->iv = gcry_malloc(crypto->blocksize);
3980 if (!crypto->iv) {
3981 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3982 return gpg_error_from_errno(ENOMEM);
3985 if (crypto->fh->v1)
3986 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
3987 else
3988 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
3990 crypto->inbuf = gcry_malloc(insize);
3992 if (!crypto->inbuf) {
3993 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3994 return gpg_error_from_errno(ENOMEM);
3997 crypto->insize = insize;
3998 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4000 if (len != crypto->insize)
4001 return GPG_ERR_INV_LENGTH;
4003 /* No encryption iterations. This is a plain (gzipped) file. */
4004 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4005 (!crypto->fh->v1 && fh_iter <= 0L)) {
4007 * cache_file_count() needs both .used == TRUE and a valid key in
4008 * order for it to count as a used cache entry. Fixes CACHE status
4009 * messages.
4011 memset(crypto->key, '!', hashlen);
4012 goto decompress;
4015 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4016 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4017 return rc;
4020 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4021 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4022 return rc;
4025 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4026 client->filename : "global", "iteration_progress");
4028 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4029 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4031 if (rc)
4032 return rc;
4035 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4037 if (rc)
4038 return rc;
4040 crypto->tkey = gcry_malloc(hashlen);
4042 if (!crypto->tkey) {
4043 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
4044 return gpg_error_from_errno(ENOMEM);
4047 memcpy(crypto->tkey, crypto->key, hashlen);
4048 guchar *tkey = crypto->tkey;
4049 tkey[0] ^= 1;
4051 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4052 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4053 return rc;
4056 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4057 if (iter_progress > 0ULL && iter >= iter_progress) {
4058 if (!(iter % iter_progress)) {
4059 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4060 ++n_iter * iter_progress, fh_iter);
4062 if (rc)
4063 return rc;
4067 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4068 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4069 return rc;
4072 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4074 if (rc) {
4075 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4076 return rc;
4079 iter++;
4082 if (iter_progress && fh_iter >= iter_progress) {
4083 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4085 if (rc)
4086 return rc;
4089 decompress:
4090 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
4091 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
4092 if (zrc == Z_MEM_ERROR)
4093 return gpg_error_from_errno(ENOMEM);
4094 else
4095 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4098 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4099 gcry_free(crypto->outbuf);
4100 crypto->outbuf = NULL;
4101 return GPG_ERR_INV_PASSPHRASE;
4104 if (ctx) {
4105 client->xml = crypto->outbuf;
4106 client->len = outsize;
4107 crypto->outbuf = NULL;
4109 else if (dst) {
4110 *dst = crypto->outbuf;
4111 *dst_len = outsize;
4112 crypto->outbuf = NULL;
4115 /* The calling function should free the crypto struct. */
4116 return 0;