Fixed a few potential memory leaks.
[pwmd.git] / src / commands.c
blobd12b1cb122be2a9ed774802db06d104cfbc6c2cb
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 client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
440 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
442 if (rc) {
443 cleanup_client(client);
444 return client->opts & OPT_INQUIRE ? rc : 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 client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : 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 client->opts & OPT_INQUIRE ? rc : 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 #endif
548 return 0;
551 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
553 struct client_s *client = data;
555 (void)value;
556 client->opts |= OPT_INQUIRE;
557 return 0;
560 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
562 struct client_s *client = data;
564 (void)value;
565 client->opts |= OPT_BASE64;
566 return 0;
569 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
571 guchar *tmp;
572 gsize len;
574 if (client->opts & OPT_BASE64)
575 tmp = g_base64_decode(key, &len);
576 else {
577 tmp = (guchar *)g_strdup(key);
578 len = strlen(key);
581 if (!tmp)
582 return GPG_ERR_ENOMEM;
584 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
585 g_free(tmp);
586 return 0;
589 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
591 gboolean cached = FALSE;
592 gpg_error_t rc;
593 struct client_s *client = assuan_get_pointer(ctx);
594 gchar **req;
595 gchar *filename = NULL;
596 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
598 if ((req = split_input_line(line, " ", 2)) != NULL)
599 filename = req[0];
601 pth_cleanup_push(req_cleanup, req);
603 if (!filename || !*filename) {
604 pth_cleanup_pop(1);
605 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
608 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
610 if (valid_filename(filename) == FALSE) {
611 pth_cleanup_pop(1);
612 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
615 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
616 CACHE_LOCK(client->ctx);
618 if (cache_has_file(client->md5file) == FALSE) {
619 if (cache_add_file(client->md5file, NULL) == FALSE) {
620 pth_cleanup_pop(1);
621 CACHE_UNLOCK;
622 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
626 cache_incr_refcount(client->md5file);
627 CACHE_UNLOCK;
628 rc = lock_file_mutex(client);
630 if (rc) {
631 pth_cleanup_pop(1);
632 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
635 client->freed = FALSE;
636 client->crypto = init_client_crypto();
638 if (!client->crypto) {
639 pth_cleanup_pop(1);
640 cleanup_client(client);
641 return client->opts & OPT_INQUIRE ? gpg_error_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
644 client->crypto->key = gcry_malloc(hashlen);
646 if (!client->crypto->key) {
647 pth_cleanup_pop(1);
648 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
649 gpg_error_from_errno(ENOMEM));
650 cleanup_client(client);
651 return client->opts & OPT_INQUIRE ? gpg_err_code_to_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
654 memset(client->crypto->key, 0, hashlen);
655 client->crypto->fh = read_file_header(filename, FALSE, &rc);
657 if (!client->crypto->fh) {
658 if (gpg_err_code_to_errno(rc) != ENOENT) {
659 log_write("%s: %s", filename, pwmd_strerror(rc));
660 pth_cleanup_pop(1);
661 cleanup_client(client);
662 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
666 * New files don't need a key.
668 if ((client->xml = new_document()) == NULL) {
669 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
670 pth_cleanup_pop(1);
671 cleanup_client(client);
672 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
675 client->len = xmlStrlen(client->xml);
676 client->new = TRUE;
677 client->filename = g_strdup(filename);
679 if (!client->filename) {
680 pth_cleanup_pop(1);
681 cleanup_client(client);
682 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
683 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
686 if (req[1] && *req[1]) {
687 rc = hash_key(client, req[1]);
689 if (rc) {
690 pth_cleanup_pop(1);
691 cleanup_client(client);
692 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
696 pth_cleanup_pop(1);
697 #ifdef WITH_PINENTRY
698 client->pinentry->filename = g_strdup(client->filename);
700 if (!client->pinentry->filename) {
701 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
702 cleanup_client(client);
703 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
705 #endif
706 return open_command_finalize(ctx, NULL, cached);
708 else {
709 if (!(client->opts & OPT_CIPHER))
710 g_key_file_set_string(keyfileh, filename, "cipher",
711 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
713 client->mtime = client->crypto->fh->st.st_mtime;
716 client->filename = g_strdup(filename);
718 if (!client->filename) {
719 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
720 pth_cleanup_pop(1);
721 cleanup_client(client);
722 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
725 #ifdef WITH_PINENTRY
726 if (client->pinentry->filename)
727 g_free(client->pinentry->filename);
729 client->pinentry->filename = g_strdup(client->filename);
731 if (!client->pinentry->filename) {
732 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
733 pth_cleanup_pop(1);
734 cleanup_client(client);
735 return client->opts & OPT_INQUIRE ? gpg_err_code_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
737 #endif
739 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
740 goto done;
742 CACHE_LOCK(client->ctx);
743 cached = cache_get_key(client->md5file, client->crypto->key);
744 CACHE_UNLOCK;
746 if (cached == FALSE) {
747 gchar *tmp = get_key_file_string(filename, "key_file");
749 if (tmp && !(client->opts & OPT_INQUIRE)) {
750 g_free(tmp);
751 pth_cleanup_pop(1);
752 cleanup_client(client);
753 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
756 if (tmp)
757 g_free(tmp);
760 * No key specified and no matching filename found in the cache. Use
761 * pinentry to retrieve the key. Cannot return assuan_process_done()
762 * here otherwise the command will be interrupted. The event loop in
763 * client_thread() will poll the file descriptor waiting for it to
764 * become ready to read a pinentry_key_s which will contain the
765 * entered key or an error code. It will then call
766 * open_command_finalize() to to finish the command.
768 if (!req[1] || !*req[1]) {
769 #ifdef WITH_PINENTRY
770 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
772 /* From set_pinentry_defaults(). */
773 if (client->opts & OPT_INQUIRE ||
774 client->pinentry->enable == FALSE ||
775 (client->pinentry->enable == -1 && b == FALSE)) {
776 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
777 goto done;
780 pth_cleanup_pop(1);
781 rc = lock_pin_mutex(client);
783 if (rc) {
784 unlock_pin_mutex(client->pinentry);
785 cleanup_client(client);
786 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
789 client->pinentry->which = PINENTRY_OPEN;
790 rc = pinentry_fork(ctx);
792 if (rc) {
793 unlock_pin_mutex(client->pinentry);
794 cleanup_client(client);
795 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
798 // Called from pinentry iterate.
799 client->pinentry->cb = open_command_finalize;
800 client->pinentry->status = PINENTRY_INIT;
801 return 0;
802 #else
803 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
804 goto done;
805 #endif
808 rc = hash_key(client, req[1]);
810 if (rc) {
811 pth_cleanup_pop(1);
812 cleanup_client(client);
813 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
816 else if (req && req[1] && *req[1]) {
817 rc = hash_key(client, req[1]);
819 if (rc) {
820 pth_cleanup_pop(1);
821 cleanup_client(client);
822 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
826 done:
827 pth_cleanup_pop(1);
828 return open_command_finalize(ctx, NULL, cached);
831 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
832 guchar *line, gsize len)
834 assuan_context_t ctx = data;
835 struct client_s *client = assuan_get_pointer(ctx);
836 gpg_error_t rc = file_modified(client);
838 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
839 if (line)
840 xfree(line);
842 return assuan_rc ? assuan_rc : rc;
845 rc = open_command_common(ctx, (gchar *)line);
847 if (line)
848 xfree(line);
850 client->inquire_status = INQUIRE_DONE;
851 return rc;
854 static gint open_command(assuan_context_t ctx, gchar *line)
856 gpg_error_t rc;
857 struct client_s *client = assuan_get_pointer(ctx);
858 struct argv_s *args[] = {
859 &(struct argv_s) { "lock", OPT_NOARG, parse_open_opt_lock },
860 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry },
861 &(struct argv_s) { "inquire", OPT_NOARG, parse_opt_inquire },
862 &(struct argv_s) { "base64", OPT_NOARG, parse_opt_base64 },
863 NULL
866 if (client->state == STATE_OPEN)
867 cleanup_client(client);
869 if (!(client->opts & OPT_LOCK))
870 client->lock_on_open = FALSE;
872 rc = parse_options(&line, args, client);
874 if (rc)
875 return send_error(ctx, rc);
877 if ((client->opts & OPT_INQUIRE)) {
878 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
879 ctx);
881 if (rc)
882 return send_error(ctx, rc);
884 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
885 client->inquire_status = INQUIRE_BUSY;
886 return 0;
889 return open_command_common(ctx, line);
892 gboolean do_compress(assuan_context_t ctx, gint level, gpointer data,
893 guint size, gpointer *out, gulong *outsize, gint *rc)
895 struct gz_s *gz;
896 gz_header h;
897 gchar buf[17];
898 gint cmd = Z_NO_FLUSH;
900 gz = g_malloc0(sizeof(struct gz_s));
902 if (!gz) {
903 *rc = gpg_error_from_errno(ENOMEM);
904 return FALSE;
907 pth_cleanup_push(gz_cleanup, &gz);
908 gz->which = STATUS_COMPRESS;
909 gz->z.zalloc = z_alloc;
910 gz->z.zfree = z_free;
911 gz->z.next_in = data;
912 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
913 gz->z.avail_out = (uInt)zlib_bufsize;
914 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
916 if (!gz->out) {
917 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
918 *rc = Z_MEM_ERROR;
919 pth_cleanup_pop(1);
920 return FALSE;
923 *rc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
925 if (*rc != Z_OK) {
926 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
927 pth_cleanup_pop(1);
928 return FALSE;
931 /* Rather than store the size of the uncompressed data in the file header,
932 * store it in the comment field of the gzip header. Don't give anyone too
933 * much information. Not sure why really, but it seems the right way. :)
935 memset(&h, 0, sizeof(gz_header));
936 g_snprintf(buf, sizeof(buf), "%u", size);
937 h.comment = (guchar *)buf;
938 *rc = deflateSetHeader(&gz->z, &h);
940 if (*rc != Z_OK) {
941 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
942 pth_cleanup_pop(1);
943 return FALSE;
946 do {
947 gpointer p;
949 *rc = deflate(&gz->z, cmd);
951 switch (*rc) {
952 case Z_OK:
953 break;
954 case Z_BUF_ERROR:
955 if (!gz->z.avail_out) {
956 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
958 if (!p) {
959 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
960 *rc = Z_MEM_ERROR;
961 goto fail;
964 gz->out = p;
965 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
966 gz->z.avail_out = zlib_bufsize;
969 if (!gz->z.avail_in && gz->z.total_in < size) {
970 if (gz->z.total_in + zlib_bufsize > size)
971 gz->z.avail_in = size - gz->z.total_in;
972 else
973 gz->z.avail_in = zlib_bufsize;
975 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
976 gz->z.total_in, size);
978 if (*rc)
979 goto fail;
982 if (gz->z.total_in >= size)
983 cmd = Z_FINISH;
985 break;
986 case Z_STREAM_END:
987 break;
988 default:
989 goto fail;
991 } while (*rc != Z_STREAM_END);
993 *rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
995 if (*rc)
996 goto fail;
998 *out = gz->out;
999 *outsize = gz->z.total_out;
1000 *rc = 0;
1001 gz->done = TRUE;
1002 pth_cleanup_pop(1);
1003 return TRUE;
1005 fail:
1006 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
1007 pth_cleanup_pop(1);
1008 return FALSE;
1011 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1014 * Useful for a large amount of data. Rather than doing all of the data in one
1015 * iteration do it in chunks. This lets the command be cancelable rather than
1016 * waiting for it to complete.
1018 static gpg_error_t iterate_crypto_once(struct client_s *client,
1019 struct crypto_s *crypto, status_msg_t which)
1021 gpg_error_t rc = 0;
1022 goffset len = CRYPTO_BLOCKSIZE(crypto);
1023 gpointer p = gcry_malloc(len);
1024 goffset total = 0;
1025 gpointer inbuf;
1027 if (!p)
1028 return gpg_err_code_from_errno(ENOMEM);
1030 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1031 len = crypto->insize;
1033 pth_cleanup_push(gcry_free, p);
1035 for (;;) {
1036 inbuf = (guchar *)crypto->inbuf + total;
1037 guchar *tmp;
1039 if (len + total > crypto->insize)
1040 len = crypto->blocksize;
1042 if (which == STATUS_ENCRYPT)
1043 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1044 else
1045 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1047 if (rc)
1048 goto done;
1050 tmp = (guchar *)crypto->inbuf + total;
1051 memmove(tmp, p, len);
1052 total += len;
1054 if (total >= crypto->insize)
1055 break;
1057 pth_cancel_point();
1060 done:
1061 pth_cleanup_pop(1);
1062 return rc;
1065 /* The crypto struct must be setup for iterations and .key. */
1066 gpg_error_t do_xml_encrypt(struct client_s *client,
1067 struct crypto_s *crypto, const gchar *filename)
1069 goffset len = crypto->insize;
1070 gpointer inbuf;
1071 gchar *p;
1072 gpg_error_t rc;
1073 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
1074 gchar tmp[FILENAME_MAX];
1075 struct stat st;
1076 mode_t mode = 0;
1077 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1079 if (!crypto->fh->ver.fh2.iter) {
1081 * cache_file_count() needs both .used == TRUE and a valid key in
1082 * order for it to count as a used cache entry. Fixes CACHE status
1083 * messages.
1085 memset(crypto->key, '!', hashlen);
1086 goto write_file;
1090 * Resize the existing xml buffer to the block size required by gcrypt
1091 * rather than duplicating it and wasting memory.
1093 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1095 if (crypto->insize % crypto->blocksize)
1096 len += crypto->blocksize;
1098 inbuf = gcry_realloc(crypto->inbuf, len);
1100 if (!inbuf) {
1101 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1102 return gpg_error_from_errno(ENOMEM);
1105 crypto->inbuf = inbuf;
1106 crypto->insize = len;
1107 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1109 if (crypto->tkey)
1110 gcry_free(crypto->tkey);
1112 crypto->tkey = gcry_malloc(hashlen);
1114 if (!crypto->tkey) {
1115 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1116 return gpg_error_from_errno(ENOMEM);
1119 memcpy(crypto->tkey, crypto->key, hashlen);
1120 guchar *tkey = crypto->tkey;
1121 tkey[0] ^= 1;
1123 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1124 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1125 return rc;
1128 iter_progress = (guint64)get_key_file_double(
1129 client ? client->filename : "global", "iteration_progress");
1131 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1132 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1133 "0 %llu", crypto->fh->ver.fh2.iter);
1135 if (rc)
1136 return rc;
1139 while (xiter < crypto->fh->ver.fh2.iter-1) {
1140 if (iter_progress > 0ULL && xiter >= iter_progress) {
1141 if (!(xiter % iter_progress)) {
1142 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1143 "%llu %llu", ++n_iter * iter_progress,
1144 crypto->fh->ver.fh2.iter);
1146 if (rc)
1147 return rc;
1151 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1152 crypto->blocksize))) {
1153 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1154 return rc;
1157 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1159 if (rc) {
1160 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1161 return rc;
1164 xiter++;
1167 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1168 crypto->blocksize))) {
1169 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1170 return rc;
1173 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1174 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
1175 return rc;
1178 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1180 if (rc)
1181 return rc;
1183 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1184 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1185 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1187 if (rc)
1188 return rc;
1191 write_file:
1192 tmp[0] = 0;
1194 if (filename) {
1195 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1196 crypto->fh->fd = STDOUT_FILENO;
1197 goto do_write_file;
1200 if (lstat(filename, &st) == 0) {
1201 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1203 if (!(mode & S_IWUSR))
1204 return gpg_error_from_errno(EACCES);
1206 else if (errno != ENOENT)
1207 return gpg_error_from_errno(errno);
1209 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1210 crypto->fh->fd = mkstemp(tmp);
1212 if (crypto->fh->fd == -1) {
1213 rc = errno;
1214 p = strrchr(tmp, '/');
1215 p++;
1216 log_write("%s: %s", p, strerror(rc));
1217 return gpg_error_from_errno(rc);
1220 pth_cleanup_push(cleanup_unlink_cb, tmp);
1222 else
1224 * xml_import() or convert_file() from command line.
1226 crypto->fh->fd = STDOUT_FILENO;
1228 do_write_file:
1229 crypto->fh->ver.fh2.magic[0] = '\177';
1230 crypto->fh->ver.fh2.magic[1] = 'P';
1231 crypto->fh->ver.fh2.magic[2] = 'W';
1232 crypto->fh->ver.fh2.magic[3] = 'M';
1233 crypto->fh->ver.fh2.magic[4] = 'D';
1234 crypto->fh->ver.fh2.version = VERSION_HEX;
1235 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1237 if (len != sizeof(crypto->fh->ver.fh2)) {
1238 len = errno;
1240 if (tmp[0])
1241 pth_cleanup_pop(1);
1243 return gpg_error_from_errno(len);
1246 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1248 if (len != crypto->insize) {
1249 len = errno;
1251 if (tmp[0])
1252 pth_cleanup_pop(1);
1254 return gpg_error_from_errno(len);
1257 if (fsync(crypto->fh->fd) == -1) {
1258 len = errno;
1260 if (tmp[0])
1261 pth_cleanup_pop(1);
1263 return gpg_error_from_errno(len);
1266 if (tmp[0]) {
1267 #ifdef WITH_LIBACL
1268 acl_t acl;
1269 #endif
1270 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1271 gchar tmp2[FILENAME_MAX];
1273 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1274 #ifdef WITH_LIBACL
1275 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1277 if (!acl)
1278 log_write("ACL: %s: %s", filename, strerror(errno));
1279 #endif
1281 if (rename(filename, tmp2) == -1) {
1282 len = errno;
1283 pth_cleanup_pop(1);
1284 #ifdef WITH_LIBACL
1285 if (acl)
1286 acl_free(acl);
1287 #endif
1288 return gpg_error_from_errno(len);
1291 #ifdef WITH_LIBACL
1292 else {
1293 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1295 if (!acl)
1296 log_write("ACL: %s: %s", filename, strerror(errno));
1298 #endif
1300 if (rename(tmp, filename) == -1) {
1301 len = errno;
1302 pth_cleanup_pop(1);
1303 #ifdef WITH_LIBACL
1304 if (acl)
1305 acl_free(acl);
1306 #endif
1307 return gpg_error_from_errno(len);
1310 pth_cleanup_pop(0);
1312 if (mode)
1313 chmod(filename, mode);
1315 #ifdef WITH_LIBACL
1316 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1317 log_write("ACL: %s: %s", filename, strerror(errno));
1319 if (acl)
1320 acl_free(acl);
1321 #endif
1324 if (client && lstat(filename, &st) == 0)
1325 client->mtime = st.st_mtime;
1327 return 0;
1330 gpg_error_t update_save_flags(const gchar *filename,
1331 struct crypto_s *crypto)
1333 gpg_error_t rc;
1334 guint64 iter;
1336 /* New file? */
1337 if (!crypto->fh) {
1338 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1340 if (!crypto->fh)
1341 return GPG_ERR_ENOMEM;
1344 rc = init_client_crypto2(filename, crypto);
1346 if (rc)
1347 return rc;
1349 if (filename && !crypto->fh->v1) {
1350 iter = (guint64)get_key_file_double(filename, "iterations");
1351 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1354 return 0;
1357 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1358 gboolean cached)
1360 struct client_s *client = assuan_get_pointer(ctx);
1361 gpointer xmlbuf;
1362 gulong outsize = 0;
1363 guint len;
1364 gint clevel;
1365 gint timeout;
1366 gpointer outbuf;
1367 gint zrc;
1368 gpg_error_t rc;
1370 if (client->crypto->key && client->crypto->key != key)
1371 gcry_free(client->crypto->key);
1373 client->crypto->key = key;
1374 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1376 if (rc) {
1377 cleanup_crypto(&client->crypto);
1378 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1381 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1382 pth_cleanup_push(xmlFree, xmlbuf);
1383 clevel = get_key_file_integer(client->filename, "compression_level");
1385 if (clevel < 0)
1386 clevel = 0;
1388 if (do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize, &zrc) == FALSE) {
1389 pth_cleanup_pop(1);
1390 cleanup_crypto(&client->crypto);
1392 if (zrc == Z_MEM_ERROR)
1393 return client->opts & OPT_INQUIRE ? gpg_error_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
1394 else
1395 return client->opts & OPT_INQUIRE ? GPG_ERR_COMPR_ALGO : send_error(ctx, GPG_ERR_COMPR_ALGO);
1397 else {
1398 pth_cleanup_pop(1);
1399 xmlbuf = outbuf;
1400 len = outsize;
1403 client->crypto->inbuf = xmlbuf;
1404 client->crypto->insize = len;
1405 rc = update_save_flags(client->filename, client->crypto);
1407 if (rc) {
1408 cleanup_crypto(&client->crypto);
1409 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1410 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1413 rc = do_xml_encrypt(client, client->crypto, client->filename);
1415 if (rc) {
1416 cleanup_crypto(&client->crypto);
1417 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1420 timeout = get_key_file_integer(client->filename, "cache_timeout");
1421 CACHE_LOCK(client->ctx);
1423 if (cached) {
1424 cache_reset_timeout(client->md5file, timeout);
1425 CACHE_UNLOCK;
1427 if (client->new == TRUE)
1428 send_status_all(STATUS_CACHE);
1430 client->new = FALSE;
1431 cleanup_crypto(&client->crypto);
1432 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1435 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1436 CACHE_UNLOCK;
1437 cleanup_crypto(&client->crypto);
1438 return client->opts & OPT_INQUIRE ? gpg_error_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
1441 client->new = FALSE;
1442 cache_reset_timeout(client->md5file, timeout);
1443 CACHE_UNLOCK;
1444 send_status_all(STATUS_CACHE);
1445 cleanup_crypto(&client->crypto);
1446 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1449 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1451 struct client_s *client = data;
1452 guint64 n;
1453 gchar *value = v;
1454 gchar *p = NULL;
1456 if (!client->filename)
1457 return EPWMD_NO_FILE;
1459 if (!value || !*value)
1460 return 0;
1462 errno = 0;
1463 n = strtoul(value, &p, 10);
1465 if (errno || (p && *p) || n == G_MAXULONG)
1466 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1468 MUTEX_LOCK(&rcfile_mutex);
1469 g_key_file_set_double(keyfileh,
1470 client->filename ? client->filename : "global", "iterations", n);
1471 MUTEX_UNLOCK(&rcfile_mutex);
1473 if (client->filename)
1474 client->opts |= OPT_ITERATIONS;
1476 return 0;
1479 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1481 struct client_s *client = data;
1482 const gchar *p = value;
1483 guint64 flags;
1485 if (!client->filename)
1486 return EPWMD_NO_FILE;
1488 if (!p || !*p)
1489 return 0;
1491 flags = pwmd_cipher_str_to_cipher(p);
1493 if (!flags)
1494 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1496 MUTEX_LOCK(&rcfile_mutex);
1497 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1498 MUTEX_UNLOCK(&rcfile_mutex);
1500 if (!value)
1501 g_free((gchar *)p);
1503 return 0;
1506 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1508 struct client_s *client = data;
1510 CACHE_LOCK(client->ctx);
1511 cache_clear(client->md5file, 1);
1512 CACHE_UNLOCK;
1513 return 0;
1516 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1518 struct client_s *client = assuan_get_pointer(ctx);
1519 gboolean cached = FALSE;
1520 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1522 CACHE_LOCK(ctx);
1523 cached = cache_iscached(client->md5file);
1524 CACHE_UNLOCK;
1527 * If a cache entry doesn't exist for this file and the file has a
1528 * "key_file" or "key" parameter, then it's an error. The reason is that
1529 * cache expiration would be useless. Unless this is an inquire, then its
1530 * fine.
1532 if (cached == FALSE) {
1533 gchar *tmp = get_key_file_string(client->filename, "key_file");
1535 if (tmp && !(client->opts & OPT_INQUIRE)) {
1536 g_free(tmp);
1537 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1540 if (tmp)
1541 g_free(tmp);
1544 cached = FALSE;
1546 /* New file? */
1547 if (!client->crypto) {
1548 client->crypto = init_client_crypto();
1550 if (!client->crypto) {
1551 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1552 return client->opts & OPT_INQUIRE ? gpg_error_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
1556 client->crypto->key = gcry_malloc(hashlen);
1558 if (!client->crypto->key) {
1559 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1560 cleanup_crypto(&client->crypto);
1561 return client->opts & OPT_INQUIRE ? gpg_error_from_errno(ENOMEM) : send_syserror(ctx, ENOMEM);
1564 memset(client->crypto->key, '!', hashlen);
1566 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1567 (!line || !*line))
1568 goto done;
1570 if (!line || !*line) {
1571 /* It doesn't make sense to use an --inquire with an empty
1572 * passphrase. This will prevent a pinentry dialog. */
1573 if (client->opts & OPT_INQUIRE) {
1574 cleanup_crypto(&client->crypto);
1575 return GPG_ERR_WRONG_KEY_USAGE;
1578 client->crypto->tkey = gcry_malloc(hashlen);
1580 if (!client->crypto->tkey) {
1581 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
1582 cleanup_crypto(&client->crypto);
1583 return send_syserror(ctx, ENOMEM);
1586 memset(client->crypto->tkey, '!', hashlen);
1587 CACHE_LOCK(ctx);
1589 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1590 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1591 CACHE_UNLOCK;
1593 #ifdef WITH_PINENTRY
1594 gpg_error_t rc;
1596 if (client->pinentry->enable == FALSE ||
1597 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1598 /* Empty keys are allowed. */
1599 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1600 goto done;
1603 lock_pin_mutex(client);
1604 client->pinentry->which = PINENTRY_SAVE;
1605 rc = pinentry_fork(ctx);
1607 if (rc) {
1608 unlock_pin_mutex(client->pinentry);
1609 cleanup_crypto(&client->crypto);
1610 return send_error(ctx, rc);
1613 client->pinentry->cb = save_command_finalize;
1614 client->pinentry->status = PINENTRY_INIT;
1615 return 0;
1616 #else
1617 /* Empty keys are allowed. */
1618 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1619 goto done;
1620 #endif
1622 else {
1623 CACHE_UNLOCK;
1624 cached = TRUE;
1627 else {
1628 gpg_error_t rc;
1630 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1631 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1633 if (iter <= 0L)
1634 iter = 1;
1636 MUTEX_LOCK(&rcfile_mutex);
1637 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1638 MUTEX_UNLOCK(&rcfile_mutex);
1639 client->opts |= OPT_ITERATIONS;
1640 rc = send_status(ctx, STATUS_CONFIG, NULL);
1642 if (rc) {
1643 cleanup_crypto(&client->crypto);
1644 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1648 rc = hash_key(client, line);
1650 if (rc) {
1651 cleanup_crypto(&client->crypto);
1652 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1656 done:
1657 return save_command_finalize(ctx, client->crypto->key, cached);
1660 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1661 guchar *line, gsize len)
1663 assuan_context_t ctx = data;
1664 struct client_s *client = assuan_get_pointer(ctx);
1665 gpg_error_t rc = file_modified(client);
1667 if (assuan_rc || rc) {
1668 if (line)
1669 xfree(line);
1671 return assuan_rc ? assuan_rc : rc;
1674 rc = save_command_common(ctx, (gchar *)line);
1676 if (line)
1677 xfree(line);
1679 client->inquire_status = INQUIRE_DONE;
1680 return rc;
1683 static gint save_command(assuan_context_t ctx, gchar *line)
1685 struct stat st;
1686 struct client_s *client = assuan_get_pointer(ctx);
1687 gpg_error_t rc;
1688 struct argv_s *args[] = {
1689 &(struct argv_s) { "iterations", OPT_OPTARG, parse_save_opt_iterations },
1690 &(struct argv_s) { "cipher", OPT_OPTARG, parse_save_opt_cipher },
1691 &(struct argv_s) { "pinentry", OPT_OPTARG, parse_opt_pinentry },
1692 &(struct argv_s) { "reset", OPT_NOARG, parse_save_opt_reset },
1693 &(struct argv_s) { "inquire", OPT_NOARG, parse_opt_inquire },
1694 &(struct argv_s) { "base64", OPT_NOARG, parse_opt_base64 },
1695 NULL
1698 rc = parse_options(&line, args, client);
1700 if (rc)
1701 return send_error(ctx, rc);
1703 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1704 return send_syserror(ctx, errno);
1706 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1707 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1708 return send_error(ctx, GPG_ERR_ENOANO);
1711 if ((client->opts & OPT_INQUIRE)) {
1712 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1713 ctx);
1715 if (rc)
1716 return send_error(ctx, rc);
1718 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1719 client->inquire_status = INQUIRE_BUSY;
1720 return 0;
1723 if (line && *line)
1724 log_write2("ARGS=%s", "<passphrase>");
1726 return save_command_common(ctx, line);
1729 static gint delete_command(assuan_context_t ctx, gchar *line)
1731 struct client_s *client = assuan_get_pointer(ctx);
1732 gchar **req;
1733 gpg_error_t rc;
1734 xmlNodePtr n;
1736 log_write2("ARGS=\"%s\"", line);
1738 if (strchr(line, '\t'))
1739 req = split_input_line(line, "\t", -1);
1740 else
1741 req = split_input_line(line, " ", -1);
1743 if (!req || !*req)
1744 return send_error(ctx, GPG_ERR_SYNTAX);
1746 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1748 if (!n) {
1749 g_strfreev(req);
1750 return send_error(ctx, rc);
1754 * No sub-node defined. Remove the entire node (root element).
1756 if (!req[1]) {
1757 if (n) {
1758 rc = unlink_node(n);
1759 xmlFreeNode(n);
1762 g_strfreev(req);
1763 return send_error(ctx, rc);
1766 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1767 g_strfreev(req);
1769 if (!n)
1770 return send_error(ctx, rc);
1772 if (n) {
1773 rc = unlink_node(n);
1774 xmlFreeNode(n);
1777 return send_error(ctx, rc);
1781 * Don't return with assuan_process_done() here. This has been called from
1782 * assuan_process_next() and the command should be finished in
1783 * client_thread().
1785 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1786 gsize len)
1788 assuan_context_t ctx = data;
1789 struct client_s *client = assuan_get_pointer(ctx);
1790 gchar **req;
1791 xmlNodePtr n;
1792 gpg_error_t rc = file_modified(client);
1794 if (assuan_rc || rc) {
1795 if (line)
1796 xfree(line);
1797 return assuan_rc ? assuan_rc : rc;
1800 req = split_input_line((gchar *)line, "\t", 0);
1801 xfree(line);
1803 if (!req || !*req)
1804 return GPG_ERR_SYNTAX;
1806 again:
1807 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1809 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1810 rc = new_root_element(client->doc, *req);
1812 if (rc) {
1813 g_strfreev(req);
1814 return rc;
1817 goto again;
1820 if (!n) {
1821 g_strfreev(req);
1822 return rc;
1825 if (req[1]) {
1826 if (!n->children)
1827 n = create_elements_cb(n, req+1, &rc, NULL);
1828 else
1829 n = find_elements(client->doc, n->children, req+1, &rc,
1830 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1833 g_strfreev(req);
1834 client->inquire_status = INQUIRE_DONE;
1836 if (!rc)
1837 rc = update_element_mtime(n);
1839 return rc;
1842 static gint store_command(assuan_context_t ctx, gchar *line)
1844 struct client_s *client = assuan_get_pointer(ctx);
1845 gpg_error_t rc;
1847 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1849 if (rc)
1850 return send_error(ctx, rc);
1852 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1853 client->inquire_status = INQUIRE_BUSY;
1854 return 0;
1857 static void *send_data_cb(void *arg)
1859 struct assuan_cmd_s *data = arg;
1860 gint old;
1861 gpg_error_t *rc;
1863 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1864 rc = g_malloc(sizeof(gpg_error_t));
1865 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1866 pth_cancel_state(old, NULL);
1867 pth_exit(rc);
1868 return NULL;
1871 /* For every assuan command that needs to be sent to the client, a timeout is
1872 * needed to determine if the client lost the connection. The timeout is the
1873 * same as the "keepalive" configuration parameter or a default if unset.
1875 gpg_error_t do_assuan_command(assuan_context_t ctx,
1876 void *(*cb)(void *data), void *data)
1878 pth_attr_t attr = pth_attr_new();
1879 pth_t tid;
1880 gint n;
1881 gint to = get_key_file_integer("global", "keepalive");
1882 pth_event_t ev, tev;
1883 pth_status_t st;
1884 gpg_error_t rc = 0;
1885 void *p;
1887 pth_attr_init(attr);
1888 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1889 tid = pth_spawn(attr, cb, data);
1890 n = errno;
1891 pth_attr_destroy(attr);
1893 if (!tid) {
1894 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__,
1895 _gpg_strerror(gpg_error_from_errno(n)));
1896 return gpg_error_from_errno(n);
1899 pth_cleanup_push(cleanup_cancel_cb, tid);
1900 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1901 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1902 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1903 ev = pth_event_concat(ev, tev, NULL);
1904 pth_cleanup_push(cleanup_ev_cb, ev);
1905 pth_yield(tid);
1906 pth_wait(ev);
1908 if (tev) {
1909 st = pth_event_status(tev);
1911 if (st == PTH_STATUS_OCCURRED) {
1912 pth_cleanup_pop(1);
1913 pth_cleanup_pop(1);
1914 return GPG_ERR_TIMEOUT;
1918 st = pth_event_status(ev);
1920 if (st == PTH_STATUS_FAILED) {
1921 pth_cancel(tid);
1922 pth_join(tid, &p);
1923 g_free(p);
1924 rc = GPG_ERR_ASS_WRITE_ERROR;
1926 else if (st == PTH_STATUS_OCCURRED) {
1927 pth_join(tid, &p);
1928 rc = *(gpg_error_t *)p;
1929 g_free(p);
1932 pth_cleanup_pop(1);
1933 pth_cleanup_pop(0);
1934 return rc;
1937 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1938 gint total)
1940 gint to_send;
1941 gint sent = 0;
1942 gpg_error_t rc;
1943 struct assuan_cmd_s data;
1944 gint progress = get_key_file_integer("global", "xfer_progress");
1945 gint flush = 0;
1947 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1948 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1949 data.ctx = ctx;
1950 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1952 if (rc)
1953 return rc;
1955 again:
1956 do {
1957 if (sent + to_send > total)
1958 to_send = total - sent;
1960 data.line = flush ? NULL : (gchar *)line+sent;
1961 data.line_len = flush ? 0 : to_send;
1962 rc = do_assuan_command(ctx, send_data_cb, &data);
1964 if (!rc) {
1965 sent += flush ? 0 : to_send;
1967 if ((progress && !(sent % progress) && sent != total) ||
1968 (sent == total && flush))
1969 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1971 if (!flush && !rc && sent == total) {
1972 flush = 1;
1973 goto again;
1976 } while (!rc && sent < total);
1978 return rc;
1981 static gint get_command(assuan_context_t ctx, gchar *line)
1983 struct client_s *client = assuan_get_pointer(ctx);
1984 gchar **req;
1985 gpg_error_t rc;
1986 xmlNodePtr n;
1988 log_write2("ARGS=\"%s\"", line);
1989 req = split_input_line(line, "\t", -1);
1991 if (!req || !*req) {
1992 g_strfreev(req);
1993 return send_error(ctx, GPG_ERR_SYNTAX);
1996 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1998 if (!n) {
1999 g_strfreev(req);
2000 return send_error(ctx, rc);
2003 if (req[1])
2004 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2006 g_strfreev(req);
2008 if (rc)
2009 return send_error(ctx, rc);
2011 if (!n || !n->children)
2012 return send_error(ctx, GPG_ERR_NO_VALUE);
2014 n = find_text_node(n->children);
2016 if (!n || !n->content || !*n->content)
2017 return send_error(ctx, GPG_ERR_NO_VALUE);
2019 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2020 return send_error(ctx, rc);
2023 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2024 gpg_error_t *rc, gchar **req_orig, void *data)
2026 gchar *path = *(gchar **)data;
2027 gchar *tmp = NULL, *result;
2029 if (path) {
2030 g_free(path);
2031 *(gchar **)data = NULL;
2034 path = g_strjoinv("\t", target);
2036 if (!path) {
2037 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2038 *rc = gpg_error_from_errno(ENOMEM);
2039 return NULL;
2042 if (req_orig) {
2043 tmp = g_strjoinv("\t", req_orig);
2045 if (!tmp) {
2046 g_free(path);
2047 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2048 *rc = gpg_error_from_errno(ENOMEM);
2049 return NULL;
2053 if (tmp && *tmp)
2054 result = g_strdup_printf("%s\t%s", path, tmp);
2055 else
2056 result = g_strdup(path);
2058 if (!result) {
2059 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2060 *rc = gpg_error_from_errno(ENOMEM);
2061 g_free(path);
2062 g_free(tmp);
2063 return NULL;
2066 g_free(path);
2067 g_free(tmp);
2068 *(gchar **)data = result;
2069 return node;
2072 static void list_command_cleanup1(void *arg);
2073 static gint realpath_command(assuan_context_t ctx, gchar *line)
2075 gpg_error_t rc;
2076 struct client_s *client = assuan_get_pointer(ctx);
2077 gchar **req;
2078 gchar *t;
2079 gint i;
2080 xmlNodePtr n;
2081 GString *string;
2082 gchar *rp = NULL;
2084 log_write2("ARGS=\"%s\"", line);
2086 if (strchr(line, '\t') != NULL) {
2087 if ((req = split_input_line(line, "\t", 0)) == NULL)
2088 return send_error(ctx, GPG_ERR_SYNTAX);
2090 else {
2091 if ((req = split_input_line(line, " ", 0)) == NULL)
2092 return send_error(ctx, GPG_ERR_SYNTAX);
2095 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2097 if (!n) {
2098 g_strfreev(req);
2099 return send_error(ctx, rc);
2102 rp = g_strjoinv("\t", req);
2104 if (!rp) {
2105 g_strfreev(req);
2106 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2107 return send_syserror(ctx, ENOMEM);
2110 if (req[1]) {
2111 n = find_elements(client->doc, n->children, req+1, &rc,
2112 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2114 if (!n) {
2115 g_free(rp);
2116 g_strfreev(req);
2117 return send_error(ctx, rc);
2121 string = g_string_new(rp);
2122 g_free(rp);
2123 g_strfreev(req);
2125 if (!string) {
2126 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2127 return send_syserror(ctx, ENOMEM);
2130 again:
2131 for (i = 0, t = string->str + i; *t; t++, i++) {
2132 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2133 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2134 goto again;
2138 pth_cleanup_push(list_command_cleanup1, string);
2139 rc = xfer_data(ctx, string->str, string->len);
2140 pth_cleanup_pop(1);
2141 return send_error(ctx, rc);
2144 static void list_command_cleanup1(void *arg)
2146 g_string_free((GString *)arg, TRUE);
2149 static void list_command_cleanup2(void *arg)
2151 struct element_list_s *elements = arg;
2153 if (elements) {
2154 if (elements->list) {
2155 gint total = g_slist_length(elements->list);
2156 gint i;
2158 for (i = 0; i < total; i++) {
2159 gchar *tmp = g_slist_nth_data(elements->list, i);
2160 g_free(tmp);
2163 g_slist_free(elements->list);
2166 if (elements->prefix)
2167 g_free(elements->prefix);
2169 if (elements->req)
2170 g_strfreev(elements->req);
2172 g_free(elements);
2176 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2178 struct element_list_s *elements = data;
2180 elements->recurse = FALSE;
2181 return 0;
2184 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2186 struct element_list_s *elements = data;
2188 elements->verbose = TRUE;
2189 return 0;
2192 static gint list_command(assuan_context_t ctx, gchar *line)
2194 struct client_s *client = assuan_get_pointer(ctx);
2195 gpg_error_t rc;
2196 struct element_list_s *elements = NULL;
2197 gchar *tmp;
2198 struct argv_s *args[] = {
2199 &(struct argv_s) { "no-recurse", OPT_NOARG, parse_list_opt_norecurse },
2200 &(struct argv_s) { "verbose", OPT_NOARG, parse_list_opt_verbose },
2201 NULL
2204 if (disable_list_and_dump == TRUE)
2205 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2207 elements = g_malloc0(sizeof(struct element_list_s));
2209 if (!elements) {
2210 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2211 return gpg_err_code_from_errno(ENOMEM);
2214 elements->recurse = TRUE; // default
2215 pth_cleanup_push(list_command_cleanup2, elements);
2216 rc = parse_options(&line, args, elements);
2218 if (rc)
2219 goto fail;
2221 if (!*line) {
2222 GString *str;
2224 rc = list_root_elements(client->doc, &str, elements->verbose);
2226 if (rc) {
2227 pth_cleanup_pop(1);
2228 return send_error(ctx, rc);
2231 pth_cleanup_push(list_command_cleanup1, str);
2232 rc = xfer_data(ctx, str->str, str->len);
2233 pth_cleanup_pop(1);
2234 pth_cleanup_pop(1);
2235 return send_error(ctx, rc);
2238 elements->req = split_input_line(line, " ", 0);
2240 if (!elements->req)
2241 strv_printf(&elements->req, "%s", line);
2243 rc = create_path_list(client->doc, elements, *elements->req);
2245 if (rc)
2246 goto fail;
2248 if (elements) {
2249 gint total = g_slist_length(elements->list);
2250 gint i;
2251 GString *str;
2253 if (!total) {
2254 rc = GPG_ERR_NO_VALUE;
2255 goto fail;
2258 str = g_string_new(NULL);
2260 if (!str) {
2261 rc = gpg_err_code_from_errno(ENOMEM);
2262 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2263 goto fail;
2266 for (i = 0; i < total; i++) {
2267 tmp = g_slist_nth_data(elements->list, i);
2268 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2271 pth_cleanup_push(list_command_cleanup1, str);
2272 rc = xfer_data(ctx, str->str, str->len);
2273 pth_cleanup_pop(1);
2275 else
2276 rc = GPG_ERR_NO_VALUE;
2278 fail:
2279 pth_cleanup_pop(1);
2280 return send_error(ctx, rc);
2284 * req[0] - element path
2286 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2288 struct client_s *client = assuan_get_pointer(ctx);
2289 gchar **attrlist = NULL;
2290 gint i = 0;
2291 gchar **path = NULL;
2292 xmlAttrPtr a;
2293 xmlNodePtr n, an;
2294 gchar *line;
2295 gpg_error_t rc;
2297 if (!req || !req[0])
2298 return GPG_ERR_SYNTAX;
2300 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2302 * The first argument may be only a root element.
2304 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2305 return GPG_ERR_SYNTAX;
2308 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2310 if (!n) {
2311 g_strfreev(path);
2312 return rc;
2315 if (path[1]) {
2316 n = find_elements(client->doc, n->children, path+1, &rc,
2317 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2319 if (!n) {
2320 g_strfreev(path);
2321 return rc;
2325 g_strfreev(path);
2327 for (a = n->properties; a; a = a->next) {
2328 gchar **pa;
2330 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2331 if (attrlist)
2332 g_strfreev(attrlist);
2334 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2335 return gpg_error_from_errno(ENOMEM);
2338 attrlist = pa;
2339 an = a->children;
2340 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2341 an && an->content ? (gchar *)an->content : "");
2343 if (!attrlist[i]) {
2344 g_strfreev(attrlist);
2345 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2346 return gpg_error_from_errno(ENOMEM);
2349 attrlist[++i] = NULL;
2352 if (!attrlist)
2353 return GPG_ERR_NO_VALUE;
2355 line = g_strjoinv("\n", attrlist);
2357 if (!line) {
2358 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2359 g_strfreev(attrlist);
2360 return gpg_error_from_errno(ENOMEM);
2363 pth_cleanup_push(g_free, line);
2364 pth_cleanup_push(req_cleanup, attrlist);
2365 rc = xfer_data(ctx, line, strlen(line));
2366 pth_cleanup_pop(1);
2367 pth_cleanup_pop(1);
2368 return rc;
2372 * req[0] - attribute
2373 * req[1] - element path
2375 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2377 xmlNodePtr n;
2378 gchar **path = NULL;
2379 gpg_error_t rc;
2381 if (!req || !req[0] || !req[1])
2382 return GPG_ERR_SYNTAX;
2384 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2386 * The first argument may be only a root element.
2388 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2389 return GPG_ERR_SYNTAX;
2393 * Don't remove the "_name" attribute for the root element. To remove an
2394 * root element use DELETE <name>.
2396 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2397 rc = GPG_ERR_SYNTAX;
2398 goto fail;
2401 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2403 if (!n)
2404 goto fail;
2406 if (path[1]) {
2407 n = find_elements(client->doc, n->children, path+1, &rc,
2408 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2410 if (!n)
2411 goto fail;
2414 rc = delete_attribute(n, (xmlChar *)req[0]);
2416 fail:
2417 g_strfreev(path);
2418 return rc;
2421 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2422 gpg_error_t *rc)
2424 gchar **src = *path;
2425 gchar **src_orig = g_strdupv(src);
2426 xmlNodePtr n = NULL;
2428 *rc = 0;
2430 if (!src_orig) {
2431 *rc = gpg_error_from_errno(ENOMEM);
2432 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2433 goto fail;
2436 again:
2437 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2439 if (!n) {
2440 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2441 *rc = new_root_element(client->doc, src[0]);
2443 if (*rc)
2444 goto fail;
2446 goto again;
2448 else
2449 goto fail;
2452 if (src[1]) {
2453 if (!n->children)
2454 n = create_target_elements_cb(n, src+1, rc, NULL);
2455 else
2456 n = find_elements(client->doc, n->children, src+1, rc,
2457 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2459 if (!n)
2460 goto fail;
2463 * Reset the position of the element tree now that the elements
2464 * have been created.
2466 g_strfreev(src);
2467 src = src_orig;
2468 src_orig = NULL;
2469 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2471 if (!n)
2472 goto fail;
2474 n = find_elements(client->doc, n->children, src+1, rc,
2475 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2477 if (!n)
2478 goto fail;
2481 fail:
2482 if (src_orig)
2483 g_strfreev(src_orig);
2485 *path = src;
2486 return n;
2490 * Creates a "target" attribute. When other commands encounter an element with
2491 * this attribute, the element path is modified to the target value. If the
2492 * source element path doesn't exist when using 'ATTR SET target', it is
2493 * created, but the destination element path must exist.
2495 * req[0] - source element path
2496 * req[1] - destination element path
2498 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2500 gchar **src, **dst, *line = NULL, **odst = NULL;
2501 gpg_error_t rc;
2502 xmlNodePtr n;
2504 if (!req || !req[0] || !req[1])
2505 return GPG_ERR_SYNTAX;
2507 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2509 * The first argument may be only a root element.
2511 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2512 return GPG_ERR_SYNTAX;
2515 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2517 * The first argument may be only a root element.
2519 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2520 rc = GPG_ERR_SYNTAX;
2521 goto fail;
2525 odst = g_strdupv(dst);
2527 if (!odst) {
2528 rc = gpg_error_from_errno(ENOMEM);
2529 goto fail;
2532 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2535 * Make sure the destination element path exists.
2537 if (!n)
2538 goto fail;
2540 if (dst[1]) {
2541 n = find_elements(client->doc, n->children, dst+1, &rc,
2542 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2544 if (!n)
2545 goto fail;
2548 n = create_element_path(client, &src, &rc);
2550 if (rc)
2551 goto fail;
2553 line = g_strjoinv("\t", odst);
2555 if (!line) {
2556 rc = gpg_error_from_errno(ENOMEM);
2557 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2558 goto fail;
2561 rc = add_attribute(n, "target", line);
2563 fail:
2564 g_free(line);
2565 g_strfreev(src);
2566 g_strfreev(dst);
2567 g_strfreev(odst);
2568 return rc;
2572 * req[0] - name
2573 * req[1] - new name
2575 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2577 gpg_error_t rc;
2578 gchar **tmp;
2579 xmlNodePtr n;
2581 tmp = g_strdupv(req);
2583 if (!tmp) {
2584 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2585 return gpg_error_from_errno(ENOMEM);
2588 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2589 g_strfreev(tmp);
2591 if (!n)
2592 return rc;
2594 if (g_utf8_collate(req[0], req[1]) == 0)
2595 return 0;
2598 * Will not overwrite an existing root.
2600 tmp = g_strdupv(req+1);
2602 if (!tmp) {
2603 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2604 return gpg_error_from_errno(ENOMEM);
2607 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2608 g_strfreev(tmp);
2610 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2611 return rc;
2613 if (n)
2614 return GPG_ERR_AMBIGUOUS_NAME;
2617 * Whitespace not allowed in root names.
2619 if (contains_whitespace(req[1]) == TRUE)
2620 return GPG_ERR_SYNTAX;
2622 tmp = g_strdupv(req);
2624 if (!tmp) {
2625 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2626 return gpg_error_from_errno(ENOMEM);
2629 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2630 g_strfreev(tmp);
2632 if (!n)
2633 return GPG_ERR_ELEMENT_NOT_FOUND;
2635 return add_attribute(n, "_name", req[1]);
2639 * req[0] - attribute
2640 * req[1] - element path
2642 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2644 struct client_s *client = assuan_get_pointer(ctx);
2645 xmlNodePtr n;
2646 xmlChar *a;
2647 gchar **path= NULL;
2648 gpg_error_t rc;
2650 if (!req || !req[0] || !req[1])
2651 return GPG_ERR_SYNTAX;
2653 if (strchr(req[1], '\t')) {
2654 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2655 return GPG_ERR_SYNTAX;
2657 else {
2658 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2659 return GPG_ERR_SYNTAX;
2662 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2664 if (!n)
2665 goto fail;
2667 if (path[1]) {
2668 n = find_elements(client->doc, n->children, path+1, &rc,
2669 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2671 if (!n)
2672 goto fail;
2675 g_strfreev(path);
2677 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2678 return GPG_ERR_NOT_FOUND;
2680 pth_cleanup_push(xmlFree, a);
2682 if (*a)
2683 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2684 else
2685 rc = GPG_ERR_NO_VALUE;
2687 pth_cleanup_pop(1);
2688 return rc;
2690 fail:
2691 g_strfreev(path);
2692 return rc;
2696 * req[0] - attribute
2697 * req[1] - element path
2698 * req[2] - value
2700 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2702 gchar **path = NULL;
2703 gpg_error_t rc;
2704 xmlNodePtr n;
2706 if (!req || !req[0] || !req[1])
2707 return GPG_ERR_SYNTAX;
2710 * Reserved attribute names.
2712 if (!strcmp(req[0], "_name")) {
2714 * Only reserved for the root element. Not the rest of the
2715 * document.
2717 if (strchr(req[1], '\t') == NULL)
2718 return name_attribute(client, req + 1);
2720 else if (!strcmp(req[0], "target"))
2721 return target_attribute(client, req + 1);
2723 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2725 * The first argument may be only a root element.
2727 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2728 return GPG_ERR_SYNTAX;
2731 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2733 if (!n)
2734 goto fail;
2736 if (path[1]) {
2737 n = find_elements(client->doc, n->children, path+1, &rc,
2738 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2740 if (!n)
2741 goto fail;
2744 rc = add_attribute(n, req[0], req[2]);
2746 fail:
2747 g_strfreev(path);
2748 return rc;
2752 * req[0] - command
2753 * req[1] - attribute name or element path if command is LIST
2754 * req[2] - element path
2755 * req[2] - element path or value
2757 static gint attr_command(assuan_context_t ctx, gchar *line)
2759 struct client_s *client = assuan_get_pointer(ctx);
2760 gchar **req;
2761 gpg_error_t rc = 0;
2763 log_write2("ARGS=\"%s\"", line);
2764 req = split_input_line(line, " ", 4);
2766 if (!req || !req[0] || !req[1]) {
2767 g_strfreev(req);
2768 return send_error(ctx, GPG_ERR_SYNTAX);
2771 pth_cleanup_push(req_cleanup, req);
2773 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2774 rc = attribute_set(client, req+1);
2775 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2776 rc = attribute_get(ctx, req+1);
2777 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2778 rc = attribute_delete(client, req+1);
2779 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2780 rc = attribute_list(ctx, req+1);
2781 else
2782 rc = GPG_ERR_SYNTAX;
2784 pth_cleanup_pop(1);
2785 return send_error(ctx, rc);
2788 static gint iscached_command(assuan_context_t ctx, gchar *line)
2790 gchar **req = split_input_line(line, " ", 0);
2791 guchar md5file[16];
2792 gchar *path, *tmp;
2794 if (!req || !*req) {
2795 g_strfreev(req);
2796 return send_error(ctx, GPG_ERR_SYNTAX);
2799 log_write2("ARGS=\"%s\"", line);
2801 if (!valid_filename(req[0])) {
2802 g_strfreev(req);
2803 return GPG_ERR_INV_VALUE;
2806 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2807 CACHE_LOCK(ctx);
2809 if (cache_iscached(md5file)) {
2810 g_strfreev(req);
2811 CACHE_UNLOCK;
2812 return send_error(ctx, 0);
2815 CACHE_UNLOCK;
2816 tmp = get_key_file_string("global", "data_directory");
2818 if (!tmp) {
2819 g_strfreev(req);
2820 return gpg_error_from_errno(ENOMEM);
2823 path = expand_homedir(tmp);
2825 if (!path) {
2826 g_strfreev(req);
2827 g_free(tmp);
2828 return gpg_error_from_errno(ENOMEM);
2831 g_free(tmp);
2832 tmp = path;
2833 path = g_strdup_printf("%s/%s", tmp, req[0]);
2834 g_free(tmp);
2836 if (!path) {
2837 g_strfreev(req);
2838 return gpg_error_from_errno(ENOMEM);
2841 if (access(path, R_OK) == -1) {
2842 gpg_error_t rc = gpg_error_from_syserror();
2844 g_free(path);
2845 g_strfreev(req);
2846 return send_error(ctx, rc);
2849 g_free(path);
2850 return send_error(ctx, GPG_ERR_NOT_FOUND);
2853 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2855 struct client_s *client = assuan_get_pointer(ctx);
2856 gchar **req = split_input_line(line, " ", 0);
2857 guchar md5file[16];
2859 log_write2("ARGS=\"%s\"", line);
2860 CACHE_LOCK(ctx);
2862 if (!req || !*req) {
2863 g_strfreev(req);
2864 cache_clear(client->md5file, 2);
2865 CACHE_UNLOCK;
2866 return send_error(ctx, 0);
2869 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2870 g_strfreev(req);
2872 if (cache_clear(md5file, 1) == FALSE) {
2873 CACHE_UNLOCK;
2874 return send_error(ctx, GPG_ERR_NOT_FOUND);
2877 CACHE_UNLOCK;
2878 return send_error(ctx, 0);
2881 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2883 guchar md5file[16];
2884 glong timeout;
2885 gchar **req = split_input_line(line, " ", 0);
2886 gchar *p;
2888 if (!req || !*req || !req[1]) {
2889 g_strfreev(req);
2890 return send_error(ctx, GPG_ERR_SYNTAX);
2893 errno = 0;
2894 timeout = strtol(req[1], &p, 10);
2896 if (errno != 0 || *p != 0 || timeout < -1) {
2897 g_strfreev(req);
2898 return send_error(ctx, GPG_ERR_SYNTAX);
2901 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2902 CACHE_LOCK(client->ctx);
2904 if (cache_set_timeout(md5file, timeout) == FALSE) {
2905 CACHE_UNLOCK;
2906 return send_error(ctx, GPG_ERR_NOT_FOUND);
2909 CACHE_UNLOCK;
2910 return send_error(ctx, 0);
2913 static gint dump_command(assuan_context_t ctx, gchar *line)
2915 xmlChar *xml;
2916 gint len;
2917 struct client_s *client = assuan_get_pointer(ctx);
2918 gpg_error_t rc;
2920 if (disable_list_and_dump == TRUE)
2921 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2923 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2925 if (!xml) {
2926 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2927 return send_syserror(ctx, ENOMEM);
2930 pth_cleanup_push(xmlFree, xml);
2931 rc = xfer_data(ctx, (gchar *)xml, len);
2932 pth_cleanup_pop(1);
2933 return send_error(ctx, rc);
2936 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2938 struct client_s *client = assuan_get_pointer(ctx);
2939 gpg_error_t rc = 0;
2940 gchar filename[255]={0}, param[747]={0};
2941 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2943 log_write2("ARGS=\"%s\"", line);
2945 if (strchr(line, ' ')) {
2946 sscanf(line, " %254[^ ] %746c", filename, param);
2947 paramp = param;
2948 fp = filename;
2951 if (fp && !valid_filename(fp))
2952 return send_error(ctx, GPG_ERR_INV_VALUE);
2954 paramp = g_ascii_strdown(paramp, -1);
2956 if (!paramp) {
2957 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
2958 return send_syserror(ctx, ENOMEM);
2961 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2962 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2963 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2965 if (!fh && rc != GPG_ERR_ENOENT)
2966 return send_error(ctx, rc);
2968 if (!rc) {
2969 g_free(paramp);
2970 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2971 close_file_header(fh);
2973 if (!p) {
2974 log_write("%s(%i): %s", __FILE__, __LINE__,
2975 strerror(ENOMEM));
2976 return send_syserror(ctx, ENOMEM);
2979 goto done;
2983 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2984 #ifdef WITH_PINENTRY
2985 gboolean n;
2987 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2988 n = client->pinentry->enable;
2989 else
2990 n = get_key_file_boolean(fp, "enable_pinentry");
2992 p = g_strdup_printf("%s", n ? "true" : "false");
2994 if (!p) {
2995 log_write("%s(%i): %s", __FILE__, __LINE__,
2996 strerror(ENOMEM));
2997 return send_syserror(ctx, ENOMEM);
3000 goto done;
3001 #else
3002 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3003 #endif
3005 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3006 #ifdef WITH_PINENTRY
3007 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3009 if (!p) {
3010 log_write("%s(%i): %s", __FILE__, __LINE__,
3011 strerror(ENOMEM));
3012 return send_syserror(ctx, ENOMEM);
3015 goto done;
3016 #else
3017 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3018 #endif
3021 p = get_key_file_string(fp ? fp : "global", paramp);
3022 g_free(paramp);
3024 if (!p)
3025 return send_error(ctx, GPG_ERR_NO_VALUE);
3027 tmp = expand_homedir(p);
3028 g_free(p);
3030 if (!tmp) {
3031 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3032 return send_syserror(ctx, ENOMEM);
3035 p = tmp;
3036 done:
3037 pth_cleanup_push(g_free, p);
3038 rc = xfer_data(ctx, p, strlen(p));
3039 pth_cleanup_pop(1);
3040 return send_error(ctx, rc);
3043 struct xpath_s {
3044 xmlXPathContextPtr xp;
3045 xmlXPathObjectPtr result;
3046 xmlBufferPtr buf;
3047 gchar **req;
3050 static void xpath_command_cleanup(void *arg)
3052 struct xpath_s *xpath = arg;
3054 req_cleanup(xpath->req);
3056 if (xpath->buf)
3057 xmlBufferFree(xpath->buf);
3059 if (xpath->result)
3060 xmlXPathFreeObject(xpath->result);
3062 if (xpath->xp)
3063 xmlXPathFreeContext(xpath->xp);
3066 static gint xpath_command(assuan_context_t ctx, gchar *line)
3068 struct client_s *client = assuan_get_pointer(ctx);
3069 gpg_error_t rc;
3070 struct xpath_s xpath;
3072 log_write2("ARGS=\"%s\"", line);
3074 if (disable_list_and_dump == TRUE)
3075 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3077 if (!line || !*line)
3078 return send_error(ctx, GPG_ERR_SYNTAX);
3080 memset(&xpath, 0, sizeof(struct xpath_s));
3082 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3083 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3084 return send_syserror(ctx, ENOMEM);
3087 xpath.xp = xmlXPathNewContext(client->doc);
3089 if (!xpath.xp) {
3090 xpath_command_cleanup(&xpath);
3091 return send_error(ctx, EPWMD_LIBXML_ERROR);
3094 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3096 if (!xpath.result) {
3097 xpath_command_cleanup(&xpath);
3098 return send_error(ctx, EPWMD_LIBXML_ERROR);
3101 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3102 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3103 goto fail;
3106 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3107 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3109 if (rc)
3110 goto fail;
3111 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3112 rc = GPG_ERR_NO_VALUE;
3113 goto fail;
3115 else if (xpath.req[1])
3116 goto fail;
3118 pth_cleanup_push(xpath_command_cleanup, &xpath);
3119 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3120 xmlBufferLength(xpath.buf));
3121 pth_cleanup_pop(0);
3123 fail:
3124 xpath_command_cleanup(&xpath);
3125 return send_error(ctx, rc);
3128 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3129 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3131 struct client_s *client = assuan_get_pointer(ctx);
3132 gpg_error_t rc;
3133 struct xpath_s xpath;
3134 gchar **req = NULL;
3135 gboolean cmd = FALSE; //SET
3137 log_write2("ARGS=\"%s\"", line);
3139 if (disable_list_and_dump == TRUE)
3140 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3142 if (!line || !*line)
3143 return send_error(ctx, GPG_ERR_SYNTAX);
3145 memset(&xpath, 0, sizeof(struct xpath_s));
3147 if ((req = split_input_line(line, " ", 3)) == NULL)
3148 return send_syserror(ctx, ENOMEM);
3150 if (!req[0]) {
3151 rc = GPG_ERR_SYNTAX;
3152 goto fail;
3155 if (!g_ascii_strcasecmp(req[0], "SET"))
3156 cmd = FALSE;
3157 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3158 cmd = TRUE;
3159 else {
3160 rc = GPG_ERR_SYNTAX;
3161 goto fail;
3164 if (!req[1] || !req[2]) {
3165 rc = GPG_ERR_SYNTAX;
3166 goto fail;
3169 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3170 rc = gpg_err_code_from_errno(ENOMEM);
3171 goto fail;
3174 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3175 rc = GPG_ERR_SYNTAX;
3176 goto fail;
3179 xpath.xp = xmlXPathNewContext(client->doc);
3181 if (!xpath.xp) {
3182 rc = EPWMD_LIBXML_ERROR;
3183 goto fail;
3186 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3188 if (!xpath.result) {
3189 rc = EPWMD_LIBXML_ERROR;
3190 goto fail;
3193 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3194 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3195 goto fail;
3198 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3199 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3201 fail:
3202 g_strfreev(req);
3203 xpath_command_cleanup(&xpath);
3204 return send_error(ctx, rc);
3207 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3208 gsize len)
3210 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3211 gpg_error_t rc = file_modified(client);
3212 gchar **req, **path = NULL, **path_orig = NULL, *content;
3213 xmlDocPtr doc = NULL;
3214 xmlNodePtr n, root, copy;
3216 if (assuan_rc || rc) {
3217 if (line)
3218 xfree(line);
3219 return assuan_rc ? assuan_rc : rc;
3222 req = split_input_line((gchar *)line, "\t", 2);
3223 xfree(line);
3225 if (!req || !*req)
3226 return GPG_ERR_SYNTAX;
3228 content = req[0];
3229 path = split_input_line(req[1], "\t", 0);
3231 if (!content || !*content) {
3232 rc = GPG_ERR_SYNTAX;
3233 goto fail;
3236 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3238 if (!doc) {
3239 rc = EPWMD_LIBXML_ERROR;
3240 goto fail;
3243 root = xmlDocGetRootElement(doc);
3244 rc = validate_import(root);
3246 if (rc)
3247 goto fail;
3249 if (path) {
3250 path_orig = g_strdupv(path);
3252 if (!path_orig) {
3253 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
3254 rc = gpg_error_from_errno(ENOMEM);
3255 goto fail;
3258 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3260 if (!a) {
3261 g_strfreev(path_orig);
3262 rc = gpg_error_from_errno(ENOMEM);
3263 goto fail;
3266 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3267 xmlFree(a);
3268 g_strfreev(path_orig);
3269 rc = gpg_error_from_errno(ENOMEM);
3270 goto fail;
3273 xmlFree(a);
3274 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3276 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3277 g_strfreev(path_orig);
3278 goto fail;
3281 if (!rc) {
3282 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3284 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3285 g_strfreev(path_orig);
3286 goto fail;
3288 else if (!rc) {
3289 xmlNodePtr parent = n->parent;
3291 xmlUnlinkNode(n);
3292 xmlFreeNode(n);
3293 n = parent;
3297 g_strfreev(path);
3298 path = path_orig;
3300 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3301 n = create_element_path(client, &path, &rc);
3303 if (rc)
3304 goto fail;
3307 copy = xmlCopyNodeList(root);
3308 n = xmlAddChildList(n, copy);
3310 if (!n)
3311 rc = EPWMD_LIBXML_ERROR;
3313 else {
3314 /* Check if the content root element can create a DTD root element. */
3315 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3316 rc = GPG_ERR_SYNTAX;
3317 goto fail;
3320 xmlChar *a;
3322 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3323 rc = GPG_ERR_SYNTAX;
3324 goto fail;
3327 gchar *tmp = g_strdup((gchar *)a);
3328 xmlFree(a);
3329 gboolean literal = is_literal_element(&tmp);
3331 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3332 g_free(tmp);
3333 rc = GPG_ERR_INV_VALUE;
3334 goto fail;
3337 if (strv_printf(&path, "%s", tmp) == FALSE) {
3338 g_free(tmp);
3339 rc = gpg_error_from_errno(ENOMEM);
3340 goto fail;
3343 g_free(tmp);
3344 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3346 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3347 rc = EPWMD_LIBXML_ERROR;
3348 goto fail;
3351 /* Overwriting the existing tree. */
3352 if (!rc) {
3353 xmlUnlinkNode(n);
3354 xmlFreeNodeList(n);
3357 rc = 0;
3358 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3359 n = xmlCopyNode(root, 1);
3360 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3363 if (n && !rc)
3364 rc = update_element_mtime(n->parent);
3366 fail:
3367 if (doc)
3368 xmlFreeDoc(doc);
3370 if (path)
3371 g_strfreev(path);
3373 g_strfreev(req);
3374 client->inquire_status = INQUIRE_DONE;
3375 return rc;
3378 static gint import_command(assuan_context_t ctx, gchar *line)
3380 gpg_error_t rc;
3381 struct client_s *client = assuan_get_pointer(ctx);
3383 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3385 if (rc)
3386 return send_error(ctx, rc);
3388 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3389 client->inquire_status = INQUIRE_BUSY;
3390 return 0;
3393 static gpg_error_t do_lock_command(struct client_s *client)
3395 gpg_error_t rc = lock_file_mutex(client);
3397 if (!rc)
3398 client->is_lock_cmd = TRUE;
3400 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3403 static gint lock_command(assuan_context_t ctx, gchar *line)
3405 struct client_s *client = assuan_get_pointer(ctx);
3407 return do_lock_command(client);
3410 static gint unlock_command(assuan_context_t ctx, gchar *line)
3412 struct client_s *client = assuan_get_pointer(ctx);
3414 unlock_file_mutex(client);
3415 return send_error(ctx, 0);
3418 static gint getpid_command(assuan_context_t ctx, gchar *line)
3420 gpg_error_t rc;
3421 gchar buf[32];
3422 pid_t pid = getpid();
3424 print_fmt(buf, sizeof(buf), "%i", pid);
3425 rc = xfer_data(ctx, buf, strlen(buf));
3426 return send_error(ctx, rc);
3429 static gint version_command(assuan_context_t ctx, gchar *line)
3431 gpg_error_t rc;
3432 gchar buf[32];
3434 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3435 rc = xfer_data(ctx, buf, strlen(buf));
3436 return send_error(ctx, rc);
3439 #ifdef WITH_PINENTRY
3440 static void set_option_value(gchar **opt, const gchar *value)
3442 if (opt)
3443 g_free(*opt);
3445 *opt = NULL;
3447 if (value)
3448 *opt = g_strdup(value);
3450 #endif
3452 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3453 const gchar *value)
3455 struct client_s *client = assuan_get_pointer(ctx);
3456 gpg_error_t rc;
3458 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3459 glong l = 0;
3461 if (value) {
3462 l = strtol(value, NULL, 10);
3464 if (l < 0 || l > 2)
3465 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3468 MUTEX_LOCK(&rcfile_mutex);
3469 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3470 MUTEX_UNLOCK(&rcfile_mutex);
3471 goto done;
3473 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3474 glong l = 0;
3476 if (value) {
3477 l = strtol(value, NULL, 10);
3479 if (l < 0 || l > 1)
3480 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3483 client->rc_on_locked = l ? TRUE : FALSE;
3484 goto done;
3486 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3487 rc = parse_open_opt_lock(client, (gpointer)value);
3489 if (rc)
3490 return rc;
3492 client->opts |= OPT_LOCK;
3494 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3495 if (!value) {
3496 client->opts &= ~(OPT_CIPHER);
3497 goto done;
3500 rc = parse_save_opt_cipher(client, (gpointer)value);
3502 if (rc)
3503 return rc;
3505 client->opts |= OPT_CIPHER;
3506 goto done;
3508 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3509 rc = parse_save_opt_iterations(client, (gpointer)value);
3511 if (rc)
3512 return rc;
3514 goto done;
3516 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3517 pth_attr_t attr = pth_attr_of(pth_self());
3518 gchar buf[41];
3520 if (!value) {
3521 pth_attr_destroy(attr);
3522 goto done;
3525 print_fmt(buf, sizeof(buf), "%s", value);
3526 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3527 pth_attr_destroy(attr);
3528 #ifdef WITH_PINENTRY
3529 if (client->pinentry->name)
3530 g_free(client->pinentry->name);
3532 client->pinentry->name = g_strdup(buf);
3534 if (!client->pinentry->name)
3535 return gpg_error_from_errno(ENOMEM);
3536 #endif
3538 goto done;
3540 #ifdef WITH_PINENTRY
3541 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3542 set_option_value(&client->pinentry->lcmessages, value);
3543 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3544 set_option_value(&client->pinentry->lcctype, value);
3545 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3546 set_option_value(&client->pinentry->ttyname, value);
3547 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3548 set_option_value(&client->pinentry->ttytype, value);
3549 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3550 set_option_value(&client->pinentry->display, value);
3551 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3552 set_option_value(&client->pinentry->path, value);
3553 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3554 set_option_value(&client->pinentry->title, value);
3555 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3556 set_option_value(&client->pinentry->prompt, value);
3557 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3558 set_option_value(&client->pinentry->desc, value);
3559 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3560 gchar *p = NULL;
3561 gint n;
3563 if (!value)
3564 goto done;
3566 n = strtol(value, &p, 10);
3568 if (*p || n < 0)
3569 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3571 MUTEX_LOCK(&rcfile_mutex);
3572 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3573 "global", "pinentry_timeout", n);
3574 MUTEX_UNLOCK(&rcfile_mutex);
3575 goto done;
3577 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3578 rc = parse_opt_pinentry(client, (gpointer)value);
3580 if (rc)
3581 return rc;
3583 goto done;
3585 #endif
3586 else
3587 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3589 done:
3590 return 0;
3593 static gint unset_command(assuan_context_t ctx, gchar *line)
3595 log_write2("ARGS=\"%s\"", line);
3596 return send_error(ctx, set_unset_common(ctx, line, NULL));
3599 static gint set_command(assuan_context_t ctx, gchar *line)
3601 gchar name[64] = {0}, value[256] = {0};
3603 log_write2("ARGS=\"%s\"", line);
3605 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3606 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3608 return send_error(ctx, set_unset_common(ctx, name, value));
3611 static gint rename_command(assuan_context_t ctx, gchar *line)
3613 struct client_s *client = assuan_get_pointer(ctx);
3614 gpg_error_t rc;
3615 gchar **req, **src, *dst;
3616 xmlNodePtr n, ndst;
3618 log_write2("ARGS=\"%s\"", line);
3619 req = split_input_line(line, " ", -1);
3621 if (!req || !req[0] || !req[1]) {
3622 g_strfreev(req);
3623 return send_error(ctx, GPG_ERR_SYNTAX);
3626 dst = req[1];
3627 is_literal_element(&dst);
3629 if (!valid_xml_element((xmlChar *)dst)) {
3630 g_strfreev(req);
3631 return GPG_ERR_INV_VALUE;
3634 if (strchr(req[0], '\t'))
3635 src = split_input_line(req[0], "\t", -1);
3636 else
3637 src = split_input_line(req[0], " ", -1);
3639 if (!src || !*src) {
3640 rc = GPG_ERR_SYNTAX;
3641 goto fail;
3644 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3646 if (src[1] && n)
3647 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3648 NULL, FALSE, 0, NULL, FALSE);
3650 if (!n)
3651 goto fail;
3654 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3656 if (!a) {
3657 rc = gpg_error_from_errno(ENOMEM);
3658 goto fail;
3661 /* To prevent unwanted effects:
3663 * <root name="a"><b/></root>
3665 * RENAME a<TAB>b b
3667 if (xmlStrEqual(a, (xmlChar *)dst)) {
3668 xmlFree(a);
3669 rc = GPG_ERR_AMBIGUOUS_NAME;
3670 goto fail;
3673 xmlFree(a);
3674 gchar **tmp = NULL;
3676 if (src[1]) {
3677 gchar **p;
3679 for (p = src; *p; p++) {
3680 if (!*(p+1))
3681 break;
3683 strv_printf(&tmp, "%s", *p);
3687 strv_printf(&tmp, "!%s", dst);
3688 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3690 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3691 g_strfreev(tmp);
3692 goto fail;
3695 if (tmp[1] && ndst)
3696 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3697 NULL, NULL, FALSE, 0, NULL, FALSE);
3699 g_strfreev(tmp);
3701 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3702 goto fail;
3704 rc = 0;
3706 /* Target may exist:
3708 * <root name="a"/>
3709 * <root name="b" target="a"/>
3711 * RENAME b a
3713 * Would need to do:
3714 * RENAME !b a
3716 if (ndst == n) {
3717 rc = GPG_ERR_AMBIGUOUS_NAME;
3718 goto fail;
3721 if (ndst) {
3722 unlink_node(ndst);
3723 xmlFreeNodeList(ndst);
3726 rc = add_attribute(n, "_name", dst);
3728 fail:
3729 g_strfreev(req);
3730 g_strfreev(src);
3731 return send_error(ctx, rc);
3734 static gint copy_command(assuan_context_t ctx, gchar *line)
3736 struct client_s *client = assuan_get_pointer(ctx);
3737 gpg_error_t rc;
3738 gchar **req, **src = NULL, **dst = NULL;
3739 xmlNodePtr nsrc, ndst, new;
3741 log_write2("ARGS=\"%s\"", line);
3742 req = split_input_line(line, " ", -1);
3744 if (!req || !req[0] || !req[1]) {
3745 g_strfreev(req);
3746 return send_error(ctx, GPG_ERR_SYNTAX);
3749 if (strchr(req[0], '\t'))
3750 src = split_input_line(req[0], "\t", -1);
3751 else
3752 src = split_input_line(req[0], " ", -1);
3754 if (!src || !*src) {
3755 rc = GPG_ERR_SYNTAX;
3756 goto fail;
3759 if (strchr(req[1], '\t'))
3760 dst = split_input_line(req[1], "\t", -1);
3761 else
3762 dst = split_input_line(req[1], " ", -1);
3764 if (!dst || !*dst) {
3765 rc = GPG_ERR_SYNTAX;
3766 goto fail;
3769 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3771 if (nsrc && src[1])
3772 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3773 NULL, NULL, FALSE, 0, NULL, FALSE);
3775 if (!nsrc)
3776 goto fail;
3778 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3780 if (ndst && dst[1])
3781 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3782 NULL, NULL, FALSE, 0, NULL, FALSE);
3784 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3785 goto fail;
3787 new = xmlCopyNodeList(nsrc);
3789 if (!new) {
3790 rc = GPG_ERR_ENOMEM;
3791 goto fail;
3794 if (!ndst)
3795 ndst = create_element_path(client, &dst, &rc);
3797 if (!ndst) {
3798 xmlUnlinkNode(new);
3799 xmlFreeNodeList(new);
3800 goto fail;
3803 /* Merge any attributes from the src node to the initial dst node. */
3804 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3805 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3806 continue;
3808 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3810 if (a)
3811 xmlRemoveProp(a);
3813 xmlChar *tmp = xmlNodeGetContent(attr->children);
3814 xmlNewProp(ndst, attr->name, tmp);
3815 xmlFree(tmp);
3816 rc = add_attribute(ndst, NULL, NULL);
3819 xmlNodePtr n = ndst->children;
3820 xmlUnlinkNode(n);
3821 xmlFreeNodeList(n);
3822 ndst->children = NULL;
3824 if (!new->children) {
3825 xmlUnlinkNode(new);
3826 xmlFreeNodeList(new);
3827 goto fail;
3830 n = xmlCopyNodeList(new->children);
3832 if (!n) {
3833 rc = GPG_ERR_ENOMEM;
3834 goto fail;
3837 xmlUnlinkNode(new);
3838 xmlFreeNodeList(new);
3839 n = xmlAddChildList(ndst, n);
3841 if (!n) {
3842 rc = GPG_ERR_ENOMEM;
3843 goto fail;
3846 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3848 fail:
3849 if (req)
3850 g_strfreev(req);
3852 if (src)
3853 g_strfreev(src);
3855 if (dst)
3856 g_strfreev(dst);
3858 return send_error(ctx, rc);
3861 static gint move_command(assuan_context_t ctx, gchar *line)
3863 struct client_s *client = assuan_get_pointer(ctx);
3864 gpg_error_t rc;
3865 gchar **req, **src = NULL, **dst = NULL;
3866 xmlNodePtr nsrc, ndst = NULL;
3868 log_write2("ARGS=\"%s\"", line);
3869 req = split_input_line(line, " ", -1);
3871 if (!req || !req[0] || !req[1]) {
3872 g_strfreev(req);
3873 return send_error(ctx, GPG_ERR_SYNTAX);
3876 if (strchr(req[0], '\t'))
3877 src = split_input_line(req[0], "\t", -1);
3878 else
3879 src = split_input_line(req[0], " ", -1);
3881 if (!src || !*src) {
3882 rc = GPG_ERR_SYNTAX;
3883 goto fail;
3886 if (strchr(req[1], '\t'))
3887 dst = split_input_line(req[1], "\t", -1);
3888 else
3889 dst = split_input_line(req[1], " ", -1);
3891 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3893 if (nsrc && src[1])
3894 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3895 NULL, NULL, FALSE, 0, NULL, FALSE);
3897 if (!nsrc)
3898 goto fail;
3900 if (dst) {
3901 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3903 if (ndst && dst[1])
3904 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3905 NULL, NULL, FALSE, 0, NULL, FALSE);
3907 else
3908 ndst = xmlDocGetRootElement(client->doc);
3910 for (xmlNodePtr n = ndst; n; n = n->parent) {
3911 if (n == nsrc) {
3912 rc = GPG_ERR_CONFLICT;
3913 goto fail;
3917 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3918 goto fail;
3920 rc = 0;
3922 if (ndst) {
3923 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3924 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3926 xmlFree(a);
3928 if (dup) {
3929 if (dup == nsrc)
3930 goto fail;
3932 if (ndst == xmlDocGetRootElement(client->doc)) {
3933 xmlNodePtr n = nsrc;
3934 gboolean match = FALSE;
3936 while (n->parent && n->parent != ndst)
3937 n = n->parent;
3939 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3940 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3942 if (xmlStrEqual(a, b)) {
3943 match = TRUE;
3944 xmlUnlinkNode(nsrc);
3945 xmlUnlinkNode(n);
3946 xmlFreeNodeList(n);
3949 xmlFree(a);
3950 xmlFree(b);
3952 if (!match) {
3953 xmlUnlinkNode(dup);
3954 xmlFreeNodeList(dup);
3957 else
3958 xmlUnlinkNode(dup);
3962 if (!ndst && dst)
3963 ndst = create_element_path(client, &dst, &rc);
3965 if (!ndst)
3966 goto fail;
3968 update_element_mtime(nsrc->parent);
3969 xmlUnlinkNode(nsrc);
3970 ndst = xmlAddChildList(ndst, nsrc);
3972 if (!ndst)
3973 rc = GPG_ERR_ENOMEM;
3975 update_element_mtime(ndst->parent);
3977 fail:
3978 if (req)
3979 g_strfreev(req);
3981 if (src)
3982 g_strfreev(src);
3984 if (dst)
3985 g_strfreev(dst);
3987 return send_error(ctx, rc);
3990 static int ls_command(assuan_context_t ctx, gchar *line)
3992 log_write2("ARGS=\"%s\"", line);
3993 gpg_error_t rc;
3994 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
3995 gchar *dir = expand_homedir(tmp);
3996 DIR *d = opendir(dir);
3997 gint n = errno;
3999 g_free(tmp);
4001 if (!d) {
4002 g_free(dir);
4003 return send_syserror(ctx, n);
4006 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4007 struct dirent *p = g_malloc(len), *cur = NULL;
4008 gchar *list = NULL;
4010 g_free(dir);
4011 rc = 0;
4013 while (!readdir_r(d, p, &cur) && cur) {
4014 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4015 continue;
4016 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4017 continue;
4019 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4021 if (!tmp) {
4022 if (list)
4023 g_free(list);
4025 rc = GPG_ERR_ENOMEM;
4026 break;
4029 g_free(list);
4030 list = tmp;
4033 closedir(d);
4034 g_free(p);
4036 if (rc)
4037 return send_error(ctx, rc);
4039 if (!list)
4040 return send_error(ctx, GPG_ERR_NO_VALUE);
4042 list[strlen(list)-1] = 0;
4043 rc = xfer_data(ctx, list, strlen(list));
4044 g_free(list);
4045 return send_error(ctx, rc);
4048 static void bye_notify(assuan_context_t ctx)
4050 struct client_s *cl = assuan_get_pointer(ctx);
4052 /* This will let assuan_process_next() return. */
4053 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4056 static void reset_notify(assuan_context_t ctx)
4058 struct client_s *cl = assuan_get_pointer(ctx);
4060 if (cl)
4061 cleanup_client(cl);
4065 * This is called before every Assuan command.
4067 gint command_startup(assuan_context_t ctx, const gchar *name)
4069 struct client_s *cl = assuan_get_pointer(ctx);
4070 gpg_error_t rc;
4072 log_write1("%s", name);
4074 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
4075 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
4076 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
4077 !g_ascii_strcasecmp(name, "GETCONFIG") ||
4078 !g_ascii_strcasecmp(name, "GETPID") ||
4079 !g_ascii_strcasecmp(name, "VERSION") ||
4080 !g_ascii_strcasecmp(name, "SET") ||
4081 !g_ascii_strcasecmp(name, "BYE") ||
4082 !g_ascii_strcasecmp(name, "NOP") ||
4083 !g_ascii_strcasecmp(name, "CANCEL") ||
4084 !g_ascii_strcasecmp(name, "RESET") ||
4085 !g_ascii_strcasecmp(name, "END") ||
4086 !g_ascii_strcasecmp(name, "HELP") ||
4087 !g_ascii_strcasecmp(name, "OPTION") ||
4088 !g_ascii_strcasecmp(name, "INPUT") ||
4089 !g_ascii_strcasecmp(name, "OUTPUT") ||
4090 !g_ascii_strcasecmp(name, "LS") ||
4091 !g_ascii_strcasecmp(name, "UNSET"))
4092 return 0;
4094 #ifdef WITH_PINENTRY
4095 if (!(cl->opts & OPT_PINENTRY))
4096 reset_pin_defaults(cl->pinentry);
4097 #endif
4099 cl->last_rc = rc = file_modified(cl);
4101 if (rc) {
4102 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4103 !g_ascii_strcasecmp(name, "OPEN"))
4104 rc = 0;
4107 return rc;
4111 * This is called after every Assuan command.
4113 void command_finalize(assuan_context_t ctx, gint rc)
4115 struct client_s *client = assuan_get_pointer(ctx);
4117 if (!client->is_lock_cmd)
4118 unlock_file_mutex(client);
4120 log_write1(N_("command completed (rc=%u)"), client->last_rc);
4121 client->opts &= ~(OPT_INQUIRE);
4122 client->opts &= ~(OPT_BASE64);
4125 gpg_error_t register_commands(assuan_context_t ctx)
4127 static struct {
4128 const gchar *name;
4129 gint (*handler)(assuan_context_t, gchar *line);
4130 } table[] = {
4131 { "OPEN", open_command },
4132 { "SAVE", save_command },
4133 { "LIST", list_command },
4134 { "REALPATH", realpath_command },
4135 { "STORE", store_command },
4136 { "DELETE", delete_command },
4137 { "GET", get_command },
4138 { "ATTR", attr_command },
4139 { "ISCACHED", iscached_command },
4140 { "CLEARCACHE", clearcache_command },
4141 { "CACHETIMEOUT", cachetimeout_command },
4142 { "GETCONFIG", getconfig_command },
4143 { "DUMP", dump_command },
4144 { "XPATH", xpath_command },
4145 { "XPATHATTR", xpathattr_command },
4146 { "IMPORT", import_command },
4147 { "LOCK", lock_command },
4148 { "UNLOCK", unlock_command },
4149 { "GETPID", getpid_command },
4150 { "VERSION", version_command },
4151 { "SET", set_command },
4152 { "UNSET", unset_command },
4153 { "RENAME", rename_command },
4154 { "COPY", copy_command },
4155 { "LS", ls_command },
4156 { "MOVE", move_command },
4157 { "INPUT", NULL },
4158 { "OUTPUT", NULL },
4159 { NULL, NULL }
4161 gint i, rc;
4163 for (i=0; table[i].name; i++) {
4164 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
4166 if (rc)
4167 return rc;
4170 rc = assuan_register_bye_notify(ctx, bye_notify);
4172 if (rc)
4173 return rc;
4175 rc = assuan_register_reset_notify(ctx, reset_notify);
4177 if (rc)
4178 return rc;
4180 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4182 if (rc)
4183 return rc;
4185 return assuan_register_post_cmd_notify(ctx, command_finalize);
4188 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4189 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4191 goffset insize, len;
4192 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4193 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
4194 gint zrc = 0;
4195 gulong outsize = 0;
4196 gpg_error_t rc;
4197 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4198 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4199 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4201 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4202 insize = crypto->fh->st.st_size - fh_size;
4203 crypto->iv = gcry_malloc(crypto->blocksize);
4205 if (!crypto->iv) {
4206 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
4207 return gpg_error_from_errno(ENOMEM);
4210 if (crypto->fh->v1)
4211 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4212 else
4213 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4215 crypto->inbuf = gcry_malloc(insize);
4217 if (!crypto->inbuf) {
4218 log_write("%s(%i): %s", __FILE__, __LINE__, strerror(ENOMEM));
4219 return gpg_error_from_errno(ENOMEM);
4222 crypto->insize = insize;
4223 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4225 if (len != crypto->insize)
4226 return GPG_ERR_INV_LENGTH;
4228 /* No encryption iterations. This is a plain (gzipped) file. */
4229 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4230 (!crypto->fh->v1 && fh_iter <= 0L)) {
4232 * cache_file_count() needs both .used == TRUE and a valid key in
4233 * order for it to count as a used cache entry. Fixes CACHE status
4234 * messages.
4236 memset(crypto->key, '!', hashlen);
4237 goto decompress;
4240 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4241 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4242 return rc;
4245 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4246 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4247 return rc;
4250 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4251 client->filename : "global", "iteration_progress");
4253 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4254 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4256 if (rc)
4257 return rc;
4260 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4262 if (rc)
4263 return rc;
4265 crypto->tkey = gcry_malloc(hashlen);
4267 if (!crypto->tkey) {
4268 log_write("%s(%i): %s", __FUNCTION__, __LINE__, strerror(ENOMEM));
4269 return gpg_error_from_errno(ENOMEM);
4272 memcpy(crypto->tkey, crypto->key, hashlen);
4273 guchar *tkey = crypto->tkey;
4274 tkey[0] ^= 1;
4276 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4277 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4278 return rc;
4281 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4282 if (iter_progress > 0ULL && iter >= iter_progress) {
4283 if (!(iter % iter_progress)) {
4284 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4285 ++n_iter * iter_progress, fh_iter);
4287 if (rc)
4288 return rc;
4292 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4293 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4294 return rc;
4297 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4299 if (rc) {
4300 log_write("%s(%i): %s", __FUNCTION__, __LINE__, _gpg_strerror(rc));
4301 return rc;
4304 iter++;
4307 if (iter_progress && fh_iter >= iter_progress) {
4308 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4310 if (rc)
4311 return rc;
4314 decompress:
4315 if (do_decompress(ctx, crypto->inbuf, crypto->insize,
4316 (gpointer *)&crypto->outbuf, &outsize, &zrc) == FALSE) {
4317 if (zrc == Z_MEM_ERROR)
4318 return gpg_error_from_errno(ENOMEM);
4319 else
4320 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4323 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4324 gcry_free(crypto->outbuf);
4325 crypto->outbuf = NULL;
4326 return GPG_ERR_INV_PASSPHRASE;
4329 if (ctx) {
4330 client->xml = crypto->outbuf;
4331 client->len = outsize;
4332 crypto->outbuf = NULL;
4334 else if (dst) {
4335 *dst = crypto->outbuf;
4336 *dst_len = outsize;
4337 crypto->outbuf = NULL;
4340 /* The calling function should free the crypto struct. */
4341 return 0;