Fixed --import.
[pwmd.git] / src / commands.c
blob2bea93fcee4895d98bb09b037cbb4d743e88f0fa
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 Ben Kibbey <bjk@luxsci.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <glib.h>
34 #include <glib/gstdio.h>
35 #include <gcrypt.h>
36 #include <zlib.h>
37 #include <dirent.h>
39 #ifdef WITH_LIBACL
40 #include <sys/acl.h>
41 #endif
43 #include "mem.h"
44 #include "xml.h"
45 #include "common.h"
47 #ifdef WITH_PINENTRY
48 #include "pinentry.h"
49 #endif
51 #include "pwmd_error.h"
52 #include "cache.h"
53 #include "misc.h"
54 #include "commands.h"
55 #include "mutex.h"
56 #include "rcfile.h"
58 struct gz_s {
59 z_stream z;
60 gpointer out;
61 gboolean done;
62 status_msg_t which;
65 struct command_table_s {
66 const gchar *name;
67 gint (*handler)(assuan_context_t, gchar *line);
68 const gchar *help;
69 gboolean ignore_startup;
72 static struct command_table_s **command_table;
73 static guchar crypto_magic[5] = "\177PWMD";
75 static gpg_error_t do_lock_command(struct client_s *client);
77 static void *z_alloc(void *data, unsigned items, unsigned size)
79 return gcry_calloc(items, size);
82 static void z_free(void *data, void *p)
84 gcry_free(p);
87 static gpg_error_t file_modified(struct client_s *client)
89 struct stat st;
90 gpg_error_t rc;
92 if (client->state != STATE_OPEN)
93 return EPWMD_NO_FILE;
95 rc = lock_file_mutex(client);
97 if (rc)
98 return rc;
100 if (g_lstat(client->filename, &st) == 0 && client->mtime) {
101 if (client->mtime != st.st_mtime)
102 return EPWMD_FILE_MODIFIED;
105 pth_cancel_point();
106 return 0;
109 static gpg_error_t parse_xml(assuan_context_t ctx)
111 struct client_s *client = assuan_get_pointer(ctx);
113 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
115 if (!client->doc)
116 return EPWMD_LIBXML_ERROR;
118 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
119 return 0;
121 return convert_elements(client->doc);
124 void unlock_file_mutex(struct client_s *client)
126 pth_mutex_t *m;
128 if (client->has_lock == FALSE)
129 return;
131 CACHE_LOCK(client->ctx);
133 if (cache_get_mutex(client->md5file, &m) == FALSE) {
134 CACHE_UNLOCK;
135 return;
138 CACHE_UNLOCK;
139 MUTEX_UNLOCK(m);
140 client->has_lock = client->is_lock_cmd = FALSE;
143 gpg_error_t lock_file_mutex(struct client_s *client)
145 pth_mutex_t *m;
146 gpg_error_t rc = 0;
148 if (client->has_lock == TRUE)
149 return 0;
151 CACHE_LOCK(client->ctx);
153 if (cache_get_mutex(client->md5file, &m) == FALSE) {
154 CACHE_UNLOCK;
155 return 0;
158 CACHE_UNLOCK;
160 if (client->rc_on_locked) {
161 if (!pth_mutex_acquire(m, TRUE, NULL))
162 return GPG_ERR_LOCKED;
163 #ifdef MUTEX_DEBUG
164 MUTEX_LOCK_DEBUG(m);
165 #endif
167 else
168 MUTEX_TRYLOCK(client, m, rc);
170 if (!rc)
171 client->has_lock = TRUE;
173 return rc;
176 void free_client(struct client_s *client)
178 if (client->doc)
179 xmlFreeDoc(client->doc);
181 if (client->xml)
182 gcry_free(client->xml);
184 if (client->filename)
185 g_free(client->filename);
187 if (client->crypto)
188 cleanup_crypto(&client->crypto);
190 if (client->xml_error)
191 xmlResetError(client->xml_error);
194 void cleanup_client(struct client_s *client)
196 assuan_context_t ctx = client->ctx;
197 struct client_thread_s *thd = client->thd;
198 gboolean rc_on_locked = client->rc_on_locked;
199 gboolean lock_on_open = client->lock_on_open;
200 #ifdef WITH_PINENTRY
201 struct pinentry_s *pin = client->pinentry;
202 #endif
204 unlock_file_mutex(client);
205 CACHE_LOCK(client->ctx);
206 cache_decr_refcount(client->md5file);
209 * This may be a new file so don't use a cache slot. save_command() will
210 * set this to FALSE on success.
212 if (client->new == TRUE)
213 cache_clear(client->md5file, 1);
215 CACHE_UNLOCK;
216 free_client(client);
217 memset(client, 0, sizeof(struct client_s));
218 client->state = STATE_CONNECTED;
219 client->ctx = ctx;
220 client->thd = thd;
221 client->freed = TRUE;
222 #ifdef WITH_PINENTRY
223 client->pinentry = pin;
224 #endif
225 client->rc_on_locked = rc_on_locked;
226 client->lock_on_open = lock_on_open;
229 static void gz_cleanup(void *arg)
231 struct gz_s **gz = (struct gz_s **)arg;
233 if (!gz)
234 return;
236 if (!(*gz)->done && (*gz)->out)
237 gcry_free((*gz)->out);
239 if ((*gz)->which == STATUS_COMPRESS) {
240 if ((*gz)->z.zalloc)
241 deflateEnd(&(*gz)->z);
243 else {
244 if ((*gz)->z.zalloc)
245 inflateEnd(&(*gz)->z);
248 g_free(*gz);
249 *gz = NULL;
252 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
253 gpointer *out, gulong *outsize)
255 struct gz_s *gz;
256 gz_header h;
257 gchar buf[17];
258 gpg_error_t rc;
259 gint zrc;
261 gz = g_malloc0(sizeof(struct gz_s));
263 if (!gz)
264 return GPG_ERR_ENOMEM;
266 pth_cleanup_push(gz_cleanup, &gz);
267 gz->which = STATUS_DECOMPRESS;
268 gz->z.zalloc = z_alloc;
269 gz->z.zfree = z_free;
270 gz->z.next_in = in;
271 gz->z.avail_in = (uInt)insize;
272 gz->z.avail_out = zlib_bufsize;
273 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
275 if (!gz->out) {
276 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
277 pth_cleanup_pop(1);
278 return GPG_ERR_ENOMEM;
281 zrc = inflateInit2(&gz->z, 47);
283 if (zrc != Z_OK) {
284 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
285 pth_cleanup_pop(1);
286 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
289 memset(&h, 0, sizeof(gz_header));
290 h.comment = (guchar *)buf;
291 h.comm_max = sizeof(buf);
292 zrc = inflateGetHeader(&gz->z, &h);
294 if (zrc != Z_OK) {
295 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
296 pth_cleanup_pop(1);
297 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
300 zrc = inflate(&gz->z, Z_BLOCK);
302 if (zrc != Z_OK) {
303 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
304 pth_cleanup_pop(1);
305 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
308 if (h.comment)
309 insize = strtoul((gchar *)h.comment, NULL, 10);
311 do {
312 gpointer p;
314 zrc = inflate(&gz->z, Z_FINISH);
316 switch (zrc) {
317 case Z_OK:
318 break;
319 case Z_BUF_ERROR:
320 if (!gz->z.avail_out) {
321 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
323 if (!p) {
324 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
325 rc = GPG_ERR_ENOMEM;
326 goto fail;
329 gz->out = p;
330 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
331 gz->z.avail_out = zlib_bufsize;
332 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
333 gz->z.total_out, insize);
335 if (rc)
336 goto fail;
338 break;
339 case Z_STREAM_END:
340 break;
341 default:
342 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
343 rc = GPG_ERR_COMPR_ALGO;
344 goto fail;
345 break;
347 } while (zrc != Z_STREAM_END);
349 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
350 insize);
352 if (rc)
353 goto fail;
355 *out = gz->out;
356 *outsize = gz->z.total_out;
357 gz->done = TRUE;
358 pth_cleanup_pop(1);
359 return 0;
361 fail:
362 pth_cleanup_pop(1);
363 return rc;
366 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
367 gpg_error_t *rc)
369 gint fd;
370 gsize len;
371 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
372 gsize fh_size;
373 gpointer p;
375 *rc = 0;
377 if (!fh) {
378 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
379 *rc = GPG_ERR_ENOMEM;
380 return NULL;
383 pth_cleanup_push(g_free, fh);
384 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2)-8; // salt
386 if (g_lstat(filename, &fh->st) == -1) {
387 *rc = gpg_error_from_syserror();
388 pth_cleanup_pop(1);
389 return NULL;
392 if (!S_ISREG(fh->st.st_mode)) {
393 *rc = GPG_ERR_ENOANO;
394 pth_cleanup_pop(1);
395 return NULL;
398 fd = open(filename, O_RDONLY);
400 if (fd == -1) {
401 *rc = gpg_error_from_syserror();
402 pth_cleanup_pop(1);
403 return NULL;
406 pth_cleanup_push(cleanup_fd_cb, &fd);
407 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
408 len = pth_read(fd, p, fh_size);
410 if (len != fh_size) {
411 *rc = gpg_error_from_syserror();
412 pth_cleanup_pop(1);
413 pth_cleanup_pop(1);
414 return NULL;
417 if (!v1) {
418 if (fh->ver.fh2.version >= 0x221) {
419 len = pth_read(fd, fh->ver.fh2.salt, sizeof(fh->ver.fh2.salt));
420 if (len != sizeof(fh->ver.fh2.salt)) {
421 *rc = gpg_error_from_syserror();
422 pth_cleanup_pop(1);
423 pth_cleanup_pop(1);
424 return NULL;
429 fh->v1 = v1;
430 fh->fd = fd;
431 pth_cleanup_pop(0);
432 pth_cleanup_pop(0);
433 return fh;
436 gpg_error_t hash_key(struct crypto_s *crypto, const guchar *key,
437 gsize keylen, gboolean kdf)
439 gpg_error_t rc = 0;
441 if (crypto->key != key) {
442 gcry_free(crypto->key);
443 crypto->key = gcry_malloc(KEYSIZE);
444 if (!crypto->key)
445 return GPG_ERR_ENOMEM;
448 if (!kdf && crypto->fh->ver.fh2.version < 0x221) {
449 gcry_md_hash_buffer(GCRY_MD_SHA256, crypto->key, key, keylen);
451 else {
452 rc = gcry_kdf_derive(key, keylen, GCRY_KDF_ITERSALTED_S2K, GCRY_MD_SHA1,
453 crypto->fh->ver.fh2.salt, 8, 1000, KEYSIZE, crypto->key);
456 return rc;
459 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *key,
460 gsize len, gboolean cached)
462 struct client_s *client = assuan_get_pointer(ctx);
463 gpg_error_t rc;
464 gint timeout;
466 if (!client->new && len) {
467 rc = hash_key(client->crypto, key, len, FALSE);
468 if (rc)
469 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
472 /* New file. */
473 if (!client->crypto->fh) {
474 guchar *tkey = client->crypto->key;
476 for (gsize i = 0; i < client->crypto->keysize; i++) {
477 if (tkey[i])
478 goto update_cache;
481 goto done;
484 rc = init_client_crypto2(client->filename, client->crypto);
486 if (rc) {
487 cleanup_client(client);
488 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
491 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
493 if (rc) {
494 cleanup_client(client);
495 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
498 update_cache:
499 key = client->crypto->key;
500 CACHE_LOCK(client->ctx);
502 if (cached == FALSE) {
503 if (cache_update_key(client->md5file, key) == FALSE) {
504 cleanup_client(client);
505 CACHE_UNLOCK;
506 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
509 timeout = get_key_file_integer(client->filename, "cache_timeout");
510 cache_reset_timeout(client->md5file, timeout);
512 else
513 cache_set_timeout(client->md5file, -2);
515 CACHE_UNLOCK;
517 done:
518 rc = parse_xml(ctx);
520 if (client->xml) {
521 gcry_free(client->xml);
522 client->xml = NULL;
525 if (!rc) {
526 if (client->new == FALSE)
527 send_status_all(STATUS_CACHE);
529 client->state = STATE_OPEN;
532 if (!rc && client->new == FALSE &&
533 client->crypto->fh->ver.fh2.iter != get_key_file_uint64(client->filename, "iterations")) {
534 gchar *s = g_strdup_printf("%llu", (unsigned long long)client->crypto->fh->ver.fh2.iter);
536 MUTEX_LOCK(&rcfile_mutex);
537 g_key_file_set_value(keyfileh, client->filename, "iterations", s);
538 g_free(s);
539 MUTEX_UNLOCK(&rcfile_mutex);
540 send_status_all(STATUS_CONFIG);
543 if (!rc && !client->new && client->crypto->fh->ver.fh2.version < 0x221)
544 client->rehash = TRUE; // For SAVE
546 cleanup_crypto(&client->crypto);
548 if (!rc && client->new)
549 rc = send_status(ctx, STATUS_NEWFILE, NULL);
551 if (!rc && client->lock_on_open)
552 return do_lock_command(client);
554 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
557 static void req_cleanup(void *arg)
559 if (!arg)
560 return;
562 g_strfreev((gchar **)arg);
565 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
567 struct client_s *client = data;
568 const gchar *p = value;
570 if (p && *p) {
571 gint n = atoi(p);
573 if (n < 0 || n > 1)
574 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
576 client->lock_on_open = n ? TRUE : FALSE;
578 else if ((!p || !*p) && (client->opts & OPT_LOCK))
579 client->lock_on_open = FALSE;
580 else
581 client->lock_on_open = TRUE;
583 return 0;
586 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
588 #ifdef WITH_PINENTRY
589 struct client_s *client = data;
590 gchar *str = value;
591 gint n;
593 if (!str || !*str) {
594 client->pinentry->enable = -1;
595 client->opts &= ~(OPT_PINENTRY);
596 return 0;
599 n = atoi(str);
601 if (n < 0 || n > 1)
602 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
604 client->pinentry->enable = n ? TRUE : FALSE;
605 client->opts |= OPT_PINENTRY;
606 return 0;
607 #else
608 return GPG_ERR_NOT_IMPLEMENTED;
609 #endif
612 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
614 struct client_s *client = data;
616 (void)value;
617 client->opts |= OPT_INQUIRE;
618 return 0;
621 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
623 gboolean cached = FALSE;
624 gpg_error_t rc;
625 struct client_s *client = assuan_get_pointer(ctx);
626 gchar **req;
627 gchar *filename = NULL;
629 if ((req = split_input_line(line, " ", 2)) != NULL)
630 filename = req[0];
632 pth_cleanup_push(req_cleanup, req);
634 if (!filename || !*filename) {
635 pth_cleanup_pop(1);
636 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
639 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
641 if (valid_filename(filename) == FALSE) {
642 pth_cleanup_pop(1);
643 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
646 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
647 CACHE_LOCK(client->ctx);
649 if (cache_has_file(client->md5file) == FALSE) {
650 if (cache_add_file(client->md5file, NULL) == FALSE) {
651 pth_cleanup_pop(1);
652 CACHE_UNLOCK;
653 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
657 CACHE_UNLOCK;
658 rc = lock_file_mutex(client);
660 if (rc) {
661 pth_cleanup_pop(1);
662 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
665 client->freed = FALSE;
666 CACHE_LOCK(client->ctx);
667 cache_incr_refcount(client->md5file);
668 CACHE_UNLOCK;
669 client->crypto = init_client_crypto();
671 if (!client->crypto) {
672 pth_cleanup_pop(1);
673 cleanup_client(client);
674 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
677 client->crypto->key = gcry_malloc(KEYSIZE);
679 if (!client->crypto->key) {
680 pth_cleanup_pop(1);
681 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
682 GPG_ERR_ENOMEM);
683 cleanup_client(client);
684 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
687 memset(client->crypto->key, 0, KEYSIZE);
688 client->crypto->fh = read_file_header(filename, FALSE, &rc);
690 if (!client->crypto->fh) {
691 if (gpg_err_code_to_errno(rc) != ENOENT) {
692 log_write("%s: %s", filename, pwmd_strerror(rc));
693 pth_cleanup_pop(1);
694 cleanup_client(client);
695 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
699 * New files don't need a key.
701 if ((client->xml = new_document()) == NULL) {
702 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
703 pth_cleanup_pop(1);
704 cleanup_client(client);
705 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
708 client->len = xmlStrlen(client->xml);
709 client->new = TRUE;
710 client->filename = g_strdup(filename);
712 if (!client->filename) {
713 pth_cleanup_pop(1);
714 cleanup_client(client);
715 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
716 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
719 pth_cleanup_pop(1);
720 #ifdef WITH_PINENTRY
721 client->pinentry->filename = g_strdup(client->filename);
723 if (!client->pinentry->filename) {
724 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
725 cleanup_client(client);
726 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
728 #endif
729 return open_command_finalize(ctx, (guchar *)req[1],
730 req[1] ? strlen(req[1]) : 0, cached);
732 else {
733 if (!(client->opts & OPT_CIPHER))
734 g_key_file_set_string(keyfileh, filename, "cipher",
735 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
737 client->mtime = client->crypto->fh->st.st_mtime;
740 client->filename = g_strdup(filename);
742 if (!client->filename) {
743 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
744 pth_cleanup_pop(1);
745 cleanup_client(client);
746 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
749 #ifdef WITH_PINENTRY
750 if (client->pinentry->filename)
751 g_free(client->pinentry->filename);
753 client->pinentry->filename = g_strdup(client->filename);
755 if (!client->pinentry->filename) {
756 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
757 pth_cleanup_pop(1);
758 cleanup_client(client);
759 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
761 #endif
763 if (client->crypto->fh->ver.fh2.iter <= 0ULL) {
764 goto done;
767 CACHE_LOCK(client->ctx);
768 cached = cache_get_key(client->md5file, client->crypto->key);
769 CACHE_UNLOCK;
771 if (cached == FALSE) {
772 gchar *tmp = get_key_file_string(filename, "key_file");
774 if (tmp && !(client->opts & OPT_INQUIRE)) {
775 g_free(tmp);
776 pth_cleanup_pop(1);
777 cleanup_client(client);
778 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
781 if (tmp)
782 g_free(tmp);
785 * No key specified and no matching filename found in the cache. Use
786 * pinentry to retrieve the key. Cannot return assuan_process_done()
787 * here otherwise the command will be interrupted. The event loop in
788 * client_thread() will poll the file descriptor waiting for it to
789 * become ready to read a pinentry_key_s which will contain the
790 * entered key or an error code. It will then call
791 * open_command_finalize() to to finish the command.
793 if (!req[1] || !*req[1]) {
794 #ifdef WITH_PINENTRY
795 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
797 /* From set_pinentry_defaults(). */
798 if (client->opts & OPT_INQUIRE ||
799 client->pinentry->enable == FALSE ||
800 (client->pinentry->enable == -1 && b == FALSE)) {
801 rc = hash_key(client->crypto, (guchar *)"", 1, FALSE);
802 if (rc) {
803 cleanup_client(client);
804 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
807 goto done;
810 pth_cleanup_pop(1);
811 // To set the keysize.
812 rc = init_client_crypto2(filename, client->crypto);
813 if (rc) {
814 cleanup_client(client);
815 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
818 rc = lock_pin_mutex(client);
819 if (rc) {
820 unlock_pin_mutex(client->pinentry);
821 cleanup_client(client);
822 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
825 client->pinentry->which = PINENTRY_OPEN;
826 rc = pinentry_fork(ctx);
828 if (rc) {
829 unlock_pin_mutex(client->pinentry);
830 cleanup_client(client);
831 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
834 // Called from pinentry iterate.
835 client->pinentry->cb = open_command_finalize;
836 client->pinentry->status = PINENTRY_INIT;
837 return 0;
838 #else
839 rc = hash_key(client->crypto, "" , 1, FALSE);
840 if (rc) {
841 cleanup_client(client);
842 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
845 goto done;
846 #endif
849 rc = hash_key(client->crypto, (guchar *)req[1], strlen(req[1]), FALSE);
851 if (rc) {
852 pth_cleanup_pop(1);
853 cleanup_client(client);
854 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
857 else if (req && req[1] && *req[1]) {
858 rc = hash_key(client->crypto, (guchar *)req[1], strlen(req[1]), FALSE);
860 if (rc) {
861 pth_cleanup_pop(1);
862 cleanup_client(client);
863 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
867 done:
868 pth_cleanup_pop(1);
869 return open_command_finalize(ctx, (guchar *)req[1],
870 req[1] ? strlen(req[1]) : 0, cached);
873 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
874 guchar *line, gsize len)
876 assuan_context_t ctx = data;
877 struct client_s *client = assuan_get_pointer(ctx);
878 gpg_error_t rc = file_modified(client);
879 guchar *p = line;
880 gint i = 0;
882 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
883 if (line)
884 xfree(line);
886 return assuan_rc ? assuan_rc : rc;
889 while (*p && *++p != ' ')
890 i++;
892 if (*p && i != len) {
893 p = line+i+2;
894 len -= i+2;
895 has_null_byte(NULL, p, len);
898 rc = open_command_common(ctx, (gchar *)line);
900 if (line)
901 xfree(line);
903 client->inquire_status = INQUIRE_DONE;
904 return rc;
907 static gint open_command(assuan_context_t ctx, gchar *line)
909 gpg_error_t rc;
910 struct client_s *client = assuan_get_pointer(ctx);
911 struct argv_s *args[] = {
912 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
913 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
914 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
915 NULL
918 if (client->state == STATE_OPEN)
919 cleanup_client(client);
921 if (!(client->opts & OPT_LOCK))
922 client->lock_on_open = FALSE;
924 rc = parse_options(&line, args, client);
926 if (rc)
927 return send_error(ctx, rc);
929 if ((client->opts & OPT_INQUIRE)) {
930 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
931 ctx);
933 if (rc)
934 return send_error(ctx, rc);
936 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
937 client->inquire_status = INQUIRE_BUSY;
938 return 0;
941 return open_command_common(ctx, line);
944 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
945 guint size, gpointer *out, gulong *outsize)
947 struct gz_s *gz;
948 gz_header h;
949 gchar buf[17];
950 gint cmd = Z_NO_FLUSH;
951 gint zrc;
952 gpg_error_t rc;
954 gz = g_malloc0(sizeof(struct gz_s));
956 if (!gz)
957 return GPG_ERR_ENOMEM;
959 pth_cleanup_push(gz_cleanup, &gz);
960 gz->which = STATUS_COMPRESS;
961 gz->z.zalloc = z_alloc;
962 gz->z.zfree = z_free;
963 gz->z.next_in = data;
964 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
965 gz->z.avail_out = (uInt)zlib_bufsize;
966 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
968 if (!gz->out) {
969 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
970 pth_cleanup_pop(1);
971 return GPG_ERR_ENOMEM;
974 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
976 if (zrc != Z_OK) {
977 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
978 pth_cleanup_pop(1);
979 return GPG_ERR_COMPR_ALGO;
982 /* Rather than store the size of the uncompressed data in the file header,
983 * store it in the comment field of the gzip header. Don't give anyone too
984 * much information. Not sure why really, but it seems the right way. :)
986 memset(&h, 0, sizeof(gz_header));
987 g_snprintf(buf, sizeof(buf), "%u", size);
988 h.comment = (guchar *)buf;
989 zrc = deflateSetHeader(&gz->z, &h);
991 if (zrc != Z_OK) {
992 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
993 pth_cleanup_pop(1);
994 return GPG_ERR_COMPR_ALGO;
997 do {
998 gpointer p;
1000 zrc = deflate(&gz->z, cmd);
1002 switch (zrc) {
1003 case Z_OK:
1004 break;
1005 case Z_BUF_ERROR:
1006 if (!gz->z.avail_out) {
1007 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
1009 if (!p) {
1010 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1011 rc = GPG_ERR_ENOMEM;
1012 goto fail;
1015 gz->out = p;
1016 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
1017 gz->z.avail_out = zlib_bufsize;
1020 if (!gz->z.avail_in && gz->z.total_in < size) {
1021 if (gz->z.total_in + zlib_bufsize > size)
1022 gz->z.avail_in = size - gz->z.total_in;
1023 else
1024 gz->z.avail_in = zlib_bufsize;
1026 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
1027 gz->z.total_in, size);
1029 if (rc)
1030 goto fail;
1033 if (gz->z.total_in >= size)
1034 cmd = Z_FINISH;
1036 break;
1037 case Z_STREAM_END:
1038 break;
1039 default:
1040 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
1041 rc = GPG_ERR_COMPR_ALGO;
1042 goto fail;
1044 } while (zrc != Z_STREAM_END);
1046 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1048 if (rc)
1049 goto fail;
1051 *out = gz->out;
1052 *outsize = gz->z.total_out;
1053 gz->done = TRUE;
1054 pth_cleanup_pop(1);
1055 return 0;
1057 fail:
1058 pth_cleanup_pop(1);
1059 return rc;
1062 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1065 * Useful for a large amount of data. Rather than doing all of the data in one
1066 * iteration do it in chunks. This lets the command be cancelable rather than
1067 * waiting for it to complete.
1069 static gpg_error_t iterate_crypto_once(struct client_s *client,
1070 struct crypto_s *crypto, status_msg_t which)
1072 gpg_error_t rc = 0;
1073 goffset len = CRYPTO_BLOCKSIZE(crypto);
1074 gpointer p = gcry_malloc(len);
1075 goffset total = 0;
1076 gpointer inbuf;
1078 if (!p)
1079 return GPG_ERR_ENOMEM;
1081 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1082 len = crypto->insize;
1084 pth_cleanup_push(gcry_free, p);
1086 for (;;) {
1087 inbuf = (guchar *)crypto->inbuf + total;
1088 guchar *tmp;
1090 if (len + total > crypto->insize)
1091 len = crypto->blocksize;
1093 if (which == STATUS_ENCRYPT)
1094 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1095 else
1096 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1098 if (rc)
1099 goto done;
1101 tmp = (guchar *)crypto->inbuf + total;
1102 memmove(tmp, p, len);
1103 total += len;
1105 if (total >= crypto->insize)
1106 break;
1108 pth_cancel_point();
1111 done:
1112 pth_cleanup_pop(1);
1113 return rc;
1116 /* The crypto struct must be setup for iterations and .key. */
1117 gpg_error_t do_xml_encrypt(struct client_s *client,
1118 struct crypto_s *crypto, const gchar *filename)
1120 goffset len = crypto->insize;
1121 gpointer inbuf;
1122 gchar *p;
1123 gpg_error_t rc;
1124 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
1125 gchar tmp[FILENAME_MAX];
1126 struct stat st;
1127 mode_t mode = 0;
1129 if (!crypto->fh->ver.fh2.iter) {
1131 * cache_file_count() needs both .used == TRUE and a valid key in
1132 * order for it to count as a used cache entry. Fixes CACHE status
1133 * messages.
1135 memset(crypto->key, '!', KEYSIZE);
1136 goto write_file;
1140 * Resize the existing xml buffer to the block size required by gcrypt
1141 * rather than duplicating it and wasting memory.
1143 crypto->insize += sizeof(crypto_magic);
1144 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1146 if (crypto->insize % crypto->blocksize)
1147 len += crypto->blocksize;
1149 inbuf = gcry_realloc(crypto->inbuf, len);
1151 if (!inbuf) {
1152 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1153 return GPG_ERR_ENOMEM;
1156 guchar *tmpbuf = inbuf;
1157 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1158 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1159 crypto->inbuf = tmpbuf;
1160 crypto->insize = len;
1161 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1163 if (crypto->tkey)
1164 gcry_free(crypto->tkey);
1166 crypto->tkey = gcry_malloc(KEYSIZE);
1168 if (!crypto->tkey) {
1169 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1170 return GPG_ERR_ENOMEM;
1173 memcpy(crypto->tkey, crypto->key, KEYSIZE);
1174 guchar *tkey = crypto->tkey;
1175 tkey[0] ^= 1;
1177 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1178 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1179 return rc;
1182 iter_progress = get_key_file_uint64(
1183 client ? client->filename : "global", "iteration_progress");
1185 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1186 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1187 "0 %llu", crypto->fh->ver.fh2.iter);
1189 if (rc)
1190 return rc;
1193 while (xiter < crypto->fh->ver.fh2.iter-1) {
1194 if (iter_progress > 0ULL && xiter >= iter_progress) {
1195 if (!(xiter % iter_progress)) {
1196 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1197 "%llu %llu", ++n_iter * iter_progress,
1198 crypto->fh->ver.fh2.iter);
1200 if (rc)
1201 return rc;
1205 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1206 crypto->blocksize))) {
1207 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1208 return rc;
1211 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1213 if (rc) {
1214 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1215 return rc;
1218 xiter++;
1221 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1222 crypto->blocksize))) {
1223 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1224 return rc;
1227 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1228 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1229 return rc;
1232 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1234 if (rc)
1235 return rc;
1237 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1238 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1239 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1241 if (rc)
1242 return rc;
1245 write_file:
1246 tmp[0] = 0;
1248 if (filename) {
1249 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1250 crypto->fh->fd = STDOUT_FILENO;
1251 goto do_write_file;
1254 if (g_lstat(filename, &st) == 0) {
1255 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1257 if (!(mode & S_IWUSR))
1258 return GPG_ERR_EACCES;
1260 else if (errno != ENOENT)
1261 return gpg_error_from_syserror();
1263 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1264 #if GLIB_CHECK_VERSION(2, 22, 0)
1265 crypto->fh->fd = g_mkstemp_full(tmp, O_WRONLY, 0600);
1266 #else
1267 crypto->fh->fd = mkstemp(tmp);
1268 #endif
1270 if (crypto->fh->fd == -1) {
1271 rc = gpg_error_from_syserror();
1272 p = strrchr(tmp, '/');
1273 p++;
1274 log_write("%s: %s", p, pwmd_strerror(rc));
1275 return rc;
1278 pth_cleanup_push(cleanup_unlink_cb, tmp);
1280 else
1282 * xml_import() or convert_file() from command line.
1284 crypto->fh->fd = STDOUT_FILENO;
1286 do_write_file:
1287 crypto->fh->ver.fh2.magic[0] = '\177';
1288 crypto->fh->ver.fh2.magic[1] = 'P';
1289 crypto->fh->ver.fh2.magic[2] = 'W';
1290 crypto->fh->ver.fh2.magic[3] = 'M';
1291 crypto->fh->ver.fh2.magic[4] = 'D';
1292 crypto->fh->ver.fh2.version = VERSION_HEX;
1293 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1295 if (len != sizeof(crypto->fh->ver.fh2)) {
1296 rc = gpg_error_from_syserror();
1298 if (tmp[0])
1299 pth_cleanup_pop(1);
1301 return rc;
1304 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1306 if (len != crypto->insize) {
1307 rc = gpg_error_from_syserror();
1309 if (tmp[0])
1310 pth_cleanup_pop(1);
1312 return rc;
1315 if (fsync(crypto->fh->fd) == -1) {
1316 rc = gpg_error_from_syserror();
1318 if (tmp[0])
1319 pth_cleanup_pop(1);
1321 return rc;
1324 if (tmp[0]) {
1325 #ifdef WITH_LIBACL
1326 acl_t acl;
1327 #endif
1328 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1329 gchar tmp2[FILENAME_MAX];
1331 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1332 #ifdef WITH_LIBACL
1333 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1335 if (!acl)
1336 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1337 #endif
1339 if (rename(filename, tmp2) == -1) {
1340 rc = gpg_error_from_syserror();
1341 pth_cleanup_pop(1);
1342 #ifdef WITH_LIBACL
1343 if (acl)
1344 acl_free(acl);
1345 #endif
1346 return rc;
1349 #ifdef WITH_LIBACL
1350 else {
1351 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1353 if (!acl)
1354 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1356 #endif
1358 if (rename(tmp, filename) == -1) {
1359 rc = gpg_error_from_syserror();
1360 pth_cleanup_pop(1);
1361 #ifdef WITH_LIBACL
1362 if (acl)
1363 acl_free(acl);
1364 #endif
1365 return rc;
1368 pth_cleanup_pop(0);
1370 if (mode)
1371 chmod(filename, mode);
1373 #ifdef WITH_LIBACL
1374 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1375 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1377 if (acl)
1378 acl_free(acl);
1379 #endif
1381 /* Be sure the file entry has been written to disk. On FreeBSD I
1382 * noticed delays causing a following command to return
1383 * GPG_ERR_CHECKSUM. Recommended from fsync(2) (Linux).
1385 DIR *dir;
1386 gchar *path;
1387 gchar *s = get_key_file_string("global", "data_directory");
1389 path = expand_homedir(s);
1390 g_free(s);
1391 dir = opendir(path);
1392 g_free(path);
1393 if (dir) {
1394 gint fd = dirfd(dir);
1395 if (fd != -1)
1396 fsync(fd);
1397 else
1398 rc = gpg_error_from_syserror();
1400 closedir(dir);
1402 else
1403 rc = gpg_error_from_syserror();
1406 if (client && g_lstat(filename, &st) == 0)
1407 client->mtime = st.st_mtime;
1409 return rc;
1412 gpg_error_t update_save_flags(const gchar *filename,
1413 struct crypto_s *crypto)
1415 gpg_error_t rc;
1417 /* New file? */
1418 if (!crypto->fh) {
1419 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1421 if (!crypto->fh)
1422 return GPG_ERR_ENOMEM;
1425 rc = init_client_crypto2(filename, crypto);
1427 if (rc)
1428 return rc;
1430 if (filename && !crypto->fh->v1)
1431 crypto->fh->ver.fh2.iter = get_key_file_uint64(filename, "iterations");
1433 return 0;
1436 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1437 gsize keylen, gboolean cached)
1439 struct client_s *client = assuan_get_pointer(ctx);
1440 gpointer xmlbuf;
1441 gulong outsize = 0;
1442 guint len;
1443 gint clevel;
1444 gint timeout;
1445 gpointer outbuf;
1446 gpg_error_t rc;
1448 rc = update_save_flags(client->filename, client->crypto);
1449 if (rc) {
1450 cleanup_crypto(&client->crypto);
1451 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1452 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1455 if (keylen) {
1456 gcry_create_nonce(client->crypto->fh->ver.fh2.salt, 8);
1457 rc = hash_key(client->crypto, key, keylen, TRUE);
1458 if (rc) {
1459 cleanup_crypto(&client->crypto);
1460 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1463 cached = FALSE;
1466 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1468 if (rc) {
1469 cleanup_crypto(&client->crypto);
1470 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1473 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1474 pth_cleanup_push(xmlFree, xmlbuf);
1475 clevel = get_key_file_integer(client->filename, "compression_level");
1477 if (clevel < 0)
1478 clevel = 0;
1480 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1482 if (rc) {
1483 pth_cleanup_pop(1);
1484 cleanup_crypto(&client->crypto);
1486 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1488 else {
1489 pth_cleanup_pop(1);
1490 xmlbuf = outbuf;
1491 len = outsize;
1494 client->crypto->inbuf = xmlbuf;
1495 client->crypto->insize = len;
1496 rc = do_xml_encrypt(client, client->crypto, client->filename);
1498 if (rc) {
1499 cleanup_crypto(&client->crypto);
1500 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1503 timeout = get_key_file_integer(client->filename, "cache_timeout");
1504 CACHE_LOCK(client->ctx);
1506 if (cached) {
1507 cache_reset_timeout(client->md5file, timeout);
1508 CACHE_UNLOCK;
1510 if (client->new == TRUE)
1511 send_status_all(STATUS_CACHE);
1513 client->new = FALSE;
1514 cleanup_crypto(&client->crypto);
1515 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1518 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1519 CACHE_UNLOCK;
1520 cleanup_crypto(&client->crypto);
1521 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1524 client->new = client->rehash = FALSE;
1525 cache_reset_timeout(client->md5file, timeout);
1526 CACHE_UNLOCK;
1527 send_status_all(STATUS_CACHE);
1528 cleanup_crypto(&client->crypto);
1529 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1532 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1534 struct client_s *client = data;
1535 guint64 n;
1536 gchar *value = v;
1537 gchar *p = NULL;
1539 if (!client->filename)
1540 return EPWMD_NO_FILE;
1542 if (!value || !*value)
1543 return 0;
1545 errno = 0;
1546 n = g_ascii_strtoull(value, &p, 10);
1548 if (errno || (p && *p) || n == G_MAXUINT64)
1549 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1551 MUTEX_LOCK(&rcfile_mutex);
1552 g_key_file_set_value(keyfileh,
1553 client->filename ? client->filename : "global", "iterations", value);
1554 MUTEX_UNLOCK(&rcfile_mutex);
1556 if (client->filename)
1557 client->opts |= OPT_ITERATIONS;
1559 return 0;
1562 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1564 struct client_s *client = data;
1565 const gchar *p = value;
1566 guint64 flags;
1568 if (!client->filename)
1569 return EPWMD_NO_FILE;
1571 if (!p || !*p)
1572 return 0;
1574 flags = pwmd_cipher_str_to_cipher(p);
1576 if (!flags)
1577 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1579 MUTEX_LOCK(&rcfile_mutex);
1580 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1581 MUTEX_UNLOCK(&rcfile_mutex);
1583 if (!value)
1584 g_free((gchar *)p);
1586 return 0;
1589 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1591 struct client_s *client = data;
1593 CACHE_LOCK(client->ctx);
1594 cache_clear(client->md5file, 1);
1595 CACHE_UNLOCK;
1596 return 0;
1599 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line,
1600 gsize len)
1602 struct client_s *client = assuan_get_pointer(ctx);
1603 gboolean cached = FALSE;
1604 gpg_error_t rc;
1605 gboolean keyfile_rehash = FALSE;
1607 CACHE_LOCK(ctx);
1608 // Force rehashing the passphrase to update to the salted header.
1609 if (client->rehash)
1610 cache_clear(client->md5file, 1);
1612 cached = cache_iscached(client->md5file);
1613 CACHE_UNLOCK;
1616 * If a cache entry doesn't exist for this file and the file has a
1617 * "key_file" or "key" parameter, then it's an error. The reason is that
1618 * cache expiration would be useless. Unless this is an inquire, then its
1619 * fine.
1621 if (cached == FALSE && !client->rehash) {
1622 gchar *tmp = get_key_file_string(client->filename, "key_file");
1624 if (tmp && !(client->opts & OPT_INQUIRE)) {
1625 g_free(tmp);
1626 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1629 g_free(tmp);
1632 cached = FALSE;
1634 if (!client->crypto) {
1635 client->crypto = init_client_crypto();
1637 if (!client->crypto) {
1638 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1639 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1642 if (!client->new) {
1643 client->crypto->fh = read_file_header(client->filename, FALSE, &rc);
1644 if (rc) {
1645 cleanup_crypto(&client->crypto);
1646 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, rc);
1651 client->crypto->key = gcry_malloc(KEYSIZE);
1653 if (!client->crypto->key) {
1654 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1655 cleanup_crypto(&client->crypto);
1656 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1659 memset(client->crypto->key, '!', KEYSIZE);
1661 if (!get_key_file_uint64(client->filename, "iterations") &&
1662 (!line || !*line))
1663 goto done;
1665 if (!line || !*line) {
1666 gchar *tmp;
1668 /* It doesn't make sense to use an --inquire with an empty
1669 * passphrase. This will prevent a pinentry dialog. */
1670 if (client->opts & OPT_INQUIRE) {
1671 cleanup_crypto(&client->crypto);
1672 return GPG_ERR_WRONG_KEY_USAGE;
1675 if (client->rehash) {
1676 tmp = get_key_file_string(client->filename, "key_file");
1677 if (tmp) {
1678 gchar *file = expand_homedir(tmp);
1679 struct stat st;
1681 g_free(tmp);
1682 if (!file) {
1683 cleanup_crypto(&client->crypto);
1684 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1685 return GPG_ERR_ENOMEM;
1688 if (stat(file, &st) == -1) {
1689 gint n = errno;
1691 cleanup_crypto(&client->crypto);
1692 return n;
1695 gint fd = open(file, O_RDONLY);
1696 if (fd == -1) {
1697 gint n = errno;
1699 cleanup_crypto(&client->crypto);
1700 return n;
1703 g_free(file);
1704 line = gcry_malloc(st.st_size);
1705 if (!line) {
1706 cleanup_crypto(&client->crypto);
1707 return GPG_ERR_ENOMEM;
1710 len = pth_read(fd, line, st.st_size);
1711 close(fd);
1713 if (len != st.st_size) {
1714 gcry_free(line);
1715 cleanup_crypto(&client->crypto);
1716 return GPG_ERR_INCOMPLETE_LINE;
1719 keyfile_rehash = TRUE;
1720 goto done;
1724 client->crypto->tkey = gcry_malloc(KEYSIZE);
1726 if (!client->crypto->tkey) {
1727 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1728 cleanup_crypto(&client->crypto);
1729 return send_error(ctx, GPG_ERR_ENOMEM);
1732 memset(client->crypto->tkey, '!', KEYSIZE);
1733 CACHE_LOCK(ctx);
1735 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1736 !memcmp(client->crypto->key, client->crypto->tkey, KEYSIZE)) {
1737 CACHE_UNLOCK;
1739 #ifdef WITH_PINENTRY
1740 gpg_error_t rc;
1742 if (client->pinentry->enable == FALSE ||
1743 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1744 /* Empty keys are allowed. */
1745 rc = hash_key(client->crypto, (guchar *)"" , 1, FALSE);
1746 if (rc) {
1747 cleanup_crypto(&client->crypto);
1748 return send_error(ctx, rc);
1751 goto done;
1754 lock_pin_mutex(client);
1755 client->pinentry->which = PINENTRY_SAVE;
1756 rc = pinentry_fork(ctx);
1758 if (rc) {
1759 unlock_pin_mutex(client->pinentry);
1760 cleanup_crypto(&client->crypto);
1761 return send_error(ctx, rc);
1764 client->pinentry->cb = save_command_finalize;
1765 client->pinentry->status = PINENTRY_INIT;
1766 return 0;
1767 #else
1768 /* Empty keys are allowed. */
1769 line = "";
1770 len = 1;
1771 goto done;
1772 #endif
1774 else {
1775 CACHE_UNLOCK;
1776 cached = TRUE;
1779 else {
1780 gpg_error_t rc;
1782 if (!get_key_file_uint64(client->filename, "iterations")) {
1783 guint64 iter = get_key_file_uint64(NULL, "iterations");
1784 gchar *p;
1786 if (!iter)
1787 iter = 1; // default? what about the "global" section?
1789 MUTEX_LOCK(&rcfile_mutex);
1790 p = g_strdup_printf("%llu", (unsigned long long)iter);
1791 g_key_file_set_value(keyfileh, client->filename, "iterations", p);
1792 g_free(p);
1793 MUTEX_UNLOCK(&rcfile_mutex);
1794 client->opts |= OPT_ITERATIONS;
1795 rc = send_status(ctx, STATUS_CONFIG, NULL);
1797 if (rc) {
1798 cleanup_crypto(&client->crypto);
1799 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1804 done:
1805 rc = save_command_finalize(ctx, (guchar *)line, len, cached);
1806 if (keyfile_rehash)
1807 gcry_free(line);
1809 return rc;
1812 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1813 guchar *line, gsize len)
1815 assuan_context_t ctx = data;
1816 struct client_s *client = assuan_get_pointer(ctx);
1817 gpg_error_t rc = file_modified(client);
1819 if (assuan_rc || rc) {
1820 if (line)
1821 xfree(line);
1823 return assuan_rc ? assuan_rc : rc;
1826 rc = save_command_common(ctx, (gchar *)line, len);
1828 if (line)
1829 xfree(line);
1831 client->inquire_status = INQUIRE_DONE;
1832 return rc;
1835 static gint save_command(assuan_context_t ctx, gchar *line)
1837 struct stat st;
1838 struct client_s *client = assuan_get_pointer(ctx);
1839 gpg_error_t rc;
1840 struct argv_s *args[] = {
1841 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1842 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1843 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1844 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1845 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1846 NULL
1849 rc = parse_options(&line, args, client);
1851 if (rc)
1852 return send_error(ctx, rc);
1854 if (g_lstat(client->filename, &st) == -1 && errno != ENOENT)
1855 return send_error(ctx, gpg_error_from_syserror());
1857 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1858 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1859 return send_error(ctx, GPG_ERR_ENOANO);
1862 if ((client->opts & OPT_INQUIRE)) {
1863 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1864 ctx);
1866 if (rc)
1867 return send_error(ctx, rc);
1869 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1870 client->inquire_status = INQUIRE_BUSY;
1871 return 0;
1874 if (line && *line)
1875 log_write2("ARGS=%s", "<passphrase>");
1877 return save_command_common(ctx, line, line ? strlen(line) : 0);
1880 static gint delete_command(assuan_context_t ctx, gchar *line)
1882 struct client_s *client = assuan_get_pointer(ctx);
1883 gchar **req;
1884 gpg_error_t rc;
1885 xmlNodePtr n;
1887 log_write2("ARGS=\"%s\"", line);
1889 if (strchr(line, '\t'))
1890 req = split_input_line(line, "\t", -1);
1891 else
1892 req = split_input_line(line, " ", -1);
1894 if (!req || !*req)
1895 return send_error(ctx, GPG_ERR_SYNTAX);
1897 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1899 if (!n) {
1900 g_strfreev(req);
1901 return send_error(ctx, rc);
1905 * No sub-node defined. Remove the entire node (root element).
1907 if (!req[1]) {
1908 if (n) {
1909 rc = unlink_node(n);
1910 xmlFreeNode(n);
1913 g_strfreev(req);
1914 return send_error(ctx, rc);
1917 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1918 g_strfreev(req);
1920 if (!n)
1921 return send_error(ctx, rc);
1923 if (n) {
1924 rc = unlink_node(n);
1925 xmlFreeNode(n);
1928 return send_error(ctx, rc);
1932 * Don't return with assuan_process_done() here. This has been called from
1933 * assuan_process_next() and the command should be finished in
1934 * client_thread().
1936 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1937 gsize len)
1939 assuan_context_t ctx = data;
1940 struct client_s *client = assuan_get_pointer(ctx);
1941 gchar **req;
1942 xmlNodePtr n, parent;
1943 gboolean has_content;
1944 gchar *content = NULL;
1945 gpg_error_t rc = file_modified(client);
1947 if (assuan_rc || rc) {
1948 if (line)
1949 xfree(line);
1950 return assuan_rc ? assuan_rc : rc;
1953 req = split_input_line((gchar *)line, "\t", 0);
1954 xfree(line);
1956 if (!req || !*req)
1957 return GPG_ERR_SYNTAX;
1959 len = g_strv_length(req);
1960 has_content = line[strlen((gchar*)line)-1] != '\t' && len > 1;
1961 if (*(req+1) && !valid_element_path(req, has_content)) {
1962 g_strfreev(req);
1963 return GPG_ERR_INV_VALUE;
1966 if (has_content) {
1967 content = req[len-1];
1968 req[len-1] = NULL;
1971 again:
1972 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1973 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1974 rc = new_root_element(client->doc, *req);
1975 if (rc) {
1976 g_strfreev(req);
1977 return rc;
1980 goto again;
1983 if (!n) {
1984 g_strfreev(req);
1985 return rc;
1988 parent = n;
1990 if (req[1] && *req[1]) {
1991 if (!n->children)
1992 parent = create_elements_cb(n, req+1, &rc, NULL);
1993 else
1994 parent = find_elements(client->doc, n->children, req+1, &rc,
1995 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1998 if (!rc && len > 1) {
1999 n = find_text_node(parent->children);
2000 if (n)
2001 xmlNodeSetContent(n, (xmlChar *)content);
2002 else
2003 xmlNodeAddContent(parent, (xmlChar *)content);
2005 update_element_mtime(parent);
2008 if (has_content)
2009 req[len-1] = content;
2011 g_strfreev(req);
2012 client->inquire_status = INQUIRE_DONE;
2013 return rc;
2016 static gint store_command(assuan_context_t ctx, gchar *line)
2018 struct client_s *client = assuan_get_pointer(ctx);
2019 gpg_error_t rc;
2021 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
2023 if (rc)
2024 return send_error(ctx, rc);
2026 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
2027 client->inquire_status = INQUIRE_BUSY;
2028 return 0;
2031 static void *send_data_cb(void *arg)
2033 struct assuan_cmd_s *data = arg;
2034 gint old;
2035 gpg_error_t *rc;
2037 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
2038 rc = g_malloc(sizeof(gpg_error_t));
2039 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
2040 pth_cancel_state(old, NULL);
2041 pth_exit(rc);
2042 return NULL;
2045 /* For every assuan command that needs to be sent to the client, a timeout is
2046 * needed to determine if the client lost the connection. The timeout is the
2047 * same as the "keepalive" configuration parameter or a default if unset.
2049 gpg_error_t do_assuan_command(assuan_context_t ctx,
2050 void *(*cb)(void *data), void *data)
2052 pth_attr_t attr = pth_attr_new();
2053 pth_t tid;
2054 pth_event_t ev;
2055 pth_status_t st;
2056 gpg_error_t rc = 0;
2057 void *p;
2059 pth_attr_init(attr);
2060 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
2061 tid = pth_spawn(attr, cb, data);
2062 rc = gpg_error_from_syserror();
2063 pth_attr_destroy(attr);
2065 if (!tid) {
2066 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
2067 return rc;
2070 pth_cleanup_push(cleanup_cancel_cb, tid);
2071 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
2072 pth_cleanup_push(cleanup_ev_cb, ev);
2073 pth_yield(tid);
2074 pth_wait(ev);
2076 st = pth_event_status(ev);
2078 if (st == PTH_STATUS_FAILED) {
2079 pth_cancel(tid);
2080 pth_join(tid, &p);
2081 g_free(p);
2082 rc = GPG_ERR_ASS_WRITE_ERROR;
2084 else if (st == PTH_STATUS_OCCURRED) {
2085 pth_join(tid, &p);
2086 rc = *(gpg_error_t *)p;
2087 g_free(p);
2090 pth_cleanup_pop(1);
2091 pth_cleanup_pop(0);
2092 return rc;
2095 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
2096 gint total)
2098 gint to_send;
2099 gint sent = 0;
2100 gpg_error_t rc;
2101 struct assuan_cmd_s data;
2102 gint progress = get_key_file_integer("global", "xfer_progress");
2103 gint flush = 0;
2105 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
2106 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
2107 data.ctx = ctx;
2108 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
2110 if (rc)
2111 return rc;
2113 again:
2114 do {
2115 if (sent + to_send > total)
2116 to_send = total - sent;
2118 data.line = flush ? NULL : (gchar *)line+sent;
2119 data.line_len = flush ? 0 : to_send;
2120 rc = do_assuan_command(ctx, send_data_cb, &data);
2122 if (!rc) {
2123 sent += flush ? 0 : to_send;
2125 if ((progress && !(sent % progress) && sent != total) ||
2126 (sent == total && flush))
2127 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
2129 if (!flush && !rc && sent == total) {
2130 flush = 1;
2131 goto again;
2134 } while (!rc && sent < total);
2136 return rc;
2139 static gint get_command(assuan_context_t ctx, gchar *line)
2141 struct client_s *client = assuan_get_pointer(ctx);
2142 gchar **req;
2143 gpg_error_t rc;
2144 xmlNodePtr n;
2146 log_write2("ARGS=\"%s\"", line);
2147 req = split_input_line(line, "\t", -1);
2149 if (!req || !*req) {
2150 g_strfreev(req);
2151 return send_error(ctx, GPG_ERR_SYNTAX);
2154 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2156 if (!n) {
2157 g_strfreev(req);
2158 return send_error(ctx, rc);
2161 if (req[1])
2162 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2164 g_strfreev(req);
2166 if (rc)
2167 return send_error(ctx, rc);
2169 if (!n || !n->children)
2170 return send_error(ctx, GPG_ERR_NO_VALUE);
2172 n = find_text_node(n->children);
2174 if (!n || !n->content || !*n->content)
2175 return send_error(ctx, GPG_ERR_NO_VALUE);
2177 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2178 return send_error(ctx, rc);
2181 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2182 gpg_error_t *rc, gchar **req_orig, void *data)
2184 gchar *path = *(gchar **)data;
2185 gchar *tmp = NULL, *result;
2187 if (path) {
2188 g_free(path);
2189 *(gchar **)data = NULL;
2192 path = g_strjoinv("\t", target);
2194 if (!path) {
2195 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2196 *rc = GPG_ERR_ENOMEM;
2197 return NULL;
2200 if (req_orig) {
2201 tmp = g_strjoinv("\t", req_orig);
2203 if (!tmp) {
2204 g_free(path);
2205 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2206 *rc = GPG_ERR_ENOMEM;
2207 return NULL;
2211 if (tmp && *tmp)
2212 result = g_strdup_printf("%s\t%s", path, tmp);
2213 else
2214 result = g_strdup(path);
2216 if (!result) {
2217 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2218 *rc = GPG_ERR_ENOMEM;
2219 g_free(path);
2220 g_free(tmp);
2221 return NULL;
2224 g_free(path);
2225 g_free(tmp);
2226 *(gchar **)data = result;
2227 return node;
2230 static void list_command_cleanup1(void *arg);
2231 static gint realpath_command(assuan_context_t ctx, gchar *line)
2233 gpg_error_t rc;
2234 struct client_s *client = assuan_get_pointer(ctx);
2235 gchar **req;
2236 gchar *t;
2237 gint i;
2238 xmlNodePtr n;
2239 GString *string;
2240 gchar *rp = NULL;
2242 log_write2("ARGS=\"%s\"", line);
2244 if (strchr(line, '\t') != NULL) {
2245 if ((req = split_input_line(line, "\t", 0)) == NULL)
2246 return send_error(ctx, GPG_ERR_SYNTAX);
2248 else {
2249 if ((req = split_input_line(line, " ", 0)) == NULL)
2250 return send_error(ctx, GPG_ERR_SYNTAX);
2253 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2255 if (!n) {
2256 g_strfreev(req);
2257 return send_error(ctx, rc);
2260 rp = g_strjoinv("\t", req);
2262 if (!rp) {
2263 g_strfreev(req);
2264 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2265 return send_error(ctx, GPG_ERR_ENOMEM);
2268 if (req[1]) {
2269 n = find_elements(client->doc, n->children, req+1, &rc,
2270 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2272 if (!n) {
2273 g_free(rp);
2274 g_strfreev(req);
2275 return send_error(ctx, rc);
2279 string = g_string_new(rp);
2280 g_free(rp);
2281 g_strfreev(req);
2283 if (!string) {
2284 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2285 return send_error(ctx, GPG_ERR_ENOMEM);
2288 again:
2289 for (i = 0, t = string->str + i; *t; t++, i++) {
2290 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2291 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2292 goto again;
2296 pth_cleanup_push(list_command_cleanup1, string);
2297 rc = xfer_data(ctx, string->str, string->len);
2298 pth_cleanup_pop(1);
2299 return send_error(ctx, rc);
2302 static void list_command_cleanup1(void *arg)
2304 g_string_free((GString *)arg, TRUE);
2307 static void list_command_cleanup2(void *arg)
2309 struct element_list_s *elements = arg;
2311 if (elements) {
2312 if (elements->list) {
2313 gint total = g_slist_length(elements->list);
2314 gint i;
2316 for (i = 0; i < total; i++) {
2317 gchar *tmp = g_slist_nth_data(elements->list, i);
2318 g_free(tmp);
2321 g_slist_free(elements->list);
2324 if (elements->prefix)
2325 g_free(elements->prefix);
2327 if (elements->req)
2328 g_strfreev(elements->req);
2330 g_free(elements);
2334 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2336 struct element_list_s *elements = data;
2338 elements->recurse = FALSE;
2339 return 0;
2342 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2344 struct element_list_s *elements = data;
2346 elements->verbose = TRUE;
2347 return 0;
2350 static gint list_command(assuan_context_t ctx, gchar *line)
2352 struct client_s *client = assuan_get_pointer(ctx);
2353 gpg_error_t rc;
2354 struct element_list_s *elements = NULL;
2355 gchar *tmp;
2356 struct argv_s *args[] = {
2357 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2358 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2359 NULL
2362 if (disable_list_and_dump == TRUE)
2363 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2365 elements = g_malloc0(sizeof(struct element_list_s));
2367 if (!elements) {
2368 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2369 return GPG_ERR_ENOMEM;
2372 elements->recurse = TRUE; // default
2373 pth_cleanup_push(list_command_cleanup2, elements);
2374 rc = parse_options(&line, args, elements);
2376 if (rc)
2377 goto fail;
2379 if (!*line) {
2380 GString *str;
2382 rc = list_root_elements(client->doc, &str, elements->verbose);
2384 if (rc) {
2385 pth_cleanup_pop(1);
2386 return send_error(ctx, rc);
2389 pth_cleanup_push(list_command_cleanup1, str);
2390 rc = xfer_data(ctx, str->str, str->len);
2391 pth_cleanup_pop(1);
2392 pth_cleanup_pop(1);
2393 return send_error(ctx, rc);
2396 elements->req = split_input_line(line, " ", 0);
2398 if (!elements->req)
2399 strv_printf(&elements->req, "%s", line);
2401 rc = create_path_list(client->doc, elements, *elements->req);
2403 if (rc)
2404 goto fail;
2406 if (elements) {
2407 gint total = g_slist_length(elements->list);
2408 gint i;
2409 GString *str;
2411 if (!total) {
2412 rc = GPG_ERR_NO_VALUE;
2413 goto fail;
2416 str = g_string_new(NULL);
2418 if (!str) {
2419 rc = GPG_ERR_ENOMEM;
2420 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2421 goto fail;
2424 for (i = 0; i < total; i++) {
2425 tmp = g_slist_nth_data(elements->list, i);
2426 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2429 pth_cleanup_push(list_command_cleanup1, str);
2430 rc = xfer_data(ctx, str->str, str->len);
2431 pth_cleanup_pop(1);
2433 else
2434 rc = GPG_ERR_NO_VALUE;
2436 fail:
2437 pth_cleanup_pop(1);
2438 return send_error(ctx, rc);
2442 * req[0] - element path
2444 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2446 struct client_s *client = assuan_get_pointer(ctx);
2447 gchar **attrlist = NULL;
2448 gint i = 0;
2449 gchar **path = NULL;
2450 xmlAttrPtr a;
2451 xmlNodePtr n, an;
2452 gchar *line;
2453 gpg_error_t rc;
2455 if (!req || !req[0])
2456 return GPG_ERR_SYNTAX;
2458 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2460 * The first argument may be only a root element.
2462 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2463 return GPG_ERR_SYNTAX;
2466 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2468 if (!n) {
2469 g_strfreev(path);
2470 return rc;
2473 if (path[1]) {
2474 n = find_elements(client->doc, n->children, path+1, &rc,
2475 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2477 if (!n) {
2478 g_strfreev(path);
2479 return rc;
2483 g_strfreev(path);
2485 for (a = n->properties; a; a = a->next) {
2486 gchar **pa;
2488 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2489 if (attrlist)
2490 g_strfreev(attrlist);
2492 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2493 return GPG_ERR_ENOMEM;
2496 attrlist = pa;
2497 an = a->children;
2498 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2499 an && an->content ? (gchar *)an->content : "");
2501 if (!attrlist[i]) {
2502 g_strfreev(attrlist);
2503 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2504 return GPG_ERR_ENOMEM;
2507 attrlist[++i] = NULL;
2510 if (!attrlist)
2511 return GPG_ERR_NO_VALUE;
2513 line = g_strjoinv("\n", attrlist);
2515 if (!line) {
2516 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2517 g_strfreev(attrlist);
2518 return GPG_ERR_ENOMEM;
2521 pth_cleanup_push(g_free, line);
2522 pth_cleanup_push(req_cleanup, attrlist);
2523 rc = xfer_data(ctx, line, strlen(line));
2524 pth_cleanup_pop(1);
2525 pth_cleanup_pop(1);
2526 return rc;
2530 * req[0] - attribute
2531 * req[1] - element path
2533 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2535 xmlNodePtr n;
2536 gchar **path = NULL;
2537 gpg_error_t rc;
2539 if (!req || !req[0] || !req[1])
2540 return GPG_ERR_SYNTAX;
2542 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2544 * The first argument may be only a root element.
2546 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2547 return GPG_ERR_SYNTAX;
2551 * Don't remove the "_name" attribute for the root element. To remove an
2552 * root element use DELETE <name>.
2554 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2555 rc = GPG_ERR_SYNTAX;
2556 goto fail;
2559 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2561 if (!n)
2562 goto fail;
2564 if (path[1]) {
2565 n = find_elements(client->doc, n->children, path+1, &rc,
2566 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2568 if (!n)
2569 goto fail;
2572 rc = delete_attribute(n, (xmlChar *)req[0]);
2574 fail:
2575 g_strfreev(path);
2576 return rc;
2579 static xmlNodePtr create_element_path(struct client_s *client,
2580 gchar ***elements, gpg_error_t *rc, xmlNodePtr parent)
2582 gchar **req = *elements;
2583 gchar **req_orig = g_strdupv(req);
2584 xmlNodePtr n = NULL;
2586 *rc = 0;
2588 if (!req_orig) {
2589 *rc = GPG_ERR_ENOMEM;
2590 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2591 goto fail;
2594 again:
2595 n = find_root_element(client->doc, &req, rc, NULL, 0, FALSE);
2596 if (!n) {
2597 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND)
2598 goto fail;
2600 *rc = new_root_element(client->doc, req[0]);
2601 if (*rc)
2602 goto fail;
2604 goto again;
2606 else if (n == parent) {
2607 *rc = GPG_ERR_CONFLICT;
2608 goto fail;
2611 if (req[1]) {
2612 if (!n->children)
2613 n = create_target_elements_cb(n, req+1, rc, NULL);
2614 else
2615 n = find_elements(client->doc, n->children, req+1, rc, NULL, NULL,
2616 create_target_elements_cb, FALSE, 0, parent, FALSE);
2618 if (!n)
2619 goto fail;
2622 * Reset the position of the element tree now that the elements
2623 * have been created.
2625 g_strfreev(req);
2626 req = req_orig;
2627 req_orig = NULL;
2628 n = find_root_element(client->doc, &req, rc, NULL, 0, FALSE);
2629 if (!n)
2630 goto fail;
2632 n = find_elements(client->doc, n->children, req+1, rc,
2633 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2634 if (!n)
2635 goto fail;
2638 fail:
2639 if (req_orig)
2640 g_strfreev(req_orig);
2642 *elements = req;
2643 return n;
2647 * Creates a "target" attribute. When other commands encounter an element with
2648 * this attribute, the element path is modified to the target value. If the
2649 * source element path doesn't exist when using 'ATTR SET target', it is
2650 * created, but the destination element path must exist.
2652 * req[0] - source element path
2653 * req[1] - destination element path
2655 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2657 gchar **src, **dst, *line = NULL, **odst = NULL;
2658 gpg_error_t rc;
2659 xmlNodePtr n;
2661 if (!req || !req[0] || !req[1])
2662 return GPG_ERR_SYNTAX;
2664 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2666 * The first argument may be only a root element.
2668 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2669 return GPG_ERR_SYNTAX;
2672 if (!valid_element_path(src, FALSE))
2673 return GPG_ERR_INV_VALUE;
2675 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2677 * The first argument may be only a root element.
2679 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2680 rc = GPG_ERR_SYNTAX;
2681 goto fail;
2685 odst = g_strdupv(dst);
2687 if (!odst) {
2688 rc = GPG_ERR_ENOMEM;
2689 goto fail;
2692 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2695 * Make sure the destination element path exists.
2697 if (!n)
2698 goto fail;
2700 if (dst[1]) {
2701 n = find_elements(client->doc, n->children, dst+1, &rc,
2702 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2704 if (!n)
2705 goto fail;
2708 n = create_element_path(client, &src, &rc, NULL);
2710 if (rc)
2711 goto fail;
2713 line = g_strjoinv("\t", odst);
2715 if (!line) {
2716 rc = GPG_ERR_ENOMEM;
2717 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2718 goto fail;
2721 rc = add_attribute(n, "target", line);
2723 fail:
2724 g_free(line);
2725 g_strfreev(src);
2726 g_strfreev(dst);
2727 g_strfreev(odst);
2728 return rc;
2732 * req[0] - name
2733 * req[1] - new name
2735 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2737 gpg_error_t rc;
2738 gchar **tmp;
2739 xmlNodePtr n;
2741 tmp = g_strdupv(req);
2743 if (!tmp) {
2744 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2745 return GPG_ERR_ENOMEM;
2748 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2749 g_strfreev(tmp);
2751 if (!n)
2752 return rc;
2754 if (g_utf8_collate(req[0], req[1]) == 0)
2755 return 0;
2758 * Will not overwrite an existing root.
2760 tmp = g_strdupv(req+1);
2762 if (!tmp) {
2763 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2764 return GPG_ERR_ENOMEM;
2767 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2768 g_strfreev(tmp);
2770 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2771 return rc;
2773 if (n)
2774 return GPG_ERR_AMBIGUOUS_NAME;
2776 if (!valid_xml_element((xmlChar *)req[1]))
2777 return GPG_ERR_SYNTAX;
2779 tmp = g_strdupv(req);
2781 if (!tmp) {
2782 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2783 return GPG_ERR_ENOMEM;
2786 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2787 g_strfreev(tmp);
2789 if (!n)
2790 return GPG_ERR_ELEMENT_NOT_FOUND;
2792 return add_attribute(n, "_name", req[1]);
2796 * req[0] - attribute
2797 * req[1] - element path
2799 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2801 struct client_s *client = assuan_get_pointer(ctx);
2802 xmlNodePtr n;
2803 xmlChar *a;
2804 gchar **path= NULL;
2805 gpg_error_t rc;
2807 if (!req || !req[0] || !req[1])
2808 return GPG_ERR_SYNTAX;
2810 if (strchr(req[1], '\t')) {
2811 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2812 return GPG_ERR_SYNTAX;
2814 else {
2815 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2816 return GPG_ERR_SYNTAX;
2819 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2821 if (!n)
2822 goto fail;
2824 if (path[1]) {
2825 n = find_elements(client->doc, n->children, path+1, &rc,
2826 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2828 if (!n)
2829 goto fail;
2832 g_strfreev(path);
2834 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2835 return GPG_ERR_NOT_FOUND;
2837 pth_cleanup_push(xmlFree, a);
2839 if (*a)
2840 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2841 else
2842 rc = GPG_ERR_NO_VALUE;
2844 pth_cleanup_pop(1);
2845 return rc;
2847 fail:
2848 g_strfreev(path);
2849 return rc;
2853 * req[0] - attribute
2854 * req[1] - element path
2855 * req[2] - value
2857 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2859 gchar **path = NULL;
2860 gpg_error_t rc;
2861 xmlNodePtr n;
2863 if (!req || !req[0] || !req[1])
2864 return GPG_ERR_SYNTAX;
2867 * Reserved attribute names.
2869 if (!g_strcmp0(req[0], "_name")) {
2871 * Only reserved for the root element. Not the rest of the
2872 * document.
2874 if (strchr(req[1], '\t') == NULL)
2875 return name_attribute(client, req + 1);
2877 else if (!g_strcmp0(req[0], "target"))
2878 return target_attribute(client, req + 1);
2880 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2882 * The first argument may be only a root element.
2884 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2885 return GPG_ERR_SYNTAX;
2888 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2890 if (!n)
2891 goto fail;
2893 if (path[1]) {
2894 n = find_elements(client->doc, n->children, path+1, &rc,
2895 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2897 if (!n)
2898 goto fail;
2901 rc = add_attribute(n, req[0], req[2]);
2903 fail:
2904 g_strfreev(path);
2905 return rc;
2909 * req[0] - command
2910 * req[1] - attribute name or element path if command is LIST
2911 * req[2] - element path
2912 * req[2] - element path or value
2914 static gint attr_command(assuan_context_t ctx, gchar *line)
2916 struct client_s *client = assuan_get_pointer(ctx);
2917 gchar **req;
2918 gpg_error_t rc = 0;
2920 log_write2("ARGS=\"%s\"", line);
2921 req = split_input_line(line, " ", 4);
2923 if (!req || !req[0] || !req[1]) {
2924 g_strfreev(req);
2925 return send_error(ctx, GPG_ERR_SYNTAX);
2928 pth_cleanup_push(req_cleanup, req);
2930 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2931 rc = attribute_set(client, req+1);
2932 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2933 rc = attribute_get(ctx, req+1);
2934 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2935 rc = attribute_delete(client, req+1);
2936 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2937 rc = attribute_list(ctx, req+1);
2938 else
2939 rc = GPG_ERR_SYNTAX;
2941 pth_cleanup_pop(1);
2942 return send_error(ctx, rc);
2945 static gint iscached_command(assuan_context_t ctx, gchar *line)
2947 gchar **req = split_input_line(line, " ", 0);
2948 guchar md5file[16];
2949 gchar *path, *tmp;
2951 if (!req || !*req) {
2952 g_strfreev(req);
2953 return send_error(ctx, GPG_ERR_SYNTAX);
2956 log_write2("ARGS=\"%s\"", line);
2958 if (!valid_filename(req[0])) {
2959 g_strfreev(req);
2960 return GPG_ERR_INV_VALUE;
2963 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2964 CACHE_LOCK(ctx);
2966 if (cache_iscached(md5file)) {
2967 g_strfreev(req);
2968 CACHE_UNLOCK;
2969 return send_error(ctx, 0);
2972 CACHE_UNLOCK;
2973 tmp = get_key_file_string("global", "data_directory");
2975 if (!tmp) {
2976 g_strfreev(req);
2977 return GPG_ERR_ENOMEM;
2980 path = expand_homedir(tmp);
2982 if (!path) {
2983 g_strfreev(req);
2984 g_free(tmp);
2985 return GPG_ERR_ENOMEM;
2988 g_free(tmp);
2989 tmp = path;
2990 path = g_strdup_printf("%s/%s", tmp, req[0]);
2991 g_free(tmp);
2993 if (!path) {
2994 g_strfreev(req);
2995 return GPG_ERR_ENOMEM;
2998 if (access(path, R_OK) == -1) {
2999 gpg_error_t rc = gpg_error_from_syserror();
3001 g_free(path);
3002 g_strfreev(req);
3003 return send_error(ctx, rc);
3006 g_free(path);
3007 return send_error(ctx, GPG_ERR_NOT_FOUND);
3010 static gint clearcache_command(assuan_context_t ctx, gchar *line)
3012 gchar **req = split_input_line(line, " ", 0);
3013 guchar md5file[16];
3015 log_write2("ARGS=\"%s\"", line);
3016 CACHE_LOCK(ctx);
3018 if (!req || !*req) {
3019 g_strfreev(req);
3020 cache_clear(NULL, 2);
3021 CACHE_UNLOCK;
3022 return send_error(ctx, 0);
3025 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
3026 g_strfreev(req);
3027 (void)cache_clear(md5file, 1);
3028 CACHE_UNLOCK;
3029 return send_error(ctx, 0);
3032 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
3034 guchar md5file[16];
3035 glong timeout;
3036 gchar **req = split_input_line(line, " ", 0);
3037 gchar *p;
3039 if (!req || !*req || !req[1]) {
3040 g_strfreev(req);
3041 return send_error(ctx, GPG_ERR_SYNTAX);
3044 errno = 0;
3045 timeout = strtol(req[1], &p, 10);
3047 if (errno != 0 || *p != 0 || timeout < -1) {
3048 g_strfreev(req);
3049 return send_error(ctx, GPG_ERR_SYNTAX);
3052 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
3053 CACHE_LOCK(client->ctx);
3055 if (cache_set_timeout(md5file, timeout) == FALSE) {
3056 CACHE_UNLOCK;
3057 return send_error(ctx, GPG_ERR_NOT_FOUND);
3060 CACHE_UNLOCK;
3061 return send_error(ctx, 0);
3064 static gint dump_command(assuan_context_t ctx, gchar *line)
3066 xmlChar *xml;
3067 gint len;
3068 struct client_s *client = assuan_get_pointer(ctx);
3069 gpg_error_t rc;
3071 if (disable_list_and_dump == TRUE)
3072 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3074 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
3076 if (!xml) {
3077 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3078 return send_error(ctx, GPG_ERR_ENOMEM);
3081 pth_cleanup_push(xmlFree, xml);
3082 rc = xfer_data(ctx, (gchar *)xml, len);
3083 pth_cleanup_pop(1);
3084 return send_error(ctx, rc);
3087 static gint getconfig_command(assuan_context_t ctx, gchar *line)
3089 struct client_s *client = assuan_get_pointer(ctx);
3090 gpg_error_t rc = 0;
3091 gchar filename[255]={0}, param[747]={0};
3092 gchar *p, *tmp, *fp = client->filename, *paramp = line;
3094 log_write2("ARGS=\"%s\"", line);
3096 if (!line || !*line)
3097 return send_error(ctx, GPG_ERR_SYNTAX);
3099 if (strchr(line, ' ')) {
3100 sscanf(line, " %254[^ ] %746c", filename, param);
3101 paramp = param;
3102 fp = filename;
3105 if (fp && !valid_filename(fp))
3106 return send_error(ctx, GPG_ERR_INV_VALUE);
3108 paramp = g_ascii_strdown(paramp, -1);
3110 if (!paramp) {
3111 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3112 return send_error(ctx, GPG_ERR_ENOMEM);
3115 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
3116 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
3117 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
3119 if (!fh && rc != GPG_ERR_ENOENT)
3120 return send_error(ctx, rc);
3122 if (!rc) {
3123 g_free(paramp);
3124 p = g_strdup_printf("%llu", (unsigned long long)fh->ver.fh2.iter);
3125 close_file_header(fh);
3127 if (!p) {
3128 log_write("%s(%i): %s", __FILE__, __LINE__,
3129 pwmd_strerror(GPG_ERR_ENOMEM));
3130 return send_error(ctx, GPG_ERR_ENOMEM);
3133 goto done;
3137 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
3138 #ifdef WITH_PINENTRY
3139 gboolean n;
3141 if (fp == client->filename && (client->opts & OPT_PINENTRY))
3142 n = client->pinentry->enable;
3143 else
3144 n = get_key_file_boolean(fp, "enable_pinentry");
3146 p = g_strdup_printf("%s", n ? "true" : "false");
3148 if (!p) {
3149 log_write("%s(%i): %s", __FILE__, __LINE__,
3150 pwmd_strerror(GPG_ERR_ENOMEM));
3151 return send_error(ctx, GPG_ERR_ENOMEM);
3154 goto done;
3155 #else
3156 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3157 #endif
3159 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3160 #ifdef WITH_PINENTRY
3161 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3163 if (!p) {
3164 log_write("%s(%i): %s", __FILE__, __LINE__,
3165 pwmd_strerror(GPG_ERR_ENOMEM));
3166 return send_error(ctx, GPG_ERR_ENOMEM);
3169 goto done;
3170 #else
3171 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3172 #endif
3175 p = get_key_file_string(fp ? fp : "global", paramp);
3176 g_free(paramp);
3178 if (!p)
3179 return send_error(ctx, GPG_ERR_UNKNOWN_OPTION);
3181 tmp = expand_homedir(p);
3182 g_free(p);
3184 if (!tmp) {
3185 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3186 return send_error(ctx, GPG_ERR_ENOMEM);
3189 p = tmp;
3190 done:
3191 pth_cleanup_push(g_free, p);
3192 rc = xfer_data(ctx, p, strlen(p));
3193 pth_cleanup_pop(1);
3194 return send_error(ctx, rc);
3197 struct xpath_s {
3198 xmlXPathContextPtr xp;
3199 xmlXPathObjectPtr result;
3200 xmlBufferPtr buf;
3201 gchar **req;
3204 static void xpath_command_cleanup(void *arg)
3206 struct xpath_s *xpath = arg;
3208 req_cleanup(xpath->req);
3210 if (xpath->buf)
3211 xmlBufferFree(xpath->buf);
3213 if (xpath->result)
3214 xmlXPathFreeObject(xpath->result);
3216 if (xpath->xp)
3217 xmlXPathFreeContext(xpath->xp);
3220 static gint xpath_command(assuan_context_t ctx, gchar *line)
3222 struct client_s *client = assuan_get_pointer(ctx);
3223 gpg_error_t rc;
3224 struct xpath_s xpath;
3226 log_write2("ARGS=\"%s\"", line);
3228 if (disable_list_and_dump == TRUE)
3229 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3231 if (!line || !*line)
3232 return send_error(ctx, GPG_ERR_SYNTAX);
3234 memset(&xpath, 0, sizeof(struct xpath_s));
3236 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3237 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3238 return send_error(ctx, GPG_ERR_ENOMEM);
3241 xpath.xp = xmlXPathNewContext(client->doc);
3243 if (!xpath.xp) {
3244 xpath_command_cleanup(&xpath);
3245 return send_error(ctx, EPWMD_LIBXML_ERROR);
3248 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3250 if (!xpath.result) {
3251 xpath_command_cleanup(&xpath);
3252 return send_error(ctx, EPWMD_LIBXML_ERROR);
3255 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3256 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3257 goto fail;
3260 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3261 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3263 if (rc)
3264 goto fail;
3265 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3266 rc = GPG_ERR_NO_VALUE;
3267 goto fail;
3269 else if (xpath.req[1])
3270 goto fail;
3272 pth_cleanup_push(xpath_command_cleanup, &xpath);
3273 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3274 xmlBufferLength(xpath.buf));
3275 pth_cleanup_pop(0);
3277 fail:
3278 xpath_command_cleanup(&xpath);
3279 return send_error(ctx, rc);
3282 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3283 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3285 struct client_s *client = assuan_get_pointer(ctx);
3286 gpg_error_t rc;
3287 struct xpath_s xpath;
3288 gchar **req = NULL;
3289 gboolean cmd = FALSE; //SET
3291 log_write2("ARGS=\"%s\"", line);
3293 if (disable_list_and_dump == TRUE)
3294 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3296 if (!line || !*line)
3297 return send_error(ctx, GPG_ERR_SYNTAX);
3299 memset(&xpath, 0, sizeof(struct xpath_s));
3301 if ((req = split_input_line(line, " ", 3)) == NULL)
3302 return send_error(ctx, GPG_ERR_ENOMEM);
3304 if (!req[0]) {
3305 rc = GPG_ERR_SYNTAX;
3306 goto fail;
3309 if (!g_ascii_strcasecmp(req[0], "SET"))
3310 cmd = FALSE;
3311 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3312 cmd = TRUE;
3313 else {
3314 rc = GPG_ERR_SYNTAX;
3315 goto fail;
3318 if (!req[1] || !req[2]) {
3319 rc = GPG_ERR_SYNTAX;
3320 goto fail;
3323 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3324 rc = GPG_ERR_ENOMEM;
3325 goto fail;
3328 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3329 rc = GPG_ERR_SYNTAX;
3330 goto fail;
3333 xpath.xp = xmlXPathNewContext(client->doc);
3335 if (!xpath.xp) {
3336 rc = EPWMD_LIBXML_ERROR;
3337 goto fail;
3340 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3342 if (!xpath.result) {
3343 rc = EPWMD_LIBXML_ERROR;
3344 goto fail;
3347 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3348 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3349 goto fail;
3352 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3353 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3355 fail:
3356 g_strfreev(req);
3357 xpath_command_cleanup(&xpath);
3358 return send_error(ctx, rc);
3361 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3362 gsize len)
3364 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3365 gpg_error_t rc = file_modified(client);
3366 gchar **req, **path = NULL, **path_orig = NULL, *content;
3367 xmlDocPtr doc = NULL;
3368 xmlNodePtr n, root, copy;
3370 if (assuan_rc || rc) {
3371 if (line)
3372 xfree(line);
3373 return assuan_rc ? assuan_rc : rc;
3376 req = split_input_line((gchar *)line, "\t", 2);
3377 xfree(line);
3379 if (!req || !*req)
3380 return GPG_ERR_SYNTAX;
3382 content = req[0];
3383 path = split_input_line(req[1], "\t", 0);
3385 if (!content || !*content) {
3386 rc = GPG_ERR_SYNTAX;
3387 goto fail;
3390 if (path && !valid_element_path(path, FALSE)) {
3391 rc = GPG_ERR_INV_VALUE;
3392 goto fail;
3395 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3397 if (!doc) {
3398 rc = EPWMD_LIBXML_ERROR;
3399 goto fail;
3402 root = xmlDocGetRootElement(doc);
3403 rc = validate_import(root);
3405 if (rc)
3406 goto fail;
3408 if (path) {
3409 path_orig = g_strdupv(path);
3411 if (!path_orig) {
3412 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3413 rc = GPG_ERR_ENOMEM;
3414 goto fail;
3417 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3419 if (!a) {
3420 g_strfreev(path_orig);
3421 rc = GPG_ERR_ENOMEM;
3422 goto fail;
3425 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3426 xmlFree(a);
3427 g_strfreev(path_orig);
3428 rc = GPG_ERR_ENOMEM;
3429 goto fail;
3432 xmlFree(a);
3433 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3435 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3436 g_strfreev(path_orig);
3437 goto fail;
3440 if (!rc) {
3441 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3443 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3444 g_strfreev(path_orig);
3445 goto fail;
3447 else if (!rc) {
3448 xmlNodePtr parent = n->parent;
3450 xmlUnlinkNode(n);
3451 xmlFreeNode(n);
3452 n = parent;
3456 g_strfreev(path);
3457 path = path_orig;
3459 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3460 n = create_element_path(client, &path, &rc, NULL);
3462 if (rc)
3463 goto fail;
3466 copy = xmlCopyNodeList(root);
3467 n = xmlAddChildList(n, copy);
3469 if (!n)
3470 rc = EPWMD_LIBXML_ERROR;
3472 else {
3473 /* Check if the content root element can create a DTD root element. */
3474 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3475 rc = GPG_ERR_SYNTAX;
3476 goto fail;
3479 xmlChar *a;
3481 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3482 rc = GPG_ERR_SYNTAX;
3483 goto fail;
3486 gchar *tmp = g_strdup((gchar *)a);
3487 xmlFree(a);
3488 gboolean literal = is_literal_element(&tmp);
3490 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3491 g_free(tmp);
3492 rc = GPG_ERR_INV_VALUE;
3493 goto fail;
3496 if (strv_printf(&path, "%s", tmp) == FALSE) {
3497 g_free(tmp);
3498 rc = GPG_ERR_ENOMEM;
3499 goto fail;
3502 g_free(tmp);
3503 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3505 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3506 rc = EPWMD_LIBXML_ERROR;
3507 goto fail;
3510 /* Overwriting the existing tree. */
3511 if (!rc) {
3512 xmlUnlinkNode(n);
3513 xmlFreeNodeList(n);
3516 rc = 0;
3517 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3518 n = xmlCopyNode(root, 1);
3519 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3522 if (n && !rc)
3523 rc = update_element_mtime(n->parent);
3525 fail:
3526 if (doc)
3527 xmlFreeDoc(doc);
3529 if (path)
3530 g_strfreev(path);
3532 g_strfreev(req);
3533 client->inquire_status = INQUIRE_DONE;
3534 return rc;
3537 static gint import_command(assuan_context_t ctx, gchar *line)
3539 gpg_error_t rc;
3540 struct client_s *client = assuan_get_pointer(ctx);
3542 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3544 if (rc)
3545 return send_error(ctx, rc);
3547 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3548 client->inquire_status = INQUIRE_BUSY;
3549 return 0;
3552 static gpg_error_t do_lock_command(struct client_s *client)
3554 gpg_error_t rc = lock_file_mutex(client);
3556 if (!rc)
3557 client->is_lock_cmd = TRUE;
3559 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3562 static gint lock_command(assuan_context_t ctx, gchar *line)
3564 struct client_s *client = assuan_get_pointer(ctx);
3566 return do_lock_command(client);
3569 static gint unlock_command(assuan_context_t ctx, gchar *line)
3571 struct client_s *client = assuan_get_pointer(ctx);
3573 unlock_file_mutex(client);
3574 return send_error(ctx, 0);
3577 static gint getpid_command(assuan_context_t ctx, gchar *line)
3579 gpg_error_t rc;
3580 gchar buf[32];
3581 pid_t pid = getpid();
3583 print_fmt(buf, sizeof(buf), "%i", pid);
3584 rc = xfer_data(ctx, buf, strlen(buf));
3585 return send_error(ctx, rc);
3588 static gint version_command(assuan_context_t ctx, gchar *line)
3590 gpg_error_t rc;
3591 gchar *buf;
3593 buf = g_strdup_printf("0x%X %s", VERSION_HEX,
3594 #ifdef WITH_PINENTRY
3595 "PINENTRY "
3596 #endif
3597 #ifdef WITH_QUALITY
3598 "QUALITY "
3599 #endif
3600 #ifdef WITH_LIBACL
3601 "ACL "
3602 #endif
3603 "");
3604 rc = xfer_data(ctx, buf, strlen(buf));
3605 g_free(buf);
3606 return send_error(ctx, rc);
3609 #ifdef WITH_PINENTRY
3610 static void set_option_value(gchar **opt, const gchar *value)
3612 if (opt)
3613 g_free(*opt);
3615 *opt = NULL;
3617 if (value)
3618 *opt = g_strdup(value);
3620 #endif
3622 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3623 const gchar *value)
3625 struct client_s *client = assuan_get_pointer(ctx);
3626 gpg_error_t rc;
3628 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3629 gint n = 0;
3631 if (value) {
3632 n = atoi(value);
3634 if (n < 0 || n > 2)
3635 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3638 MUTEX_LOCK(&rcfile_mutex);
3639 g_key_file_set_integer(keyfileh, "global", "log_level", n);
3640 MUTEX_UNLOCK(&rcfile_mutex);
3641 goto done;
3643 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3644 gint n = 0;
3646 if (value) {
3647 n = atoi(value);
3649 if (n < 0 || n > 1)
3650 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3653 client->rc_on_locked = n ? TRUE : FALSE;
3654 goto done;
3656 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3657 rc = parse_open_opt_lock(client, (gpointer)value);
3659 if (rc)
3660 return rc;
3662 client->opts |= OPT_LOCK;
3664 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3665 if (!value) {
3666 client->opts &= ~(OPT_CIPHER);
3667 goto done;
3670 rc = parse_save_opt_cipher(client, (gpointer)value);
3672 if (rc)
3673 return rc;
3675 client->opts |= OPT_CIPHER;
3676 goto done;
3678 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3679 rc = parse_save_opt_iterations(client, (gpointer)value);
3681 if (rc)
3682 return rc;
3684 goto done;
3686 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3687 pth_attr_t attr = pth_attr_of(pth_self());
3688 gchar buf[41];
3690 if (!value) {
3691 pth_attr_destroy(attr);
3692 goto done;
3695 print_fmt(buf, sizeof(buf), "%s", value);
3696 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3697 pth_attr_destroy(attr);
3698 #ifdef WITH_PINENTRY
3699 if (client->pinentry->name)
3700 g_free(client->pinentry->name);
3702 client->pinentry->name = g_strdup(buf);
3704 if (!client->pinentry->name)
3705 return GPG_ERR_ENOMEM;
3706 #endif
3708 goto done;
3710 #ifdef WITH_PINENTRY
3711 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3712 set_option_value(&client->pinentry->lcmessages, value);
3713 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3714 set_option_value(&client->pinentry->lcctype, value);
3715 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3716 set_option_value(&client->pinentry->ttyname, value);
3717 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3718 set_option_value(&client->pinentry->ttytype, value);
3719 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3720 set_option_value(&client->pinentry->display, value);
3721 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3722 set_option_value(&client->pinentry->path, value);
3723 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3724 set_option_value(&client->pinentry->title, value);
3725 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3726 set_option_value(&client->pinentry->prompt, value);
3727 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3728 set_option_value(&client->pinentry->desc, value);
3729 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3730 gchar *p = NULL;
3731 gint n;
3733 if (!value)
3734 goto done;
3736 n = atoi(value);
3738 if (*p || n < 0)
3739 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3741 MUTEX_LOCK(&rcfile_mutex);
3742 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3743 "global", "pinentry_timeout", n);
3744 MUTEX_UNLOCK(&rcfile_mutex);
3745 goto done;
3747 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3748 rc = parse_opt_pinentry(client, (gpointer)value);
3750 if (rc)
3751 return rc;
3753 goto done;
3755 #else
3756 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3757 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3758 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3759 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3760 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3761 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3762 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3763 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3764 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3765 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3766 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3767 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3768 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3769 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3770 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3771 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3772 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3773 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3774 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3775 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3776 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3777 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3778 #endif
3779 else
3780 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3782 done:
3783 return 0;
3786 static gint unset_command(assuan_context_t ctx, gchar *line)
3788 log_write2("ARGS=\"%s\"", line);
3789 return send_error(ctx, set_unset_common(ctx, line, NULL));
3792 static gint set_command(assuan_context_t ctx, gchar *line)
3794 gchar name[64] = {0}, value[256] = {0};
3796 log_write2("ARGS=\"%s\"", line);
3798 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3799 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3801 return send_error(ctx, set_unset_common(ctx, name, value));
3804 static gint rename_command(assuan_context_t ctx, gchar *line)
3806 struct client_s *client = assuan_get_pointer(ctx);
3807 gpg_error_t rc;
3808 gchar **req, **src, *dst;
3809 xmlNodePtr n, ndst;
3811 log_write2("ARGS=\"%s\"", line);
3812 req = split_input_line(line, " ", -1);
3814 if (!req || !req[0] || !req[1]) {
3815 g_strfreev(req);
3816 return send_error(ctx, GPG_ERR_SYNTAX);
3819 dst = req[1];
3820 is_literal_element(&dst);
3822 if (!valid_xml_element((xmlChar *)dst)) {
3823 g_strfreev(req);
3824 return GPG_ERR_INV_VALUE;
3827 if (strchr(req[0], '\t'))
3828 src = split_input_line(req[0], "\t", -1);
3829 else
3830 src = split_input_line(req[0], " ", -1);
3832 if (!src || !*src) {
3833 rc = GPG_ERR_SYNTAX;
3834 goto fail;
3837 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3839 if (src[1] && n)
3840 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3841 NULL, FALSE, 0, NULL, FALSE);
3843 if (!n)
3844 goto fail;
3847 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3849 if (!a) {
3850 rc = GPG_ERR_ENOMEM;
3851 goto fail;
3854 /* To prevent unwanted effects:
3856 * <root name="a"><b/></root>
3858 * RENAME a<TAB>b b
3860 if (xmlStrEqual(a, (xmlChar *)dst)) {
3861 xmlFree(a);
3862 rc = GPG_ERR_AMBIGUOUS_NAME;
3863 goto fail;
3866 xmlFree(a);
3867 gchar **tmp = NULL;
3869 if (src[1]) {
3870 gchar **p;
3872 for (p = src; *p; p++) {
3873 if (!*(p+1))
3874 break;
3876 strv_printf(&tmp, "%s", *p);
3880 strv_printf(&tmp, "!%s", dst);
3881 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3883 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3884 g_strfreev(tmp);
3885 goto fail;
3888 if (tmp[1] && ndst)
3889 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3890 NULL, NULL, FALSE, 0, NULL, FALSE);
3892 g_strfreev(tmp);
3894 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3895 goto fail;
3897 rc = 0;
3899 /* Target may exist:
3901 * <root name="a"/>
3902 * <root name="b" target="a"/>
3904 * RENAME b a
3906 * Would need to do:
3907 * RENAME !b a
3909 if (ndst == n) {
3910 rc = GPG_ERR_AMBIGUOUS_NAME;
3911 goto fail;
3914 if (ndst) {
3915 unlink_node(ndst);
3916 xmlFreeNodeList(ndst);
3919 rc = add_attribute(n, "_name", dst);
3921 fail:
3922 g_strfreev(req);
3923 g_strfreev(src);
3924 return send_error(ctx, rc);
3927 static gint copy_command(assuan_context_t ctx, gchar *line)
3929 struct client_s *client = assuan_get_pointer(ctx);
3930 gpg_error_t rc;
3931 gchar **req, **src = NULL, **dst = NULL;
3932 xmlNodePtr nsrc, ndst, new = NULL;
3934 log_write2("ARGS=\"%s\"", line);
3935 req = split_input_line(line, " ", -1);
3937 if (!req || !req[0] || !req[1]) {
3938 g_strfreev(req);
3939 return send_error(ctx, GPG_ERR_SYNTAX);
3942 if (strchr(req[0], '\t'))
3943 src = split_input_line(req[0], "\t", -1);
3944 else
3945 src = split_input_line(req[0], " ", -1);
3947 if (!src || !*src) {
3948 rc = GPG_ERR_SYNTAX;
3949 goto fail;
3952 if (strchr(req[1], '\t'))
3953 dst = split_input_line(req[1], "\t", -1);
3954 else
3955 dst = split_input_line(req[1], " ", -1);
3957 if (!dst || !*dst) {
3958 rc = GPG_ERR_SYNTAX;
3959 goto fail;
3962 if (!valid_element_path(dst, FALSE)) {
3963 rc = GPG_ERR_INV_VALUE;
3964 goto fail;
3967 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3968 if (nsrc && src[1])
3969 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3970 NULL, NULL, FALSE, 0, NULL, FALSE);
3972 if (!nsrc)
3973 goto fail;
3975 new = xmlCopyNodeList(nsrc);
3976 if (!new) {
3977 rc = GPG_ERR_ENOMEM;
3978 goto fail;
3981 gboolean create = FALSE;
3982 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3983 if (ndst && dst[1]) {
3984 if (ndst->children)
3985 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3986 NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
3987 else
3988 create = TRUE;
3990 else
3991 create = TRUE;
3993 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3994 goto fail;
3995 else if (create) {
3996 ndst = create_element_path(client, &dst, &rc, NULL);
3997 if (!ndst)
3998 goto fail;
4001 /* Merge any attributes from the src node to the initial dst node. */
4002 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
4003 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
4004 continue;
4006 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
4007 if (a)
4008 xmlRemoveProp(a);
4010 xmlChar *tmp = xmlNodeGetContent(attr->children);
4011 xmlNewProp(ndst, attr->name, tmp);
4012 xmlFree(tmp);
4013 rc = add_attribute(ndst, NULL, NULL);
4016 xmlNodePtr n = ndst->children;
4017 xmlUnlinkNode(n);
4018 xmlFreeNodeList(n);
4019 ndst->children = NULL;
4021 if (new->children) {
4022 n = xmlCopyNodeList(new->children);
4023 if (!n) {
4024 rc = GPG_ERR_ENOMEM;
4025 goto fail;
4028 n = xmlAddChildList(ndst, n);
4029 if (!n) {
4030 rc = GPG_ERR_ENOMEM;
4031 goto fail;
4034 rc = update_element_mtime(xmlDocGetRootElement(client->doc) ==
4035 ndst->parent ? ndst : ndst->parent);
4038 fail:
4039 if (new) {
4040 xmlUnlinkNode(new);
4041 xmlFreeNodeList(new);
4044 if (req)
4045 g_strfreev(req);
4047 if (src)
4048 g_strfreev(src);
4050 if (dst)
4051 g_strfreev(dst);
4053 return send_error(ctx, rc);
4056 static gint move_command(assuan_context_t ctx, gchar *line)
4058 struct client_s *client = assuan_get_pointer(ctx);
4059 gpg_error_t rc;
4060 gchar **req, **src = NULL, **dst = NULL;
4061 xmlNodePtr nsrc, ndst = NULL;
4063 log_write2("ARGS=\"%s\"", line);
4064 req = split_input_line(line, " ", -1);
4066 if (!req || !req[0] || !req[1]) {
4067 g_strfreev(req);
4068 return send_error(ctx, GPG_ERR_SYNTAX);
4071 if (strchr(req[0], '\t'))
4072 src = split_input_line(req[0], "\t", -1);
4073 else
4074 src = split_input_line(req[0], " ", -1);
4076 if (!src || !*src) {
4077 rc = GPG_ERR_SYNTAX;
4078 goto fail;
4081 if (strchr(req[1], '\t'))
4082 dst = split_input_line(req[1], "\t", -1);
4083 else
4084 dst = split_input_line(req[1], " ", -1);
4086 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
4088 if (nsrc && src[1])
4089 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
4090 NULL, NULL, FALSE, 0, NULL, FALSE);
4092 if (!nsrc)
4093 goto fail;
4095 if (dst) {
4096 if (!valid_element_path(dst, FALSE)) {
4097 rc = GPG_ERR_INV_VALUE;
4098 goto fail;
4101 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
4103 if (ndst && dst[1])
4104 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
4105 NULL, NULL, FALSE, 0, NULL, FALSE);
4107 else
4108 ndst = xmlDocGetRootElement(client->doc);
4110 for (xmlNodePtr n = ndst; n; n = n->parent) {
4111 if (n == nsrc) {
4112 rc = GPG_ERR_CONFLICT;
4113 goto fail;
4117 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
4118 goto fail;
4120 rc = 0;
4122 if (ndst) {
4123 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
4124 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
4126 xmlFree(a);
4128 if (dup) {
4129 if (dup == nsrc)
4130 goto fail;
4132 if (ndst == xmlDocGetRootElement(client->doc)) {
4133 xmlNodePtr n = nsrc;
4134 gboolean match = FALSE;
4136 while (n->parent && n->parent != ndst)
4137 n = n->parent;
4139 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
4140 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
4142 if (xmlStrEqual(a, b)) {
4143 match = TRUE;
4144 xmlUnlinkNode(nsrc);
4145 xmlUnlinkNode(n);
4146 xmlFreeNodeList(n);
4149 xmlFree(a);
4150 xmlFree(b);
4152 if (!match) {
4153 xmlUnlinkNode(dup);
4154 xmlFreeNodeList(dup);
4157 else
4158 xmlUnlinkNode(dup);
4162 if (!ndst && dst) {
4163 xmlChar *name = node_has_attribute(nsrc, (xmlChar *)"_name");
4165 if (nsrc->parent == xmlDocGetRootElement(client->doc)
4166 && !g_strcmp0((gchar *)name, *dst)) {
4167 xmlFree(name);
4168 rc = GPG_ERR_CONFLICT;
4169 goto fail;
4172 xmlFree(name);
4173 ndst = create_element_path(client, &dst, &rc, nsrc);
4176 if (!ndst)
4177 goto fail;
4179 update_element_mtime(nsrc->parent);
4180 xmlUnlinkNode(nsrc);
4181 ndst = xmlAddChildList(ndst, nsrc);
4183 if (!ndst)
4184 rc = GPG_ERR_ENOMEM;
4186 update_element_mtime(ndst->parent);
4188 fail:
4189 if (req)
4190 g_strfreev(req);
4192 if (src)
4193 g_strfreev(src);
4195 if (dst)
4196 g_strfreev(dst);
4198 return send_error(ctx, rc);
4201 static int ls_command(assuan_context_t ctx, gchar *line)
4203 log_write2("ARGS=\"%s\"", line);
4204 gpg_error_t rc;
4205 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4206 gchar *dir = expand_homedir(tmp);
4207 DIR *d = opendir(dir);
4209 rc = gpg_error_from_syserror();
4210 g_free(tmp);
4212 if (!d) {
4213 g_free(dir);
4214 return send_error(ctx, rc);
4217 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4218 struct dirent *p = g_malloc(len), *cur = NULL;
4219 gchar *list = NULL;
4221 g_free(dir);
4222 rc = 0;
4224 while (!readdir_r(d, p, &cur) && cur) {
4225 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4226 continue;
4227 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4228 continue;
4230 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4232 if (!tmp) {
4233 if (list)
4234 g_free(list);
4236 rc = GPG_ERR_ENOMEM;
4237 break;
4240 g_free(list);
4241 list = tmp;
4244 closedir(d);
4245 g_free(p);
4247 if (rc)
4248 return send_error(ctx, rc);
4250 if (!list)
4251 return send_error(ctx, GPG_ERR_NO_VALUE);
4253 list[strlen(list)-1] = 0;
4254 rc = xfer_data(ctx, list, strlen(list));
4255 g_free(list);
4256 return send_error(ctx, rc);
4259 static void bye_notify(assuan_context_t ctx)
4261 struct client_s *cl = assuan_get_pointer(ctx);
4263 /* This will let assuan_process_next() return. */
4264 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4265 cl->last_rc = 0; // BYE command result
4268 static void reset_notify(assuan_context_t ctx)
4270 struct client_s *cl = assuan_get_pointer(ctx);
4272 if (cl)
4273 cleanup_client(cl);
4277 * This is called before every Assuan command.
4279 gint command_startup(assuan_context_t ctx, const gchar *name)
4281 struct client_s *cl = assuan_get_pointer(ctx);
4282 gpg_error_t rc;
4284 log_write1("%s", name);
4286 for (int i = 0; command_table[i]; i++) {
4287 if (!g_ascii_strcasecmp(name, command_table[i]->name) &&
4288 command_table[i]->ignore_startup)
4289 return 0;
4292 #ifdef WITH_PINENTRY
4293 if (!(cl->opts & OPT_PINENTRY))
4294 reset_pin_defaults(cl->pinentry);
4295 #endif
4297 cl->last_rc = rc = file_modified(cl);
4299 if (rc) {
4300 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4301 !g_ascii_strcasecmp(name, "OPEN"))
4302 rc = 0;
4305 return rc;
4309 * This is called after every Assuan command.
4311 void command_finalize(assuan_context_t ctx, gint rc)
4313 struct client_s *client = assuan_get_pointer(ctx);
4315 if (!client->is_lock_cmd)
4316 unlock_file_mutex(client);
4318 log_write1(_("command completed (rc=%u)"), client->last_rc);
4319 client->opts &= ~(OPT_INQUIRE);
4322 static gint help_command(assuan_context_t ctx, gchar *line)
4324 gpg_error_t rc;
4325 gint i;
4327 if (!line || !*line) {
4328 gchar *tmp;
4329 gchar *buf = g_strdup(_(
4330 "Usage: HELP [<COMMAND>]\n"
4331 " For commands that take an element path as an argument, each element is\n"
4332 " separated with an ASCII tab character (ASCII 0x09).\n"
4333 "\n"
4334 " Each element may contain a \"target\" attribute whose value is also an\n"
4335 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4336 " filesystem. When found, the element path of the \"target\" attribute will\n"
4337 " be used as a prefix for further elements in the current element path. To\n"
4338 " ignore any \"target\" attribute for the current element, prefix the element\n"
4339 " with an ! (ASCII 0x21).\n"
4340 "\n"
4341 " See pwmd(1) for configuration file options which may also set default\n"
4342 " options for specific data files.\n"
4343 "\n"
4344 "COMMANDS:"));
4346 for (i = 0; command_table[i]; i++) {
4347 gchar *p = strrchr(buf, '\n');
4348 gboolean newline = FALSE;
4350 if (!command_table[i]->help)
4351 continue;
4353 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4354 tmp = g_strdup_printf("%s\n", buf);
4355 g_free(buf);
4356 buf = tmp;
4357 newline = TRUE;
4360 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4361 command_table[i]->name);
4362 g_free(buf);
4363 buf = tmp;
4366 tmp = g_strdup_printf("%s\n", buf);
4367 g_free(buf);
4368 buf = tmp;
4369 rc = xfer_data(ctx, buf, strlen(buf));
4370 g_free(buf);
4371 return send_error(ctx, rc);
4374 for (i = 0; command_table[i]; i++) {
4375 if (!g_strcasecmp(line, command_table[i]->name)) {
4376 if (!command_table[i]->help)
4377 break;
4379 gchar *tmp = g_strdup_printf(_("Usage: %s"), command_table[i]->help);
4380 rc = xfer_data(ctx, tmp, strlen(tmp));
4381 g_free(tmp);
4382 return send_error(ctx, rc);
4386 return send_error(ctx, GPG_ERR_INV_NAME);
4389 void new_command(const gchar *name, gboolean ignore,
4390 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4392 gint i = 0;
4394 if (command_table)
4395 for (i = 0; command_table[i]; i++);
4397 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4398 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4399 command_table[i]->name = name;
4400 command_table[i]->handler = handler;
4401 command_table[i]->ignore_startup = ignore;
4402 command_table[i++]->help = help;
4403 command_table[i] = NULL;
4406 void deinit_commands()
4408 gint i;
4410 for (i = 0; command_table[i]; i++)
4411 g_free(command_table[i]);
4413 g_free(command_table);
4416 static gint sort_commands(const void *arg1, const void *arg2)
4418 struct command_table_s* const *a = arg1;
4419 struct command_table_s* const *b = arg2;
4421 if (!*a || !*b)
4422 return 0;
4423 else if (*a && !*b)
4424 return 1;
4425 else if (!*a && *b)
4426 return -1;
4428 return g_strcmp0((*a)->name, (*b)->name);
4431 void init_commands()
4433 /* !BEGIN-HELP-TEXT!
4435 * This comment is used as a marker to generate the offline documentation
4436 * for commands found in doc/COMMANDS.
4438 new_command("HELP", TRUE, help_command, _(
4439 "HELP [<COMMAND>]\n"
4440 " Show available commands or command specific help text.\n"
4443 new_command("OPEN", FALSE, open_command, _(
4444 "OPEN [--lock] [--inquire | --pinentry=[0|1]] <filename> [<key>]\n"
4445 " Opens <filename> using <key>. When the filename is not found on the\n"
4446 " file-system a new document will be created. If the file is found, it is\n"
4447 " looked for in the file cache for an existing key. When found and no key\n"
4448 " was specified, the cached key will be used for decryption (if encrypted).\n"
4449 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4450 " OPTIONS documentation).\n"
4451 "\n"
4452 " When the --lock option is passed then the file mutex will be locked as if\n"
4453 " the LOCK command had been sent after the file had been opened.\n"
4454 "\n"
4455 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4456 " retrieve the filename and key arguments.\n"
4457 "\n"
4458 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4459 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4460 " no value is specified then the configuration file value will be used. If\n"
4461 " the passphrase is invalid then it is up to the client whether to retry or\n"
4462 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4463 " pinentry dialog, use --pinentry=0.\n"
4464 "\n"
4465 " When a \"key_file\" configuration parameter has been set for the current\n"
4466 " file and there is no cache entry, then an --inquire must be used to\n"
4467 " retrieve the key.\n"
4470 new_command("SAVE", FALSE, save_command, _(
4471 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4472 " [--iterations=[N]] [<key>]\n"
4473 " Writes the XML document to disk. The file written to is the file that was\n"
4474 " opened using the OPEN command. If <key> is not specified then the\n"
4475 " currently cached key will be used. If the file is a new file or the file\n"
4476 " is not found in the file cache then <key> will be used. If both <key> is\n"
4477 " not specified and the file is not cached then pinentry(1) will be used to\n"
4478 " retrieve the key (see below) unless the configured number of iterations is\n"
4479 " 0 in which case the file will be saved unencrypted.\n"
4480 "\n"
4481 " Note that when both <key> is specified and the configured number of\n"
4482 " iterations is 0 the iterations for the current filename will be reset to\n"
4483 " 1. This is to be on the safe side and prevent misuse.\n"
4484 "\n"
4485 " The --iterations option can be used to change the number of encryption\n"
4486 " iterations for the opened file. When 0 no encryption will be performed.\n"
4487 " When this option is either not passed or is specified without a value then\n"
4488 " the previous setting obtained from the file header will be used.\n"
4489 "\n"
4490 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4491 " string with the --cipher option. Omitting the string uses the current\n"
4492 " cipher of the opened file or the default if the file is a new one. The\n"
4493 " default is specified in the configuration file. See pwmd(1) for available\n"
4494 " ciphers.\n"
4495 "\n"
4496 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4497 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4498 " no value is specified then the configuration file value will be used.\n"
4499 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4500 " is started over again until either the passphrases match or until the\n"
4501 " input is canceled by the user. To save with encryption and with an empty\n"
4502 " passphrase, use --pinentry=0.\n"
4503 "\n"
4504 " When --reset is specified then the cached passphrase for the opened file\n"
4505 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4506 " had been sent.\n"
4507 "\n"
4508 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4509 " retrieve the key.\n"
4510 "\n"
4511 " When a \"key_file\" configuration parameter has been set for the current\n"
4512 " file and there is no cache entry, then an --inquire must be used to\n"
4513 " retrieve the key.\n"
4516 new_command("ISCACHED", TRUE, iscached_command, _(
4517 "ISCACHED <filename>\n"
4518 " An OK response is returned if the specified file is found in the file\n"
4519 " cache. If not found in the cache but exists on the filesystem,\n"
4520 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4523 new_command("CLEARCACHE", TRUE, clearcache_command, _(
4524 "CLEARCACHE [<filename>]\n"
4525 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4526 " the specified file. Always returns an OK response.\n"
4529 new_command("CACHETIMEOUT", TRUE, cachetimeout_command, _(
4530 "CACHETIMEOUT <filename> <seconds>\n"
4531 " Specify the number of seconds the specified file will be cached. -1 will\n"
4532 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4533 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4534 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4535 " invalid. OK otherwise.\n"
4538 new_command("LIST", FALSE, list_command, _(
4539 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4540 " If no element path is given then a newline separated list of root elements\n"
4541 " is returned with the data response. If given, then all reachable elements\n"
4542 " for the specified element path are returned unless the --no-recurse option\n"
4543 " is specified. If specified, only the child elements of the element path\n"
4544 " are returned without recursing into grandchildren. Each element in the\n"
4545 " path is prefixed with the literal '!' character when the element contains\n"
4546 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4547 "\n"
4548 " When the --verbose option is passed then each element path returned in the\n"
4549 " list will have a single space character followed by either a 0 or 1\n"
4550 " appended to it. When 0, the element path has no children, otherwise it\n"
4551 " does have children. When used with the --no-recurse option this may be\n"
4552 " useful to limit the amount of data transferred to the client.\n"
4555 new_command("REALPATH", FALSE, realpath_command, _(
4556 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4557 " Resolves all \"target\" attributes of the specified element path and returns\n"
4558 " the result with a data response.\n"
4561 new_command("STORE", FALSE, store_command, _(
4562 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4563 " Creates a new element path or modifies the content of an existing element\n"
4564 " path. If only a single element is specified, a new root element is\n"
4565 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4566 " to the last TAB delimited argument. If no content is specified after the\n"
4567 " last TAB then the content for the last specified element will be removed,\n"
4568 " or empty when creating a new element.\n"
4569 "\n"
4570 " The only restriction of an element name is that it not contain whitespace\n"
4571 " or begin with the literal element character '!' unless specifying a\n"
4572 " literal element. There is no whitespace between the TAB delimited\n"
4573 " elements. It is recommended that the value or content be base64 encoded\n"
4574 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4575 " errors.\n"
4576 "\n"
4577 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4580 new_command("RENAME", FALSE, rename_command, _(
4581 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4582 " Renames the specified element to the new value. If an element of the same\n"
4583 " name as the value exists then it will be overwritten.\n"
4586 new_command("COPY", FALSE, copy_command, _(
4587 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4588 " Copies the entire element tree starting from the child node of the source\n"
4589 " element path, to the destination element path. If the destination element\n"
4590 " path does not exist then it will be created; otherwise it is overwritten.\n"
4591 "\n"
4592 " Note that attributes from the source element path are merged into the\n"
4593 " destination element path when the destination element path exists. When an\n"
4594 " attribute of the same name exists in both the source and destination\n"
4595 " element paths then the destination attribute will be updated to the source\n"
4596 " attribute value.\n"
4599 new_command("MOVE", FALSE, move_command, _(
4600 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4601 " Moves the source element path to the destination element path. If the\n"
4602 " destination is not specified then it will be moved to the root of the\n"
4603 " document. If the destination is specified and exists then it will be\n"
4604 " overwritten; otherwise it will be created.\n"
4607 new_command("DELETE", FALSE, delete_command, _(
4608 "DELETE [!]element[<TAB>[!]element[...]]\n"
4609 " Removes the specified element path and any children from the XML document.\n"
4612 new_command("GET", FALSE, get_command, _(
4613 "GET [!]element[<TAB>[!]element[...]]\n"
4614 " Retrieves the content or XML text node of the specified element path. The\n"
4615 " content is returned with a data response.\n"
4618 new_command("ATTR", FALSE, attr_command, _(
4619 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4620 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4621 " Stores or updates an attribute name and optional value of an element\n"
4622 " path.\n"
4623 "\n"
4624 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4625 " Removes an attribute from an element path.\n"
4626 "\n"
4627 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4628 " Retrieves a newline separated list of attributes names and values from\n"
4629 " the specified element path. The attribute names and values are space\n"
4630 " delimited.\n"
4631 "\n"
4632 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4633 " Retrieves the value of an attribute from an element path.\n"
4634 "\n"
4635 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4636 " if the element path is the root element. Although it can be SET to change\n"
4637 " the element name but only if the destination element name doesn't exist.\n"
4638 " Use the RENAME command for that instead.\n"
4639 "\n"
4640 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4641 " either storing content, editing attributes or by deleting a child element.\n"
4642 "\n"
4643 " Also see THE TARGET ATTRIBUTE.\n"
4646 new_command("XPATH", FALSE, xpath_command, _(
4647 "XPATH <expression>[<TAB>[value]]\n"
4648 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4649 " assumed the expression is a request to return a result. Otherwise, the\n"
4650 " result is set to the value argument and the document is updated. If there\n"
4651 " is no value after the <TAB> character, the value is assumed to be empty\n"
4652 " and the document is updated.\n"
4655 new_command("XPATHATTR", FALSE, xpathattr_command, _(
4656 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4657 " Like the XPATH command but operates on element attributes and won't return\n"
4658 " a result. For the SET operation the <value> is optional but the field is\n"
4659 " required in which case the value will be empty.\n"
4662 new_command("IMPORT", FALSE, import_command, _(
4663 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4664 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4665 " data. The content is created as a child of the specified element path. If\n"
4666 " an element of the element path does not exist then it is created. If no\n"
4667 " element path is specified then the content must begin with an pwmd DTD\n"
4668 " root element.\n"
4669 "\n"
4670 " Note that the new content must begin with an XML element node. Also note\n"
4671 " that an existing child node of the same element name as the root node of\n"
4672 " the imported content will be overwritten.\n"
4675 new_command("DUMP", FALSE, dump_command, _(
4676 "DUMP\n"
4677 " Shows the in memory XML document with indenting. To dump a specific\n"
4678 " element tree, use the XPATH command.\n"
4681 new_command("LOCK", FALSE, lock_command, _(
4682 "LOCK\n"
4683 " Locks the mutex associated with the opened file. This prevents other\n"
4684 " clients from sending commands to the same opened file until the client\n"
4685 " that sent this command either disconnects or sends the UNLOCK command.\n"
4688 new_command("UNLOCK", FALSE, unlock_command, _(
4689 "UNLOCK\n"
4690 " Unlocks the file mutex which was locked with the LOCK command.\n"
4693 new_command("GETPID", TRUE, getpid_command, _(
4694 "GETPID\n"
4695 " Retrieves the process id of the server.\n"
4698 new_command("GETCONFIG", TRUE, getconfig_command, _(
4699 "GETCONFIG [filename] <parameter>\n"
4700 " Returns the value of a pwmd configuration variable with a data response.\n"
4701 " If no file has been opened then the value for the specified file or the\n"
4702 " default from the \"global\" section will be returned. If a file has been\n"
4703 " opened and no filename is specified, the value previously set with the SET\n"
4704 " command, if any, will be returned.\n"
4705 "\n"
4706 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4707 " is returned.\n"
4710 new_command("VERSION", TRUE, version_command, _(
4711 "VERSION\n"
4712 " Returns the server version number and compile-time features with a data\n"
4713 " response with each being space delimited.\n"
4716 new_command("SET", TRUE, set_command, _(
4717 "SET <NAME>=<VALUE>\n"
4718 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4719 " option to its default value.\n"
4720 "\n"
4721 " NAME |VALUE |Description\n"
4722 " -----------------|----------|----------------------------------------------\n"
4723 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4724 " is 1.\n"
4725 "\n"
4726 " * Deprecated. Pass --pinentry to the OPEN and\n"
4727 " SAVE commands instead.\n"
4728 "\n"
4729 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4730 " process will terminate while waiting for a\n"
4731 " passphrase. The default is 20, 0 disables.\n"
4732 "\n"
4733 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4734 " is specified at compile time.\n"
4735 "\n"
4736 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4737 "\n"
4738 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4739 "\n"
4740 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4741 "\n"
4742 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4743 "\n"
4744 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4745 "\n"
4746 " DESC <string> Sets the error or description string of the\n"
4747 " pinentry dialog.\n"
4748 "\n"
4749 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4750 "\n"
4751 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4752 " pinentry(1).\n"
4753 "\n"
4754 " NAME <string> Associates the thread ID of the connection\n"
4755 " with the specified textual representation.\n"
4756 " Useful for debugging log messages.\n"
4757 "\n"
4758 " CIPHER <string> The cipher to use for the next SAVE.\n"
4759 "\n"
4760 " * Deprecated. Use --cipher instead.\n"
4761 "\n"
4762 " ITERATIONS <integer> The number of encryption iterations to do\n"
4763 " when the SAVE command is sent. An opened file\n"
4764 " is needed when setting this option. The\n"
4765 " CONFIG status message is sent after receiving\n"
4766 " this command.\n"
4767 "\n"
4768 " * Deprecated. Use --iterations instead.\n"
4769 "\n"
4770 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4771 " after a successful OPEN as if the LOCK\n"
4772 " command had been sent.\n"
4773 "\n"
4774 " * Deprecated. Use --lock instead.\n"
4775 "\n"
4776 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4777 " of a status message when the file mutex is\n"
4778 " locked by another client.\n"
4781 new_command("UNSET", TRUE, unset_command, _(
4782 "UNSET <NAME>\n"
4783 " Resets option NAME to the value specified in the server configuration\n"
4784 " file. Some options have no default and will be reset to NULL or 0\n"
4785 " depending on the value type. See the SET command for available options.\n"
4788 new_command("LS", TRUE, ls_command, _(
4789 "LS\n"
4790 " Lists the contents of the configured data_directory. The result is a\n"
4791 " newline separated list of filenames.\n"
4794 new_command("RESET", TRUE, NULL, _(
4795 "RESET\n"
4796 " Closes the currently opened file but keeps any previously set client\n"
4797 " options.\n"
4800 new_command("BYE", TRUE, NULL, _(
4801 "BYE\n"
4802 " Closes the connection discarding any unsaved changes.\n"
4805 new_command("NOP", TRUE, NULL, _(
4806 "NOP\n"
4807 " Does nothing. Always returns successfully.\n"
4810 /* !END-HELP-TEXT! */
4811 new_command("CANCEL", TRUE, NULL, NULL);
4812 new_command("END", TRUE, NULL, NULL);
4814 gint i;
4815 for (i = 0; command_table[i]; i++);
4816 qsort(command_table, i-1, sizeof(struct command_table_s *), sort_commands);
4819 gpg_error_t register_commands(assuan_context_t ctx)
4821 gint i = 0, rc;
4823 for (; command_table[i]; i++) {
4824 if (!command_table[i]->handler)
4825 continue;
4827 rc = assuan_register_command (ctx, command_table[i]->name,
4828 command_table[i]->handler);
4830 if (rc)
4831 return rc;
4834 rc = assuan_register_bye_notify(ctx, bye_notify);
4836 if (rc)
4837 return rc;
4839 rc = assuan_register_reset_notify(ctx, reset_notify);
4841 if (rc)
4842 return rc;
4844 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4846 if (rc)
4847 return rc;
4849 return assuan_register_post_cmd_notify(ctx, command_finalize);
4852 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4853 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4855 goffset insize, len;
4856 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4857 guint64 iter = 0, n_iter = 0, iter_progress = 0;
4858 gulong outsize = 0;
4859 gpg_error_t rc;
4860 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4861 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4863 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version < 0x221)
4864 fh_size -= sizeof(crypto->fh->ver.fh2.salt);
4866 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4867 insize = crypto->fh->st.st_size - fh_size;
4868 crypto->iv = gcry_malloc(crypto->blocksize);
4870 if (!crypto->iv) {
4871 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4872 return GPG_ERR_ENOMEM;
4875 if (crypto->fh->v1)
4876 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4877 else
4878 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4880 crypto->inbuf = gcry_malloc(insize);
4882 if (!crypto->inbuf) {
4883 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4884 return GPG_ERR_ENOMEM;
4887 crypto->insize = insize;
4888 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4890 if (len != crypto->insize)
4891 return GPG_ERR_INV_LENGTH;
4893 /* No encryption iterations. This is a plain (gzipped) file. */
4894 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4895 (!crypto->fh->v1 && fh_iter <= 0L)) {
4897 * cache_file_count() needs both .used == TRUE and a valid key in
4898 * order for it to count as a used cache entry. Fixes CACHE status
4899 * messages.
4901 memset(crypto->key, '!', KEYSIZE);
4902 goto decompress;
4905 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4906 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4907 return rc;
4910 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4911 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4912 return rc;
4915 iter_progress = get_key_file_uint64(client && client->filename ?
4916 client->filename : "global", "iteration_progress");
4918 if (iter_progress > 0 && fh_iter >= iter_progress) {
4919 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4921 if (rc)
4922 return rc;
4925 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4927 if (rc)
4928 return rc;
4930 crypto->tkey = gcry_malloc(KEYSIZE);
4932 if (!crypto->tkey) {
4933 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4934 return GPG_ERR_ENOMEM;
4937 memcpy(crypto->tkey, crypto->key, KEYSIZE);
4938 guchar *tkey = crypto->tkey;
4939 tkey[0] ^= 1;
4941 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4942 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4943 return rc;
4946 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4947 if (iter_progress > 0ULL && iter >= iter_progress) {
4948 if (!(iter % iter_progress)) {
4949 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4950 ++n_iter * iter_progress, fh_iter);
4952 if (rc)
4953 return rc;
4957 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4958 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4959 return rc;
4962 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4964 if (rc) {
4965 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4966 return rc;
4969 iter++;
4972 if (iter_progress && fh_iter >= iter_progress) {
4973 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4975 if (rc)
4976 return rc;
4979 decompress:
4980 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4981 len = 0;
4983 if (crypto->fh->ver.fh2.iter > 0ULL) {
4984 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4985 return GPG_ERR_INV_PASSPHRASE;
4987 len = sizeof(crypto_magic);
4990 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4991 (gpointer *)&crypto->outbuf, &outsize);
4993 if (rc)
4994 return rc;
4996 else {
4997 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4998 (gpointer *)&crypto->outbuf, &outsize);
5000 if (rc == GPG_ERR_ENOMEM)
5001 return rc;
5002 else if (rc)
5003 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
5005 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
5006 gcry_free(crypto->outbuf);
5007 crypto->outbuf = NULL;
5008 return GPG_ERR_INV_PASSPHRASE;
5012 if (ctx) {
5013 client->xml = crypto->outbuf;
5014 client->len = outsize;
5015 crypto->outbuf = NULL;
5017 else if (dst) {
5018 *dst = crypto->outbuf;
5019 *dst_len = outsize;
5020 crypto->outbuf = NULL;
5023 /* The calling function should free the crypto struct. */
5024 return 0;