Damn. Fixed the --cipher option to SAVE.
[pwmd.git] / src / commands.c
blob8f9a2250f82c5ee52144ad328031b4fb134523d4
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 client->lock_on_open = FALSE;
554 rc = parse_options(&line, args, client);
556 if (rc)
557 return send_error(ctx, rc);
559 if ((req = split_input_line(line, " ", 2)) != NULL)
560 filename = req[0];
562 pth_cleanup_push(req_cleanup, req);
564 if (!filename || !*filename) {
565 pth_cleanup_pop(1);
566 return send_error(ctx, GPG_ERR_SYNTAX);
569 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
571 if (valid_filename(filename) == FALSE) {
572 pth_cleanup_pop(1);
573 return send_error(ctx, GPG_ERR_INV_VALUE);
576 if (client->state == STATE_OPEN)
577 cleanup_client(client);
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 gint save_command(assuan_context_t ctx, gchar *line)
1386 gboolean cached = FALSE;
1387 struct stat st;
1388 struct client_s *client = assuan_get_pointer(ctx);
1389 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1390 gpg_error_t rc;
1391 struct argv_s *args[] = {
1392 &(struct argv_s) { "iterations", OPT_OPTARG, parse_save_opt_iterations },
1393 &(struct argv_s) { "cipher", OPT_OPTARG, parse_save_opt_cipher },
1394 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry},
1395 NULL
1398 rc = parse_options(&line, args, client);
1400 if (rc)
1401 return send_error(ctx, rc);
1403 if (line && *line)
1404 log_write2("ARGS=%s", "<passphrase>");
1406 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1407 return send_syserror(ctx, errno);
1409 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1410 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1411 return send_error(ctx, GPG_ERR_ENOANO);
1414 CACHE_LOCK(ctx);
1415 cached = cache_iscached(client->md5file);
1416 CACHE_UNLOCK;
1419 * If a cache entry doesn't exist for this file and the file has a
1420 * "key_file" or "key" parameter, then it's an error. The reason is that
1421 * cache expiration would be useless.
1423 if (cached == FALSE) {
1424 gchar *tmp = get_key_file_string(client->filename, "key_file");
1426 if (tmp) {
1427 g_free(tmp);
1428 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1432 cached = FALSE;
1434 /* New file? */
1435 if (!client->crypto) {
1436 client->crypto = init_client_crypto();
1438 if (!client->crypto) {
1439 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1440 return send_syserror(ctx, ENOMEM);
1444 client->crypto->key = gcry_malloc(hashlen);
1446 if (!client->crypto->key) {
1447 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1448 cleanup_crypto(&client->crypto);
1449 return send_syserror(ctx, ENOMEM);
1452 memset(client->crypto->key, '!', hashlen);
1454 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1455 (!line || !*line))
1456 goto done;
1458 if (!line || !*line) {
1459 client->crypto->tkey = gcry_malloc(hashlen);
1461 if (!client->crypto->tkey) {
1462 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1463 cleanup_crypto(&client->crypto);
1464 return send_syserror(ctx, ENOMEM);
1467 memset(client->crypto->tkey, '!', hashlen);
1468 CACHE_LOCK(ctx);
1470 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1471 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1472 CACHE_UNLOCK;
1474 #ifdef WITH_PINENTRY
1475 gpg_error_t rc;
1477 if (client->pinentry->enable == FALSE ||
1478 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1479 /* Empty keys are allowed. */
1480 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1481 goto done;
1484 lock_pin_mutex(client);
1485 client->pinentry->which = PINENTRY_SAVE;
1486 rc = pinentry_fork(ctx);
1488 if (rc) {
1489 unlock_pin_mutex(client->pinentry);
1490 cleanup_crypto(&client->crypto);
1491 return send_error(ctx, rc);
1494 client->pinentry->cb = save_command_finalize;
1495 client->pinentry->status = PINENTRY_INIT;
1496 return 0;
1497 #else
1498 /* Empty keys are allowed. */
1499 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1500 goto done;
1501 #endif
1503 else {
1504 CACHE_UNLOCK;
1505 cached = TRUE;
1508 else {
1509 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1510 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1512 if (iter <= 0L)
1513 iter = 1;
1515 MUTEX_LOCK(&rcfile_mutex);
1516 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1517 MUTEX_UNLOCK(&rcfile_mutex);
1518 client->opts |= OPT_ITERATIONS;
1519 gpg_error_t rc = send_status(ctx, STATUS_CONFIG, NULL);
1521 if (rc)
1522 return send_error(ctx, rc);
1525 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1526 strlen(line));
1529 done:
1530 return save_command_finalize(ctx, client->crypto->key, cached);
1533 static gint delete_command(assuan_context_t ctx, gchar *line)
1535 struct client_s *client = assuan_get_pointer(ctx);
1536 gchar **req;
1537 gpg_error_t rc;
1538 xmlNodePtr n;
1540 log_write2("ARGS=\"%s\"", line);
1542 if (strchr(line, '\t'))
1543 req = split_input_line(line, "\t", -1);
1544 else
1545 req = split_input_line(line, " ", -1);
1547 if (!req || !*req)
1548 return send_error(ctx, GPG_ERR_SYNTAX);
1550 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1552 if (!n) {
1553 g_strfreev(req);
1554 return send_error(ctx, rc);
1558 * No sub-node defined. Remove the entire node (root element).
1560 if (!req[1]) {
1561 xmlNodePtr parent = n->parent;
1563 if (n) {
1564 xmlUnlinkNode(n);
1565 xmlFreeNode(n);
1568 g_strfreev(req);
1569 rc = 0;
1571 if (parent)
1572 rc = update_element_mtime(parent);
1574 return send_error(ctx, rc);
1577 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1578 g_strfreev(req);
1580 if (!n)
1581 return send_error(ctx, rc);
1583 if (n) {
1584 xmlNodePtr parent = n->parent;
1586 xmlUnlinkNode(n);
1587 xmlFreeNode(n);
1588 rc = 0;
1590 if (parent)
1591 rc = update_element_mtime(parent);
1594 return send_error(ctx, rc);
1598 * Don't return with assuan_process_done() here. This has been called from
1599 * assuan_process_next() and the command should be finished in
1600 * client_thread().
1602 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1603 gsize len)
1605 assuan_context_t ctx = data;
1606 struct client_s *client = assuan_get_pointer(ctx);
1607 gchar **req;
1608 xmlNodePtr n;
1609 gpg_error_t rc = file_modified(client);
1611 if (assuan_rc || rc) {
1612 if (line)
1613 xfree(line);
1614 return assuan_rc ? assuan_rc : rc;
1617 req = split_input_line((gchar *)line, "\t", 0);
1618 xfree(line);
1620 if (!req || !*req)
1621 return GPG_ERR_SYNTAX;
1623 again:
1624 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1626 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1627 rc = new_root_element(client->doc, *req);
1629 if (rc) {
1630 g_strfreev(req);
1631 return rc;
1634 goto again;
1637 if (!n) {
1638 g_strfreev(req);
1639 return rc;
1642 if (req[1]) {
1643 if (!n->children)
1644 n = create_elements_cb(n, req+1, &rc, NULL);
1645 else
1646 n = find_elements(client->doc, n->children, req+1, &rc,
1647 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1650 g_strfreev(req);
1651 client->inquire_status = INQUIRE_DONE;
1653 if (!rc)
1654 rc = update_element_mtime(n);
1656 return rc;
1659 static gint store_command(assuan_context_t ctx, gchar *line)
1661 struct client_s *client = assuan_get_pointer(ctx);
1662 gpg_error_t rc;
1664 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1666 if (rc)
1667 return send_error(ctx, rc);
1669 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1670 client->inquire_status = INQUIRE_BUSY;
1671 return 0;
1674 static void *send_data_cb(void *arg)
1676 struct assuan_cmd_s *data = arg;
1677 gint old;
1678 gpg_error_t *rc;
1680 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1681 rc = g_malloc(sizeof(gpg_error_t));
1682 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1683 pth_cancel_state(old, NULL);
1684 pth_exit(rc);
1685 return NULL;
1688 /* For every assuan command that needs to be sent to the client, a timeout is
1689 * needed to determine if the client lost the connection. The timeout is the
1690 * same as the "keepalive" configuration parameter or a default if unset.
1692 gpg_error_t do_assuan_command(assuan_context_t ctx,
1693 void *(*cb)(void *data), void *data)
1695 pth_attr_t attr = pth_attr_new();
1696 pth_t tid;
1697 gint n;
1698 gint to = get_key_file_integer("global", "keepalive");
1699 pth_event_t ev, tev;
1700 pth_status_t st;
1701 gpg_error_t rc = 0;
1702 void *p;
1704 pth_attr_init(attr);
1705 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1706 tid = pth_spawn(attr, cb, data);
1707 n = errno;
1708 pth_attr_destroy(attr);
1710 if (!tid) {
1711 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1712 _gpg_strerror(gpg_error_from_errno(n)));
1713 return gpg_error_from_errno(n);
1716 pth_cleanup_push(cleanup_cancel_cb, tid);
1717 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1718 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1719 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1720 ev = pth_event_concat(ev, tev, NULL);
1721 pth_cleanup_push(cleanup_ev_cb, ev);
1722 pth_yield(tid);
1723 pth_wait(ev);
1725 if (tev) {
1726 st = pth_event_status(tev);
1728 if (st == PTH_STATUS_OCCURRED) {
1729 pth_cleanup_pop(1);
1730 pth_cleanup_pop(1);
1731 return GPG_ERR_TIMEOUT;
1735 st = pth_event_status(ev);
1737 if (st == PTH_STATUS_FAILED) {
1738 pth_cancel(tid);
1739 pth_join(tid, &p);
1740 g_free(p);
1741 rc = GPG_ERR_ASS_WRITE_ERROR;
1743 else if (st == PTH_STATUS_OCCURRED) {
1744 pth_join(tid, &p);
1745 rc = *(gpg_error_t *)p;
1746 g_free(p);
1749 pth_cleanup_pop(1);
1750 pth_cleanup_pop(0);
1751 return rc;
1754 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1755 gint total)
1757 gint to_send;
1758 gint sent = 0;
1759 gpg_error_t rc;
1760 struct assuan_cmd_s data;
1761 gint progress = get_key_file_integer("global", "xfer_progress");
1762 gint flush = 0;
1764 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1765 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1766 data.ctx = ctx;
1767 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1769 if (rc)
1770 return rc;
1772 again:
1773 do {
1774 if (sent + to_send > total)
1775 to_send = total - sent;
1777 data.line = flush ? NULL : (gchar *)line+sent;
1778 data.line_len = flush ? 0 : to_send;
1779 rc = do_assuan_command(ctx, send_data_cb, &data);
1781 if (!rc) {
1782 sent += flush ? 0 : to_send;
1784 if ((progress && !(sent % progress) && sent != total) ||
1785 (sent == total && flush))
1786 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1788 if (!flush && !rc && sent == total) {
1789 flush = 1;
1790 goto again;
1793 } while (!rc && sent < total);
1795 return rc;
1798 static gint get_command(assuan_context_t ctx, gchar *line)
1800 struct client_s *client = assuan_get_pointer(ctx);
1801 gchar **req;
1802 gpg_error_t rc;
1803 xmlNodePtr n;
1805 log_write2("ARGS=\"%s\"", line);
1806 req = split_input_line(line, "\t", -1);
1808 if (!req || !*req) {
1809 g_strfreev(req);
1810 return send_error(ctx, GPG_ERR_SYNTAX);
1813 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1815 if (!n) {
1816 g_strfreev(req);
1817 return send_error(ctx, rc);
1820 if (req[1])
1821 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1823 g_strfreev(req);
1825 if (rc)
1826 return send_error(ctx, rc);
1828 if (!n || !n->children)
1829 return send_error(ctx, GPG_ERR_NO_VALUE);
1831 n = find_text_node(n->children);
1833 if (!n || !n->content || !*n->content)
1834 return send_error(ctx, GPG_ERR_NO_VALUE);
1836 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1837 return send_error(ctx, rc);
1840 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1841 gpg_error_t *rc, gchar **req_orig, void *data)
1843 gchar *path = *(gchar **)data;
1844 gchar *tmp = NULL, *result;
1846 if (path) {
1847 g_free(path);
1848 *(gchar **)data = NULL;
1851 path = g_strjoinv("\t", target);
1853 if (!path) {
1854 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1855 *rc = gpg_error_from_errno(ENOMEM);
1856 return NULL;
1859 if (req_orig) {
1860 tmp = g_strjoinv("\t", req_orig);
1862 if (!tmp) {
1863 g_free(path);
1864 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1865 *rc = gpg_error_from_errno(ENOMEM);
1866 return NULL;
1870 if (tmp && *tmp)
1871 result = g_strdup_printf("%s\t%s", path, tmp);
1872 else
1873 result = g_strdup(path);
1875 if (!result) {
1876 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1877 *rc = gpg_error_from_errno(ENOMEM);
1878 g_free(path);
1879 g_free(tmp);
1880 return NULL;
1883 g_free(path);
1884 g_free(tmp);
1885 *(gchar **)data = result;
1886 return node;
1889 static void list_command_cleanup1(void *arg);
1890 static gint realpath_command(assuan_context_t ctx, gchar *line)
1892 gpg_error_t rc;
1893 struct client_s *client = assuan_get_pointer(ctx);
1894 gchar **req;
1895 gchar *t;
1896 gint i;
1897 xmlNodePtr n;
1898 GString *string;
1899 gchar *rp = NULL;
1901 log_write2("ARGS=\"%s\"", line);
1903 if (strchr(line, '\t') != NULL) {
1904 if ((req = split_input_line(line, "\t", 0)) == NULL)
1905 return send_error(ctx, GPG_ERR_SYNTAX);
1907 else {
1908 if ((req = split_input_line(line, " ", 0)) == NULL)
1909 return send_error(ctx, GPG_ERR_SYNTAX);
1912 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1914 if (!n) {
1915 g_strfreev(req);
1916 return send_error(ctx, rc);
1919 rp = g_strjoinv("\t", req);
1921 if (!rp) {
1922 g_strfreev(req);
1923 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1924 return send_syserror(ctx, ENOMEM);
1927 if (req[1]) {
1928 n = find_elements(client->doc, n->children, req+1, &rc,
1929 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
1931 if (!n) {
1932 g_free(rp);
1933 g_strfreev(req);
1934 return send_error(ctx, rc);
1938 string = g_string_new(rp);
1939 g_free(rp);
1940 g_strfreev(req);
1942 if (!string) {
1943 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1944 return send_syserror(ctx, ENOMEM);
1947 again:
1948 for (i = 0, t = string->str + i; *t; t++, i++) {
1949 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1950 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1951 goto again;
1955 pth_cleanup_push(list_command_cleanup1, string);
1956 rc = xfer_data(ctx, string->str, string->len);
1957 pth_cleanup_pop(1);
1958 return send_error(ctx, rc);
1961 static void list_command_cleanup1(void *arg)
1963 g_string_free((GString *)arg, TRUE);
1966 static void list_command_cleanup2(void *arg)
1968 struct element_list_s *elements = arg;
1970 if (elements) {
1971 if (elements->list) {
1972 gint total = g_slist_length(elements->list);
1973 gint i;
1975 for (i = 0; i < total; i++) {
1976 gchar *tmp = g_slist_nth_data(elements->list, i);
1977 g_free(tmp);
1980 g_slist_free(elements->list);
1983 if (elements->prefix)
1984 g_free(elements->prefix);
1986 if (elements->req)
1987 g_strfreev(elements->req);
1989 g_free(elements);
1993 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
1995 struct element_list_s *elements = data;
1997 elements->recurse = FALSE;
1998 return 0;
2001 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2003 struct element_list_s *elements = data;
2005 elements->verbose = TRUE;
2006 return 0;
2009 static gint list_command(assuan_context_t ctx, gchar *line)
2011 struct client_s *client = assuan_get_pointer(ctx);
2012 gpg_error_t rc;
2013 struct element_list_s *elements = NULL;
2014 gchar *tmp;
2015 struct argv_s *args[] = {
2016 &(struct argv_s) { "norecurse", OPT_NOARG, parse_list_opt_norecurse },
2017 &(struct argv_s) { "verbose", OPT_NOARG, parse_list_opt_verbose },
2018 NULL
2021 if (disable_list_and_dump == TRUE)
2022 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2024 elements = g_malloc0(sizeof(struct element_list_s));
2026 if (!elements) {
2027 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2028 return gpg_err_code_from_errno(ENOMEM);
2031 elements->recurse = TRUE; // default
2032 pth_cleanup_push(list_command_cleanup2, elements);
2033 rc = parse_options(&line, args, elements);
2035 if (rc)
2036 goto fail;
2038 if (!*line) {
2039 GString *str;
2041 rc = list_root_elements(client->doc, &str, elements->verbose);
2043 if (rc) {
2044 pth_cleanup_pop(1);
2045 return send_error(ctx, rc);
2048 pth_cleanup_push(list_command_cleanup1, str);
2049 rc = xfer_data(ctx, str->str, str->len);
2050 pth_cleanup_pop(1);
2051 pth_cleanup_pop(1);
2052 return send_error(ctx, rc);
2055 elements->req = split_input_line(line, " ", 0);
2057 if (!elements->req)
2058 strv_printf(&elements->req, "%s", line);
2060 rc = create_path_list(client->doc, elements, *elements->req);
2062 if (rc)
2063 goto fail;
2065 if (elements) {
2066 gint total = g_slist_length(elements->list);
2067 gint i;
2068 GString *str;
2070 if (!total) {
2071 rc = GPG_ERR_NO_VALUE;
2072 goto fail;
2075 str = g_string_new(NULL);
2077 if (!str) {
2078 rc = gpg_err_code_from_errno(ENOMEM);
2079 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2080 goto fail;
2083 for (i = 0; i < total; i++) {
2084 tmp = g_slist_nth_data(elements->list, i);
2085 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2088 pth_cleanup_push(list_command_cleanup1, str);
2089 rc = xfer_data(ctx, str->str, str->len);
2090 pth_cleanup_pop(1);
2092 else
2093 rc = GPG_ERR_NO_VALUE;
2095 fail:
2096 pth_cleanup_pop(1);
2097 return send_error(ctx, rc);
2101 * req[0] - element path
2103 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2105 struct client_s *client = assuan_get_pointer(ctx);
2106 gchar **attrlist = NULL;
2107 gint i = 0;
2108 gchar **path = NULL;
2109 xmlAttrPtr a;
2110 xmlNodePtr n, an;
2111 gchar *line;
2112 gpg_error_t rc;
2114 if (!req || !req[0])
2115 return GPG_ERR_SYNTAX;
2117 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2119 * The first argument may be only a root element.
2121 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2122 return GPG_ERR_SYNTAX;
2125 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2127 if (!n) {
2128 g_strfreev(path);
2129 return rc;
2132 if (path[1]) {
2133 n = find_elements(client->doc, n->children, path+1, &rc,
2134 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2136 if (!n) {
2137 g_strfreev(path);
2138 return rc;
2142 g_strfreev(path);
2144 for (a = n->properties; a; a = a->next) {
2145 gchar **pa;
2147 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2148 if (attrlist)
2149 g_strfreev(attrlist);
2151 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2152 return gpg_error_from_errno(ENOMEM);
2155 attrlist = pa;
2156 an = a->children;
2157 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2158 an && an->content ? (gchar *)an->content : "");
2160 if (!attrlist[i]) {
2161 g_strfreev(attrlist);
2162 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2163 return gpg_error_from_errno(ENOMEM);
2166 attrlist[++i] = NULL;
2169 if (!attrlist)
2170 return GPG_ERR_NO_VALUE;
2172 line = g_strjoinv("\n", attrlist);
2174 if (!line) {
2175 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2176 g_strfreev(attrlist);
2177 return gpg_error_from_errno(ENOMEM);
2180 pth_cleanup_push(g_free, line);
2181 pth_cleanup_push(req_cleanup, attrlist);
2182 rc = xfer_data(ctx, line, strlen(line));
2183 pth_cleanup_pop(1);
2184 pth_cleanup_pop(1);
2185 return rc;
2189 * req[0] - attribute
2190 * req[1] - element path
2192 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2194 xmlNodePtr n;
2195 gchar **path = NULL;
2196 gpg_error_t rc;
2198 if (!req || !req[0] || !req[1])
2199 return GPG_ERR_SYNTAX;
2201 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2203 * The first argument may be only a root element.
2205 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2206 return GPG_ERR_SYNTAX;
2210 * Don't remove the "_name" attribute for the root element. To remove an
2211 * root element use DELETE <name>.
2213 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2214 rc = GPG_ERR_SYNTAX;
2215 goto fail;
2218 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2220 if (!n)
2221 goto fail;
2223 if (path[1]) {
2224 n = find_elements(client->doc, n->children, path+1, &rc,
2225 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2227 if (!n)
2228 goto fail;
2231 rc = delete_attribute(n, (xmlChar *)req[0]);
2233 fail:
2234 g_strfreev(path);
2235 return rc;
2238 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2239 gpg_error_t *rc)
2241 gchar **src = *path;
2242 gchar **src_orig = g_strdupv(src);
2243 xmlNodePtr n = NULL;
2245 *rc = 0;
2247 if (!src_orig) {
2248 *rc = gpg_error_from_errno(ENOMEM);
2249 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2250 goto fail;
2253 again:
2254 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2256 if (!n) {
2257 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2258 *rc = new_root_element(client->doc, src[0]);
2260 if (*rc)
2261 goto fail;
2263 goto again;
2265 else
2266 goto fail;
2269 if (src[1]) {
2270 if (!n->children)
2271 n = create_target_elements_cb(n, src+1, rc, NULL);
2272 else
2273 n = find_elements(client->doc, n->children, src+1, rc,
2274 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2276 if (!n)
2277 goto fail;
2280 * Reset the position of the element tree now that the elements
2281 * have been created.
2283 g_strfreev(src);
2284 src = src_orig;
2285 src_orig = NULL;
2286 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2288 if (!n)
2289 goto fail;
2291 n = find_elements(client->doc, n->children, src+1, rc,
2292 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2294 if (!n)
2295 goto fail;
2298 fail:
2299 if (src_orig)
2300 g_strfreev(src_orig);
2302 *path = src;
2303 return n;
2307 * Creates a "target" attribute. When other commands encounter an element with
2308 * this attribute, the element path is modified to the target value. If the
2309 * source element path doesn't exist when using 'ATTR SET target', it is
2310 * created, but the destination element path must exist.
2312 * req[0] - source element path
2313 * req[1] - destination element path
2315 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2317 gchar **src, **dst, *line = NULL, **odst = NULL;
2318 gpg_error_t rc;
2319 xmlNodePtr n;
2321 if (!req || !req[0] || !req[1])
2322 return GPG_ERR_SYNTAX;
2324 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2326 * The first argument may be only a root element.
2328 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2329 return GPG_ERR_SYNTAX;
2332 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2334 * The first argument may be only a root element.
2336 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2337 rc = GPG_ERR_SYNTAX;
2338 goto fail;
2342 odst = g_strdupv(dst);
2344 if (!odst) {
2345 rc = gpg_error_from_errno(ENOMEM);
2346 goto fail;
2349 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2352 * Make sure the destination element path exists.
2354 if (!n)
2355 goto fail;
2357 if (dst[1]) {
2358 n = find_elements(client->doc, n->children, dst+1, &rc,
2359 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2361 if (!n)
2362 goto fail;
2365 n = create_element_path(client, &src, &rc);
2367 if (rc)
2368 goto fail;
2370 line = g_strjoinv("\t", odst);
2372 if (!line) {
2373 rc = gpg_error_from_errno(ENOMEM);
2374 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2375 goto fail;
2378 rc = add_attribute(n, "target", line);
2380 fail:
2381 g_free(line);
2382 g_strfreev(src);
2383 g_strfreev(dst);
2384 g_strfreev(odst);
2385 return rc;
2389 * req[0] - name
2390 * req[1] - new name
2392 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2394 gpg_error_t rc;
2395 gchar **tmp;
2396 xmlNodePtr n;
2398 tmp = g_strdupv(req);
2400 if (!tmp) {
2401 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2402 return gpg_error_from_errno(ENOMEM);
2405 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2406 g_strfreev(tmp);
2408 if (!n)
2409 return rc;
2411 if (g_utf8_collate(req[0], req[1]) == 0)
2412 return 0;
2415 * Will not overwrite an existing root.
2417 tmp = g_strdupv(req+1);
2419 if (!tmp) {
2420 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2421 return gpg_error_from_errno(ENOMEM);
2424 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2425 g_strfreev(tmp);
2427 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2428 return rc;
2430 if (n)
2431 return GPG_ERR_AMBIGUOUS_NAME;
2434 * Whitespace not allowed in root names.
2436 if (contains_whitespace(req[1]) == TRUE)
2437 return GPG_ERR_SYNTAX;
2439 tmp = g_strdupv(req);
2441 if (!tmp) {
2442 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2443 return gpg_error_from_errno(ENOMEM);
2446 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2447 g_strfreev(tmp);
2449 if (!n)
2450 return GPG_ERR_ELEMENT_NOT_FOUND;
2452 return add_attribute(n, "_name", req[1]);
2456 * req[0] - attribute
2457 * req[1] - element path
2459 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2461 struct client_s *client = assuan_get_pointer(ctx);
2462 xmlNodePtr n;
2463 xmlChar *a;
2464 gchar **path= NULL;
2465 gpg_error_t rc;
2467 if (!req || !req[0] || !req[1])
2468 return GPG_ERR_SYNTAX;
2470 if (strchr(req[1], '\t')) {
2471 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2472 return GPG_ERR_SYNTAX;
2474 else {
2475 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2476 return GPG_ERR_SYNTAX;
2479 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2481 if (!n)
2482 goto fail;
2484 if (path[1]) {
2485 n = find_elements(client->doc, n->children, path+1, &rc,
2486 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2488 if (!n)
2489 goto fail;
2492 g_strfreev(path);
2494 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2495 return GPG_ERR_NOT_FOUND;
2497 pth_cleanup_push(xmlFree, a);
2499 if (*a)
2500 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2501 else
2502 rc = GPG_ERR_NO_VALUE;
2504 pth_cleanup_pop(1);
2505 return rc;
2507 fail:
2508 g_strfreev(path);
2509 return rc;
2513 * req[0] - attribute
2514 * req[1] - element path
2515 * req[2] - value
2517 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2519 gchar **path = NULL;
2520 gpg_error_t rc;
2521 xmlNodePtr n;
2523 if (!req || !req[0] || !req[1])
2524 return GPG_ERR_SYNTAX;
2527 * Reserved attribute names.
2529 if (!strcmp(req[0], "_name")) {
2531 * Only reserved for the root element. Not the rest of the
2532 * document.
2534 if (strchr(req[1], '\t') == NULL)
2535 return name_attribute(client, req + 1);
2537 else if (!strcmp(req[0], "target"))
2538 return target_attribute(client, req + 1);
2540 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2542 * The first argument may be only a root element.
2544 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2545 return GPG_ERR_SYNTAX;
2548 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2550 if (!n)
2551 goto fail;
2553 if (path[1]) {
2554 n = find_elements(client->doc, n->children, path+1, &rc,
2555 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2557 if (!n)
2558 goto fail;
2561 rc = add_attribute(n, req[0], req[2]);
2563 fail:
2564 g_strfreev(path);
2565 return rc;
2569 * req[0] - command
2570 * req[1] - attribute name or element path if command is LIST
2571 * req[2] - element path
2572 * req[2] - element path or value
2574 static gint attr_command(assuan_context_t ctx, gchar *line)
2576 struct client_s *client = assuan_get_pointer(ctx);
2577 gchar **req;
2578 gpg_error_t rc = 0;
2580 log_write2("ARGS=\"%s\"", line);
2581 req = split_input_line(line, " ", 4);
2583 if (!req || !req[0] || !req[1]) {
2584 g_strfreev(req);
2585 return send_error(ctx, GPG_ERR_SYNTAX);
2588 pth_cleanup_push(req_cleanup, req);
2590 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2591 rc = attribute_set(client, req+1);
2592 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2593 rc = attribute_get(ctx, req+1);
2594 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2595 rc = attribute_delete(client, req+1);
2596 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2597 rc = attribute_list(ctx, req+1);
2598 else
2599 rc = GPG_ERR_SYNTAX;
2601 pth_cleanup_pop(1);
2602 return send_error(ctx, rc);
2605 static gint iscached_command(assuan_context_t ctx, gchar *line)
2607 gchar **req = split_input_line(line, " ", 0);
2608 guchar md5file[16];
2609 gchar *path, *tmp;
2611 if (!req || !*req) {
2612 g_strfreev(req);
2613 return send_error(ctx, GPG_ERR_SYNTAX);
2616 log_write2("ARGS=\"%s\"", line);
2618 if (!valid_filename(req[0])) {
2619 g_strfreev(req);
2620 return GPG_ERR_INV_VALUE;
2623 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2624 CACHE_LOCK(ctx);
2626 if (cache_iscached(md5file)) {
2627 g_strfreev(req);
2628 CACHE_UNLOCK;
2629 return send_error(ctx, 0);
2632 CACHE_UNLOCK;
2633 tmp = get_key_file_string("global", "data_directory");
2635 if (!tmp) {
2636 g_strfreev(req);
2637 return gpg_error_from_errno(ENOMEM);
2640 path = expand_homedir(tmp);
2642 if (!path) {
2643 g_strfreev(req);
2644 g_free(tmp);
2645 return gpg_error_from_errno(ENOMEM);
2648 g_free(tmp);
2649 tmp = path;
2650 path = g_strdup_printf("%s/%s", tmp, req[0]);
2651 g_free(tmp);
2653 if (!path) {
2654 g_strfreev(req);
2655 return gpg_error_from_errno(ENOMEM);
2658 if (access(path, R_OK) == -1) {
2659 gpg_error_t rc = gpg_error_from_syserror();
2661 g_free(path);
2662 g_strfreev(req);
2663 return send_error(ctx, rc);
2666 g_free(path);
2667 return send_error(ctx, GPG_ERR_NOT_FOUND);
2670 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2672 struct client_s *client = assuan_get_pointer(ctx);
2673 gchar **req = split_input_line(line, " ", 0);
2674 guchar md5file[16];
2676 log_write2("ARGS=\"%s\"", line);
2677 CACHE_LOCK(ctx);
2679 if (!req || !*req) {
2680 g_strfreev(req);
2681 cache_clear(client->md5file, 2);
2682 CACHE_UNLOCK;
2683 return send_error(ctx, 0);
2686 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2687 g_strfreev(req);
2689 if (cache_clear(md5file, 1) == FALSE) {
2690 CACHE_UNLOCK;
2691 return send_error(ctx, GPG_ERR_NOT_FOUND);
2694 CACHE_UNLOCK;
2695 return send_error(ctx, 0);
2698 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2700 guchar md5file[16];
2701 glong timeout;
2702 gchar **req = split_input_line(line, " ", 0);
2703 gchar *p;
2705 if (!req || !*req || !req[1]) {
2706 g_strfreev(req);
2707 return send_error(ctx, GPG_ERR_SYNTAX);
2710 errno = 0;
2711 timeout = strtol(req[1], &p, 10);
2713 if (errno != 0 || *p != 0 || timeout < -1) {
2714 g_strfreev(req);
2715 return send_error(ctx, GPG_ERR_SYNTAX);
2718 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2719 CACHE_LOCK(client->ctx);
2721 if (cache_set_timeout(md5file, timeout) == FALSE) {
2722 CACHE_UNLOCK;
2723 return send_error(ctx, GPG_ERR_NOT_FOUND);
2726 CACHE_UNLOCK;
2727 return send_error(ctx, 0);
2730 static gint dump_command(assuan_context_t ctx, gchar *line)
2732 xmlChar *xml;
2733 gint len;
2734 struct client_s *client = assuan_get_pointer(ctx);
2735 gpg_error_t rc;
2737 if (disable_list_and_dump == TRUE)
2738 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2740 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2742 if (!xml) {
2743 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2744 return send_syserror(ctx, ENOMEM);
2747 pth_cleanup_push(xmlFree, xml);
2748 rc = xfer_data(ctx, (gchar *)xml, len);
2749 pth_cleanup_pop(1);
2750 return send_error(ctx, rc);
2753 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2755 struct client_s *client = assuan_get_pointer(ctx);
2756 gpg_error_t rc = 0;
2757 gchar filename[255]={0}, param[747]={0};
2758 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2760 log_write2("ARGS=\"%s\"", line);
2762 if (strchr(line, ' ')) {
2763 sscanf(line, " %254[^ ] %746c", filename, param);
2764 paramp = param;
2765 fp = filename;
2768 if (fp && !valid_filename(fp))
2769 return send_error(ctx, GPG_ERR_INV_VALUE);
2771 paramp = g_ascii_strdown(paramp, -1);
2773 if (!paramp) {
2774 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2775 return send_syserror(ctx, ENOMEM);
2778 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2779 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2780 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2782 if (!fh && rc != GPG_ERR_ENOENT)
2783 return send_error(ctx, rc);
2785 if (!rc) {
2786 g_free(paramp);
2787 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2788 close_file_header(fh);
2790 if (!p) {
2791 log_write("%s(%i): %s", __FILE__, __LINE__,
2792 strerror(ENOMEM));
2793 return send_syserror(ctx, ENOMEM);
2796 goto done;
2800 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2801 #ifdef WITH_PINENTRY
2802 gboolean n;
2804 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2805 n = client->pinentry->enable;
2806 else
2807 n = get_key_file_boolean(fp, "enable_pinentry");
2809 p = g_strdup_printf("%s", n ? "true" : "false");
2811 if (!p) {
2812 log_write("%s(%i): %s", __FILE__, __LINE__,
2813 strerror(ENOMEM));
2814 return send_syserror(ctx, ENOMEM);
2817 goto done;
2818 #else
2819 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2820 #endif
2822 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2823 #ifdef WITH_PINENTRY
2824 if (fp == client->filename && (client->opts & OPT_PINENTRY_TO))
2825 p = g_strdup_printf("%i", client->pinentry->timeout);
2826 else
2827 p = g_strdup_printf("%i",
2828 get_key_file_integer(fp, "pinentry_timeout"));
2830 if (!p) {
2831 log_write("%s(%i): %s", __FILE__, __LINE__,
2832 strerror(ENOMEM));
2833 return send_syserror(ctx, ENOMEM);
2836 goto done;
2837 #else
2838 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2839 #endif
2842 p = get_key_file_string(fp ? fp : "global", paramp);
2843 g_free(paramp);
2845 if (!p)
2846 return send_error(ctx, GPG_ERR_NO_VALUE);
2848 tmp = expand_homedir(p);
2849 g_free(p);
2851 if (!tmp) {
2852 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2853 return send_syserror(ctx, ENOMEM);
2856 p = tmp;
2857 done:
2858 pth_cleanup_push(g_free, p);
2859 rc = xfer_data(ctx, p, strlen(p));
2860 pth_cleanup_pop(1);
2861 return send_error(ctx, rc);
2864 struct xpath_s {
2865 xmlXPathContextPtr xp;
2866 xmlXPathObjectPtr result;
2867 xmlBufferPtr buf;
2868 gchar **req;
2871 static void xpath_command_cleanup(void *arg)
2873 struct xpath_s *xpath = arg;
2875 req_cleanup(xpath->req);
2877 if (xpath->buf)
2878 xmlBufferFree(xpath->buf);
2880 if (xpath->result)
2881 xmlXPathFreeObject(xpath->result);
2883 if (xpath->xp)
2884 xmlXPathFreeContext(xpath->xp);
2887 static gint xpath_command(assuan_context_t ctx, gchar *line)
2889 struct client_s *client = assuan_get_pointer(ctx);
2890 gpg_error_t rc;
2891 struct xpath_s xpath;
2893 log_write2("ARGS=\"%s\"", line);
2895 if (disable_list_and_dump == TRUE)
2896 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2898 if (!line || !*line)
2899 return send_error(ctx, GPG_ERR_SYNTAX);
2901 memset(&xpath, 0, sizeof(struct xpath_s));
2903 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2904 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2905 return send_syserror(ctx, ENOMEM);
2908 xpath.xp = xmlXPathNewContext(client->doc);
2910 if (!xpath.xp) {
2911 xpath_command_cleanup(&xpath);
2912 return send_error(ctx, EPWMD_LIBXML_ERROR);
2915 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2917 if (!xpath.result) {
2918 xpath_command_cleanup(&xpath);
2919 return send_error(ctx, EPWMD_LIBXML_ERROR);
2922 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2923 rc = GPG_ERR_ELEMENT_NOT_FOUND;
2924 goto fail;
2927 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2928 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
2930 if (rc)
2931 goto fail;
2932 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2933 rc = GPG_ERR_NO_VALUE;
2934 goto fail;
2936 else if (xpath.req[1])
2937 goto fail;
2939 pth_cleanup_push(xpath_command_cleanup, &xpath);
2940 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2941 xmlBufferLength(xpath.buf));
2942 pth_cleanup_pop(0);
2944 fail:
2945 xpath_command_cleanup(&xpath);
2946 return send_error(ctx, rc);
2949 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2950 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
2952 struct client_s *client = assuan_get_pointer(ctx);
2953 gpg_error_t rc;
2954 struct xpath_s xpath;
2955 gchar **req = NULL;
2956 gboolean cmd = FALSE; //SET
2958 log_write2("ARGS=\"%s\"", line);
2960 if (disable_list_and_dump == TRUE)
2961 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2963 if (!line || !*line)
2964 return send_error(ctx, GPG_ERR_SYNTAX);
2966 memset(&xpath, 0, sizeof(struct xpath_s));
2968 if ((req = split_input_line(line, " ", 3)) == NULL)
2969 return send_syserror(ctx, ENOMEM);
2971 if (!req[0]) {
2972 rc = GPG_ERR_SYNTAX;
2973 goto fail;
2976 if (!g_ascii_strcasecmp(req[0], "SET"))
2977 cmd = FALSE;
2978 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
2979 cmd = TRUE;
2980 else {
2981 rc = GPG_ERR_SYNTAX;
2982 goto fail;
2985 if (!req[1] || !req[2]) {
2986 rc = GPG_ERR_SYNTAX;
2987 goto fail;
2990 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
2991 rc = gpg_err_code_from_errno(ENOMEM);
2992 goto fail;
2995 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
2996 rc = GPG_ERR_SYNTAX;
2997 goto fail;
3000 xpath.xp = xmlXPathNewContext(client->doc);
3002 if (!xpath.xp) {
3003 rc = EPWMD_LIBXML_ERROR;
3004 goto fail;
3007 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3009 if (!xpath.result) {
3010 rc = EPWMD_LIBXML_ERROR;
3011 goto fail;
3014 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3015 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3016 goto fail;
3019 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3020 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3022 fail:
3023 g_strfreev(req);
3024 xpath_command_cleanup(&xpath);
3025 return send_error(ctx, rc);
3028 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3029 gsize len)
3031 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3032 gpg_error_t rc = file_modified(client);
3033 gchar **req, **path = NULL, **path_orig = NULL, *content;
3034 xmlDocPtr doc = NULL;
3035 xmlNodePtr n, root, copy;
3037 if (assuan_rc || rc) {
3038 if (line)
3039 xfree(line);
3040 return assuan_rc ? assuan_rc : rc;
3043 req = split_input_line((gchar *)line, "\t", 2);
3044 xfree(line);
3046 if (!req || !*req)
3047 return GPG_ERR_SYNTAX;
3049 content = req[0];
3050 path = split_input_line(req[1], "\t", 0);
3052 if (!content || !*content) {
3053 rc = GPG_ERR_SYNTAX;
3054 goto fail;
3057 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3059 if (!doc) {
3060 rc = EPWMD_LIBXML_ERROR;
3061 goto fail;
3064 root = xmlDocGetRootElement(doc);
3065 rc = validate_import(root);
3067 if (rc)
3068 goto fail;
3070 if (path) {
3071 path_orig = g_strdupv(path);
3073 if (!path_orig) {
3074 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3075 rc = gpg_error_from_errno(ENOMEM);
3076 goto fail;
3079 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3081 if (!a) {
3082 g_strfreev(path_orig);
3083 rc = gpg_error_from_errno(ENOMEM);
3084 goto fail;
3087 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3088 xmlFree(a);
3089 g_strfreev(path_orig);
3090 rc = gpg_error_from_errno(ENOMEM);
3091 goto fail;
3094 xmlFree(a);
3095 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3097 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3098 g_strfreev(path_orig);
3099 goto fail;
3102 if (!rc) {
3103 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3105 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3106 g_strfreev(path_orig);
3107 goto fail;
3109 else if (!rc) {
3110 xmlNodePtr parent = n->parent;
3112 xmlUnlinkNode(n);
3113 xmlFreeNode(n);
3114 n = parent;
3118 g_strfreev(path);
3119 path = path_orig;
3121 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3122 n = create_element_path(client, &path, &rc);
3124 if (rc)
3125 goto fail;
3128 copy = xmlCopyNodeList(root);
3129 n = xmlAddChildList(n, copy);
3131 if (!n)
3132 rc = EPWMD_LIBXML_ERROR;
3134 else {
3135 /* Check if the content root element can create a DTD root element. */
3136 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3137 rc = GPG_ERR_SYNTAX;
3138 goto fail;
3141 xmlChar *a;
3143 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3144 rc = GPG_ERR_SYNTAX;
3145 goto fail;
3148 gchar *tmp = g_strdup((gchar *)a);
3149 xmlFree(a);
3150 gboolean literal = is_literal_element(&tmp);
3152 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3153 g_free(tmp);
3154 rc = GPG_ERR_INV_VALUE;
3155 goto fail;
3158 if (strv_printf(&path, "%s", tmp) == FALSE) {
3159 g_free(tmp);
3160 rc = gpg_error_from_errno(ENOMEM);
3161 goto fail;
3164 g_free(tmp);
3165 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3167 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3168 rc = EPWMD_LIBXML_ERROR;
3169 goto fail;
3172 /* Overwriting the existing tree. */
3173 if (!rc) {
3174 xmlUnlinkNode(n);
3175 xmlFreeNodeList(n);
3178 rc = 0;
3179 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3180 n = xmlCopyNode(root, 1);
3181 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3184 fail:
3185 if (doc)
3186 xmlFreeDoc(doc);
3188 if (path)
3189 g_strfreev(path);
3191 g_strfreev(req);
3192 client->inquire_status = INQUIRE_DONE;
3193 return rc;
3196 static gint import_command(assuan_context_t ctx, gchar *line)
3198 gpg_error_t rc;
3199 struct client_s *client = assuan_get_pointer(ctx);
3201 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3203 if (rc)
3204 return send_error(ctx, rc);
3206 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3207 client->inquire_status = INQUIRE_BUSY;
3208 return 0;
3211 static gpg_error_t do_lock_command(struct client_s *client)
3213 gpg_error_t rc = lock_file_mutex(client);
3215 if (!rc)
3216 client->is_lock_cmd = TRUE;
3218 return send_error(client->ctx, rc);
3221 static gint lock_command(assuan_context_t ctx, gchar *line)
3223 struct client_s *client = assuan_get_pointer(ctx);
3225 return do_lock_command(client);
3228 static gint unlock_command(assuan_context_t ctx, gchar *line)
3230 struct client_s *client = assuan_get_pointer(ctx);
3232 unlock_file_mutex(client);
3233 return send_error(ctx, 0);
3236 static gint getpid_command(assuan_context_t ctx, gchar *line)
3238 gpg_error_t rc;
3239 gchar buf[32];
3240 pid_t pid = getpid();
3242 print_fmt(buf, sizeof(buf), "%i", pid);
3243 rc = xfer_data(ctx, buf, strlen(buf));
3244 return send_error(ctx, rc);
3247 static gint version_command(assuan_context_t ctx, gchar *line)
3249 gpg_error_t rc;
3250 gchar buf[32];
3252 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3253 rc = xfer_data(ctx, buf, strlen(buf));
3254 return send_error(ctx, rc);
3257 #ifdef WITH_PINENTRY
3258 static void set_option_value(gchar **opt, const gchar *value)
3260 if (opt)
3261 g_free(*opt);
3263 *opt = NULL;
3265 if (value)
3266 *opt = g_strdup(value);
3268 #endif
3270 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3271 const gchar *value)
3273 struct client_s *client = assuan_get_pointer(ctx);
3275 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3276 glong l = 0;
3278 if (value) {
3279 l = strtol(value, NULL, 10);
3281 if (l < 0 || l > 2)
3282 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3285 log_write1("log_level=%li", l);
3286 MUTEX_LOCK(&rcfile_mutex);
3287 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3288 MUTEX_UNLOCK(&rcfile_mutex);
3289 goto done;
3291 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3292 glong l = 0;
3294 if (value) {
3295 l = strtol(value, NULL, 10);
3297 if (l < 0 || l > 1)
3298 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3301 log_write1("rc_on_locked=%li", l);
3302 client->rc_on_locked = l ? TRUE : FALSE;
3303 goto done;
3305 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3306 pth_attr_t attr = pth_attr_of(pth_self());
3307 gchar buf[41];
3309 if (!value) {
3310 pth_attr_destroy(attr);
3311 goto done;
3314 print_fmt(buf, sizeof(buf), "%s", value);
3315 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3316 pth_attr_destroy(attr);
3317 log_write1("name=%s", buf);
3318 #ifdef WITH_PINENTRY
3319 if (client->pinentry->name)
3320 g_free(client->pinentry->name);
3322 client->pinentry->name = g_strdup(buf);
3324 if (!client->pinentry->name)
3325 return gpg_error_from_errno(ENOMEM);
3326 #endif
3328 goto done;
3330 #ifdef WITH_PINENTRY
3331 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3332 set_option_value(&client->pinentry->lcmessages, value);
3333 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3334 set_option_value(&client->pinentry->lcctype, value);
3335 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3336 set_option_value(&client->pinentry->ttyname, value);
3337 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3338 set_option_value(&client->pinentry->ttytype, value);
3339 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3340 set_option_value(&client->pinentry->display, value);
3341 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3342 set_option_value(&client->pinentry->path, value);
3343 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3344 set_option_value(&client->pinentry->title, value);
3345 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3346 set_option_value(&client->pinentry->prompt, value);
3347 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3348 set_option_value(&client->pinentry->desc, value);
3349 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3350 gchar *p = NULL;
3351 gint n;
3353 if (!value) {
3354 client->pinentry->timeout =
3355 get_key_file_integer(client->filename, "pinentry_timeout");
3356 client->opts &= ~(OPT_PINENTRY_TO);
3357 log_write1("pinentry_timeout=%i",
3358 get_key_file_integer(client->filename, "pinentry_timeout"));
3359 goto done;
3362 n = strtol(value, &p, 10);
3364 if (*p || n < 0)
3365 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3367 client->pinentry->timeout = n;
3368 client->opts |= OPT_PINENTRY_TO;
3369 log_write1("pinentry_timeout=%i", n);
3370 goto done;
3372 #endif
3373 else
3374 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3376 log_write1("%s=%s", name, value ? value : "");
3378 done:
3379 return 0;
3382 static gint unset_command(assuan_context_t ctx, gchar *line)
3384 log_write2("ARGS=\"%s\"", line);
3385 return send_error(ctx, set_unset_common(ctx, line, NULL));
3388 static gint set_command(assuan_context_t ctx, gchar *line)
3390 gchar name[64] = {0}, value[256] = {0};
3392 log_write2("ARGS=\"%s\"", line);
3394 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3395 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3397 return send_error(ctx, set_unset_common(ctx, name, value));
3400 static gint rename_command(assuan_context_t ctx, gchar *line)
3402 struct client_s *client = assuan_get_pointer(ctx);
3403 gpg_error_t rc;
3404 gchar **req, **src, *dst;
3405 xmlNodePtr n, ndst;
3407 log_write2("ARGS=\"%s\"", line);
3408 req = split_input_line(line, " ", -1);
3410 if (!req || !req[0] || !req[1]) {
3411 g_strfreev(req);
3412 return send_error(ctx, GPG_ERR_SYNTAX);
3415 dst = req[1];
3416 is_literal_element(&dst);
3418 if (!valid_xml_element((xmlChar *)dst)) {
3419 g_strfreev(req);
3420 return GPG_ERR_INV_VALUE;
3423 if (strchr(req[0], '\t'))
3424 src = split_input_line(req[0], "\t", -1);
3425 else
3426 src = split_input_line(req[0], " ", -1);
3428 if (!src || !*src) {
3429 rc = GPG_ERR_SYNTAX;
3430 goto fail;
3433 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3435 if (src[1] && n)
3436 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3437 NULL, FALSE, 0, NULL, FALSE);
3439 if (!n)
3440 goto fail;
3443 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3445 if (!a) {
3446 rc = gpg_error_from_errno(ENOMEM);
3447 goto fail;
3450 /* To prevent unwanted effects:
3452 * <root name="a"><b/></root>
3454 * RENAME a<TAB>b b
3456 if (xmlStrEqual(a, (xmlChar *)dst)) {
3457 xmlFree(a);
3458 rc = GPG_ERR_AMBIGUOUS_NAME;
3459 goto fail;
3462 xmlFree(a);
3463 gchar **tmp = NULL;
3465 if (src[1]) {
3466 gchar **p;
3468 for (p = src; *p; p++) {
3469 if (!*(p+1))
3470 break;
3472 strv_printf(&tmp, "%s", *p);
3476 strv_printf(&tmp, "!%s", dst);
3477 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3479 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3480 g_strfreev(tmp);
3481 goto fail;
3484 if (tmp[1] && ndst)
3485 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3486 NULL, NULL, FALSE, 0, NULL, FALSE);
3488 g_strfreev(tmp);
3490 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3491 goto fail;
3493 rc = 0;
3495 /* Target may exist:
3497 * <root name="a"/>
3498 * <root name="b" target="a"/>
3500 * RENAME b a
3502 * Would need to do:
3503 * RENAME !b a
3505 if (ndst == n) {
3506 rc = GPG_ERR_AMBIGUOUS_NAME;
3507 goto fail;
3510 if (ndst) {
3511 xmlUnlinkNode(ndst);
3512 xmlFreeNodeList(ndst);
3515 rc = add_attribute(n, "_name", dst);
3517 fail:
3518 g_strfreev(req);
3519 g_strfreev(src);
3520 return send_error(ctx, rc);
3523 static gint copy_command(assuan_context_t ctx, gchar *line)
3525 struct client_s *client = assuan_get_pointer(ctx);
3526 gpg_error_t rc;
3527 gchar **req, **src = NULL, **dst = NULL;
3528 xmlNodePtr nsrc, ndst, new;
3530 log_write2("ARGS=\"%s\"", line);
3531 req = split_input_line(line, " ", -1);
3533 if (!req || !req[0] || !req[1]) {
3534 g_strfreev(req);
3535 return send_error(ctx, GPG_ERR_SYNTAX);
3538 if (strchr(req[0], '\t'))
3539 src = split_input_line(req[0], "\t", -1);
3540 else
3541 src = split_input_line(req[0], " ", -1);
3543 if (!src || !*src) {
3544 rc = GPG_ERR_SYNTAX;
3545 goto fail;
3548 if (strchr(req[1], '\t'))
3549 dst = split_input_line(req[1], "\t", -1);
3550 else
3551 dst = split_input_line(req[1], " ", -1);
3553 if (!dst || !*dst) {
3554 rc = GPG_ERR_SYNTAX;
3555 goto fail;
3558 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3560 if (nsrc && src[1])
3561 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3562 NULL, NULL, FALSE, 0, NULL, FALSE);
3564 if (!nsrc)
3565 goto fail;
3567 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3569 if (ndst && dst[1])
3570 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3571 NULL, NULL, FALSE, 0, NULL, FALSE);
3573 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3574 goto fail;
3576 new = xmlCopyNodeList(nsrc);
3578 if (!new) {
3579 rc = GPG_ERR_ENOMEM;
3580 goto fail;
3583 if (!ndst)
3584 ndst = create_element_path(client, &dst, &rc);
3586 if (!ndst) {
3587 xmlUnlinkNode(new);
3588 xmlFreeNodeList(new);
3589 goto fail;
3592 /* Merge any attributes from the src node to the initial dst node. */
3593 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3594 if ((!src[1] || !dst[1]) && xmlStrEqual(attr->name, (xmlChar *)"_name"))
3595 continue;
3597 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3599 if (a)
3600 xmlRemoveProp(a);
3602 xmlChar *tmp = xmlNodeGetContent(attr->children);
3603 xmlNewProp(ndst, attr->name, tmp);
3604 xmlFree(tmp);
3607 xmlNodePtr n = ndst->children;
3608 xmlUnlinkNode(n);
3609 xmlFreeNodeList(n);
3610 ndst->children = NULL;
3612 if (!new->children) {
3613 xmlUnlinkNode(new);
3614 xmlFreeNodeList(new);
3615 goto fail;
3618 n = xmlCopyNodeList(new->children);
3620 if (!n) {
3621 rc = GPG_ERR_ENOMEM;
3622 goto fail;
3625 xmlUnlinkNode(new);
3626 xmlFreeNodeList(new);
3627 n = xmlAddChildList(ndst, n);
3629 if (!n) {
3630 rc = GPG_ERR_ENOMEM;
3631 goto fail;
3634 fail:
3635 if (req)
3636 g_strfreev(req);
3638 if (src)
3639 g_strfreev(src);
3641 if (dst)
3642 g_strfreev(dst);
3644 return send_error(ctx, rc);
3647 static gint move_command(assuan_context_t ctx, gchar *line)
3649 struct client_s *client = assuan_get_pointer(ctx);
3650 gpg_error_t rc;
3651 gchar **req, **src = NULL, **dst = NULL;
3652 xmlNodePtr nsrc, ndst = NULL;
3654 log_write2("ARGS=\"%s\"", line);
3655 req = split_input_line(line, " ", -1);
3657 if (!req || !req[0] || !req[1]) {
3658 g_strfreev(req);
3659 return send_error(ctx, GPG_ERR_SYNTAX);
3662 if (strchr(req[0], '\t'))
3663 src = split_input_line(req[0], "\t", -1);
3664 else
3665 src = split_input_line(req[0], " ", -1);
3667 if (!src || !*src) {
3668 rc = GPG_ERR_SYNTAX;
3669 goto fail;
3672 if (strchr(req[1], '\t'))
3673 dst = split_input_line(req[1], "\t", -1);
3674 else
3675 dst = split_input_line(req[1], " ", -1);
3677 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3679 if (nsrc && src[1])
3680 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3681 NULL, NULL, FALSE, 0, NULL, FALSE);
3683 if (!nsrc)
3684 goto fail;
3686 if (dst) {
3687 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3689 if (ndst && dst[1])
3690 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3691 NULL, NULL, FALSE, 0, NULL, FALSE);
3693 else
3694 ndst = xmlDocGetRootElement(client->doc);
3696 for (xmlNodePtr n = ndst; n; n = n->parent) {
3697 if (n == nsrc) {
3698 rc = GPG_ERR_CONFLICT;
3699 goto fail;
3703 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3704 goto fail;
3706 rc = 0;
3708 if (ndst) {
3709 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3710 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3712 xmlFree(a);
3714 if (dup) {
3715 if (dup == nsrc)
3716 goto fail;
3718 if (ndst == xmlDocGetRootElement(client->doc)) {
3719 xmlNodePtr n = nsrc;
3720 gboolean match = FALSE;
3722 while (n->parent && n->parent != ndst)
3723 n = n->parent;
3725 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3726 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3728 if (xmlStrEqual(a, b)) {
3729 match = TRUE;
3730 xmlUnlinkNode(nsrc);
3731 xmlUnlinkNode(n);
3732 xmlFreeNodeList(n);
3735 xmlFree(a);
3736 xmlFree(b);
3738 if (!match) {
3739 xmlUnlinkNode(dup);
3740 xmlFreeNodeList(dup);
3743 else
3744 xmlUnlinkNode(dup);
3748 if (!ndst && dst)
3749 ndst = create_element_path(client, &dst, &rc);
3751 if (!ndst)
3752 goto fail;
3754 xmlUnlinkNode(nsrc);
3755 ndst = xmlAddChildList(ndst, nsrc);
3757 if (!ndst)
3758 rc = GPG_ERR_ENOMEM;
3760 fail:
3761 if (req)
3762 g_strfreev(req);
3764 if (src)
3765 g_strfreev(src);
3767 if (dst)
3768 g_strfreev(dst);
3770 return send_error(ctx, rc);
3773 static int ls_command(assuan_context_t ctx, gchar *line)
3775 log_write2("ARGS=\"%s\"", line);
3776 gpg_error_t rc;
3777 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3778 gchar *dir = expand_homedir(tmp);
3779 DIR *d = opendir(dir);
3780 gint n = errno;
3782 g_free(tmp);
3784 if (!d) {
3785 g_free(dir);
3786 return send_syserror(ctx, n);
3789 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
3790 struct dirent *p = g_malloc(len), *cur = NULL;
3791 gchar *list = NULL;
3793 g_free(dir);
3794 rc = 0;
3796 while (!readdir_r(d, p, &cur) && cur) {
3797 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
3798 continue;
3799 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
3800 continue;
3802 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
3804 if (!tmp) {
3805 if (list)
3806 g_free(list);
3808 rc = GPG_ERR_ENOMEM;
3809 break;
3812 g_free(list);
3813 list = tmp;
3816 closedir(d);
3817 g_free(p);
3819 if (rc)
3820 return send_error(ctx, rc);
3822 if (!list)
3823 return send_error(ctx, GPG_ERR_NO_VALUE);
3825 list[strlen(list)-1] = 0;
3826 rc = xfer_data(ctx, list, strlen(list));
3827 g_free(list);
3828 return send_error(ctx, rc);
3831 static void bye_notify(assuan_context_t ctx)
3833 struct client_s *cl = assuan_get_pointer(ctx);
3835 /* This will let assuan_process_next() return. */
3836 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3839 static void reset_notify(assuan_context_t ctx)
3841 struct client_s *cl = assuan_get_pointer(ctx);
3843 if (cl)
3844 cleanup_client(cl);
3848 * This is called before every Assuan command.
3850 gint command_startup(assuan_context_t ctx, const gchar *name)
3852 struct client_s *cl = assuan_get_pointer(ctx);
3853 gpg_error_t rc;
3855 log_write1("%s", name);
3857 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
3858 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
3859 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
3860 !g_ascii_strcasecmp(name, "GETCONFIG") ||
3861 !g_ascii_strcasecmp(name, "GETPID") ||
3862 !g_ascii_strcasecmp(name, "VERSION") ||
3863 !g_ascii_strcasecmp(name, "SET") ||
3864 !g_ascii_strcasecmp(name, "BYE") ||
3865 !g_ascii_strcasecmp(name, "NOP") ||
3866 !g_ascii_strcasecmp(name, "CANCEL") ||
3867 !g_ascii_strcasecmp(name, "RESET") ||
3868 !g_ascii_strcasecmp(name, "END") ||
3869 !g_ascii_strcasecmp(name, "HELP") ||
3870 !g_ascii_strcasecmp(name, "OPTION") ||
3871 !g_ascii_strcasecmp(name, "INPUT") ||
3872 !g_ascii_strcasecmp(name, "OUTPUT") ||
3873 !g_ascii_strcasecmp(name, "LS") ||
3874 !g_ascii_strcasecmp(name, "UNSET"))
3875 return 0;
3877 cl->last_rc = rc = file_modified(cl);
3879 if (rc) {
3880 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3881 !g_ascii_strcasecmp(name, "OPEN"))
3882 rc = 0;
3885 return rc;
3889 * This is called after every Assuan command.
3891 void command_finalize(assuan_context_t ctx, gint rc)
3893 struct client_s *client = assuan_get_pointer(ctx);
3895 if (!client->is_lock_cmd)
3896 unlock_file_mutex(client);
3898 log_write1(N_("command completed (rc=%u)"), client->last_rc);
3901 gpg_error_t register_commands(assuan_context_t ctx)
3903 static struct {
3904 const gchar *name;
3905 gint (*handler)(assuan_context_t, gchar *line);
3906 } table[] = {
3907 { "OPEN", open_command },
3908 { "SAVE", save_command },
3909 { "LIST", list_command },
3910 { "REALPATH", realpath_command },
3911 { "STORE", store_command },
3912 { "DELETE", delete_command },
3913 { "GET", get_command },
3914 { "ATTR", attr_command },
3915 { "ISCACHED", iscached_command },
3916 { "CLEARCACHE", clearcache_command },
3917 { "CACHETIMEOUT", cachetimeout_command },
3918 { "GETCONFIG", getconfig_command },
3919 { "DUMP", dump_command },
3920 { "XPATH", xpath_command },
3921 { "XPATHATTR", xpathattr_command },
3922 { "IMPORT", import_command },
3923 { "LOCK", lock_command },
3924 { "UNLOCK", unlock_command },
3925 { "GETPID", getpid_command },
3926 { "VERSION", version_command },
3927 { "SET", set_command },
3928 { "UNSET", unset_command },
3929 { "RENAME", rename_command },
3930 { "COPY", copy_command },
3931 { "LS", ls_command },
3932 { "MOVE", move_command },
3933 { "INPUT", NULL },
3934 { "OUTPUT", NULL },
3935 { NULL, NULL }
3937 gint i, rc;
3939 for (i=0; table[i].name; i++) {
3940 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
3942 if (rc)
3943 return rc;
3946 rc = assuan_register_bye_notify(ctx, bye_notify);
3948 if (rc)
3949 return rc;
3951 rc = assuan_register_reset_notify(ctx, reset_notify);
3953 if (rc)
3954 return rc;
3956 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
3958 if (rc)
3959 return rc;
3961 return assuan_register_post_cmd_notify(ctx, command_finalize);
3964 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
3965 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
3967 goffset insize, len;
3968 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
3969 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
3970 gint zrc = 0;
3971 gulong outsize = 0;
3972 gpg_error_t rc;
3973 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
3974 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
3975 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
3977 lseek(crypto->fh->fd, fh_size, SEEK_SET);
3978 insize = crypto->fh->st.st_size - fh_size;
3979 crypto->iv = gcry_malloc(crypto->blocksize);
3981 if (!crypto->iv) {
3982 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3983 return gpg_error_from_errno(ENOMEM);
3986 if (crypto->fh->v1)
3987 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
3988 else
3989 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
3991 crypto->inbuf = gcry_malloc(insize);
3993 if (!crypto->inbuf) {
3994 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3995 return gpg_error_from_errno(ENOMEM);
3998 crypto->insize = insize;
3999 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4001 if (len != crypto->insize)
4002 return GPG_ERR_INV_LENGTH;
4004 /* No encryption iterations. This is a plain (gzipped) file. */
4005 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4006 (!crypto->fh->v1 && fh_iter <= 0L)) {
4008 * cache_file_count() needs both .used == TRUE and a valid key in
4009 * order for it to count as a used cache entry. Fixes CACHE status
4010 * messages.
4012 memset(crypto->key, '!', hashlen);
4013 goto decompress;
4016 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4017 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4018 return rc;
4021 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4022 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4023 return rc;
4026 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4027 client->filename : "global", "iteration_progress");
4029 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4030 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4032 if (rc)
4033 return rc;
4036 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4038 if (rc)
4039 return rc;
4041 crypto->tkey = gcry_malloc(hashlen);
4043 if (!crypto->tkey) {
4044 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
4045 return gpg_error_from_errno(ENOMEM);
4048 memcpy(crypto->tkey, crypto->key, hashlen);
4049 guchar *tkey = crypto->tkey;
4050 tkey[0] ^= 1;
4052 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4053 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4054 return rc;
4057 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4058 if (iter_progress > 0ULL && iter >= iter_progress) {
4059 if (!(iter % iter_progress)) {
4060 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4061 ++n_iter * iter_progress, fh_iter);
4063 if (rc)
4064 return rc;
4068 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4069 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4070 return rc;
4073 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4075 if (rc) {
4076 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4077 return rc;
4080 iter++;
4083 if (iter_progress && fh_iter >= iter_progress) {
4084 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4086 if (rc)
4087 return rc;
4090 decompress:
4091 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
4092 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
4093 if (zrc == Z_MEM_ERROR)
4094 return gpg_error_from_errno(ENOMEM);
4095 else
4096 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4099 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4100 gcry_free(crypto->outbuf);
4101 crypto->outbuf = NULL;
4102 return GPG_ERR_INV_PASSPHRASE;
4105 if (ctx) {
4106 client->xml = crypto->outbuf;
4107 client->len = outsize;
4108 crypto->outbuf = NULL;
4110 else if (dst) {
4111 *dst = crypto->outbuf;
4112 *dst_len = outsize;
4113 crypto->outbuf = NULL;
4116 /* The calling function should free the crypto struct. */
4117 return 0;