Renamed the --force option to the SAVE command to --reset.
[pwmd.git] / src / commands.c
blobd600f150a031c646786575ad2be53de87b235628
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;
508 const gchar *p = value;
510 if (p && *p) {
511 long l = strtol(p, NULL, 10);
513 if (l < 0 || l > 1)
514 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
516 client->lock_on_open = l ? TRUE : FALSE;
518 else if ((!p || !*p) && (client->opts & OPT_LOCK))
519 client->lock_on_open = FALSE;
520 else
521 client->lock_on_open = TRUE;
523 return 0;
526 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
528 #ifdef WITH_PINENTRY
529 struct client_s *client = data;
530 gchar *p = NULL;
531 gchar *str = value;
532 gint n;
534 if (!str || !*str) {
535 client->pinentry->enable = -1;
536 client->opts &= ~(OPT_PINENTRY);
537 return 0;
540 n = strtol(str, &p, 10);
542 if (*p || n < 0 || n > 1)
543 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
545 client->pinentry->enable = n ? TRUE : FALSE;
546 client->opts |= OPT_PINENTRY;
547 log_write1("enable_pinentry=%i", n);
548 #endif
549 return 0;
552 static gint open_command(assuan_context_t ctx, gchar *line)
554 gboolean cached = FALSE;
555 gpg_error_t rc;
556 struct client_s *client = assuan_get_pointer(ctx);
557 gchar **req;
558 gchar *filename = NULL;
559 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
560 struct argv_s *args[] = {
561 &(struct argv_s) { "lock", OPT_NOARG, parse_open_opt_lock },
562 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry},
563 NULL
566 if (client->state == STATE_OPEN)
567 cleanup_client(client);
569 if (!(client->opts & OPT_LOCK))
570 client->lock_on_open = FALSE;
572 rc = parse_options(&line, args, client);
574 if (rc)
575 return send_error(ctx, rc);
577 if ((req = split_input_line(line, " ", 2)) != NULL)
578 filename = req[0];
580 pth_cleanup_push(req_cleanup, req);
582 if (!filename || !*filename) {
583 pth_cleanup_pop(1);
584 return send_error(ctx, GPG_ERR_SYNTAX);
587 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
589 if (valid_filename(filename) == FALSE) {
590 pth_cleanup_pop(1);
591 return send_error(ctx, GPG_ERR_INV_VALUE);
594 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
595 CACHE_LOCK(client->ctx);
597 if (cache_has_file(client->md5file) == FALSE) {
598 if (cache_add_file(client->md5file, NULL) == FALSE) {
599 pth_cleanup_pop(1);
600 CACHE_UNLOCK;
601 return send_syserror(ctx, ENOMEM);
605 cache_incr_refcount(client->md5file);
606 CACHE_UNLOCK;
607 rc = lock_file_mutex(client);
609 if (rc) {
610 pth_cleanup_pop(1);
611 return send_error(ctx, rc);
614 client->freed = FALSE;
615 client->crypto = init_client_crypto();
617 if (!client->crypto) {
618 pth_cleanup_pop(1);
619 cleanup_client(client);
620 return send_syserror(ctx, ENOMEM);
623 client->crypto->key = gcry_malloc(hashlen);
625 if (!client->crypto->key) {
626 pth_cleanup_pop(1);
627 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
628 gpg_error_from_errno(ENOMEM));
629 cleanup_client(client);
630 return send_syserror(ctx, ENOMEM);
633 memset(client->crypto->key, 0, hashlen);
634 client->crypto->fh = read_file_header(filename, FALSE, &rc);
636 if (!client->crypto->fh) {
637 if (gpg_err_code_to_errno(rc) != ENOENT) {
638 log_write("%s: %s", filename, pwmd_strerror(rc));
639 pth_cleanup_pop(1);
640 cleanup_client(client);
641 return send_error(ctx, rc);
645 * New files don't need a key.
647 if ((client->xml = new_document()) == NULL) {
648 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
649 pth_cleanup_pop(1);
650 cleanup_client(client);
651 return send_syserror(ctx, ENOMEM);
654 client->len = xmlStrlen(client->xml);
655 client->new = TRUE;
656 client->filename = g_strdup(filename);
658 if (!client->filename) {
659 pth_cleanup_pop(1);
660 cleanup_client(client);
661 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
662 return send_syserror(ctx, ENOMEM);
665 if (req[1] && *req[1])
666 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
667 strlen(req[1]));
669 pth_cleanup_pop(1);
670 #ifdef WITH_PINENTRY
671 client->pinentry->filename = g_strdup(client->filename);
673 if (!client->pinentry->filename) {
674 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
675 cleanup_client(client);
676 return send_syserror(ctx, ENOMEM);
678 #endif
679 return open_command_finalize(ctx, NULL, cached);
681 else {
682 if (!(client->opts & OPT_CIPHER))
683 g_key_file_set_string(keyfileh, filename, "cipher",
684 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
686 client->mtime = client->crypto->fh->st.st_mtime;
689 client->filename = g_strdup(filename);
691 if (!client->filename) {
692 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
693 pth_cleanup_pop(1);
694 cleanup_client(client);
695 return send_syserror(ctx, ENOMEM);
698 #ifdef WITH_PINENTRY
699 if (client->pinentry->filename)
700 g_free(client->pinentry->filename);
702 client->pinentry->filename = g_strdup(client->filename);
704 if (!client->pinentry->filename) {
705 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
706 pth_cleanup_pop(1);
707 cleanup_client(client);
708 return send_syserror(ctx, ENOMEM);
710 #endif
712 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
713 goto done;
715 CACHE_LOCK(client->ctx);
716 cached = cache_get_key(client->md5file, client->crypto->key);
717 CACHE_UNLOCK;
719 if (cached == FALSE) {
720 gchar *tmp = get_key_file_string(filename, "key_file");
722 if (tmp) {
723 g_free(tmp);
724 pth_cleanup_pop(1);
725 cleanup_client(client);
726 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
730 * No key specified and no matching filename found in the cache. Use
731 * pinentry to retrieve the key. Cannot return assuan_process_done()
732 * here otherwise the command will be interrupted. The event loop in
733 * client_thread() will poll the file descriptor waiting for it to
734 * become ready to read a pinentry_key_s which will contain the
735 * entered key or an error code. It will then call
736 * open_command_finalize() to to finish the command.
738 if (!req[1] || !*req[1]) {
739 #ifdef WITH_PINENTRY
740 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
742 /* From set_pinentry_defaults(). */
743 if (client->pinentry->enable == FALSE ||
744 (client->pinentry->enable == -1 && b == FALSE)) {
745 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
746 goto done;
749 pth_cleanup_pop(1);
750 rc = lock_pin_mutex(client);
752 if (rc) {
753 unlock_pin_mutex(client->pinentry);
754 cleanup_client(client);
755 return send_error(ctx, rc);
758 client->pinentry->which = PINENTRY_OPEN;
759 rc = pinentry_fork(ctx);
761 if (rc) {
762 unlock_pin_mutex(client->pinentry);
763 cleanup_client(client);
764 return send_error(ctx, rc);
767 // Called from pinentry iterate.
768 client->pinentry->cb = open_command_finalize;
769 client->pinentry->status = PINENTRY_INIT;
770 return 0;
771 #else
772 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
773 goto done;
774 #endif
777 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
778 strlen(req[1]));
780 else if (req && req[1] && *req[1]) {
781 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, req[1],
782 strlen(req[1]) ? strlen(req[1]) : 1);
785 done:
786 pth_cleanup_pop(1);
787 return open_command_finalize(ctx, NULL, cached);
790 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
791 guint size, gpointer *out, gulong *outsize, gint *rc)
793 struct gz_s *gz;
794 gz_header h;
795 gchar buf[17];
796 gint cmd = Z_NO_FLUSH;
798 gz = g_malloc0(sizeof(struct gz_s));
800 if (!gz) {
801 *rc = gpg_error_from_errno(ENOMEM);
802 return FALSE;
805 pth_cleanup_push(gz_cleanup, &gz);
806 gz->which = STATUS_COMPRESS;
807 gz->z.zalloc = z_alloc;
808 gz->z.zfree = z_free;
809 gz->z.next_in = data;
810 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
811 gz->z.avail_out = (uInt)zlib_bufsize;
812 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
814 if (!gz->out) {
815 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
816 *rc = Z_MEM_ERROR;
817 pth_cleanup_pop(1);
818 return FALSE;
821 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
823 if (*rc != Z_OK) {
824 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
825 pth_cleanup_pop(1);
826 return FALSE;
829 /* Rather than store the size of the uncompressed data in the file header,
830 * store it in the comment field of the gzip header. Don't give anyone too
831 * much information. Not sure why really, but it seems the right way. :)
833 memset(&h, 0, sizeof(gz_header));
834 g_snprintf(buf, sizeof(buf), "%u", size);
835 h.comment = (guchar *)buf;
836 *rc = deflateSetHeader(&gz->z, &h);
838 if (*rc != Z_OK) {
839 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
840 pth_cleanup_pop(1);
841 return FALSE;
844 do {
845 gpointer p;
847 *rc = deflate(&gz->z, cmd);
849 switch (*rc) {
850 case Z_OK:
851 break;
852 case Z_BUF_ERROR:
853 if (!gz->z.avail_out) {
854 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
856 if (!p) {
857 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
858 *rc = Z_MEM_ERROR;
859 goto fail;
862 gz->out = p;
863 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
864 gz->z.avail_out = zlib_bufsize;
867 if (!gz->z.avail_in && gz->z.total_in < size) {
868 if (gz->z.total_in + zlib_bufsize > size)
869 gz->z.avail_in = size - gz->z.total_in;
870 else
871 gz->z.avail_in = zlib_bufsize;
873 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
874 gz->z.total_in, size);
876 if (*rc)
877 goto fail;
880 if (gz->z.total_in >= size)
881 cmd = Z_FINISH;
883 break;
884 case Z_STREAM_END:
885 break;
886 default:
887 goto fail;
889 } while (*rc != Z_STREAM_END);
891 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
893 if (*rc)
894 goto fail;
896 *out = gz->out;
897 *outsize = gz->z.total_out;
898 *rc = 0;
899 gz->done = TRUE;
900 pth_cleanup_pop(1);
901 return TRUE;
903 fail:
904 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
905 pth_cleanup_pop(1);
906 return FALSE;
909 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
912 * Useful for a large amount of data. Rather than doing all of the data in one
913 * iteration do it in chunks. This lets the command be cancelable rather than
914 * waiting for it to complete.
916 static gpg_error_t iterate_crypto_once(struct client_s *client,
917 struct crypto_s *crypto, status_msg_t which)
919 gpg_error_t rc = 0;
920 goffset len = CRYPTO_BLOCKSIZE(crypto);
921 gpointer p = gcry_malloc(len);
922 goffset total = 0;
923 gpointer inbuf;
925 if (!p)
926 return gpg_err_code_from_errno(ENOMEM);
928 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
929 len = crypto->insize;
931 pth_cleanup_push(gcry_free, p);
933 for (;;) {
934 inbuf = (guchar *)crypto->inbuf + total;
935 guchar *tmp;
937 if (len + total > crypto->insize)
938 len = crypto->blocksize;
940 if (which == STATUS_ENCRYPT)
941 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
942 else
943 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
945 if (rc)
946 goto done;
948 tmp = (guchar *)crypto->inbuf + total;
949 memmove(tmp, p, len);
950 total += len;
952 if (total >= crypto->insize)
953 break;
955 pth_cancel_point();
958 done:
959 pth_cleanup_pop(1);
960 return rc;
963 /* The crypto struct must be setup for iterations and .key. */
964 gpg_error_t do_xml_encrypt(struct client_s *client,
965 struct crypto_s *crypto, const gchar *filename)
967 goffset len = crypto->insize;
968 gpointer inbuf;
969 gchar *p;
970 gpg_error_t rc;
971 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
972 gchar tmp[FILENAME_MAX];
973 struct stat st;
974 mode_t mode = 0;
975 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
977 if (!crypto->fh->ver.fh2.iter) {
979 * cache_file_count() needs both .used == TRUE and a valid key in
980 * order for it to count as a used cache entry. Fixes CACHE status
981 * messages.
983 memset(crypto->key, '!', hashlen);
984 goto write_file;
988 * Resize the existing xml buffer to the block size required by gcrypt
989 * rather than duplicating it and wasting memory.
991 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
993 if (crypto->insize % crypto->blocksize)
994 len += crypto->blocksize;
996 inbuf = gcry_realloc(crypto->inbuf, len);
998 if (!inbuf) {
999 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1000 return gpg_error_from_errno(ENOMEM);
1003 crypto->inbuf = inbuf;
1004 crypto->insize = len;
1005 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1007 if (crypto->tkey)
1008 gcry_free(crypto->tkey);
1010 crypto->tkey = gcry_malloc(hashlen);
1012 if (!crypto->tkey) {
1013 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1014 return gpg_error_from_errno(ENOMEM);
1017 memcpy(crypto->tkey, crypto->key, hashlen);
1018 guchar *tkey = crypto->tkey;
1019 tkey[0] ^= 1;
1021 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1022 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1023 return rc;
1026 iter_progress = (guint64)get_key_file_double(
1027 client ? client->filename : "global", "iteration_progress");
1029 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1030 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1031 "0 %llu", crypto->fh->ver.fh2.iter);
1033 if (rc)
1034 return rc;
1037 while (xiter < crypto->fh->ver.fh2.iter-1) {
1038 if (iter_progress > 0ULL && xiter >= iter_progress) {
1039 if (!(xiter % iter_progress)) {
1040 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1041 "%llu %llu", ++n_iter * iter_progress,
1042 crypto->fh->ver.fh2.iter);
1044 if (rc)
1045 return rc;
1049 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1050 crypto->blocksize))) {
1051 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1052 return rc;
1055 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1057 if (rc) {
1058 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1059 return rc;
1062 xiter++;
1065 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1066 crypto->blocksize))) {
1067 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1068 return rc;
1071 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1072 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1073 return rc;
1076 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1078 if (rc)
1079 return rc;
1081 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1082 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1083 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1085 if (rc)
1086 return rc;
1089 write_file:
1090 tmp[0] = 0;
1092 if (filename) {
1093 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1094 crypto->fh->fd = STDOUT_FILENO;
1095 goto do_write_file;
1098 if (lstat(filename, &st) == 0) {
1099 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1101 if (!(mode & S_IWUSR))
1102 return gpg_error_from_errno(EACCES);
1104 else if (errno != ENOENT)
1105 return gpg_error_from_errno(errno);
1107 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1108 crypto->fh->fd = mkstemp(tmp);
1110 if (crypto->fh->fd == -1) {
1111 rc = errno;
1112 p = strrchr(tmp, '/');
1113 p++;
1114 log_write("%s: %s", p, strerror(rc));
1115 return gpg_error_from_errno(rc);
1118 pth_cleanup_push(cleanup_unlink_cb, tmp);
1120 else
1122 * xml_import() or convert_file() from command line.
1124 crypto->fh->fd = STDOUT_FILENO;
1126 do_write_file:
1127 crypto->fh->ver.fh2.magic[0] = '\177';
1128 crypto->fh->ver.fh2.magic[1] = 'P';
1129 crypto->fh->ver.fh2.magic[2] = 'W';
1130 crypto->fh->ver.fh2.magic[3] = 'M';
1131 crypto->fh->ver.fh2.magic[4] = 'D';
1132 crypto->fh->ver.fh2.version = VERSION_HEX;
1133 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1135 if (len != sizeof(crypto->fh->ver.fh2)) {
1136 len = errno;
1138 if (tmp[0])
1139 pth_cleanup_pop(1);
1141 return gpg_error_from_errno(len);
1144 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1146 if (len != crypto->insize) {
1147 len = errno;
1149 if (tmp[0])
1150 pth_cleanup_pop(1);
1152 return gpg_error_from_errno(len);
1155 if (fsync(crypto->fh->fd) == -1) {
1156 len = errno;
1158 if (tmp[0])
1159 pth_cleanup_pop(1);
1161 return gpg_error_from_errno(len);
1164 if (tmp[0]) {
1165 #ifdef WITH_LIBACL
1166 acl_t acl;
1167 #endif
1168 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1169 gchar tmp2[FILENAME_MAX];
1171 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1172 #ifdef WITH_LIBACL
1173 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1175 if (!acl)
1176 log_write("ACL: %s: %s", filename, strerror(errno));
1177 #endif
1179 if (rename(filename, tmp2) == -1) {
1180 len = errno;
1181 pth_cleanup_pop(1);
1182 #ifdef WITH_LIBACL
1183 if (acl)
1184 acl_free(acl);
1185 #endif
1186 return gpg_error_from_errno(len);
1189 #ifdef WITH_LIBACL
1190 else {
1191 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1193 if (!acl)
1194 log_write("ACL: %s: %s", filename, strerror(errno));
1196 #endif
1198 if (rename(tmp, filename) == -1) {
1199 len = errno;
1200 pth_cleanup_pop(1);
1201 #ifdef WITH_LIBACL
1202 if (acl)
1203 acl_free(acl);
1204 #endif
1205 return gpg_error_from_errno(len);
1208 pth_cleanup_pop(0);
1210 if (mode)
1211 chmod(filename, mode);
1213 #ifdef WITH_LIBACL
1214 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1215 log_write("ACL: %s: %s", filename, strerror(errno));
1217 if (acl)
1218 acl_free(acl);
1219 #endif
1222 if (client && lstat(filename, &st) == 0)
1223 client->mtime = st.st_mtime;
1225 return 0;
1228 gpg_error_t update_save_flags(const gchar *filename,
1229 struct crypto_s *crypto)
1231 gpg_error_t rc;
1232 guint64 iter;
1234 /* New file? */
1235 if (!crypto->fh) {
1236 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1238 if (!crypto->fh)
1239 return GPG_ERR_ENOMEM;
1242 rc = init_client_crypto2(filename, crypto);
1244 if (rc)
1245 return rc;
1247 if (filename && !crypto->fh->v1) {
1248 iter = (guint64)get_key_file_double(filename, "iterations");
1249 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1252 return 0;
1255 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1256 gboolean cached)
1258 struct client_s *client = assuan_get_pointer(ctx);
1259 gpointer xmlbuf;
1260 gulong outsize = 0;
1261 guint len;
1262 gint clevel;
1263 gint timeout;
1264 gpointer outbuf;
1265 gint zrc;
1266 gpg_error_t rc;
1268 if (client->crypto->key && client->crypto->key != key)
1269 gcry_free(client->crypto->key);
1271 client->crypto->key = key;
1272 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1274 if (rc)
1275 return send_error(ctx, rc);
1277 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1278 pth_cleanup_push(xmlFree, xmlbuf);
1279 clevel = get_key_file_integer(client->filename, "compression_level");
1281 if (clevel < 0)
1282 clevel = 0;
1284 if (do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1285 pth_cleanup_pop(1);
1286 cleanup_crypto(&client->crypto);
1288 if (zrc == Z_MEM_ERROR)
1289 return send_syserror(ctx, ENOMEM);
1290 else
1291 return send_error(ctx, GPG_ERR_COMPR_ALGO);
1293 else {
1294 pth_cleanup_pop(1);
1295 xmlbuf = outbuf;
1296 len = outsize;
1299 client->crypto->inbuf = xmlbuf;
1300 client->crypto->insize = len;
1301 rc = update_save_flags(client->filename, client->crypto);
1303 if (rc) {
1304 cleanup_crypto(&client->crypto);
1305 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1306 return send_error(ctx, rc);
1309 rc = do_xml_encrypt(client, client->crypto, client->filename);
1311 if (rc) {
1312 cleanup_crypto(&client->crypto);
1313 return send_error(ctx, rc);
1316 timeout = get_key_file_integer(client->filename, "cache_timeout");
1317 CACHE_LOCK(client->ctx);
1319 if (cached) {
1320 cache_reset_timeout(client->md5file, timeout);
1321 CACHE_UNLOCK;
1323 if (client->new == TRUE)
1324 send_status_all(STATUS_CACHE);
1326 client->new = FALSE;
1327 cleanup_crypto(&client->crypto);
1328 return send_error(ctx, 0);
1331 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1332 CACHE_UNLOCK;
1333 cleanup_crypto(&client->crypto);
1334 return send_syserror(ctx, ENOMEM);
1337 client->new = FALSE;
1338 cache_reset_timeout(client->md5file, timeout);
1339 CACHE_UNLOCK;
1340 send_status_all(STATUS_CACHE);
1341 cleanup_crypto(&client->crypto);
1342 return send_error(ctx, 0);
1345 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1347 struct client_s *client = data;
1348 guint64 n;
1349 gchar *value = v;
1350 gchar *p = NULL;
1352 if (!client->filename)
1353 return EPWMD_NO_FILE;
1355 if (!value || !*value)
1356 return 0;
1358 errno = 0;
1359 n = strtoul(value, &p, 10);
1361 if (errno || (p && *p) || n == G_MAXULONG)
1362 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1364 MUTEX_LOCK(&rcfile_mutex);
1365 g_key_file_set_double(keyfileh,
1366 client->filename ? client->filename : "global", "iterations", n);
1367 MUTEX_UNLOCK(&rcfile_mutex);
1369 if (client->filename)
1370 client->opts |= OPT_ITERATIONS;
1372 log_write1("iterations=%lu", n);
1373 return 0;
1376 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1378 struct client_s *client = data;
1379 const gchar *p = value;
1380 guint64 flags;
1382 if (!client->filename)
1383 return EPWMD_NO_FILE;
1385 if (!p || !*p)
1386 return 0;
1388 flags = pwmd_cipher_str_to_cipher(p);
1390 if (!flags)
1391 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1393 MUTEX_LOCK(&rcfile_mutex);
1394 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1395 MUTEX_UNLOCK(&rcfile_mutex);
1396 log_write1("cipher=%s", p);
1398 if (!value)
1399 g_free((gchar *)p);
1401 return 0;
1404 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1406 struct client_s *client = data;
1408 CACHE_LOCK(client->ctx);
1409 cache_clear(client->md5file, 1);
1410 CACHE_UNLOCK;
1411 return 0;
1414 static gint save_command(assuan_context_t ctx, gchar *line)
1416 gboolean cached = FALSE;
1417 struct stat st;
1418 struct client_s *client = assuan_get_pointer(ctx);
1419 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1420 gpg_error_t rc;
1421 struct argv_s *args[] = {
1422 &(struct argv_s) { "iterations", OPT_OPTARG, parse_save_opt_iterations },
1423 &(struct argv_s) { "cipher", OPT_OPTARG, parse_save_opt_cipher },
1424 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry},
1425 &(struct argv_s) { "reset", OPT_NOARG, parse_save_opt_reset},
1426 NULL
1429 rc = parse_options(&line, args, client);
1431 if (rc)
1432 return send_error(ctx, rc);
1434 if (line && *line)
1435 log_write2("ARGS=%s", "<passphrase>");
1437 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1438 return send_syserror(ctx, errno);
1440 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1441 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1442 return send_error(ctx, GPG_ERR_ENOANO);
1445 CACHE_LOCK(ctx);
1446 cached = cache_iscached(client->md5file);
1447 CACHE_UNLOCK;
1450 * If a cache entry doesn't exist for this file and the file has a
1451 * "key_file" or "key" parameter, then it's an error. The reason is that
1452 * cache expiration would be useless.
1454 if (cached == FALSE) {
1455 gchar *tmp = get_key_file_string(client->filename, "key_file");
1457 if (tmp) {
1458 g_free(tmp);
1459 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1463 cached = FALSE;
1465 /* New file? */
1466 if (!client->crypto) {
1467 client->crypto = init_client_crypto();
1469 if (!client->crypto) {
1470 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1471 return send_syserror(ctx, ENOMEM);
1475 client->crypto->key = gcry_malloc(hashlen);
1477 if (!client->crypto->key) {
1478 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1479 cleanup_crypto(&client->crypto);
1480 return send_syserror(ctx, ENOMEM);
1483 memset(client->crypto->key, '!', hashlen);
1485 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1486 (!line || !*line))
1487 goto done;
1489 if (!line || !*line) {
1490 client->crypto->tkey = gcry_malloc(hashlen);
1492 if (!client->crypto->tkey) {
1493 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1494 cleanup_crypto(&client->crypto);
1495 return send_syserror(ctx, ENOMEM);
1498 memset(client->crypto->tkey, '!', hashlen);
1499 CACHE_LOCK(ctx);
1501 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1502 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1503 CACHE_UNLOCK;
1505 #ifdef WITH_PINENTRY
1506 gpg_error_t rc;
1508 if (client->pinentry->enable == FALSE ||
1509 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1510 /* Empty keys are allowed. */
1511 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1512 goto done;
1515 lock_pin_mutex(client);
1516 client->pinentry->which = PINENTRY_SAVE;
1517 rc = pinentry_fork(ctx);
1519 if (rc) {
1520 unlock_pin_mutex(client->pinentry);
1521 cleanup_crypto(&client->crypto);
1522 return send_error(ctx, rc);
1525 client->pinentry->cb = save_command_finalize;
1526 client->pinentry->status = PINENTRY_INIT;
1527 return 0;
1528 #else
1529 /* Empty keys are allowed. */
1530 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1531 goto done;
1532 #endif
1534 else {
1535 CACHE_UNLOCK;
1536 cached = TRUE;
1539 else {
1540 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1541 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1543 if (iter <= 0L)
1544 iter = 1;
1546 MUTEX_LOCK(&rcfile_mutex);
1547 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1548 MUTEX_UNLOCK(&rcfile_mutex);
1549 client->opts |= OPT_ITERATIONS;
1550 gpg_error_t rc = send_status(ctx, STATUS_CONFIG, NULL);
1552 if (rc)
1553 return send_error(ctx, rc);
1556 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, line,
1557 strlen(line));
1560 done:
1561 return save_command_finalize(ctx, client->crypto->key, cached);
1564 static gint delete_command(assuan_context_t ctx, gchar *line)
1566 struct client_s *client = assuan_get_pointer(ctx);
1567 gchar **req;
1568 gpg_error_t rc;
1569 xmlNodePtr n;
1571 log_write2("ARGS=\"%s\"", line);
1573 if (strchr(line, '\t'))
1574 req = split_input_line(line, "\t", -1);
1575 else
1576 req = split_input_line(line, " ", -1);
1578 if (!req || !*req)
1579 return send_error(ctx, GPG_ERR_SYNTAX);
1581 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1583 if (!n) {
1584 g_strfreev(req);
1585 return send_error(ctx, rc);
1589 * No sub-node defined. Remove the entire node (root element).
1591 if (!req[1]) {
1592 if (n) {
1593 rc = unlink_node(n);
1594 xmlFreeNode(n);
1597 g_strfreev(req);
1598 return send_error(ctx, rc);
1601 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1602 g_strfreev(req);
1604 if (!n)
1605 return send_error(ctx, rc);
1607 if (n) {
1608 rc = unlink_node(n);
1609 xmlFreeNode(n);
1612 return send_error(ctx, rc);
1616 * Don't return with assuan_process_done() here. This has been called from
1617 * assuan_process_next() and the command should be finished in
1618 * client_thread().
1620 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1621 gsize len)
1623 assuan_context_t ctx = data;
1624 struct client_s *client = assuan_get_pointer(ctx);
1625 gchar **req;
1626 xmlNodePtr n;
1627 gpg_error_t rc = file_modified(client);
1629 if (assuan_rc || rc) {
1630 if (line)
1631 xfree(line);
1632 return assuan_rc ? assuan_rc : rc;
1635 req = split_input_line((gchar *)line, "\t", 0);
1636 xfree(line);
1638 if (!req || !*req)
1639 return GPG_ERR_SYNTAX;
1641 again:
1642 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1644 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1645 rc = new_root_element(client->doc, *req);
1647 if (rc) {
1648 g_strfreev(req);
1649 return rc;
1652 goto again;
1655 if (!n) {
1656 g_strfreev(req);
1657 return rc;
1660 if (req[1]) {
1661 if (!n->children)
1662 n = create_elements_cb(n, req+1, &rc, NULL);
1663 else
1664 n = find_elements(client->doc, n->children, req+1, &rc,
1665 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1668 g_strfreev(req);
1669 client->inquire_status = INQUIRE_DONE;
1671 if (!rc)
1672 rc = update_element_mtime(n);
1674 return rc;
1677 static gint store_command(assuan_context_t ctx, gchar *line)
1679 struct client_s *client = assuan_get_pointer(ctx);
1680 gpg_error_t rc;
1682 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1684 if (rc)
1685 return send_error(ctx, rc);
1687 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1688 client->inquire_status = INQUIRE_BUSY;
1689 return 0;
1692 static void *send_data_cb(void *arg)
1694 struct assuan_cmd_s *data = arg;
1695 gint old;
1696 gpg_error_t *rc;
1698 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1699 rc = g_malloc(sizeof(gpg_error_t));
1700 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1701 pth_cancel_state(old, NULL);
1702 pth_exit(rc);
1703 return NULL;
1706 /* For every assuan command that needs to be sent to the client, a timeout is
1707 * needed to determine if the client lost the connection. The timeout is the
1708 * same as the "keepalive" configuration parameter or a default if unset.
1710 gpg_error_t do_assuan_command(assuan_context_t ctx,
1711 void *(*cb)(void *data), void *data)
1713 pth_attr_t attr = pth_attr_new();
1714 pth_t tid;
1715 gint n;
1716 gint to = get_key_file_integer("global", "keepalive");
1717 pth_event_t ev, tev;
1718 pth_status_t st;
1719 gpg_error_t rc = 0;
1720 void *p;
1722 pth_attr_init(attr);
1723 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1724 tid = pth_spawn(attr, cb, data);
1725 n = errno;
1726 pth_attr_destroy(attr);
1728 if (!tid) {
1729 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1730 _gpg_strerror(gpg_error_from_errno(n)));
1731 return gpg_error_from_errno(n);
1734 pth_cleanup_push(cleanup_cancel_cb, tid);
1735 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1736 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1737 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1738 ev = pth_event_concat(ev, tev, NULL);
1739 pth_cleanup_push(cleanup_ev_cb, ev);
1740 pth_yield(tid);
1741 pth_wait(ev);
1743 if (tev) {
1744 st = pth_event_status(tev);
1746 if (st == PTH_STATUS_OCCURRED) {
1747 pth_cleanup_pop(1);
1748 pth_cleanup_pop(1);
1749 return GPG_ERR_TIMEOUT;
1753 st = pth_event_status(ev);
1755 if (st == PTH_STATUS_FAILED) {
1756 pth_cancel(tid);
1757 pth_join(tid, &p);
1758 g_free(p);
1759 rc = GPG_ERR_ASS_WRITE_ERROR;
1761 else if (st == PTH_STATUS_OCCURRED) {
1762 pth_join(tid, &p);
1763 rc = *(gpg_error_t *)p;
1764 g_free(p);
1767 pth_cleanup_pop(1);
1768 pth_cleanup_pop(0);
1769 return rc;
1772 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1773 gint total)
1775 gint to_send;
1776 gint sent = 0;
1777 gpg_error_t rc;
1778 struct assuan_cmd_s data;
1779 gint progress = get_key_file_integer("global", "xfer_progress");
1780 gint flush = 0;
1782 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1783 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1784 data.ctx = ctx;
1785 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1787 if (rc)
1788 return rc;
1790 again:
1791 do {
1792 if (sent + to_send > total)
1793 to_send = total - sent;
1795 data.line = flush ? NULL : (gchar *)line+sent;
1796 data.line_len = flush ? 0 : to_send;
1797 rc = do_assuan_command(ctx, send_data_cb, &data);
1799 if (!rc) {
1800 sent += flush ? 0 : to_send;
1802 if ((progress && !(sent % progress) && sent != total) ||
1803 (sent == total && flush))
1804 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1806 if (!flush && !rc && sent == total) {
1807 flush = 1;
1808 goto again;
1811 } while (!rc && sent < total);
1813 return rc;
1816 static gint get_command(assuan_context_t ctx, gchar *line)
1818 struct client_s *client = assuan_get_pointer(ctx);
1819 gchar **req;
1820 gpg_error_t rc;
1821 xmlNodePtr n;
1823 log_write2("ARGS=\"%s\"", line);
1824 req = split_input_line(line, "\t", -1);
1826 if (!req || !*req) {
1827 g_strfreev(req);
1828 return send_error(ctx, GPG_ERR_SYNTAX);
1831 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1833 if (!n) {
1834 g_strfreev(req);
1835 return send_error(ctx, rc);
1838 if (req[1])
1839 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1841 g_strfreev(req);
1843 if (rc)
1844 return send_error(ctx, rc);
1846 if (!n || !n->children)
1847 return send_error(ctx, GPG_ERR_NO_VALUE);
1849 n = find_text_node(n->children);
1851 if (!n || !n->content || !*n->content)
1852 return send_error(ctx, GPG_ERR_NO_VALUE);
1854 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
1855 return send_error(ctx, rc);
1858 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
1859 gpg_error_t *rc, gchar **req_orig, void *data)
1861 gchar *path = *(gchar **)data;
1862 gchar *tmp = NULL, *result;
1864 if (path) {
1865 g_free(path);
1866 *(gchar **)data = NULL;
1869 path = g_strjoinv("\t", target);
1871 if (!path) {
1872 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1873 *rc = gpg_error_from_errno(ENOMEM);
1874 return NULL;
1877 if (req_orig) {
1878 tmp = g_strjoinv("\t", req_orig);
1880 if (!tmp) {
1881 g_free(path);
1882 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1883 *rc = gpg_error_from_errno(ENOMEM);
1884 return NULL;
1888 if (tmp && *tmp)
1889 result = g_strdup_printf("%s\t%s", path, tmp);
1890 else
1891 result = g_strdup(path);
1893 if (!result) {
1894 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1895 *rc = gpg_error_from_errno(ENOMEM);
1896 g_free(path);
1897 g_free(tmp);
1898 return NULL;
1901 g_free(path);
1902 g_free(tmp);
1903 *(gchar **)data = result;
1904 return node;
1907 static void list_command_cleanup1(void *arg);
1908 static gint realpath_command(assuan_context_t ctx, gchar *line)
1910 gpg_error_t rc;
1911 struct client_s *client = assuan_get_pointer(ctx);
1912 gchar **req;
1913 gchar *t;
1914 gint i;
1915 xmlNodePtr n;
1916 GString *string;
1917 gchar *rp = NULL;
1919 log_write2("ARGS=\"%s\"", line);
1921 if (strchr(line, '\t') != NULL) {
1922 if ((req = split_input_line(line, "\t", 0)) == NULL)
1923 return send_error(ctx, GPG_ERR_SYNTAX);
1925 else {
1926 if ((req = split_input_line(line, " ", 0)) == NULL)
1927 return send_error(ctx, GPG_ERR_SYNTAX);
1930 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1932 if (!n) {
1933 g_strfreev(req);
1934 return send_error(ctx, rc);
1937 rp = g_strjoinv("\t", req);
1939 if (!rp) {
1940 g_strfreev(req);
1941 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1942 return send_syserror(ctx, ENOMEM);
1945 if (req[1]) {
1946 n = find_elements(client->doc, n->children, req+1, &rc,
1947 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
1949 if (!n) {
1950 g_free(rp);
1951 g_strfreev(req);
1952 return send_error(ctx, rc);
1956 string = g_string_new(rp);
1957 g_free(rp);
1958 g_strfreev(req);
1960 if (!string) {
1961 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1962 return send_syserror(ctx, ENOMEM);
1965 again:
1966 for (i = 0, t = string->str + i; *t; t++, i++) {
1967 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
1968 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
1969 goto again;
1973 pth_cleanup_push(list_command_cleanup1, string);
1974 rc = xfer_data(ctx, string->str, string->len);
1975 pth_cleanup_pop(1);
1976 return send_error(ctx, rc);
1979 static void list_command_cleanup1(void *arg)
1981 g_string_free((GString *)arg, TRUE);
1984 static void list_command_cleanup2(void *arg)
1986 struct element_list_s *elements = arg;
1988 if (elements) {
1989 if (elements->list) {
1990 gint total = g_slist_length(elements->list);
1991 gint i;
1993 for (i = 0; i < total; i++) {
1994 gchar *tmp = g_slist_nth_data(elements->list, i);
1995 g_free(tmp);
1998 g_slist_free(elements->list);
2001 if (elements->prefix)
2002 g_free(elements->prefix);
2004 if (elements->req)
2005 g_strfreev(elements->req);
2007 g_free(elements);
2011 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2013 struct element_list_s *elements = data;
2015 elements->recurse = FALSE;
2016 return 0;
2019 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2021 struct element_list_s *elements = data;
2023 elements->verbose = TRUE;
2024 return 0;
2027 static gint list_command(assuan_context_t ctx, gchar *line)
2029 struct client_s *client = assuan_get_pointer(ctx);
2030 gpg_error_t rc;
2031 struct element_list_s *elements = NULL;
2032 gchar *tmp;
2033 struct argv_s *args[] = {
2034 &(struct argv_s) { "no-recurse", OPT_NOARG, parse_list_opt_norecurse },
2035 &(struct argv_s) { "verbose", OPT_NOARG, parse_list_opt_verbose },
2036 NULL
2039 if (disable_list_and_dump == TRUE)
2040 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2042 elements = g_malloc0(sizeof(struct element_list_s));
2044 if (!elements) {
2045 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2046 return gpg_err_code_from_errno(ENOMEM);
2049 elements->recurse = TRUE; // default
2050 pth_cleanup_push(list_command_cleanup2, elements);
2051 rc = parse_options(&line, args, elements);
2053 if (rc)
2054 goto fail;
2056 if (!*line) {
2057 GString *str;
2059 rc = list_root_elements(client->doc, &str, elements->verbose);
2061 if (rc) {
2062 pth_cleanup_pop(1);
2063 return send_error(ctx, rc);
2066 pth_cleanup_push(list_command_cleanup1, str);
2067 rc = xfer_data(ctx, str->str, str->len);
2068 pth_cleanup_pop(1);
2069 pth_cleanup_pop(1);
2070 return send_error(ctx, rc);
2073 elements->req = split_input_line(line, " ", 0);
2075 if (!elements->req)
2076 strv_printf(&elements->req, "%s", line);
2078 rc = create_path_list(client->doc, elements, *elements->req);
2080 if (rc)
2081 goto fail;
2083 if (elements) {
2084 gint total = g_slist_length(elements->list);
2085 gint i;
2086 GString *str;
2088 if (!total) {
2089 rc = GPG_ERR_NO_VALUE;
2090 goto fail;
2093 str = g_string_new(NULL);
2095 if (!str) {
2096 rc = gpg_err_code_from_errno(ENOMEM);
2097 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2098 goto fail;
2101 for (i = 0; i < total; i++) {
2102 tmp = g_slist_nth_data(elements->list, i);
2103 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2106 pth_cleanup_push(list_command_cleanup1, str);
2107 rc = xfer_data(ctx, str->str, str->len);
2108 pth_cleanup_pop(1);
2110 else
2111 rc = GPG_ERR_NO_VALUE;
2113 fail:
2114 pth_cleanup_pop(1);
2115 return send_error(ctx, rc);
2119 * req[0] - element path
2121 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2123 struct client_s *client = assuan_get_pointer(ctx);
2124 gchar **attrlist = NULL;
2125 gint i = 0;
2126 gchar **path = NULL;
2127 xmlAttrPtr a;
2128 xmlNodePtr n, an;
2129 gchar *line;
2130 gpg_error_t rc;
2132 if (!req || !req[0])
2133 return GPG_ERR_SYNTAX;
2135 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2137 * The first argument may be only a root element.
2139 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2140 return GPG_ERR_SYNTAX;
2143 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2145 if (!n) {
2146 g_strfreev(path);
2147 return rc;
2150 if (path[1]) {
2151 n = find_elements(client->doc, n->children, path+1, &rc,
2152 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2154 if (!n) {
2155 g_strfreev(path);
2156 return rc;
2160 g_strfreev(path);
2162 for (a = n->properties; a; a = a->next) {
2163 gchar **pa;
2165 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2166 if (attrlist)
2167 g_strfreev(attrlist);
2169 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2170 return gpg_error_from_errno(ENOMEM);
2173 attrlist = pa;
2174 an = a->children;
2175 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2176 an && an->content ? (gchar *)an->content : "");
2178 if (!attrlist[i]) {
2179 g_strfreev(attrlist);
2180 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2181 return gpg_error_from_errno(ENOMEM);
2184 attrlist[++i] = NULL;
2187 if (!attrlist)
2188 return GPG_ERR_NO_VALUE;
2190 line = g_strjoinv("\n", attrlist);
2192 if (!line) {
2193 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2194 g_strfreev(attrlist);
2195 return gpg_error_from_errno(ENOMEM);
2198 pth_cleanup_push(g_free, line);
2199 pth_cleanup_push(req_cleanup, attrlist);
2200 rc = xfer_data(ctx, line, strlen(line));
2201 pth_cleanup_pop(1);
2202 pth_cleanup_pop(1);
2203 return rc;
2207 * req[0] - attribute
2208 * req[1] - element path
2210 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2212 xmlNodePtr n;
2213 gchar **path = NULL;
2214 gpg_error_t rc;
2216 if (!req || !req[0] || !req[1])
2217 return GPG_ERR_SYNTAX;
2219 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2221 * The first argument may be only a root element.
2223 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2224 return GPG_ERR_SYNTAX;
2228 * Don't remove the "_name" attribute for the root element. To remove an
2229 * root element use DELETE <name>.
2231 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2232 rc = GPG_ERR_SYNTAX;
2233 goto fail;
2236 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2238 if (!n)
2239 goto fail;
2241 if (path[1]) {
2242 n = find_elements(client->doc, n->children, path+1, &rc,
2243 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2245 if (!n)
2246 goto fail;
2249 rc = delete_attribute(n, (xmlChar *)req[0]);
2251 fail:
2252 g_strfreev(path);
2253 return rc;
2256 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2257 gpg_error_t *rc)
2259 gchar **src = *path;
2260 gchar **src_orig = g_strdupv(src);
2261 xmlNodePtr n = NULL;
2263 *rc = 0;
2265 if (!src_orig) {
2266 *rc = gpg_error_from_errno(ENOMEM);
2267 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2268 goto fail;
2271 again:
2272 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2274 if (!n) {
2275 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2276 *rc = new_root_element(client->doc, src[0]);
2278 if (*rc)
2279 goto fail;
2281 goto again;
2283 else
2284 goto fail;
2287 if (src[1]) {
2288 if (!n->children)
2289 n = create_target_elements_cb(n, src+1, rc, NULL);
2290 else
2291 n = find_elements(client->doc, n->children, src+1, rc,
2292 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2294 if (!n)
2295 goto fail;
2298 * Reset the position of the element tree now that the elements
2299 * have been created.
2301 g_strfreev(src);
2302 src = src_orig;
2303 src_orig = NULL;
2304 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2306 if (!n)
2307 goto fail;
2309 n = find_elements(client->doc, n->children, src+1, rc,
2310 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2312 if (!n)
2313 goto fail;
2316 fail:
2317 if (src_orig)
2318 g_strfreev(src_orig);
2320 *path = src;
2321 return n;
2325 * Creates a "target" attribute. When other commands encounter an element with
2326 * this attribute, the element path is modified to the target value. If the
2327 * source element path doesn't exist when using 'ATTR SET target', it is
2328 * created, but the destination element path must exist.
2330 * req[0] - source element path
2331 * req[1] - destination element path
2333 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2335 gchar **src, **dst, *line = NULL, **odst = NULL;
2336 gpg_error_t rc;
2337 xmlNodePtr n;
2339 if (!req || !req[0] || !req[1])
2340 return GPG_ERR_SYNTAX;
2342 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2344 * The first argument may be only a root element.
2346 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2347 return GPG_ERR_SYNTAX;
2350 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2352 * The first argument may be only a root element.
2354 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2355 rc = GPG_ERR_SYNTAX;
2356 goto fail;
2360 odst = g_strdupv(dst);
2362 if (!odst) {
2363 rc = gpg_error_from_errno(ENOMEM);
2364 goto fail;
2367 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2370 * Make sure the destination element path exists.
2372 if (!n)
2373 goto fail;
2375 if (dst[1]) {
2376 n = find_elements(client->doc, n->children, dst+1, &rc,
2377 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2379 if (!n)
2380 goto fail;
2383 n = create_element_path(client, &src, &rc);
2385 if (rc)
2386 goto fail;
2388 line = g_strjoinv("\t", odst);
2390 if (!line) {
2391 rc = gpg_error_from_errno(ENOMEM);
2392 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2393 goto fail;
2396 rc = add_attribute(n, "target", line);
2398 fail:
2399 g_free(line);
2400 g_strfreev(src);
2401 g_strfreev(dst);
2402 g_strfreev(odst);
2403 return rc;
2407 * req[0] - name
2408 * req[1] - new name
2410 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2412 gpg_error_t rc;
2413 gchar **tmp;
2414 xmlNodePtr n;
2416 tmp = g_strdupv(req);
2418 if (!tmp) {
2419 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2420 return gpg_error_from_errno(ENOMEM);
2423 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2424 g_strfreev(tmp);
2426 if (!n)
2427 return rc;
2429 if (g_utf8_collate(req[0], req[1]) == 0)
2430 return 0;
2433 * Will not overwrite an existing root.
2435 tmp = g_strdupv(req+1);
2437 if (!tmp) {
2438 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2439 return gpg_error_from_errno(ENOMEM);
2442 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2443 g_strfreev(tmp);
2445 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2446 return rc;
2448 if (n)
2449 return GPG_ERR_AMBIGUOUS_NAME;
2452 * Whitespace not allowed in root names.
2454 if (contains_whitespace(req[1]) == TRUE)
2455 return GPG_ERR_SYNTAX;
2457 tmp = g_strdupv(req);
2459 if (!tmp) {
2460 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2461 return gpg_error_from_errno(ENOMEM);
2464 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2465 g_strfreev(tmp);
2467 if (!n)
2468 return GPG_ERR_ELEMENT_NOT_FOUND;
2470 return add_attribute(n, "_name", req[1]);
2474 * req[0] - attribute
2475 * req[1] - element path
2477 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2479 struct client_s *client = assuan_get_pointer(ctx);
2480 xmlNodePtr n;
2481 xmlChar *a;
2482 gchar **path= NULL;
2483 gpg_error_t rc;
2485 if (!req || !req[0] || !req[1])
2486 return GPG_ERR_SYNTAX;
2488 if (strchr(req[1], '\t')) {
2489 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2490 return GPG_ERR_SYNTAX;
2492 else {
2493 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2494 return GPG_ERR_SYNTAX;
2497 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2499 if (!n)
2500 goto fail;
2502 if (path[1]) {
2503 n = find_elements(client->doc, n->children, path+1, &rc,
2504 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2506 if (!n)
2507 goto fail;
2510 g_strfreev(path);
2512 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2513 return GPG_ERR_NOT_FOUND;
2515 pth_cleanup_push(xmlFree, a);
2517 if (*a)
2518 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2519 else
2520 rc = GPG_ERR_NO_VALUE;
2522 pth_cleanup_pop(1);
2523 return rc;
2525 fail:
2526 g_strfreev(path);
2527 return rc;
2531 * req[0] - attribute
2532 * req[1] - element path
2533 * req[2] - value
2535 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2537 gchar **path = NULL;
2538 gpg_error_t rc;
2539 xmlNodePtr n;
2541 if (!req || !req[0] || !req[1])
2542 return GPG_ERR_SYNTAX;
2545 * Reserved attribute names.
2547 if (!strcmp(req[0], "_name")) {
2549 * Only reserved for the root element. Not the rest of the
2550 * document.
2552 if (strchr(req[1], '\t') == NULL)
2553 return name_attribute(client, req + 1);
2555 else if (!strcmp(req[0], "target"))
2556 return target_attribute(client, req + 1);
2558 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2560 * The first argument may be only a root element.
2562 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2563 return GPG_ERR_SYNTAX;
2566 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2568 if (!n)
2569 goto fail;
2571 if (path[1]) {
2572 n = find_elements(client->doc, n->children, path+1, &rc,
2573 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2575 if (!n)
2576 goto fail;
2579 rc = add_attribute(n, req[0], req[2]);
2581 fail:
2582 g_strfreev(path);
2583 return rc;
2587 * req[0] - command
2588 * req[1] - attribute name or element path if command is LIST
2589 * req[2] - element path
2590 * req[2] - element path or value
2592 static gint attr_command(assuan_context_t ctx, gchar *line)
2594 struct client_s *client = assuan_get_pointer(ctx);
2595 gchar **req;
2596 gpg_error_t rc = 0;
2598 log_write2("ARGS=\"%s\"", line);
2599 req = split_input_line(line, " ", 4);
2601 if (!req || !req[0] || !req[1]) {
2602 g_strfreev(req);
2603 return send_error(ctx, GPG_ERR_SYNTAX);
2606 pth_cleanup_push(req_cleanup, req);
2608 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2609 rc = attribute_set(client, req+1);
2610 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2611 rc = attribute_get(ctx, req+1);
2612 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2613 rc = attribute_delete(client, req+1);
2614 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2615 rc = attribute_list(ctx, req+1);
2616 else
2617 rc = GPG_ERR_SYNTAX;
2619 pth_cleanup_pop(1);
2620 return send_error(ctx, rc);
2623 static gint iscached_command(assuan_context_t ctx, gchar *line)
2625 gchar **req = split_input_line(line, " ", 0);
2626 guchar md5file[16];
2627 gchar *path, *tmp;
2629 if (!req || !*req) {
2630 g_strfreev(req);
2631 return send_error(ctx, GPG_ERR_SYNTAX);
2634 log_write2("ARGS=\"%s\"", line);
2636 if (!valid_filename(req[0])) {
2637 g_strfreev(req);
2638 return GPG_ERR_INV_VALUE;
2641 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2642 CACHE_LOCK(ctx);
2644 if (cache_iscached(md5file)) {
2645 g_strfreev(req);
2646 CACHE_UNLOCK;
2647 return send_error(ctx, 0);
2650 CACHE_UNLOCK;
2651 tmp = get_key_file_string("global", "data_directory");
2653 if (!tmp) {
2654 g_strfreev(req);
2655 return gpg_error_from_errno(ENOMEM);
2658 path = expand_homedir(tmp);
2660 if (!path) {
2661 g_strfreev(req);
2662 g_free(tmp);
2663 return gpg_error_from_errno(ENOMEM);
2666 g_free(tmp);
2667 tmp = path;
2668 path = g_strdup_printf("%s/%s", tmp, req[0]);
2669 g_free(tmp);
2671 if (!path) {
2672 g_strfreev(req);
2673 return gpg_error_from_errno(ENOMEM);
2676 if (access(path, R_OK) == -1) {
2677 gpg_error_t rc = gpg_error_from_syserror();
2679 g_free(path);
2680 g_strfreev(req);
2681 return send_error(ctx, rc);
2684 g_free(path);
2685 return send_error(ctx, GPG_ERR_NOT_FOUND);
2688 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2690 struct client_s *client = assuan_get_pointer(ctx);
2691 gchar **req = split_input_line(line, " ", 0);
2692 guchar md5file[16];
2694 log_write2("ARGS=\"%s\"", line);
2695 CACHE_LOCK(ctx);
2697 if (!req || !*req) {
2698 g_strfreev(req);
2699 cache_clear(client->md5file, 2);
2700 CACHE_UNLOCK;
2701 return send_error(ctx, 0);
2704 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2705 g_strfreev(req);
2707 if (cache_clear(md5file, 1) == FALSE) {
2708 CACHE_UNLOCK;
2709 return send_error(ctx, GPG_ERR_NOT_FOUND);
2712 CACHE_UNLOCK;
2713 return send_error(ctx, 0);
2716 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2718 guchar md5file[16];
2719 glong timeout;
2720 gchar **req = split_input_line(line, " ", 0);
2721 gchar *p;
2723 if (!req || !*req || !req[1]) {
2724 g_strfreev(req);
2725 return send_error(ctx, GPG_ERR_SYNTAX);
2728 errno = 0;
2729 timeout = strtol(req[1], &p, 10);
2731 if (errno != 0 || *p != 0 || timeout < -1) {
2732 g_strfreev(req);
2733 return send_error(ctx, GPG_ERR_SYNTAX);
2736 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2737 CACHE_LOCK(client->ctx);
2739 if (cache_set_timeout(md5file, timeout) == FALSE) {
2740 CACHE_UNLOCK;
2741 return send_error(ctx, GPG_ERR_NOT_FOUND);
2744 CACHE_UNLOCK;
2745 return send_error(ctx, 0);
2748 static gint dump_command(assuan_context_t ctx, gchar *line)
2750 xmlChar *xml;
2751 gint len;
2752 struct client_s *client = assuan_get_pointer(ctx);
2753 gpg_error_t rc;
2755 if (disable_list_and_dump == TRUE)
2756 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2758 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2760 if (!xml) {
2761 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2762 return send_syserror(ctx, ENOMEM);
2765 pth_cleanup_push(xmlFree, xml);
2766 rc = xfer_data(ctx, (gchar *)xml, len);
2767 pth_cleanup_pop(1);
2768 return send_error(ctx, rc);
2771 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2773 struct client_s *client = assuan_get_pointer(ctx);
2774 gpg_error_t rc = 0;
2775 gchar filename[255]={0}, param[747]={0};
2776 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2778 log_write2("ARGS=\"%s\"", line);
2780 if (strchr(line, ' ')) {
2781 sscanf(line, " %254[^ ] %746c", filename, param);
2782 paramp = param;
2783 fp = filename;
2786 if (fp && !valid_filename(fp))
2787 return send_error(ctx, GPG_ERR_INV_VALUE);
2789 paramp = g_ascii_strdown(paramp, -1);
2791 if (!paramp) {
2792 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2793 return send_syserror(ctx, ENOMEM);
2796 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2797 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2798 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2800 if (!fh && rc != GPG_ERR_ENOENT)
2801 return send_error(ctx, rc);
2803 if (!rc) {
2804 g_free(paramp);
2805 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2806 close_file_header(fh);
2808 if (!p) {
2809 log_write("%s(%i): %s", __FILE__, __LINE__,
2810 strerror(ENOMEM));
2811 return send_syserror(ctx, ENOMEM);
2814 goto done;
2818 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2819 #ifdef WITH_PINENTRY
2820 gboolean n;
2822 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2823 n = client->pinentry->enable;
2824 else
2825 n = get_key_file_boolean(fp, "enable_pinentry");
2827 p = g_strdup_printf("%s", n ? "true" : "false");
2829 if (!p) {
2830 log_write("%s(%i): %s", __FILE__, __LINE__,
2831 strerror(ENOMEM));
2832 return send_syserror(ctx, ENOMEM);
2835 goto done;
2836 #else
2837 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2838 #endif
2840 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
2841 #ifdef WITH_PINENTRY
2842 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
2844 if (!p) {
2845 log_write("%s(%i): %s", __FILE__, __LINE__,
2846 strerror(ENOMEM));
2847 return send_syserror(ctx, ENOMEM);
2850 goto done;
2851 #else
2852 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2853 #endif
2856 p = get_key_file_string(fp ? fp : "global", paramp);
2857 g_free(paramp);
2859 if (!p)
2860 return send_error(ctx, GPG_ERR_NO_VALUE);
2862 tmp = expand_homedir(p);
2863 g_free(p);
2865 if (!tmp) {
2866 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2867 return send_syserror(ctx, ENOMEM);
2870 p = tmp;
2871 done:
2872 pth_cleanup_push(g_free, p);
2873 rc = xfer_data(ctx, p, strlen(p));
2874 pth_cleanup_pop(1);
2875 return send_error(ctx, rc);
2878 struct xpath_s {
2879 xmlXPathContextPtr xp;
2880 xmlXPathObjectPtr result;
2881 xmlBufferPtr buf;
2882 gchar **req;
2885 static void xpath_command_cleanup(void *arg)
2887 struct xpath_s *xpath = arg;
2889 req_cleanup(xpath->req);
2891 if (xpath->buf)
2892 xmlBufferFree(xpath->buf);
2894 if (xpath->result)
2895 xmlXPathFreeObject(xpath->result);
2897 if (xpath->xp)
2898 xmlXPathFreeContext(xpath->xp);
2901 static gint xpath_command(assuan_context_t ctx, gchar *line)
2903 struct client_s *client = assuan_get_pointer(ctx);
2904 gpg_error_t rc;
2905 struct xpath_s xpath;
2907 log_write2("ARGS=\"%s\"", line);
2909 if (disable_list_and_dump == TRUE)
2910 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2912 if (!line || !*line)
2913 return send_error(ctx, GPG_ERR_SYNTAX);
2915 memset(&xpath, 0, sizeof(struct xpath_s));
2917 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
2918 if (strv_printf(&xpath.req, "%s", line) == FALSE)
2919 return send_syserror(ctx, ENOMEM);
2922 xpath.xp = xmlXPathNewContext(client->doc);
2924 if (!xpath.xp) {
2925 xpath_command_cleanup(&xpath);
2926 return send_error(ctx, EPWMD_LIBXML_ERROR);
2929 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
2931 if (!xpath.result) {
2932 xpath_command_cleanup(&xpath);
2933 return send_error(ctx, EPWMD_LIBXML_ERROR);
2936 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
2937 rc = GPG_ERR_ELEMENT_NOT_FOUND;
2938 goto fail;
2941 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
2942 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
2944 if (rc)
2945 goto fail;
2946 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
2947 rc = GPG_ERR_NO_VALUE;
2948 goto fail;
2950 else if (xpath.req[1])
2951 goto fail;
2953 pth_cleanup_push(xpath_command_cleanup, &xpath);
2954 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
2955 xmlBufferLength(xpath.buf));
2956 pth_cleanup_pop(0);
2958 fail:
2959 xpath_command_cleanup(&xpath);
2960 return send_error(ctx, rc);
2963 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
2964 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
2966 struct client_s *client = assuan_get_pointer(ctx);
2967 gpg_error_t rc;
2968 struct xpath_s xpath;
2969 gchar **req = NULL;
2970 gboolean cmd = FALSE; //SET
2972 log_write2("ARGS=\"%s\"", line);
2974 if (disable_list_and_dump == TRUE)
2975 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2977 if (!line || !*line)
2978 return send_error(ctx, GPG_ERR_SYNTAX);
2980 memset(&xpath, 0, sizeof(struct xpath_s));
2982 if ((req = split_input_line(line, " ", 3)) == NULL)
2983 return send_syserror(ctx, ENOMEM);
2985 if (!req[0]) {
2986 rc = GPG_ERR_SYNTAX;
2987 goto fail;
2990 if (!g_ascii_strcasecmp(req[0], "SET"))
2991 cmd = FALSE;
2992 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
2993 cmd = TRUE;
2994 else {
2995 rc = GPG_ERR_SYNTAX;
2996 goto fail;
2999 if (!req[1] || !req[2]) {
3000 rc = GPG_ERR_SYNTAX;
3001 goto fail;
3004 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3005 rc = gpg_err_code_from_errno(ENOMEM);
3006 goto fail;
3009 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3010 rc = GPG_ERR_SYNTAX;
3011 goto fail;
3014 xpath.xp = xmlXPathNewContext(client->doc);
3016 if (!xpath.xp) {
3017 rc = EPWMD_LIBXML_ERROR;
3018 goto fail;
3021 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3023 if (!xpath.result) {
3024 rc = EPWMD_LIBXML_ERROR;
3025 goto fail;
3028 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3029 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3030 goto fail;
3033 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3034 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3036 fail:
3037 g_strfreev(req);
3038 xpath_command_cleanup(&xpath);
3039 return send_error(ctx, rc);
3042 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3043 gsize len)
3045 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3046 gpg_error_t rc = file_modified(client);
3047 gchar **req, **path = NULL, **path_orig = NULL, *content;
3048 xmlDocPtr doc = NULL;
3049 xmlNodePtr n, root, copy;
3051 if (assuan_rc || rc) {
3052 if (line)
3053 xfree(line);
3054 return assuan_rc ? assuan_rc : rc;
3057 req = split_input_line((gchar *)line, "\t", 2);
3058 xfree(line);
3060 if (!req || !*req)
3061 return GPG_ERR_SYNTAX;
3063 content = req[0];
3064 path = split_input_line(req[1], "\t", 0);
3066 if (!content || !*content) {
3067 rc = GPG_ERR_SYNTAX;
3068 goto fail;
3071 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3073 if (!doc) {
3074 rc = EPWMD_LIBXML_ERROR;
3075 goto fail;
3078 root = xmlDocGetRootElement(doc);
3079 rc = validate_import(root);
3081 if (rc)
3082 goto fail;
3084 if (path) {
3085 path_orig = g_strdupv(path);
3087 if (!path_orig) {
3088 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3089 rc = gpg_error_from_errno(ENOMEM);
3090 goto fail;
3093 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3095 if (!a) {
3096 g_strfreev(path_orig);
3097 rc = gpg_error_from_errno(ENOMEM);
3098 goto fail;
3101 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3102 xmlFree(a);
3103 g_strfreev(path_orig);
3104 rc = gpg_error_from_errno(ENOMEM);
3105 goto fail;
3108 xmlFree(a);
3109 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3111 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3112 g_strfreev(path_orig);
3113 goto fail;
3116 if (!rc) {
3117 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3119 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3120 g_strfreev(path_orig);
3121 goto fail;
3123 else if (!rc) {
3124 xmlNodePtr parent = n->parent;
3126 xmlUnlinkNode(n);
3127 xmlFreeNode(n);
3128 n = parent;
3132 g_strfreev(path);
3133 path = path_orig;
3135 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3136 n = create_element_path(client, &path, &rc);
3138 if (rc)
3139 goto fail;
3142 copy = xmlCopyNodeList(root);
3143 n = xmlAddChildList(n, copy);
3145 if (!n)
3146 rc = EPWMD_LIBXML_ERROR;
3148 else {
3149 /* Check if the content root element can create a DTD root element. */
3150 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3151 rc = GPG_ERR_SYNTAX;
3152 goto fail;
3155 xmlChar *a;
3157 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3158 rc = GPG_ERR_SYNTAX;
3159 goto fail;
3162 gchar *tmp = g_strdup((gchar *)a);
3163 xmlFree(a);
3164 gboolean literal = is_literal_element(&tmp);
3166 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3167 g_free(tmp);
3168 rc = GPG_ERR_INV_VALUE;
3169 goto fail;
3172 if (strv_printf(&path, "%s", tmp) == FALSE) {
3173 g_free(tmp);
3174 rc = gpg_error_from_errno(ENOMEM);
3175 goto fail;
3178 g_free(tmp);
3179 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3181 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3182 rc = EPWMD_LIBXML_ERROR;
3183 goto fail;
3186 /* Overwriting the existing tree. */
3187 if (!rc) {
3188 xmlUnlinkNode(n);
3189 xmlFreeNodeList(n);
3192 rc = 0;
3193 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3194 n = xmlCopyNode(root, 1);
3195 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3198 if (n && !rc)
3199 rc = update_element_mtime(n->parent);
3201 fail:
3202 if (doc)
3203 xmlFreeDoc(doc);
3205 if (path)
3206 g_strfreev(path);
3208 g_strfreev(req);
3209 client->inquire_status = INQUIRE_DONE;
3210 return rc;
3213 static gint import_command(assuan_context_t ctx, gchar *line)
3215 gpg_error_t rc;
3216 struct client_s *client = assuan_get_pointer(ctx);
3218 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3220 if (rc)
3221 return send_error(ctx, rc);
3223 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3224 client->inquire_status = INQUIRE_BUSY;
3225 return 0;
3228 static gpg_error_t do_lock_command(struct client_s *client)
3230 gpg_error_t rc = lock_file_mutex(client);
3232 if (!rc)
3233 client->is_lock_cmd = TRUE;
3235 return send_error(client->ctx, rc);
3238 static gint lock_command(assuan_context_t ctx, gchar *line)
3240 struct client_s *client = assuan_get_pointer(ctx);
3242 return do_lock_command(client);
3245 static gint unlock_command(assuan_context_t ctx, gchar *line)
3247 struct client_s *client = assuan_get_pointer(ctx);
3249 unlock_file_mutex(client);
3250 return send_error(ctx, 0);
3253 static gint getpid_command(assuan_context_t ctx, gchar *line)
3255 gpg_error_t rc;
3256 gchar buf[32];
3257 pid_t pid = getpid();
3259 print_fmt(buf, sizeof(buf), "%i", pid);
3260 rc = xfer_data(ctx, buf, strlen(buf));
3261 return send_error(ctx, rc);
3264 static gint version_command(assuan_context_t ctx, gchar *line)
3266 gpg_error_t rc;
3267 gchar buf[32];
3269 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3270 rc = xfer_data(ctx, buf, strlen(buf));
3271 return send_error(ctx, rc);
3274 #ifdef WITH_PINENTRY
3275 static void set_option_value(gchar **opt, const gchar *value)
3277 if (opt)
3278 g_free(*opt);
3280 *opt = NULL;
3282 if (value)
3283 *opt = g_strdup(value);
3285 #endif
3287 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3288 const gchar *value)
3290 struct client_s *client = assuan_get_pointer(ctx);
3291 gpg_error_t rc;
3293 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3294 glong l = 0;
3296 if (value) {
3297 l = strtol(value, NULL, 10);
3299 if (l < 0 || l > 2)
3300 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3303 log_write1("log_level=%li", l);
3304 MUTEX_LOCK(&rcfile_mutex);
3305 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3306 MUTEX_UNLOCK(&rcfile_mutex);
3307 goto done;
3309 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3310 glong l = 0;
3312 if (value) {
3313 l = strtol(value, NULL, 10);
3315 if (l < 0 || l > 1)
3316 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3319 log_write1("rc_on_locked=%li", l);
3320 client->rc_on_locked = l ? TRUE : FALSE;
3321 goto done;
3323 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3324 rc = parse_open_opt_lock(client, (gpointer)value);
3326 if (rc)
3327 return rc;
3329 client->opts |= OPT_LOCK;
3331 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3332 if (!value) {
3333 client->opts &= ~(OPT_CIPHER);
3334 goto done;
3337 rc = parse_save_opt_cipher(client, (gpointer)value);
3339 if (rc)
3340 return rc;
3342 client->opts |= OPT_CIPHER;
3343 goto done;
3345 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3346 rc = parse_save_opt_iterations(client, (gpointer)value);
3348 if (rc)
3349 return rc;
3351 goto done;
3353 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3354 pth_attr_t attr = pth_attr_of(pth_self());
3355 gchar buf[41];
3357 if (!value) {
3358 pth_attr_destroy(attr);
3359 goto done;
3362 print_fmt(buf, sizeof(buf), "%s", value);
3363 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3364 pth_attr_destroy(attr);
3365 log_write1("name=%s", buf);
3366 #ifdef WITH_PINENTRY
3367 if (client->pinentry->name)
3368 g_free(client->pinentry->name);
3370 client->pinentry->name = g_strdup(buf);
3372 if (!client->pinentry->name)
3373 return gpg_error_from_errno(ENOMEM);
3374 #endif
3376 goto done;
3378 #ifdef WITH_PINENTRY
3379 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3380 set_option_value(&client->pinentry->lcmessages, value);
3381 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3382 set_option_value(&client->pinentry->lcctype, value);
3383 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3384 set_option_value(&client->pinentry->ttyname, value);
3385 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3386 set_option_value(&client->pinentry->ttytype, value);
3387 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3388 set_option_value(&client->pinentry->display, value);
3389 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3390 set_option_value(&client->pinentry->path, value);
3391 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3392 set_option_value(&client->pinentry->title, value);
3393 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3394 set_option_value(&client->pinentry->prompt, value);
3395 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3396 set_option_value(&client->pinentry->desc, value);
3397 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3398 gchar *p = NULL;
3399 gint n;
3401 if (!value)
3402 goto done;
3404 n = strtol(value, &p, 10);
3406 if (*p || n < 0)
3407 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3409 MUTEX_LOCK(&rcfile_mutex);
3410 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3411 "global", "pinentry_timeout", n);
3412 MUTEX_UNLOCK(&rcfile_mutex);
3413 log_write1("pinentry_timeout=%i", n);
3414 goto done;
3416 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3417 rc = parse_opt_pinentry(client, (gpointer)value);
3419 if (rc)
3420 return rc;
3422 goto done;
3424 #endif
3425 else
3426 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3428 log_write1("%s=%s", name, value ? value : "");
3430 done:
3431 return 0;
3434 static gint unset_command(assuan_context_t ctx, gchar *line)
3436 log_write2("ARGS=\"%s\"", line);
3437 return send_error(ctx, set_unset_common(ctx, line, NULL));
3440 static gint set_command(assuan_context_t ctx, gchar *line)
3442 gchar name[64] = {0}, value[256] = {0};
3444 log_write2("ARGS=\"%s\"", line);
3446 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3447 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3449 return send_error(ctx, set_unset_common(ctx, name, value));
3452 static gint rename_command(assuan_context_t ctx, gchar *line)
3454 struct client_s *client = assuan_get_pointer(ctx);
3455 gpg_error_t rc;
3456 gchar **req, **src, *dst;
3457 xmlNodePtr n, ndst;
3459 log_write2("ARGS=\"%s\"", line);
3460 req = split_input_line(line, " ", -1);
3462 if (!req || !req[0] || !req[1]) {
3463 g_strfreev(req);
3464 return send_error(ctx, GPG_ERR_SYNTAX);
3467 dst = req[1];
3468 is_literal_element(&dst);
3470 if (!valid_xml_element((xmlChar *)dst)) {
3471 g_strfreev(req);
3472 return GPG_ERR_INV_VALUE;
3475 if (strchr(req[0], '\t'))
3476 src = split_input_line(req[0], "\t", -1);
3477 else
3478 src = split_input_line(req[0], " ", -1);
3480 if (!src || !*src) {
3481 rc = GPG_ERR_SYNTAX;
3482 goto fail;
3485 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3487 if (src[1] && n)
3488 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3489 NULL, FALSE, 0, NULL, FALSE);
3491 if (!n)
3492 goto fail;
3495 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3497 if (!a) {
3498 rc = gpg_error_from_errno(ENOMEM);
3499 goto fail;
3502 /* To prevent unwanted effects:
3504 * <root name="a"><b/></root>
3506 * RENAME a<TAB>b b
3508 if (xmlStrEqual(a, (xmlChar *)dst)) {
3509 xmlFree(a);
3510 rc = GPG_ERR_AMBIGUOUS_NAME;
3511 goto fail;
3514 xmlFree(a);
3515 gchar **tmp = NULL;
3517 if (src[1]) {
3518 gchar **p;
3520 for (p = src; *p; p++) {
3521 if (!*(p+1))
3522 break;
3524 strv_printf(&tmp, "%s", *p);
3528 strv_printf(&tmp, "!%s", dst);
3529 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3531 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3532 g_strfreev(tmp);
3533 goto fail;
3536 if (tmp[1] && ndst)
3537 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3538 NULL, NULL, FALSE, 0, NULL, FALSE);
3540 g_strfreev(tmp);
3542 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3543 goto fail;
3545 rc = 0;
3547 /* Target may exist:
3549 * <root name="a"/>
3550 * <root name="b" target="a"/>
3552 * RENAME b a
3554 * Would need to do:
3555 * RENAME !b a
3557 if (ndst == n) {
3558 rc = GPG_ERR_AMBIGUOUS_NAME;
3559 goto fail;
3562 if (ndst) {
3563 unlink_node(ndst);
3564 xmlFreeNodeList(ndst);
3567 rc = add_attribute(n, "_name", dst);
3569 fail:
3570 g_strfreev(req);
3571 g_strfreev(src);
3572 return send_error(ctx, rc);
3575 static gint copy_command(assuan_context_t ctx, gchar *line)
3577 struct client_s *client = assuan_get_pointer(ctx);
3578 gpg_error_t rc;
3579 gchar **req, **src = NULL, **dst = NULL;
3580 xmlNodePtr nsrc, ndst, new;
3582 log_write2("ARGS=\"%s\"", line);
3583 req = split_input_line(line, " ", -1);
3585 if (!req || !req[0] || !req[1]) {
3586 g_strfreev(req);
3587 return send_error(ctx, GPG_ERR_SYNTAX);
3590 if (strchr(req[0], '\t'))
3591 src = split_input_line(req[0], "\t", -1);
3592 else
3593 src = split_input_line(req[0], " ", -1);
3595 if (!src || !*src) {
3596 rc = GPG_ERR_SYNTAX;
3597 goto fail;
3600 if (strchr(req[1], '\t'))
3601 dst = split_input_line(req[1], "\t", -1);
3602 else
3603 dst = split_input_line(req[1], " ", -1);
3605 if (!dst || !*dst) {
3606 rc = GPG_ERR_SYNTAX;
3607 goto fail;
3610 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3612 if (nsrc && src[1])
3613 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3614 NULL, NULL, FALSE, 0, NULL, FALSE);
3616 if (!nsrc)
3617 goto fail;
3619 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3621 if (ndst && dst[1])
3622 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3623 NULL, NULL, FALSE, 0, NULL, FALSE);
3625 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3626 goto fail;
3628 new = xmlCopyNodeList(nsrc);
3630 if (!new) {
3631 rc = GPG_ERR_ENOMEM;
3632 goto fail;
3635 if (!ndst)
3636 ndst = create_element_path(client, &dst, &rc);
3638 if (!ndst) {
3639 xmlUnlinkNode(new);
3640 xmlFreeNodeList(new);
3641 goto fail;
3644 /* Merge any attributes from the src node to the initial dst node. */
3645 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3646 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3647 continue;
3649 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3651 if (a)
3652 xmlRemoveProp(a);
3654 xmlChar *tmp = xmlNodeGetContent(attr->children);
3655 xmlNewProp(ndst, attr->name, tmp);
3656 xmlFree(tmp);
3657 rc = add_attribute(ndst, NULL, NULL);
3660 xmlNodePtr n = ndst->children;
3661 xmlUnlinkNode(n);
3662 xmlFreeNodeList(n);
3663 ndst->children = NULL;
3665 if (!new->children) {
3666 xmlUnlinkNode(new);
3667 xmlFreeNodeList(new);
3668 goto fail;
3671 n = xmlCopyNodeList(new->children);
3673 if (!n) {
3674 rc = GPG_ERR_ENOMEM;
3675 goto fail;
3678 xmlUnlinkNode(new);
3679 xmlFreeNodeList(new);
3680 n = xmlAddChildList(ndst, n);
3682 if (!n) {
3683 rc = GPG_ERR_ENOMEM;
3684 goto fail;
3687 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3689 fail:
3690 if (req)
3691 g_strfreev(req);
3693 if (src)
3694 g_strfreev(src);
3696 if (dst)
3697 g_strfreev(dst);
3699 return send_error(ctx, rc);
3702 static gint move_command(assuan_context_t ctx, gchar *line)
3704 struct client_s *client = assuan_get_pointer(ctx);
3705 gpg_error_t rc;
3706 gchar **req, **src = NULL, **dst = NULL;
3707 xmlNodePtr nsrc, ndst = NULL;
3709 log_write2("ARGS=\"%s\"", line);
3710 req = split_input_line(line, " ", -1);
3712 if (!req || !req[0] || !req[1]) {
3713 g_strfreev(req);
3714 return send_error(ctx, GPG_ERR_SYNTAX);
3717 if (strchr(req[0], '\t'))
3718 src = split_input_line(req[0], "\t", -1);
3719 else
3720 src = split_input_line(req[0], " ", -1);
3722 if (!src || !*src) {
3723 rc = GPG_ERR_SYNTAX;
3724 goto fail;
3727 if (strchr(req[1], '\t'))
3728 dst = split_input_line(req[1], "\t", -1);
3729 else
3730 dst = split_input_line(req[1], " ", -1);
3732 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3734 if (nsrc && src[1])
3735 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3736 NULL, NULL, FALSE, 0, NULL, FALSE);
3738 if (!nsrc)
3739 goto fail;
3741 if (dst) {
3742 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3744 if (ndst && dst[1])
3745 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3746 NULL, NULL, FALSE, 0, NULL, FALSE);
3748 else
3749 ndst = xmlDocGetRootElement(client->doc);
3751 for (xmlNodePtr n = ndst; n; n = n->parent) {
3752 if (n == nsrc) {
3753 rc = GPG_ERR_CONFLICT;
3754 goto fail;
3758 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3759 goto fail;
3761 rc = 0;
3763 if (ndst) {
3764 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3765 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3767 xmlFree(a);
3769 if (dup) {
3770 if (dup == nsrc)
3771 goto fail;
3773 if (ndst == xmlDocGetRootElement(client->doc)) {
3774 xmlNodePtr n = nsrc;
3775 gboolean match = FALSE;
3777 while (n->parent && n->parent != ndst)
3778 n = n->parent;
3780 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3781 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3783 if (xmlStrEqual(a, b)) {
3784 match = TRUE;
3785 xmlUnlinkNode(nsrc);
3786 xmlUnlinkNode(n);
3787 xmlFreeNodeList(n);
3790 xmlFree(a);
3791 xmlFree(b);
3793 if (!match) {
3794 xmlUnlinkNode(dup);
3795 xmlFreeNodeList(dup);
3798 else
3799 xmlUnlinkNode(dup);
3803 if (!ndst && dst)
3804 ndst = create_element_path(client, &dst, &rc);
3806 if (!ndst)
3807 goto fail;
3809 update_element_mtime(nsrc->parent);
3810 xmlUnlinkNode(nsrc);
3811 ndst = xmlAddChildList(ndst, nsrc);
3813 if (!ndst)
3814 rc = GPG_ERR_ENOMEM;
3816 update_element_mtime(ndst->parent);
3818 fail:
3819 if (req)
3820 g_strfreev(req);
3822 if (src)
3823 g_strfreev(src);
3825 if (dst)
3826 g_strfreev(dst);
3828 return send_error(ctx, rc);
3831 static int ls_command(assuan_context_t ctx, gchar *line)
3833 log_write2("ARGS=\"%s\"", line);
3834 gpg_error_t rc;
3835 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3836 gchar *dir = expand_homedir(tmp);
3837 DIR *d = opendir(dir);
3838 gint n = errno;
3840 g_free(tmp);
3842 if (!d) {
3843 g_free(dir);
3844 return send_syserror(ctx, n);
3847 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
3848 struct dirent *p = g_malloc(len), *cur = NULL;
3849 gchar *list = NULL;
3851 g_free(dir);
3852 rc = 0;
3854 while (!readdir_r(d, p, &cur) && cur) {
3855 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
3856 continue;
3857 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
3858 continue;
3860 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
3862 if (!tmp) {
3863 if (list)
3864 g_free(list);
3866 rc = GPG_ERR_ENOMEM;
3867 break;
3870 g_free(list);
3871 list = tmp;
3874 closedir(d);
3875 g_free(p);
3877 if (rc)
3878 return send_error(ctx, rc);
3880 if (!list)
3881 return send_error(ctx, GPG_ERR_NO_VALUE);
3883 list[strlen(list)-1] = 0;
3884 rc = xfer_data(ctx, list, strlen(list));
3885 g_free(list);
3886 return send_error(ctx, rc);
3889 static void bye_notify(assuan_context_t ctx)
3891 struct client_s *cl = assuan_get_pointer(ctx);
3893 /* This will let assuan_process_next() return. */
3894 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
3897 static void reset_notify(assuan_context_t ctx)
3899 struct client_s *cl = assuan_get_pointer(ctx);
3901 if (cl)
3902 cleanup_client(cl);
3906 * This is called before every Assuan command.
3908 gint command_startup(assuan_context_t ctx, const gchar *name)
3910 struct client_s *cl = assuan_get_pointer(ctx);
3911 gpg_error_t rc;
3913 log_write1("%s", name);
3915 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
3916 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
3917 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
3918 !g_ascii_strcasecmp(name, "GETCONFIG") ||
3919 !g_ascii_strcasecmp(name, "GETPID") ||
3920 !g_ascii_strcasecmp(name, "VERSION") ||
3921 !g_ascii_strcasecmp(name, "SET") ||
3922 !g_ascii_strcasecmp(name, "BYE") ||
3923 !g_ascii_strcasecmp(name, "NOP") ||
3924 !g_ascii_strcasecmp(name, "CANCEL") ||
3925 !g_ascii_strcasecmp(name, "RESET") ||
3926 !g_ascii_strcasecmp(name, "END") ||
3927 !g_ascii_strcasecmp(name, "HELP") ||
3928 !g_ascii_strcasecmp(name, "OPTION") ||
3929 !g_ascii_strcasecmp(name, "INPUT") ||
3930 !g_ascii_strcasecmp(name, "OUTPUT") ||
3931 !g_ascii_strcasecmp(name, "LS") ||
3932 !g_ascii_strcasecmp(name, "UNSET"))
3933 return 0;
3935 #ifdef WITH_PINENTRY
3936 if (!(cl->opts & OPT_PINENTRY))
3937 reset_pin_defaults(cl->pinentry);
3938 #endif
3940 cl->last_rc = rc = file_modified(cl);
3942 if (rc) {
3943 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
3944 !g_ascii_strcasecmp(name, "OPEN"))
3945 rc = 0;
3948 return rc;
3952 * This is called after every Assuan command.
3954 void command_finalize(assuan_context_t ctx, gint rc)
3956 struct client_s *client = assuan_get_pointer(ctx);
3958 if (!client->is_lock_cmd)
3959 unlock_file_mutex(client);
3961 log_write1(N_("command completed (rc=%u)"), client->last_rc);
3964 gpg_error_t register_commands(assuan_context_t ctx)
3966 static struct {
3967 const gchar *name;
3968 gint (*handler)(assuan_context_t, gchar *line);
3969 } table[] = {
3970 { "OPEN", open_command },
3971 { "SAVE", save_command },
3972 { "LIST", list_command },
3973 { "REALPATH", realpath_command },
3974 { "STORE", store_command },
3975 { "DELETE", delete_command },
3976 { "GET", get_command },
3977 { "ATTR", attr_command },
3978 { "ISCACHED", iscached_command },
3979 { "CLEARCACHE", clearcache_command },
3980 { "CACHETIMEOUT", cachetimeout_command },
3981 { "GETCONFIG", getconfig_command },
3982 { "DUMP", dump_command },
3983 { "XPATH", xpath_command },
3984 { "XPATHATTR", xpathattr_command },
3985 { "IMPORT", import_command },
3986 { "LOCK", lock_command },
3987 { "UNLOCK", unlock_command },
3988 { "GETPID", getpid_command },
3989 { "VERSION", version_command },
3990 { "SET", set_command },
3991 { "UNSET", unset_command },
3992 { "RENAME", rename_command },
3993 { "COPY", copy_command },
3994 { "LS", ls_command },
3995 { "MOVE", move_command },
3996 { "INPUT", NULL },
3997 { "OUTPUT", NULL },
3998 { NULL, NULL }
4000 gint i, rc;
4002 for (i=0; table[i].name; i++) {
4003 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
4005 if (rc)
4006 return rc;
4009 rc = assuan_register_bye_notify(ctx, bye_notify);
4011 if (rc)
4012 return rc;
4014 rc = assuan_register_reset_notify(ctx, reset_notify);
4016 if (rc)
4017 return rc;
4019 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4021 if (rc)
4022 return rc;
4024 return assuan_register_post_cmd_notify(ctx, command_finalize);
4027 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4028 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4030 goffset insize, len;
4031 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4032 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
4033 gint zrc = 0;
4034 gulong outsize = 0;
4035 gpg_error_t rc;
4036 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4037 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4038 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4040 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4041 insize = crypto->fh->st.st_size - fh_size;
4042 crypto->iv = gcry_malloc(crypto->blocksize);
4044 if (!crypto->iv) {
4045 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
4046 return gpg_error_from_errno(ENOMEM);
4049 if (crypto->fh->v1)
4050 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4051 else
4052 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4054 crypto->inbuf = gcry_malloc(insize);
4056 if (!crypto->inbuf) {
4057 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
4058 return gpg_error_from_errno(ENOMEM);
4061 crypto->insize = insize;
4062 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4064 if (len != crypto->insize)
4065 return GPG_ERR_INV_LENGTH;
4067 /* No encryption iterations. This is a plain (gzipped) file. */
4068 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4069 (!crypto->fh->v1 && fh_iter <= 0L)) {
4071 * cache_file_count() needs both .used == TRUE and a valid key in
4072 * order for it to count as a used cache entry. Fixes CACHE status
4073 * messages.
4075 memset(crypto->key, '!', hashlen);
4076 goto decompress;
4079 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4080 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4081 return rc;
4084 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4085 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4086 return rc;
4089 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4090 client->filename : "global", "iteration_progress");
4092 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4093 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4095 if (rc)
4096 return rc;
4099 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4101 if (rc)
4102 return rc;
4104 crypto->tkey = gcry_malloc(hashlen);
4106 if (!crypto->tkey) {
4107 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
4108 return gpg_error_from_errno(ENOMEM);
4111 memcpy(crypto->tkey, crypto->key, hashlen);
4112 guchar *tkey = crypto->tkey;
4113 tkey[0] ^= 1;
4115 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4116 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4117 return rc;
4120 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4121 if (iter_progress > 0ULL && iter >= iter_progress) {
4122 if (!(iter % iter_progress)) {
4123 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4124 ++n_iter * iter_progress, fh_iter);
4126 if (rc)
4127 return rc;
4131 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4132 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4133 return rc;
4136 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4138 if (rc) {
4139 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4140 return rc;
4143 iter++;
4146 if (iter_progress && fh_iter >= iter_progress) {
4147 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4149 if (rc)
4150 return rc;
4153 decompress:
4154 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
4155 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
4156 if (zrc == Z_MEM_ERROR)
4157 return gpg_error_from_errno(ENOMEM);
4158 else
4159 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4162 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4163 gcry_free(crypto->outbuf);
4164 crypto->outbuf = NULL;
4165 return GPG_ERR_INV_PASSPHRASE;
4168 if (ctx) {
4169 client->xml = crypto->outbuf;
4170 client->len = outsize;
4171 crypto->outbuf = NULL;
4173 else if (dst) {
4174 *dst = crypto->outbuf;
4175 *dst_len = outsize;
4176 crypto->outbuf = NULL;
4179 /* The calling function should free the crypto struct. */
4180 return 0;