Fix compile time warnings.
[pwmd.git] / src / commands.c
blob58076d3b18ee6c20e8eacceaa8920dc6b2854b54
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2011 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include <gcrypt.h>
35 #include <zlib.h>
36 #include <dirent.h>
38 #ifdef WITH_LIBACL
39 #include <sys/acl.h>
40 #endif
42 #include "mem.h"
43 #include "xml.h"
44 #include "common.h"
46 #ifdef WITH_PINENTRY
47 #include "pinentry.h"
48 #endif
50 #include "pwmd_error.h"
51 #include "cache.h"
52 #include "misc.h"
53 #include "commands.h"
54 #include "mutex.h"
55 #include "rcfile.h"
57 struct gz_s {
58 z_stream z;
59 gpointer out;
60 gboolean done;
61 status_msg_t which;
64 struct command_table_s {
65 const gchar *name;
66 gint (*handler)(assuan_context_t, gchar *line);
67 const gchar *help;
68 gboolean ignore_startup;
71 static struct command_table_s **command_table;
72 static guchar crypto_magic[5] = "\177PWMD";
74 static gpg_error_t do_lock_command(struct client_s *client);
76 static void *z_alloc(void *data, unsigned items, unsigned size)
78 return gcry_calloc(items, size);
81 static void z_free(void *data, void *p)
83 gcry_free(p);
86 static gpg_error_t file_modified(struct client_s *client)
88 struct stat st;
89 gpg_error_t rc;
91 if (client->state != STATE_OPEN)
92 return EPWMD_NO_FILE;
94 rc = lock_file_mutex(client);
96 if (rc)
97 return rc;
99 if (g_lstat(client->filename, &st) == 0 && client->mtime) {
100 if (client->mtime != st.st_mtime)
101 return EPWMD_FILE_MODIFIED;
104 pth_cancel_point();
105 return 0;
108 static gpg_error_t parse_xml(assuan_context_t ctx)
110 struct client_s *client = assuan_get_pointer(ctx);
112 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
114 if (!client->doc)
115 return EPWMD_LIBXML_ERROR;
117 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
118 return 0;
120 return convert_elements(client->doc);
123 void unlock_file_mutex(struct client_s *client)
125 pth_mutex_t *m;
127 if (client->has_lock == FALSE)
128 return;
130 CACHE_LOCK(client->ctx);
132 if (cache_get_mutex(client->md5file, &m) == FALSE) {
133 CACHE_UNLOCK;
134 return;
137 CACHE_UNLOCK;
138 MUTEX_UNLOCK(m);
139 client->has_lock = client->is_lock_cmd = FALSE;
142 gpg_error_t lock_file_mutex(struct client_s *client)
144 pth_mutex_t *m;
145 gpg_error_t rc = 0;
147 if (client->has_lock == TRUE)
148 return 0;
150 CACHE_LOCK(client->ctx);
152 if (cache_get_mutex(client->md5file, &m) == FALSE) {
153 CACHE_UNLOCK;
154 return 0;
157 CACHE_UNLOCK;
159 if (client->rc_on_locked) {
160 if (!pth_mutex_acquire(m, TRUE, NULL))
161 return GPG_ERR_LOCKED;
162 #ifdef MUTEX_DEBUG
163 MUTEX_LOCK_DEBUG(m);
164 #endif
166 else
167 MUTEX_TRYLOCK(client, m, rc);
169 if (!rc)
170 client->has_lock = TRUE;
172 return rc;
175 void free_client(struct client_s *client)
177 if (client->doc)
178 xmlFreeDoc(client->doc);
180 if (client->xml)
181 gcry_free(client->xml);
183 if (client->filename)
184 g_free(client->filename);
186 if (client->crypto)
187 cleanup_crypto(&client->crypto);
189 if (client->xml_error)
190 xmlResetError(client->xml_error);
193 void cleanup_client(struct client_s *client)
195 assuan_context_t ctx = client->ctx;
196 struct client_thread_s *thd = client->thd;
197 gboolean rc_on_locked = client->rc_on_locked;
198 gboolean lock_on_open = client->lock_on_open;
199 #ifdef WITH_PINENTRY
200 struct pinentry_s *pin = client->pinentry;
201 #endif
203 unlock_file_mutex(client);
204 CACHE_LOCK(client->ctx);
205 cache_decr_refcount(client->md5file);
208 * This may be a new file so don't use a cache slot. save_command() will
209 * set this to FALSE on success.
211 if (client->new == TRUE)
212 cache_clear(client->md5file, 1);
214 CACHE_UNLOCK;
215 free_client(client);
216 memset(client, 0, sizeof(struct client_s));
217 client->state = STATE_CONNECTED;
218 client->ctx = ctx;
219 client->thd = thd;
220 client->freed = TRUE;
221 #ifdef WITH_PINENTRY
222 client->pinentry = pin;
223 #endif
224 client->rc_on_locked = rc_on_locked;
225 client->lock_on_open = lock_on_open;
228 static void gz_cleanup(void *arg)
230 struct gz_s **gz = (struct gz_s **)arg;
232 if (!gz)
233 return;
235 if (!(*gz)->done && (*gz)->out)
236 gcry_free((*gz)->out);
238 if ((*gz)->which == STATUS_COMPRESS) {
239 if ((*gz)->z.zalloc)
240 deflateEnd(&(*gz)->z);
242 else {
243 if ((*gz)->z.zalloc)
244 inflateEnd(&(*gz)->z);
247 g_free(*gz);
248 *gz = NULL;
251 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
252 gpointer *out, gulong *outsize)
254 struct gz_s *gz;
255 gz_header h;
256 gchar buf[17];
257 gpg_error_t rc;
258 gint zrc;
260 gz = g_malloc0(sizeof(struct gz_s));
262 if (!gz)
263 return GPG_ERR_ENOMEM;
265 pth_cleanup_push(gz_cleanup, &gz);
266 gz->which = STATUS_DECOMPRESS;
267 gz->z.zalloc = z_alloc;
268 gz->z.zfree = z_free;
269 gz->z.next_in = in;
270 gz->z.avail_in = (uInt)insize;
271 gz->z.avail_out = zlib_bufsize;
272 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
274 if (!gz->out) {
275 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
276 pth_cleanup_pop(1);
277 return GPG_ERR_ENOMEM;
280 zrc = inflateInit2(&gz->z, 47);
282 if (zrc != Z_OK) {
283 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
284 pth_cleanup_pop(1);
285 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
288 memset(&h, 0, sizeof(gz_header));
289 h.comment = (guchar *)buf;
290 h.comm_max = sizeof(buf);
291 zrc = inflateGetHeader(&gz->z, &h);
293 if (zrc != Z_OK) {
294 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
295 pth_cleanup_pop(1);
296 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
299 zrc = inflate(&gz->z, Z_BLOCK);
301 if (zrc != Z_OK) {
302 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
303 pth_cleanup_pop(1);
304 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
307 if (h.comment)
308 insize = strtoul((gchar *)h.comment, NULL, 10);
310 do {
311 gpointer p;
313 zrc = inflate(&gz->z, Z_FINISH);
315 switch (zrc) {
316 case Z_OK:
317 break;
318 case Z_BUF_ERROR:
319 if (!gz->z.avail_out) {
320 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
322 if (!p) {
323 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
324 rc = GPG_ERR_ENOMEM;
325 goto fail;
328 gz->out = p;
329 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
330 gz->z.avail_out = zlib_bufsize;
331 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
332 gz->z.total_out, insize);
334 if (rc)
335 goto fail;
337 break;
338 case Z_STREAM_END:
339 break;
340 default:
341 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
342 rc = GPG_ERR_COMPR_ALGO;
343 goto fail;
344 break;
346 } while (zrc != Z_STREAM_END);
348 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
349 insize);
351 if (rc)
352 goto fail;
354 *out = gz->out;
355 *outsize = gz->z.total_out;
356 gz->done = TRUE;
357 pth_cleanup_pop(1);
358 return 0;
360 fail:
361 pth_cleanup_pop(1);
362 return rc;
365 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
366 gpg_error_t *rc)
368 gint fd;
369 gsize len;
370 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
371 gsize fh_size;
372 gpointer p;
374 *rc = 0;
376 if (!fh) {
377 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
378 *rc = GPG_ERR_ENOMEM;
379 return NULL;
382 pth_cleanup_push(g_free, fh);
383 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
385 if (g_lstat(filename, &fh->st) == -1) {
386 *rc = gpg_error_from_syserror();
387 pth_cleanup_pop(1);
388 return NULL;
391 if (!S_ISREG(fh->st.st_mode)) {
392 *rc = GPG_ERR_ENOANO;
393 pth_cleanup_pop(1);
394 return NULL;
397 fd = open(filename, O_RDONLY);
399 if (fd == -1) {
400 *rc = gpg_error_from_syserror();
401 pth_cleanup_pop(1);
402 return NULL;
405 pth_cleanup_push(cleanup_fd_cb, &fd);
406 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
407 len = pth_read(fd, p, fh_size);
409 if (len != fh_size) {
410 *rc = gpg_error_from_syserror();
411 pth_cleanup_pop(1);
412 pth_cleanup_pop(1);
413 return NULL;
416 fh->v1 = v1;
417 fh->fd = fd;
418 pth_cleanup_pop(0);
419 pth_cleanup_pop(0);
420 return fh;
423 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
424 gboolean cached)
426 struct client_s *client = assuan_get_pointer(ctx);
427 gpg_error_t rc;
428 gint timeout;
429 guchar *key = client->crypto->key;
431 /* New file. */
432 if (!client->crypto->fh) {
433 if (key[0])
434 goto update_cache;
436 goto done;
439 rc = init_client_crypto2(client->filename, client->crypto);
441 if (rc) {
442 cleanup_client(client);
443 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
446 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
448 if (rc) {
449 cleanup_client(client);
450 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
453 update_cache:
454 CACHE_LOCK(client->ctx);
456 if (cached == FALSE) {
457 if (cache_update_key(client->md5file, key) == FALSE) {
458 cleanup_client(client);
459 CACHE_UNLOCK;
460 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
463 timeout = get_key_file_integer(client->filename, "cache_timeout");
464 cache_reset_timeout(client->md5file, timeout);
466 else
467 cache_set_timeout(client->md5file, -2);
469 CACHE_UNLOCK;
471 done:
472 rc = parse_xml(ctx);
474 if (client->xml) {
475 gcry_free(client->xml);
476 client->xml = NULL;
479 if (!rc) {
480 if (client->new == FALSE)
481 send_status_all(STATUS_CACHE);
483 client->state = STATE_OPEN;
486 if (!rc && client->new == FALSE &&
487 client->crypto->fh->ver.fh2.iter != get_key_file_uint64(client->filename, "iterations")) {
488 gchar *s = g_strdup_printf("%llu", (unsigned long long)client->crypto->fh->ver.fh2.iter);
490 MUTEX_LOCK(&rcfile_mutex);
491 g_key_file_set_value(keyfileh, client->filename, "iterations", s);
492 g_free(s);
493 MUTEX_UNLOCK(&rcfile_mutex);
494 send_status_all(STATUS_CONFIG);
497 cleanup_crypto(&client->crypto);
499 if (!rc && client->new)
500 rc = send_status(ctx, STATUS_NEWFILE, NULL);
502 if (!rc && client->lock_on_open)
503 return do_lock_command(client);
505 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
508 static void req_cleanup(void *arg)
510 if (!arg)
511 return;
513 g_strfreev((gchar **)arg);
516 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
518 struct client_s *client = data;
519 const gchar *p = value;
521 if (p && *p) {
522 gint n = atoi(p);
524 if (n < 0 || n > 1)
525 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
527 client->lock_on_open = n ? TRUE : FALSE;
529 else if ((!p || !*p) && (client->opts & OPT_LOCK))
530 client->lock_on_open = FALSE;
531 else
532 client->lock_on_open = TRUE;
534 return 0;
537 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
539 #ifdef WITH_PINENTRY
540 struct client_s *client = data;
541 gchar *str = value;
542 gint n;
544 if (!str || !*str) {
545 client->pinentry->enable = -1;
546 client->opts &= ~(OPT_PINENTRY);
547 return 0;
550 n = atoi(str);
552 if (n < 0 || n > 1)
553 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
555 client->pinentry->enable = n ? TRUE : FALSE;
556 client->opts |= OPT_PINENTRY;
557 return 0;
558 #else
559 return GPG_ERR_NOT_IMPLEMENTED;
560 #endif
563 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
565 struct client_s *client = data;
567 (void)value;
568 client->opts |= OPT_INQUIRE;
569 return 0;
572 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
574 struct client_s *client = data;
576 (void)value;
577 client->opts |= OPT_BASE64;
578 return 0;
581 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
583 guchar *tmp;
584 gsize len;
586 if (client->opts & OPT_BASE64)
587 tmp = g_base64_decode(key, &len);
588 else {
589 tmp = (guchar *)g_strdup(key);
590 len = strlen(key);
593 if (!tmp)
594 return GPG_ERR_ENOMEM;
596 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
597 g_free(tmp);
598 return 0;
601 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
603 gboolean cached = FALSE;
604 gpg_error_t rc;
605 struct client_s *client = assuan_get_pointer(ctx);
606 gchar **req;
607 gchar *filename = NULL;
608 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
610 if ((req = split_input_line(line, " ", 2)) != NULL)
611 filename = req[0];
613 pth_cleanup_push(req_cleanup, req);
615 if (!filename || !*filename) {
616 pth_cleanup_pop(1);
617 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
620 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
622 if (valid_filename(filename) == FALSE) {
623 pth_cleanup_pop(1);
624 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
627 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
628 CACHE_LOCK(client->ctx);
630 if (cache_has_file(client->md5file) == FALSE) {
631 if (cache_add_file(client->md5file, NULL) == FALSE) {
632 pth_cleanup_pop(1);
633 CACHE_UNLOCK;
634 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
638 CACHE_UNLOCK;
639 rc = lock_file_mutex(client);
641 if (rc) {
642 pth_cleanup_pop(1);
643 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
646 client->freed = FALSE;
647 CACHE_LOCK(client->ctx);
648 cache_incr_refcount(client->md5file);
649 CACHE_UNLOCK;
650 client->crypto = init_client_crypto();
652 if (!client->crypto) {
653 pth_cleanup_pop(1);
654 cleanup_client(client);
655 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
658 client->crypto->key = gcry_malloc(hashlen);
660 if (!client->crypto->key) {
661 pth_cleanup_pop(1);
662 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
663 GPG_ERR_ENOMEM);
664 cleanup_client(client);
665 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
668 memset(client->crypto->key, 0, hashlen);
669 client->crypto->fh = read_file_header(filename, FALSE, &rc);
671 if (!client->crypto->fh) {
672 if (gpg_err_code_to_errno(rc) != ENOENT) {
673 log_write("%s: %s", filename, pwmd_strerror(rc));
674 pth_cleanup_pop(1);
675 cleanup_client(client);
676 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
680 * New files don't need a key.
682 if ((client->xml = new_document()) == NULL) {
683 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
684 pth_cleanup_pop(1);
685 cleanup_client(client);
686 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
689 client->len = xmlStrlen(client->xml);
690 client->new = TRUE;
691 client->filename = g_strdup(filename);
693 if (!client->filename) {
694 pth_cleanup_pop(1);
695 cleanup_client(client);
696 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
697 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
700 if (req[1] && *req[1]) {
701 rc = hash_key(client, req[1]);
703 if (rc) {
704 pth_cleanup_pop(1);
705 cleanup_client(client);
706 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
710 pth_cleanup_pop(1);
711 #ifdef WITH_PINENTRY
712 client->pinentry->filename = g_strdup(client->filename);
714 if (!client->pinentry->filename) {
715 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
716 cleanup_client(client);
717 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
719 #endif
720 return open_command_finalize(ctx, NULL, cached);
722 else {
723 if (!(client->opts & OPT_CIPHER))
724 g_key_file_set_string(keyfileh, filename, "cipher",
725 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
727 client->mtime = client->crypto->fh->st.st_mtime;
730 client->filename = g_strdup(filename);
732 if (!client->filename) {
733 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
734 pth_cleanup_pop(1);
735 cleanup_client(client);
736 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
739 #ifdef WITH_PINENTRY
740 if (client->pinentry->filename)
741 g_free(client->pinentry->filename);
743 client->pinentry->filename = g_strdup(client->filename);
745 if (!client->pinentry->filename) {
746 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
747 pth_cleanup_pop(1);
748 cleanup_client(client);
749 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
751 #endif
753 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
754 goto done;
756 CACHE_LOCK(client->ctx);
757 cached = cache_get_key(client->md5file, client->crypto->key);
758 CACHE_UNLOCK;
760 if (cached == FALSE) {
761 gchar *tmp = get_key_file_string(filename, "key_file");
763 if (tmp && !(client->opts & OPT_INQUIRE)) {
764 g_free(tmp);
765 pth_cleanup_pop(1);
766 cleanup_client(client);
767 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
770 if (tmp)
771 g_free(tmp);
774 * No key specified and no matching filename found in the cache. Use
775 * pinentry to retrieve the key. Cannot return assuan_process_done()
776 * here otherwise the command will be interrupted. The event loop in
777 * client_thread() will poll the file descriptor waiting for it to
778 * become ready to read a pinentry_key_s which will contain the
779 * entered key or an error code. It will then call
780 * open_command_finalize() to to finish the command.
782 if (!req[1] || !*req[1]) {
783 #ifdef WITH_PINENTRY
784 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
786 /* From set_pinentry_defaults(). */
787 if (client->opts & OPT_INQUIRE ||
788 client->pinentry->enable == FALSE ||
789 (client->pinentry->enable == -1 && b == FALSE)) {
790 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
791 goto done;
794 pth_cleanup_pop(1);
795 rc = lock_pin_mutex(client);
797 if (rc) {
798 unlock_pin_mutex(client->pinentry);
799 cleanup_client(client);
800 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
803 client->pinentry->which = PINENTRY_OPEN;
804 rc = pinentry_fork(ctx);
806 if (rc) {
807 unlock_pin_mutex(client->pinentry);
808 cleanup_client(client);
809 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
812 // Called from pinentry iterate.
813 client->pinentry->cb = open_command_finalize;
814 client->pinentry->status = PINENTRY_INIT;
815 return 0;
816 #else
817 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
818 goto done;
819 #endif
822 rc = hash_key(client, req[1]);
824 if (rc) {
825 pth_cleanup_pop(1);
826 cleanup_client(client);
827 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
830 else if (req && req[1] && *req[1]) {
831 rc = hash_key(client, req[1]);
833 if (rc) {
834 pth_cleanup_pop(1);
835 cleanup_client(client);
836 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
840 done:
841 pth_cleanup_pop(1);
842 return open_command_finalize(ctx, NULL, cached);
845 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
846 guchar *line, gsize len)
848 assuan_context_t ctx = data;
849 struct client_s *client = assuan_get_pointer(ctx);
850 gpg_error_t rc = file_modified(client);
852 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
853 if (line)
854 xfree(line);
856 return assuan_rc ? assuan_rc : rc;
859 rc = open_command_common(ctx, (gchar *)line);
861 if (line)
862 xfree(line);
864 client->inquire_status = INQUIRE_DONE;
865 return rc;
868 static gint open_command(assuan_context_t ctx, gchar *line)
870 gpg_error_t rc;
871 struct client_s *client = assuan_get_pointer(ctx);
872 struct argv_s *args[] = {
873 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
874 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
875 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
876 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
877 NULL
880 if (client->state == STATE_OPEN)
881 cleanup_client(client);
883 if (!(client->opts & OPT_LOCK))
884 client->lock_on_open = FALSE;
886 rc = parse_options(&line, args, client);
888 if (rc)
889 return send_error(ctx, rc);
891 if ((client->opts & OPT_INQUIRE)) {
892 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
893 ctx);
895 if (rc)
896 return send_error(ctx, rc);
898 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
899 client->inquire_status = INQUIRE_BUSY;
900 return 0;
903 return open_command_common(ctx, line);
906 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
907 guint size, gpointer *out, gulong *outsize)
909 struct gz_s *gz;
910 gz_header h;
911 gchar buf[17];
912 gint cmd = Z_NO_FLUSH;
913 gint zrc;
914 gpg_error_t rc;
916 gz = g_malloc0(sizeof(struct gz_s));
918 if (!gz)
919 return GPG_ERR_ENOMEM;
921 pth_cleanup_push(gz_cleanup, &gz);
922 gz->which = STATUS_COMPRESS;
923 gz->z.zalloc = z_alloc;
924 gz->z.zfree = z_free;
925 gz->z.next_in = data;
926 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
927 gz->z.avail_out = (uInt)zlib_bufsize;
928 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
930 if (!gz->out) {
931 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
932 pth_cleanup_pop(1);
933 return GPG_ERR_ENOMEM;
936 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
938 if (zrc != Z_OK) {
939 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
940 pth_cleanup_pop(1);
941 return GPG_ERR_COMPR_ALGO;
944 /* Rather than store the size of the uncompressed data in the file header,
945 * store it in the comment field of the gzip header. Don't give anyone too
946 * much information. Not sure why really, but it seems the right way. :)
948 memset(&h, 0, sizeof(gz_header));
949 g_snprintf(buf, sizeof(buf), "%u", size);
950 h.comment = (guchar *)buf;
951 zrc = deflateSetHeader(&gz->z, &h);
953 if (zrc != Z_OK) {
954 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
955 pth_cleanup_pop(1);
956 return GPG_ERR_COMPR_ALGO;
959 do {
960 gpointer p;
962 zrc = deflate(&gz->z, cmd);
964 switch (zrc) {
965 case Z_OK:
966 break;
967 case Z_BUF_ERROR:
968 if (!gz->z.avail_out) {
969 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
971 if (!p) {
972 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
973 rc = GPG_ERR_ENOMEM;
974 goto fail;
977 gz->out = p;
978 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
979 gz->z.avail_out = zlib_bufsize;
982 if (!gz->z.avail_in && gz->z.total_in < size) {
983 if (gz->z.total_in + zlib_bufsize > size)
984 gz->z.avail_in = size - gz->z.total_in;
985 else
986 gz->z.avail_in = zlib_bufsize;
988 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
989 gz->z.total_in, size);
991 if (rc)
992 goto fail;
995 if (gz->z.total_in >= size)
996 cmd = Z_FINISH;
998 break;
999 case Z_STREAM_END:
1000 break;
1001 default:
1002 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
1003 rc = GPG_ERR_COMPR_ALGO;
1004 goto fail;
1006 } while (zrc != Z_STREAM_END);
1008 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1010 if (rc)
1011 goto fail;
1013 *out = gz->out;
1014 *outsize = gz->z.total_out;
1015 gz->done = TRUE;
1016 pth_cleanup_pop(1);
1017 return 0;
1019 fail:
1020 pth_cleanup_pop(1);
1021 return rc;
1024 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1027 * Useful for a large amount of data. Rather than doing all of the data in one
1028 * iteration do it in chunks. This lets the command be cancelable rather than
1029 * waiting for it to complete.
1031 static gpg_error_t iterate_crypto_once(struct client_s *client,
1032 struct crypto_s *crypto, status_msg_t which)
1034 gpg_error_t rc = 0;
1035 goffset len = CRYPTO_BLOCKSIZE(crypto);
1036 gpointer p = gcry_malloc(len);
1037 goffset total = 0;
1038 gpointer inbuf;
1040 if (!p)
1041 return GPG_ERR_ENOMEM;
1043 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1044 len = crypto->insize;
1046 pth_cleanup_push(gcry_free, p);
1048 for (;;) {
1049 inbuf = (guchar *)crypto->inbuf + total;
1050 guchar *tmp;
1052 if (len + total > crypto->insize)
1053 len = crypto->blocksize;
1055 if (which == STATUS_ENCRYPT)
1056 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1057 else
1058 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1060 if (rc)
1061 goto done;
1063 tmp = (guchar *)crypto->inbuf + total;
1064 memmove(tmp, p, len);
1065 total += len;
1067 if (total >= crypto->insize)
1068 break;
1070 pth_cancel_point();
1073 done:
1074 pth_cleanup_pop(1);
1075 return rc;
1078 /* The crypto struct must be setup for iterations and .key. */
1079 gpg_error_t do_xml_encrypt(struct client_s *client,
1080 struct crypto_s *crypto, const gchar *filename)
1082 goffset len = crypto->insize;
1083 gpointer inbuf;
1084 gchar *p;
1085 gpg_error_t rc;
1086 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
1087 gchar tmp[FILENAME_MAX];
1088 struct stat st;
1089 mode_t mode = 0;
1090 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1092 if (!crypto->fh->ver.fh2.iter) {
1094 * cache_file_count() needs both .used == TRUE and a valid key in
1095 * order for it to count as a used cache entry. Fixes CACHE status
1096 * messages.
1098 memset(crypto->key, '!', hashlen);
1099 goto write_file;
1103 * Resize the existing xml buffer to the block size required by gcrypt
1104 * rather than duplicating it and wasting memory.
1106 crypto->insize += sizeof(crypto_magic);
1107 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1109 if (crypto->insize % crypto->blocksize)
1110 len += crypto->blocksize;
1112 inbuf = gcry_realloc(crypto->inbuf, len);
1114 if (!inbuf) {
1115 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1116 return GPG_ERR_ENOMEM;
1119 guchar *tmpbuf = inbuf;
1120 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1121 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1122 crypto->inbuf = tmpbuf;
1123 crypto->insize = len;
1124 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1126 if (crypto->tkey)
1127 gcry_free(crypto->tkey);
1129 crypto->tkey = gcry_malloc(hashlen);
1131 if (!crypto->tkey) {
1132 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1133 return GPG_ERR_ENOMEM;
1136 memcpy(crypto->tkey, crypto->key, hashlen);
1137 guchar *tkey = crypto->tkey;
1138 tkey[0] ^= 1;
1140 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1141 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1142 return rc;
1145 iter_progress = get_key_file_uint64(
1146 client ? client->filename : "global", "iteration_progress");
1148 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1149 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1150 "0 %llu", crypto->fh->ver.fh2.iter);
1152 if (rc)
1153 return rc;
1156 while (xiter < crypto->fh->ver.fh2.iter-1) {
1157 if (iter_progress > 0ULL && xiter >= iter_progress) {
1158 if (!(xiter % iter_progress)) {
1159 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1160 "%llu %llu", ++n_iter * iter_progress,
1161 crypto->fh->ver.fh2.iter);
1163 if (rc)
1164 return rc;
1168 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1169 crypto->blocksize))) {
1170 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1171 return rc;
1174 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1176 if (rc) {
1177 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1178 return rc;
1181 xiter++;
1184 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1185 crypto->blocksize))) {
1186 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1187 return rc;
1190 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1191 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1192 return rc;
1195 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1197 if (rc)
1198 return rc;
1200 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1201 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1202 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1204 if (rc)
1205 return rc;
1208 write_file:
1209 tmp[0] = 0;
1211 if (filename) {
1212 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1213 crypto->fh->fd = STDOUT_FILENO;
1214 goto do_write_file;
1217 if (g_lstat(filename, &st) == 0) {
1218 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1220 if (!(mode & S_IWUSR))
1221 return GPG_ERR_EACCES;
1223 else if (errno != ENOENT)
1224 return gpg_error_from_syserror();
1226 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1227 #if GLIB_CHECK_VERSION(2, 22, 0)
1228 crypto->fh->fd = g_mkstemp_full(tmp, O_WRONLY, 0600);
1229 #else
1230 crypto->fh->fd = mkstemp(tmp);
1231 #endif
1233 if (crypto->fh->fd == -1) {
1234 rc = gpg_error_from_syserror();
1235 p = strrchr(tmp, '/');
1236 p++;
1237 log_write("%s: %s", p, pwmd_strerror(rc));
1238 return rc;
1241 pth_cleanup_push(cleanup_unlink_cb, tmp);
1243 else
1245 * xml_import() or convert_file() from command line.
1247 crypto->fh->fd = STDOUT_FILENO;
1249 do_write_file:
1250 crypto->fh->ver.fh2.magic[0] = '\177';
1251 crypto->fh->ver.fh2.magic[1] = 'P';
1252 crypto->fh->ver.fh2.magic[2] = 'W';
1253 crypto->fh->ver.fh2.magic[3] = 'M';
1254 crypto->fh->ver.fh2.magic[4] = 'D';
1255 crypto->fh->ver.fh2.version = VERSION_HEX;
1256 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1258 if (len != sizeof(crypto->fh->ver.fh2)) {
1259 rc = gpg_error_from_syserror();
1261 if (tmp[0])
1262 pth_cleanup_pop(1);
1264 return rc;
1267 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1269 if (len != crypto->insize) {
1270 rc = gpg_error_from_syserror();
1272 if (tmp[0])
1273 pth_cleanup_pop(1);
1275 return rc;
1278 if (fsync(crypto->fh->fd) == -1) {
1279 rc = gpg_error_from_syserror();
1281 if (tmp[0])
1282 pth_cleanup_pop(1);
1284 return rc;
1287 if (tmp[0]) {
1288 #ifdef WITH_LIBACL
1289 acl_t acl;
1290 #endif
1291 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1292 gchar tmp2[FILENAME_MAX];
1294 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1295 #ifdef WITH_LIBACL
1296 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1298 if (!acl)
1299 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1300 #endif
1302 if (rename(filename, tmp2) == -1) {
1303 rc = gpg_error_from_syserror();
1304 pth_cleanup_pop(1);
1305 #ifdef WITH_LIBACL
1306 if (acl)
1307 acl_free(acl);
1308 #endif
1309 return rc;
1312 #ifdef WITH_LIBACL
1313 else {
1314 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1316 if (!acl)
1317 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1319 #endif
1321 if (rename(tmp, filename) == -1) {
1322 rc = gpg_error_from_syserror();
1323 pth_cleanup_pop(1);
1324 #ifdef WITH_LIBACL
1325 if (acl)
1326 acl_free(acl);
1327 #endif
1328 return rc;
1331 pth_cleanup_pop(0);
1333 if (mode)
1334 chmod(filename, mode);
1336 #ifdef WITH_LIBACL
1337 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1338 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1340 if (acl)
1341 acl_free(acl);
1342 #endif
1344 /* Be sure the file entry has been written to disk. On FreeBSD I
1345 * noticed delays causing a following command to return
1346 * GPG_ERR_CHECKSUM. Recommended from fsync(2) (Linux).
1348 DIR *dir;
1349 gchar *path;
1350 gchar *s = get_key_file_string("global", "data_directory");
1352 path = expand_homedir(s);
1353 g_free(s);
1354 dir = opendir(path);
1355 g_free(path);
1356 if (dir) {
1357 gint fd = dirfd(dir);
1358 if (fd != -1)
1359 fsync(fd);
1360 else
1361 rc = gpg_error_from_syserror();
1363 closedir(dir);
1365 else
1366 rc = gpg_error_from_syserror();
1369 if (client && g_lstat(filename, &st) == 0)
1370 client->mtime = st.st_mtime;
1372 return rc;
1375 gpg_error_t update_save_flags(const gchar *filename,
1376 struct crypto_s *crypto)
1378 gpg_error_t rc;
1380 /* New file? */
1381 if (!crypto->fh) {
1382 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1384 if (!crypto->fh)
1385 return GPG_ERR_ENOMEM;
1388 rc = init_client_crypto2(filename, crypto);
1390 if (rc)
1391 return rc;
1393 if (filename && !crypto->fh->v1)
1394 crypto->fh->ver.fh2.iter = get_key_file_uint64(filename, "iterations");
1396 return 0;
1399 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1400 gboolean cached)
1402 struct client_s *client = assuan_get_pointer(ctx);
1403 gpointer xmlbuf;
1404 gulong outsize = 0;
1405 guint len;
1406 gint clevel;
1407 gint timeout;
1408 gpointer outbuf;
1409 gpg_error_t rc;
1411 if (client->crypto->key && client->crypto->key != key)
1412 gcry_free(client->crypto->key);
1414 client->crypto->key = key;
1415 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1417 if (rc) {
1418 cleanup_crypto(&client->crypto);
1419 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1422 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1423 pth_cleanup_push(xmlFree, xmlbuf);
1424 clevel = get_key_file_integer(client->filename, "compression_level");
1426 if (clevel < 0)
1427 clevel = 0;
1429 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1431 if (rc) {
1432 pth_cleanup_pop(1);
1433 cleanup_crypto(&client->crypto);
1435 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1437 else {
1438 pth_cleanup_pop(1);
1439 xmlbuf = outbuf;
1440 len = outsize;
1443 client->crypto->inbuf = xmlbuf;
1444 client->crypto->insize = len;
1445 rc = update_save_flags(client->filename, client->crypto);
1447 if (rc) {
1448 cleanup_crypto(&client->crypto);
1449 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1450 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1453 rc = do_xml_encrypt(client, client->crypto, client->filename);
1455 if (rc) {
1456 cleanup_crypto(&client->crypto);
1457 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1460 timeout = get_key_file_integer(client->filename, "cache_timeout");
1461 CACHE_LOCK(client->ctx);
1463 if (cached) {
1464 cache_reset_timeout(client->md5file, timeout);
1465 CACHE_UNLOCK;
1467 if (client->new == TRUE)
1468 send_status_all(STATUS_CACHE);
1470 client->new = FALSE;
1471 cleanup_crypto(&client->crypto);
1472 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1475 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1476 CACHE_UNLOCK;
1477 cleanup_crypto(&client->crypto);
1478 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1481 client->new = FALSE;
1482 cache_reset_timeout(client->md5file, timeout);
1483 CACHE_UNLOCK;
1484 send_status_all(STATUS_CACHE);
1485 cleanup_crypto(&client->crypto);
1486 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1489 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1491 struct client_s *client = data;
1492 guint64 n;
1493 gchar *value = v;
1494 gchar *p = NULL;
1496 if (!client->filename)
1497 return EPWMD_NO_FILE;
1499 if (!value || !*value)
1500 return 0;
1502 errno = 0;
1503 n = g_ascii_strtoull(value, &p, 10);
1505 if (errno || (p && *p) || n == G_MAXUINT64)
1506 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1508 MUTEX_LOCK(&rcfile_mutex);
1509 g_key_file_set_value(keyfileh,
1510 client->filename ? client->filename : "global", "iterations", value);
1511 MUTEX_UNLOCK(&rcfile_mutex);
1513 if (client->filename)
1514 client->opts |= OPT_ITERATIONS;
1516 return 0;
1519 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1521 struct client_s *client = data;
1522 const gchar *p = value;
1523 guint64 flags;
1525 if (!client->filename)
1526 return EPWMD_NO_FILE;
1528 if (!p || !*p)
1529 return 0;
1531 flags = pwmd_cipher_str_to_cipher(p);
1533 if (!flags)
1534 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1536 MUTEX_LOCK(&rcfile_mutex);
1537 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1538 MUTEX_UNLOCK(&rcfile_mutex);
1540 if (!value)
1541 g_free((gchar *)p);
1543 return 0;
1546 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1548 struct client_s *client = data;
1550 CACHE_LOCK(client->ctx);
1551 cache_clear(client->md5file, 1);
1552 CACHE_UNLOCK;
1553 return 0;
1556 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1558 struct client_s *client = assuan_get_pointer(ctx);
1559 gboolean cached = FALSE;
1560 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1562 CACHE_LOCK(ctx);
1563 cached = cache_iscached(client->md5file);
1564 CACHE_UNLOCK;
1567 * If a cache entry doesn't exist for this file and the file has a
1568 * "key_file" or "key" parameter, then it's an error. The reason is that
1569 * cache expiration would be useless. Unless this is an inquire, then its
1570 * fine.
1572 if (cached == FALSE) {
1573 gchar *tmp = get_key_file_string(client->filename, "key_file");
1575 if (tmp && !(client->opts & OPT_INQUIRE)) {
1576 g_free(tmp);
1577 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1580 if (tmp)
1581 g_free(tmp);
1584 cached = FALSE;
1586 /* New file? */
1587 if (!client->crypto) {
1588 client->crypto = init_client_crypto();
1590 if (!client->crypto) {
1591 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1592 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1596 client->crypto->key = gcry_malloc(hashlen);
1598 if (!client->crypto->key) {
1599 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1600 cleanup_crypto(&client->crypto);
1601 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1604 memset(client->crypto->key, '!', hashlen);
1606 if (!get_key_file_uint64(client->filename, "iterations") &&
1607 (!line || !*line))
1608 goto done;
1610 if (!line || !*line) {
1611 /* It doesn't make sense to use an --inquire with an empty
1612 * passphrase. This will prevent a pinentry dialog. */
1613 if (client->opts & OPT_INQUIRE) {
1614 cleanup_crypto(&client->crypto);
1615 return GPG_ERR_WRONG_KEY_USAGE;
1618 client->crypto->tkey = gcry_malloc(hashlen);
1620 if (!client->crypto->tkey) {
1621 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1622 cleanup_crypto(&client->crypto);
1623 return send_error(ctx, GPG_ERR_ENOMEM);
1626 memset(client->crypto->tkey, '!', hashlen);
1627 CACHE_LOCK(ctx);
1629 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1630 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1631 CACHE_UNLOCK;
1633 #ifdef WITH_PINENTRY
1634 gpg_error_t rc;
1636 if (client->pinentry->enable == FALSE ||
1637 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1638 /* Empty keys are allowed. */
1639 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1640 goto done;
1643 lock_pin_mutex(client);
1644 client->pinentry->which = PINENTRY_SAVE;
1645 rc = pinentry_fork(ctx);
1647 if (rc) {
1648 unlock_pin_mutex(client->pinentry);
1649 cleanup_crypto(&client->crypto);
1650 return send_error(ctx, rc);
1653 client->pinentry->cb = save_command_finalize;
1654 client->pinentry->status = PINENTRY_INIT;
1655 return 0;
1656 #else
1657 /* Empty keys are allowed. */
1658 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1659 goto done;
1660 #endif
1662 else {
1663 CACHE_UNLOCK;
1664 cached = TRUE;
1667 else {
1668 gpg_error_t rc;
1670 if (!get_key_file_uint64(client->filename, "iterations")) {
1671 guint64 iter = get_key_file_uint64(NULL, "iterations");
1672 gchar *p;
1674 if (!iter)
1675 iter = 1; // default? what about the "global" section?
1677 MUTEX_LOCK(&rcfile_mutex);
1678 p = g_strdup_printf("%llu", (unsigned long long)iter);
1679 g_key_file_set_value(keyfileh, client->filename, "iterations", p);
1680 g_free(p);
1681 MUTEX_UNLOCK(&rcfile_mutex);
1682 client->opts |= OPT_ITERATIONS;
1683 rc = send_status(ctx, STATUS_CONFIG, NULL);
1685 if (rc) {
1686 cleanup_crypto(&client->crypto);
1687 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1691 rc = hash_key(client, line);
1693 if (rc) {
1694 cleanup_crypto(&client->crypto);
1695 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1699 done:
1700 return save_command_finalize(ctx, client->crypto->key, cached);
1703 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1704 guchar *line, gsize len)
1706 assuan_context_t ctx = data;
1707 struct client_s *client = assuan_get_pointer(ctx);
1708 gpg_error_t rc = file_modified(client);
1710 if (assuan_rc || rc) {
1711 if (line)
1712 xfree(line);
1714 return assuan_rc ? assuan_rc : rc;
1717 rc = save_command_common(ctx, (gchar *)line);
1719 if (line)
1720 xfree(line);
1722 client->inquire_status = INQUIRE_DONE;
1723 return rc;
1726 static gint save_command(assuan_context_t ctx, gchar *line)
1728 struct stat st;
1729 struct client_s *client = assuan_get_pointer(ctx);
1730 gpg_error_t rc;
1731 struct argv_s *args[] = {
1732 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1733 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1734 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1735 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1736 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1737 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1738 NULL
1741 rc = parse_options(&line, args, client);
1743 if (rc)
1744 return send_error(ctx, rc);
1746 if (g_lstat(client->filename, &st) == -1 && errno != ENOENT)
1747 return send_error(ctx, gpg_error_from_syserror());
1749 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1750 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1751 return send_error(ctx, GPG_ERR_ENOANO);
1754 if ((client->opts & OPT_INQUIRE)) {
1755 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1756 ctx);
1758 if (rc)
1759 return send_error(ctx, rc);
1761 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1762 client->inquire_status = INQUIRE_BUSY;
1763 return 0;
1766 if (line && *line)
1767 log_write2("ARGS=%s", "<passphrase>");
1769 return save_command_common(ctx, line);
1772 static gint delete_command(assuan_context_t ctx, gchar *line)
1774 struct client_s *client = assuan_get_pointer(ctx);
1775 gchar **req;
1776 gpg_error_t rc;
1777 xmlNodePtr n;
1779 log_write2("ARGS=\"%s\"", line);
1781 if (strchr(line, '\t'))
1782 req = split_input_line(line, "\t", -1);
1783 else
1784 req = split_input_line(line, " ", -1);
1786 if (!req || !*req)
1787 return send_error(ctx, GPG_ERR_SYNTAX);
1789 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1791 if (!n) {
1792 g_strfreev(req);
1793 return send_error(ctx, rc);
1797 * No sub-node defined. Remove the entire node (root element).
1799 if (!req[1]) {
1800 if (n) {
1801 rc = unlink_node(n);
1802 xmlFreeNode(n);
1805 g_strfreev(req);
1806 return send_error(ctx, rc);
1809 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1810 g_strfreev(req);
1812 if (!n)
1813 return send_error(ctx, rc);
1815 if (n) {
1816 rc = unlink_node(n);
1817 xmlFreeNode(n);
1820 return send_error(ctx, rc);
1824 * Don't return with assuan_process_done() here. This has been called from
1825 * assuan_process_next() and the command should be finished in
1826 * client_thread().
1828 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1829 gsize len)
1831 assuan_context_t ctx = data;
1832 struct client_s *client = assuan_get_pointer(ctx);
1833 gchar **req;
1834 xmlNodePtr n, parent;
1835 gboolean has_content;
1836 gchar *content = NULL;
1837 gpg_error_t rc = file_modified(client);
1839 if (assuan_rc || rc) {
1840 if (line)
1841 xfree(line);
1842 return assuan_rc ? assuan_rc : rc;
1845 req = split_input_line((gchar *)line, "\t", 0);
1846 xfree(line);
1848 if (!req || !*req)
1849 return GPG_ERR_SYNTAX;
1851 len = g_strv_length(req);
1852 has_content = line[strlen((gchar*)line)-1] != '\t' && len > 1;
1853 if (*(req+1) && !valid_element_path(req, has_content)) {
1854 g_strfreev(req);
1855 return GPG_ERR_INV_VALUE;
1858 if (has_content) {
1859 content = req[len-1];
1860 req[len-1] = NULL;
1863 again:
1864 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1865 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1866 rc = new_root_element(client->doc, *req);
1867 if (rc) {
1868 g_strfreev(req);
1869 return rc;
1872 goto again;
1875 if (!n) {
1876 g_strfreev(req);
1877 return rc;
1880 parent = n;
1882 if (req[1] && *req[1]) {
1883 if (!n->children)
1884 parent = create_elements_cb(n, req+1, &rc, NULL);
1885 else
1886 parent = find_elements(client->doc, n->children, req+1, &rc,
1887 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1890 if (!rc && len > 1) {
1891 n = find_text_node(parent->children);
1892 if (n)
1893 xmlNodeSetContent(n, (xmlChar *)content);
1894 else
1895 xmlNodeAddContent(parent, (xmlChar *)content);
1897 update_element_mtime(parent);
1900 if (has_content)
1901 req[len-1] = content;
1903 g_strfreev(req);
1904 client->inquire_status = INQUIRE_DONE;
1905 return rc;
1908 static gint store_command(assuan_context_t ctx, gchar *line)
1910 struct client_s *client = assuan_get_pointer(ctx);
1911 gpg_error_t rc;
1913 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1915 if (rc)
1916 return send_error(ctx, rc);
1918 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1919 client->inquire_status = INQUIRE_BUSY;
1920 return 0;
1923 static void *send_data_cb(void *arg)
1925 struct assuan_cmd_s *data = arg;
1926 gint old;
1927 gpg_error_t *rc;
1929 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1930 rc = g_malloc(sizeof(gpg_error_t));
1931 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1932 pth_cancel_state(old, NULL);
1933 pth_exit(rc);
1934 return NULL;
1937 /* For every assuan command that needs to be sent to the client, a timeout is
1938 * needed to determine if the client lost the connection. The timeout is the
1939 * same as the "keepalive" configuration parameter or a default if unset.
1941 gpg_error_t do_assuan_command(assuan_context_t ctx,
1942 void *(*cb)(void *data), void *data)
1944 pth_attr_t attr = pth_attr_new();
1945 pth_t tid;
1946 pth_event_t ev;
1947 pth_status_t st;
1948 gpg_error_t rc = 0;
1949 void *p;
1951 pth_attr_init(attr);
1952 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1953 tid = pth_spawn(attr, cb, data);
1954 rc = gpg_error_from_syserror();
1955 pth_attr_destroy(attr);
1957 if (!tid) {
1958 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1959 return rc;
1962 pth_cleanup_push(cleanup_cancel_cb, tid);
1963 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1964 pth_cleanup_push(cleanup_ev_cb, ev);
1965 pth_yield(tid);
1966 pth_wait(ev);
1968 st = pth_event_status(ev);
1970 if (st == PTH_STATUS_FAILED) {
1971 pth_cancel(tid);
1972 pth_join(tid, &p);
1973 g_free(p);
1974 rc = GPG_ERR_ASS_WRITE_ERROR;
1976 else if (st == PTH_STATUS_OCCURRED) {
1977 pth_join(tid, &p);
1978 rc = *(gpg_error_t *)p;
1979 g_free(p);
1982 pth_cleanup_pop(1);
1983 pth_cleanup_pop(0);
1984 return rc;
1987 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1988 gint total)
1990 gint to_send;
1991 gint sent = 0;
1992 gpg_error_t rc;
1993 struct assuan_cmd_s data;
1994 gint progress = get_key_file_integer("global", "xfer_progress");
1995 gint flush = 0;
1997 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1998 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1999 data.ctx = ctx;
2000 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
2002 if (rc)
2003 return rc;
2005 again:
2006 do {
2007 if (sent + to_send > total)
2008 to_send = total - sent;
2010 data.line = flush ? NULL : (gchar *)line+sent;
2011 data.line_len = flush ? 0 : to_send;
2012 rc = do_assuan_command(ctx, send_data_cb, &data);
2014 if (!rc) {
2015 sent += flush ? 0 : to_send;
2017 if ((progress && !(sent % progress) && sent != total) ||
2018 (sent == total && flush))
2019 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
2021 if (!flush && !rc && sent == total) {
2022 flush = 1;
2023 goto again;
2026 } while (!rc && sent < total);
2028 return rc;
2031 static gint get_command(assuan_context_t ctx, gchar *line)
2033 struct client_s *client = assuan_get_pointer(ctx);
2034 gchar **req;
2035 gpg_error_t rc;
2036 xmlNodePtr n;
2038 log_write2("ARGS=\"%s\"", line);
2039 req = split_input_line(line, "\t", -1);
2041 if (!req || !*req) {
2042 g_strfreev(req);
2043 return send_error(ctx, GPG_ERR_SYNTAX);
2046 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2048 if (!n) {
2049 g_strfreev(req);
2050 return send_error(ctx, rc);
2053 if (req[1])
2054 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2056 g_strfreev(req);
2058 if (rc)
2059 return send_error(ctx, rc);
2061 if (!n || !n->children)
2062 return send_error(ctx, GPG_ERR_NO_VALUE);
2064 n = find_text_node(n->children);
2066 if (!n || !n->content || !*n->content)
2067 return send_error(ctx, GPG_ERR_NO_VALUE);
2069 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2070 return send_error(ctx, rc);
2073 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2074 gpg_error_t *rc, gchar **req_orig, void *data)
2076 gchar *path = *(gchar **)data;
2077 gchar *tmp = NULL, *result;
2079 if (path) {
2080 g_free(path);
2081 *(gchar **)data = NULL;
2084 path = g_strjoinv("\t", target);
2086 if (!path) {
2087 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2088 *rc = GPG_ERR_ENOMEM;
2089 return NULL;
2092 if (req_orig) {
2093 tmp = g_strjoinv("\t", req_orig);
2095 if (!tmp) {
2096 g_free(path);
2097 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2098 *rc = GPG_ERR_ENOMEM;
2099 return NULL;
2103 if (tmp && *tmp)
2104 result = g_strdup_printf("%s\t%s", path, tmp);
2105 else
2106 result = g_strdup(path);
2108 if (!result) {
2109 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2110 *rc = GPG_ERR_ENOMEM;
2111 g_free(path);
2112 g_free(tmp);
2113 return NULL;
2116 g_free(path);
2117 g_free(tmp);
2118 *(gchar **)data = result;
2119 return node;
2122 static void list_command_cleanup1(void *arg);
2123 static gint realpath_command(assuan_context_t ctx, gchar *line)
2125 gpg_error_t rc;
2126 struct client_s *client = assuan_get_pointer(ctx);
2127 gchar **req;
2128 gchar *t;
2129 gint i;
2130 xmlNodePtr n;
2131 GString *string;
2132 gchar *rp = NULL;
2134 log_write2("ARGS=\"%s\"", line);
2136 if (strchr(line, '\t') != NULL) {
2137 if ((req = split_input_line(line, "\t", 0)) == NULL)
2138 return send_error(ctx, GPG_ERR_SYNTAX);
2140 else {
2141 if ((req = split_input_line(line, " ", 0)) == NULL)
2142 return send_error(ctx, GPG_ERR_SYNTAX);
2145 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2147 if (!n) {
2148 g_strfreev(req);
2149 return send_error(ctx, rc);
2152 rp = g_strjoinv("\t", req);
2154 if (!rp) {
2155 g_strfreev(req);
2156 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2157 return send_error(ctx, GPG_ERR_ENOMEM);
2160 if (req[1]) {
2161 n = find_elements(client->doc, n->children, req+1, &rc,
2162 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2164 if (!n) {
2165 g_free(rp);
2166 g_strfreev(req);
2167 return send_error(ctx, rc);
2171 string = g_string_new(rp);
2172 g_free(rp);
2173 g_strfreev(req);
2175 if (!string) {
2176 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2177 return send_error(ctx, GPG_ERR_ENOMEM);
2180 again:
2181 for (i = 0, t = string->str + i; *t; t++, i++) {
2182 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2183 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2184 goto again;
2188 pth_cleanup_push(list_command_cleanup1, string);
2189 rc = xfer_data(ctx, string->str, string->len);
2190 pth_cleanup_pop(1);
2191 return send_error(ctx, rc);
2194 static void list_command_cleanup1(void *arg)
2196 g_string_free((GString *)arg, TRUE);
2199 static void list_command_cleanup2(void *arg)
2201 struct element_list_s *elements = arg;
2203 if (elements) {
2204 if (elements->list) {
2205 gint total = g_slist_length(elements->list);
2206 gint i;
2208 for (i = 0; i < total; i++) {
2209 gchar *tmp = g_slist_nth_data(elements->list, i);
2210 g_free(tmp);
2213 g_slist_free(elements->list);
2216 if (elements->prefix)
2217 g_free(elements->prefix);
2219 if (elements->req)
2220 g_strfreev(elements->req);
2222 g_free(elements);
2226 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2228 struct element_list_s *elements = data;
2230 elements->recurse = FALSE;
2231 return 0;
2234 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2236 struct element_list_s *elements = data;
2238 elements->verbose = TRUE;
2239 return 0;
2242 static gint list_command(assuan_context_t ctx, gchar *line)
2244 struct client_s *client = assuan_get_pointer(ctx);
2245 gpg_error_t rc;
2246 struct element_list_s *elements = NULL;
2247 gchar *tmp;
2248 struct argv_s *args[] = {
2249 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2250 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2251 NULL
2254 if (disable_list_and_dump == TRUE)
2255 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2257 elements = g_malloc0(sizeof(struct element_list_s));
2259 if (!elements) {
2260 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2261 return GPG_ERR_ENOMEM;
2264 elements->recurse = TRUE; // default
2265 pth_cleanup_push(list_command_cleanup2, elements);
2266 rc = parse_options(&line, args, elements);
2268 if (rc)
2269 goto fail;
2271 if (!*line) {
2272 GString *str;
2274 rc = list_root_elements(client->doc, &str, elements->verbose);
2276 if (rc) {
2277 pth_cleanup_pop(1);
2278 return send_error(ctx, rc);
2281 pth_cleanup_push(list_command_cleanup1, str);
2282 rc = xfer_data(ctx, str->str, str->len);
2283 pth_cleanup_pop(1);
2284 pth_cleanup_pop(1);
2285 return send_error(ctx, rc);
2288 elements->req = split_input_line(line, " ", 0);
2290 if (!elements->req)
2291 strv_printf(&elements->req, "%s", line);
2293 rc = create_path_list(client->doc, elements, *elements->req);
2295 if (rc)
2296 goto fail;
2298 if (elements) {
2299 gint total = g_slist_length(elements->list);
2300 gint i;
2301 GString *str;
2303 if (!total) {
2304 rc = GPG_ERR_NO_VALUE;
2305 goto fail;
2308 str = g_string_new(NULL);
2310 if (!str) {
2311 rc = GPG_ERR_ENOMEM;
2312 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2313 goto fail;
2316 for (i = 0; i < total; i++) {
2317 tmp = g_slist_nth_data(elements->list, i);
2318 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2321 pth_cleanup_push(list_command_cleanup1, str);
2322 rc = xfer_data(ctx, str->str, str->len);
2323 pth_cleanup_pop(1);
2325 else
2326 rc = GPG_ERR_NO_VALUE;
2328 fail:
2329 pth_cleanup_pop(1);
2330 return send_error(ctx, rc);
2334 * req[0] - element path
2336 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2338 struct client_s *client = assuan_get_pointer(ctx);
2339 gchar **attrlist = NULL;
2340 gint i = 0;
2341 gchar **path = NULL;
2342 xmlAttrPtr a;
2343 xmlNodePtr n, an;
2344 gchar *line;
2345 gpg_error_t rc;
2347 if (!req || !req[0])
2348 return GPG_ERR_SYNTAX;
2350 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2352 * The first argument may be only a root element.
2354 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2355 return GPG_ERR_SYNTAX;
2358 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2360 if (!n) {
2361 g_strfreev(path);
2362 return rc;
2365 if (path[1]) {
2366 n = find_elements(client->doc, n->children, path+1, &rc,
2367 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2369 if (!n) {
2370 g_strfreev(path);
2371 return rc;
2375 g_strfreev(path);
2377 for (a = n->properties; a; a = a->next) {
2378 gchar **pa;
2380 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2381 if (attrlist)
2382 g_strfreev(attrlist);
2384 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2385 return GPG_ERR_ENOMEM;
2388 attrlist = pa;
2389 an = a->children;
2390 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2391 an && an->content ? (gchar *)an->content : "");
2393 if (!attrlist[i]) {
2394 g_strfreev(attrlist);
2395 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2396 return GPG_ERR_ENOMEM;
2399 attrlist[++i] = NULL;
2402 if (!attrlist)
2403 return GPG_ERR_NO_VALUE;
2405 line = g_strjoinv("\n", attrlist);
2407 if (!line) {
2408 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2409 g_strfreev(attrlist);
2410 return GPG_ERR_ENOMEM;
2413 pth_cleanup_push(g_free, line);
2414 pth_cleanup_push(req_cleanup, attrlist);
2415 rc = xfer_data(ctx, line, strlen(line));
2416 pth_cleanup_pop(1);
2417 pth_cleanup_pop(1);
2418 return rc;
2422 * req[0] - attribute
2423 * req[1] - element path
2425 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2427 xmlNodePtr n;
2428 gchar **path = NULL;
2429 gpg_error_t rc;
2431 if (!req || !req[0] || !req[1])
2432 return GPG_ERR_SYNTAX;
2434 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2436 * The first argument may be only a root element.
2438 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2439 return GPG_ERR_SYNTAX;
2443 * Don't remove the "_name" attribute for the root element. To remove an
2444 * root element use DELETE <name>.
2446 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2447 rc = GPG_ERR_SYNTAX;
2448 goto fail;
2451 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2453 if (!n)
2454 goto fail;
2456 if (path[1]) {
2457 n = find_elements(client->doc, n->children, path+1, &rc,
2458 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2460 if (!n)
2461 goto fail;
2464 rc = delete_attribute(n, (xmlChar *)req[0]);
2466 fail:
2467 g_strfreev(path);
2468 return rc;
2471 static xmlNodePtr create_element_path(struct client_s *client,
2472 gchar ***elements, gpg_error_t *rc, xmlNodePtr parent)
2474 gchar **req = *elements;
2475 gchar **req_orig = g_strdupv(req);
2476 xmlNodePtr n = NULL;
2478 *rc = 0;
2480 if (!req_orig) {
2481 *rc = GPG_ERR_ENOMEM;
2482 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2483 goto fail;
2486 again:
2487 n = find_root_element(client->doc, &req, rc, NULL, 0, FALSE);
2488 if (!n) {
2489 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND)
2490 goto fail;
2492 *rc = new_root_element(client->doc, req[0]);
2493 if (*rc)
2494 goto fail;
2496 goto again;
2498 else if (n == parent) {
2499 *rc = GPG_ERR_CONFLICT;
2500 goto fail;
2503 if (req[1]) {
2504 if (!n->children)
2505 n = create_target_elements_cb(n, req+1, rc, NULL);
2506 else
2507 n = find_elements(client->doc, n->children, req+1, rc, NULL, NULL,
2508 create_target_elements_cb, FALSE, 0, parent, FALSE);
2510 if (!n)
2511 goto fail;
2514 * Reset the position of the element tree now that the elements
2515 * have been created.
2517 g_strfreev(req);
2518 req = req_orig;
2519 req_orig = NULL;
2520 n = find_root_element(client->doc, &req, rc, NULL, 0, FALSE);
2521 if (!n)
2522 goto fail;
2524 n = find_elements(client->doc, n->children, req+1, rc,
2525 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2526 if (!n)
2527 goto fail;
2530 fail:
2531 if (req_orig)
2532 g_strfreev(req_orig);
2534 *elements = req;
2535 return n;
2539 * Creates a "target" attribute. When other commands encounter an element with
2540 * this attribute, the element path is modified to the target value. If the
2541 * source element path doesn't exist when using 'ATTR SET target', it is
2542 * created, but the destination element path must exist.
2544 * req[0] - source element path
2545 * req[1] - destination element path
2547 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2549 gchar **src, **dst, *line = NULL, **odst = NULL;
2550 gpg_error_t rc;
2551 xmlNodePtr n;
2553 if (!req || !req[0] || !req[1])
2554 return GPG_ERR_SYNTAX;
2556 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2558 * The first argument may be only a root element.
2560 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2561 return GPG_ERR_SYNTAX;
2564 if (!valid_element_path(src, FALSE))
2565 return GPG_ERR_INV_VALUE;
2567 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2569 * The first argument may be only a root element.
2571 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2572 rc = GPG_ERR_SYNTAX;
2573 goto fail;
2577 odst = g_strdupv(dst);
2579 if (!odst) {
2580 rc = GPG_ERR_ENOMEM;
2581 goto fail;
2584 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2587 * Make sure the destination element path exists.
2589 if (!n)
2590 goto fail;
2592 if (dst[1]) {
2593 n = find_elements(client->doc, n->children, dst+1, &rc,
2594 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2596 if (!n)
2597 goto fail;
2600 n = create_element_path(client, &src, &rc, NULL);
2602 if (rc)
2603 goto fail;
2605 line = g_strjoinv("\t", odst);
2607 if (!line) {
2608 rc = GPG_ERR_ENOMEM;
2609 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2610 goto fail;
2613 rc = add_attribute(n, "target", line);
2615 fail:
2616 g_free(line);
2617 g_strfreev(src);
2618 g_strfreev(dst);
2619 g_strfreev(odst);
2620 return rc;
2624 * req[0] - name
2625 * req[1] - new name
2627 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2629 gpg_error_t rc;
2630 gchar **tmp;
2631 xmlNodePtr n;
2633 tmp = g_strdupv(req);
2635 if (!tmp) {
2636 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2637 return GPG_ERR_ENOMEM;
2640 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2641 g_strfreev(tmp);
2643 if (!n)
2644 return rc;
2646 if (g_utf8_collate(req[0], req[1]) == 0)
2647 return 0;
2650 * Will not overwrite an existing root.
2652 tmp = g_strdupv(req+1);
2654 if (!tmp) {
2655 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2656 return GPG_ERR_ENOMEM;
2659 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2660 g_strfreev(tmp);
2662 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2663 return rc;
2665 if (n)
2666 return GPG_ERR_AMBIGUOUS_NAME;
2668 if (!valid_xml_element((xmlChar *)req[1]))
2669 return GPG_ERR_SYNTAX;
2671 tmp = g_strdupv(req);
2673 if (!tmp) {
2674 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2675 return GPG_ERR_ENOMEM;
2678 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2679 g_strfreev(tmp);
2681 if (!n)
2682 return GPG_ERR_ELEMENT_NOT_FOUND;
2684 return add_attribute(n, "_name", req[1]);
2688 * req[0] - attribute
2689 * req[1] - element path
2691 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2693 struct client_s *client = assuan_get_pointer(ctx);
2694 xmlNodePtr n;
2695 xmlChar *a;
2696 gchar **path= NULL;
2697 gpg_error_t rc;
2699 if (!req || !req[0] || !req[1])
2700 return GPG_ERR_SYNTAX;
2702 if (strchr(req[1], '\t')) {
2703 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2704 return GPG_ERR_SYNTAX;
2706 else {
2707 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2708 return GPG_ERR_SYNTAX;
2711 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2713 if (!n)
2714 goto fail;
2716 if (path[1]) {
2717 n = find_elements(client->doc, n->children, path+1, &rc,
2718 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2720 if (!n)
2721 goto fail;
2724 g_strfreev(path);
2726 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2727 return GPG_ERR_NOT_FOUND;
2729 pth_cleanup_push(xmlFree, a);
2731 if (*a)
2732 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2733 else
2734 rc = GPG_ERR_NO_VALUE;
2736 pth_cleanup_pop(1);
2737 return rc;
2739 fail:
2740 g_strfreev(path);
2741 return rc;
2745 * req[0] - attribute
2746 * req[1] - element path
2747 * req[2] - value
2749 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2751 gchar **path = NULL;
2752 gpg_error_t rc;
2753 xmlNodePtr n;
2755 if (!req || !req[0] || !req[1])
2756 return GPG_ERR_SYNTAX;
2759 * Reserved attribute names.
2761 if (!g_strcmp0(req[0], "_name")) {
2763 * Only reserved for the root element. Not the rest of the
2764 * document.
2766 if (strchr(req[1], '\t') == NULL)
2767 return name_attribute(client, req + 1);
2769 else if (!g_strcmp0(req[0], "target"))
2770 return target_attribute(client, req + 1);
2772 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2774 * The first argument may be only a root element.
2776 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2777 return GPG_ERR_SYNTAX;
2780 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2782 if (!n)
2783 goto fail;
2785 if (path[1]) {
2786 n = find_elements(client->doc, n->children, path+1, &rc,
2787 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2789 if (!n)
2790 goto fail;
2793 rc = add_attribute(n, req[0], req[2]);
2795 fail:
2796 g_strfreev(path);
2797 return rc;
2801 * req[0] - command
2802 * req[1] - attribute name or element path if command is LIST
2803 * req[2] - element path
2804 * req[2] - element path or value
2806 static gint attr_command(assuan_context_t ctx, gchar *line)
2808 struct client_s *client = assuan_get_pointer(ctx);
2809 gchar **req;
2810 gpg_error_t rc = 0;
2812 log_write2("ARGS=\"%s\"", line);
2813 req = split_input_line(line, " ", 4);
2815 if (!req || !req[0] || !req[1]) {
2816 g_strfreev(req);
2817 return send_error(ctx, GPG_ERR_SYNTAX);
2820 pth_cleanup_push(req_cleanup, req);
2822 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2823 rc = attribute_set(client, req+1);
2824 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2825 rc = attribute_get(ctx, req+1);
2826 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2827 rc = attribute_delete(client, req+1);
2828 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2829 rc = attribute_list(ctx, req+1);
2830 else
2831 rc = GPG_ERR_SYNTAX;
2833 pth_cleanup_pop(1);
2834 return send_error(ctx, rc);
2837 static gint iscached_command(assuan_context_t ctx, gchar *line)
2839 gchar **req = split_input_line(line, " ", 0);
2840 guchar md5file[16];
2841 gchar *path, *tmp;
2843 if (!req || !*req) {
2844 g_strfreev(req);
2845 return send_error(ctx, GPG_ERR_SYNTAX);
2848 log_write2("ARGS=\"%s\"", line);
2850 if (!valid_filename(req[0])) {
2851 g_strfreev(req);
2852 return GPG_ERR_INV_VALUE;
2855 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2856 CACHE_LOCK(ctx);
2858 if (cache_iscached(md5file)) {
2859 g_strfreev(req);
2860 CACHE_UNLOCK;
2861 return send_error(ctx, 0);
2864 CACHE_UNLOCK;
2865 tmp = get_key_file_string("global", "data_directory");
2867 if (!tmp) {
2868 g_strfreev(req);
2869 return GPG_ERR_ENOMEM;
2872 path = expand_homedir(tmp);
2874 if (!path) {
2875 g_strfreev(req);
2876 g_free(tmp);
2877 return GPG_ERR_ENOMEM;
2880 g_free(tmp);
2881 tmp = path;
2882 path = g_strdup_printf("%s/%s", tmp, req[0]);
2883 g_free(tmp);
2885 if (!path) {
2886 g_strfreev(req);
2887 return GPG_ERR_ENOMEM;
2890 if (access(path, R_OK) == -1) {
2891 gpg_error_t rc = gpg_error_from_syserror();
2893 g_free(path);
2894 g_strfreev(req);
2895 return send_error(ctx, rc);
2898 g_free(path);
2899 return send_error(ctx, GPG_ERR_NOT_FOUND);
2902 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2904 gchar **req = split_input_line(line, " ", 0);
2905 guchar md5file[16];
2907 log_write2("ARGS=\"%s\"", line);
2908 CACHE_LOCK(ctx);
2910 if (!req || !*req) {
2911 g_strfreev(req);
2912 cache_clear(NULL, 2);
2913 CACHE_UNLOCK;
2914 return send_error(ctx, 0);
2917 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2918 g_strfreev(req);
2919 (void)cache_clear(md5file, 1);
2920 CACHE_UNLOCK;
2921 return send_error(ctx, 0);
2924 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2926 guchar md5file[16];
2927 glong timeout;
2928 gchar **req = split_input_line(line, " ", 0);
2929 gchar *p;
2931 if (!req || !*req || !req[1]) {
2932 g_strfreev(req);
2933 return send_error(ctx, GPG_ERR_SYNTAX);
2936 errno = 0;
2937 timeout = strtol(req[1], &p, 10);
2939 if (errno != 0 || *p != 0 || timeout < -1) {
2940 g_strfreev(req);
2941 return send_error(ctx, GPG_ERR_SYNTAX);
2944 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2945 CACHE_LOCK(client->ctx);
2947 if (cache_set_timeout(md5file, timeout) == FALSE) {
2948 CACHE_UNLOCK;
2949 return send_error(ctx, GPG_ERR_NOT_FOUND);
2952 CACHE_UNLOCK;
2953 return send_error(ctx, 0);
2956 static gint dump_command(assuan_context_t ctx, gchar *line)
2958 xmlChar *xml;
2959 gint len;
2960 struct client_s *client = assuan_get_pointer(ctx);
2961 gpg_error_t rc;
2963 if (disable_list_and_dump == TRUE)
2964 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2966 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2968 if (!xml) {
2969 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2970 return send_error(ctx, GPG_ERR_ENOMEM);
2973 pth_cleanup_push(xmlFree, xml);
2974 rc = xfer_data(ctx, (gchar *)xml, len);
2975 pth_cleanup_pop(1);
2976 return send_error(ctx, rc);
2979 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2981 struct client_s *client = assuan_get_pointer(ctx);
2982 gpg_error_t rc = 0;
2983 gchar filename[255]={0}, param[747]={0};
2984 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2986 log_write2("ARGS=\"%s\"", line);
2988 if (!line || !*line)
2989 return send_error(ctx, GPG_ERR_SYNTAX);
2991 if (strchr(line, ' ')) {
2992 sscanf(line, " %254[^ ] %746c", filename, param);
2993 paramp = param;
2994 fp = filename;
2997 if (fp && !valid_filename(fp))
2998 return send_error(ctx, GPG_ERR_INV_VALUE);
3000 paramp = g_ascii_strdown(paramp, -1);
3002 if (!paramp) {
3003 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3004 return send_error(ctx, GPG_ERR_ENOMEM);
3007 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
3008 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
3009 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
3011 if (!fh && rc != GPG_ERR_ENOENT)
3012 return send_error(ctx, rc);
3014 if (!rc) {
3015 g_free(paramp);
3016 p = g_strdup_printf("%llu", (unsigned long long)fh->ver.fh2.iter);
3017 close_file_header(fh);
3019 if (!p) {
3020 log_write("%s(%i): %s", __FILE__, __LINE__,
3021 pwmd_strerror(GPG_ERR_ENOMEM));
3022 return send_error(ctx, GPG_ERR_ENOMEM);
3025 goto done;
3029 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
3030 #ifdef WITH_PINENTRY
3031 gboolean n;
3033 if (fp == client->filename && (client->opts & OPT_PINENTRY))
3034 n = client->pinentry->enable;
3035 else
3036 n = get_key_file_boolean(fp, "enable_pinentry");
3038 p = g_strdup_printf("%s", n ? "true" : "false");
3040 if (!p) {
3041 log_write("%s(%i): %s", __FILE__, __LINE__,
3042 pwmd_strerror(GPG_ERR_ENOMEM));
3043 return send_error(ctx, GPG_ERR_ENOMEM);
3046 goto done;
3047 #else
3048 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3049 #endif
3051 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3052 #ifdef WITH_PINENTRY
3053 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3055 if (!p) {
3056 log_write("%s(%i): %s", __FILE__, __LINE__,
3057 pwmd_strerror(GPG_ERR_ENOMEM));
3058 return send_error(ctx, GPG_ERR_ENOMEM);
3061 goto done;
3062 #else
3063 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3064 #endif
3067 p = get_key_file_string(fp ? fp : "global", paramp);
3068 g_free(paramp);
3070 if (!p)
3071 return send_error(ctx, GPG_ERR_UNKNOWN_OPTION);
3073 tmp = expand_homedir(p);
3074 g_free(p);
3076 if (!tmp) {
3077 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3078 return send_error(ctx, GPG_ERR_ENOMEM);
3081 p = tmp;
3082 done:
3083 pth_cleanup_push(g_free, p);
3084 rc = xfer_data(ctx, p, strlen(p));
3085 pth_cleanup_pop(1);
3086 return send_error(ctx, rc);
3089 struct xpath_s {
3090 xmlXPathContextPtr xp;
3091 xmlXPathObjectPtr result;
3092 xmlBufferPtr buf;
3093 gchar **req;
3096 static void xpath_command_cleanup(void *arg)
3098 struct xpath_s *xpath = arg;
3100 req_cleanup(xpath->req);
3102 if (xpath->buf)
3103 xmlBufferFree(xpath->buf);
3105 if (xpath->result)
3106 xmlXPathFreeObject(xpath->result);
3108 if (xpath->xp)
3109 xmlXPathFreeContext(xpath->xp);
3112 static gint xpath_command(assuan_context_t ctx, gchar *line)
3114 struct client_s *client = assuan_get_pointer(ctx);
3115 gpg_error_t rc;
3116 struct xpath_s xpath;
3118 log_write2("ARGS=\"%s\"", line);
3120 if (disable_list_and_dump == TRUE)
3121 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3123 if (!line || !*line)
3124 return send_error(ctx, GPG_ERR_SYNTAX);
3126 memset(&xpath, 0, sizeof(struct xpath_s));
3128 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3129 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3130 return send_error(ctx, GPG_ERR_ENOMEM);
3133 xpath.xp = xmlXPathNewContext(client->doc);
3135 if (!xpath.xp) {
3136 xpath_command_cleanup(&xpath);
3137 return send_error(ctx, EPWMD_LIBXML_ERROR);
3140 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3142 if (!xpath.result) {
3143 xpath_command_cleanup(&xpath);
3144 return send_error(ctx, EPWMD_LIBXML_ERROR);
3147 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3148 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3149 goto fail;
3152 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3153 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3155 if (rc)
3156 goto fail;
3157 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3158 rc = GPG_ERR_NO_VALUE;
3159 goto fail;
3161 else if (xpath.req[1])
3162 goto fail;
3164 pth_cleanup_push(xpath_command_cleanup, &xpath);
3165 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3166 xmlBufferLength(xpath.buf));
3167 pth_cleanup_pop(0);
3169 fail:
3170 xpath_command_cleanup(&xpath);
3171 return send_error(ctx, rc);
3174 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3175 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3177 struct client_s *client = assuan_get_pointer(ctx);
3178 gpg_error_t rc;
3179 struct xpath_s xpath;
3180 gchar **req = NULL;
3181 gboolean cmd = FALSE; //SET
3183 log_write2("ARGS=\"%s\"", line);
3185 if (disable_list_and_dump == TRUE)
3186 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3188 if (!line || !*line)
3189 return send_error(ctx, GPG_ERR_SYNTAX);
3191 memset(&xpath, 0, sizeof(struct xpath_s));
3193 if ((req = split_input_line(line, " ", 3)) == NULL)
3194 return send_error(ctx, GPG_ERR_ENOMEM);
3196 if (!req[0]) {
3197 rc = GPG_ERR_SYNTAX;
3198 goto fail;
3201 if (!g_ascii_strcasecmp(req[0], "SET"))
3202 cmd = FALSE;
3203 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3204 cmd = TRUE;
3205 else {
3206 rc = GPG_ERR_SYNTAX;
3207 goto fail;
3210 if (!req[1] || !req[2]) {
3211 rc = GPG_ERR_SYNTAX;
3212 goto fail;
3215 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3216 rc = GPG_ERR_ENOMEM;
3217 goto fail;
3220 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3221 rc = GPG_ERR_SYNTAX;
3222 goto fail;
3225 xpath.xp = xmlXPathNewContext(client->doc);
3227 if (!xpath.xp) {
3228 rc = EPWMD_LIBXML_ERROR;
3229 goto fail;
3232 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3234 if (!xpath.result) {
3235 rc = EPWMD_LIBXML_ERROR;
3236 goto fail;
3239 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3240 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3241 goto fail;
3244 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3245 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3247 fail:
3248 g_strfreev(req);
3249 xpath_command_cleanup(&xpath);
3250 return send_error(ctx, rc);
3253 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3254 gsize len)
3256 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3257 gpg_error_t rc = file_modified(client);
3258 gchar **req, **path = NULL, **path_orig = NULL, *content;
3259 xmlDocPtr doc = NULL;
3260 xmlNodePtr n, root, copy;
3262 if (assuan_rc || rc) {
3263 if (line)
3264 xfree(line);
3265 return assuan_rc ? assuan_rc : rc;
3268 req = split_input_line((gchar *)line, "\t", 2);
3269 xfree(line);
3271 if (!req || !*req)
3272 return GPG_ERR_SYNTAX;
3274 content = req[0];
3275 path = split_input_line(req[1], "\t", 0);
3277 if (!content || !*content) {
3278 rc = GPG_ERR_SYNTAX;
3279 goto fail;
3282 if (path && !valid_element_path(path, FALSE)) {
3283 rc = GPG_ERR_INV_VALUE;
3284 goto fail;
3287 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3289 if (!doc) {
3290 rc = EPWMD_LIBXML_ERROR;
3291 goto fail;
3294 root = xmlDocGetRootElement(doc);
3295 rc = validate_import(root);
3297 if (rc)
3298 goto fail;
3300 if (path) {
3301 path_orig = g_strdupv(path);
3303 if (!path_orig) {
3304 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3305 rc = GPG_ERR_ENOMEM;
3306 goto fail;
3309 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3311 if (!a) {
3312 g_strfreev(path_orig);
3313 rc = GPG_ERR_ENOMEM;
3314 goto fail;
3317 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3318 xmlFree(a);
3319 g_strfreev(path_orig);
3320 rc = GPG_ERR_ENOMEM;
3321 goto fail;
3324 xmlFree(a);
3325 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3327 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3328 g_strfreev(path_orig);
3329 goto fail;
3332 if (!rc) {
3333 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3335 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3336 g_strfreev(path_orig);
3337 goto fail;
3339 else if (!rc) {
3340 xmlNodePtr parent = n->parent;
3342 xmlUnlinkNode(n);
3343 xmlFreeNode(n);
3344 n = parent;
3348 g_strfreev(path);
3349 path = path_orig;
3351 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3352 n = create_element_path(client, &path, &rc, NULL);
3354 if (rc)
3355 goto fail;
3358 copy = xmlCopyNodeList(root);
3359 n = xmlAddChildList(n, copy);
3361 if (!n)
3362 rc = EPWMD_LIBXML_ERROR;
3364 else {
3365 /* Check if the content root element can create a DTD root element. */
3366 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3367 rc = GPG_ERR_SYNTAX;
3368 goto fail;
3371 xmlChar *a;
3373 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3374 rc = GPG_ERR_SYNTAX;
3375 goto fail;
3378 gchar *tmp = g_strdup((gchar *)a);
3379 xmlFree(a);
3380 gboolean literal = is_literal_element(&tmp);
3382 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3383 g_free(tmp);
3384 rc = GPG_ERR_INV_VALUE;
3385 goto fail;
3388 if (strv_printf(&path, "%s", tmp) == FALSE) {
3389 g_free(tmp);
3390 rc = GPG_ERR_ENOMEM;
3391 goto fail;
3394 g_free(tmp);
3395 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3397 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3398 rc = EPWMD_LIBXML_ERROR;
3399 goto fail;
3402 /* Overwriting the existing tree. */
3403 if (!rc) {
3404 xmlUnlinkNode(n);
3405 xmlFreeNodeList(n);
3408 rc = 0;
3409 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3410 n = xmlCopyNode(root, 1);
3411 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3414 if (n && !rc)
3415 rc = update_element_mtime(n->parent);
3417 fail:
3418 if (doc)
3419 xmlFreeDoc(doc);
3421 if (path)
3422 g_strfreev(path);
3424 g_strfreev(req);
3425 client->inquire_status = INQUIRE_DONE;
3426 return rc;
3429 static gint import_command(assuan_context_t ctx, gchar *line)
3431 gpg_error_t rc;
3432 struct client_s *client = assuan_get_pointer(ctx);
3434 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3436 if (rc)
3437 return send_error(ctx, rc);
3439 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3440 client->inquire_status = INQUIRE_BUSY;
3441 return 0;
3444 static gpg_error_t do_lock_command(struct client_s *client)
3446 gpg_error_t rc = lock_file_mutex(client);
3448 if (!rc)
3449 client->is_lock_cmd = TRUE;
3451 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3454 static gint lock_command(assuan_context_t ctx, gchar *line)
3456 struct client_s *client = assuan_get_pointer(ctx);
3458 return do_lock_command(client);
3461 static gint unlock_command(assuan_context_t ctx, gchar *line)
3463 struct client_s *client = assuan_get_pointer(ctx);
3465 unlock_file_mutex(client);
3466 return send_error(ctx, 0);
3469 static gint getpid_command(assuan_context_t ctx, gchar *line)
3471 gpg_error_t rc;
3472 gchar buf[32];
3473 pid_t pid = getpid();
3475 print_fmt(buf, sizeof(buf), "%i", pid);
3476 rc = xfer_data(ctx, buf, strlen(buf));
3477 return send_error(ctx, rc);
3480 static gint version_command(assuan_context_t ctx, gchar *line)
3482 gpg_error_t rc;
3483 gchar *buf;
3485 buf = g_strdup_printf("0x%X %s", VERSION_HEX,
3486 #ifdef WITH_PINENTRY
3487 "PINENTRY "
3488 #endif
3489 #ifdef WITH_QUALITY
3490 "QUALITY "
3491 #endif
3492 #ifdef WITH_LIBACL
3493 "ACL "
3494 #endif
3495 "");
3496 rc = xfer_data(ctx, buf, strlen(buf));
3497 g_free(buf);
3498 return send_error(ctx, rc);
3501 #ifdef WITH_PINENTRY
3502 static void set_option_value(gchar **opt, const gchar *value)
3504 if (opt)
3505 g_free(*opt);
3507 *opt = NULL;
3509 if (value)
3510 *opt = g_strdup(value);
3512 #endif
3514 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3515 const gchar *value)
3517 struct client_s *client = assuan_get_pointer(ctx);
3518 gpg_error_t rc;
3520 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3521 gint n = 0;
3523 if (value) {
3524 n = atoi(value);
3526 if (n < 0 || n > 2)
3527 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3530 MUTEX_LOCK(&rcfile_mutex);
3531 g_key_file_set_integer(keyfileh, "global", "log_level", n);
3532 MUTEX_UNLOCK(&rcfile_mutex);
3533 goto done;
3535 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3536 gint n = 0;
3538 if (value) {
3539 n = atoi(value);
3541 if (n < 0 || n > 1)
3542 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3545 client->rc_on_locked = n ? TRUE : FALSE;
3546 goto done;
3548 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3549 rc = parse_open_opt_lock(client, (gpointer)value);
3551 if (rc)
3552 return rc;
3554 client->opts |= OPT_LOCK;
3556 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3557 if (!value) {
3558 client->opts &= ~(OPT_CIPHER);
3559 goto done;
3562 rc = parse_save_opt_cipher(client, (gpointer)value);
3564 if (rc)
3565 return rc;
3567 client->opts |= OPT_CIPHER;
3568 goto done;
3570 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3571 rc = parse_save_opt_iterations(client, (gpointer)value);
3573 if (rc)
3574 return rc;
3576 goto done;
3578 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3579 pth_attr_t attr = pth_attr_of(pth_self());
3580 gchar buf[41];
3582 if (!value) {
3583 pth_attr_destroy(attr);
3584 goto done;
3587 print_fmt(buf, sizeof(buf), "%s", value);
3588 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3589 pth_attr_destroy(attr);
3590 #ifdef WITH_PINENTRY
3591 if (client->pinentry->name)
3592 g_free(client->pinentry->name);
3594 client->pinentry->name = g_strdup(buf);
3596 if (!client->pinentry->name)
3597 return GPG_ERR_ENOMEM;
3598 #endif
3600 goto done;
3602 #ifdef WITH_PINENTRY
3603 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3604 set_option_value(&client->pinentry->lcmessages, value);
3605 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3606 set_option_value(&client->pinentry->lcctype, value);
3607 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3608 set_option_value(&client->pinentry->ttyname, value);
3609 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3610 set_option_value(&client->pinentry->ttytype, value);
3611 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3612 set_option_value(&client->pinentry->display, value);
3613 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3614 set_option_value(&client->pinentry->path, value);
3615 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3616 set_option_value(&client->pinentry->title, value);
3617 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3618 set_option_value(&client->pinentry->prompt, value);
3619 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3620 set_option_value(&client->pinentry->desc, value);
3621 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3622 gchar *p = NULL;
3623 gint n;
3625 if (!value)
3626 goto done;
3628 n = atoi(value);
3630 if (*p || n < 0)
3631 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3633 MUTEX_LOCK(&rcfile_mutex);
3634 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3635 "global", "pinentry_timeout", n);
3636 MUTEX_UNLOCK(&rcfile_mutex);
3637 goto done;
3639 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3640 rc = parse_opt_pinentry(client, (gpointer)value);
3642 if (rc)
3643 return rc;
3645 goto done;
3647 #else
3648 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3649 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3650 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3651 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3652 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3653 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3654 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3655 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3656 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3657 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3658 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3659 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3660 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3661 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3662 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3663 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3664 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3665 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3666 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3667 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3668 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3669 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3670 #endif
3671 else
3672 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3674 done:
3675 return 0;
3678 static gint unset_command(assuan_context_t ctx, gchar *line)
3680 log_write2("ARGS=\"%s\"", line);
3681 return send_error(ctx, set_unset_common(ctx, line, NULL));
3684 static gint set_command(assuan_context_t ctx, gchar *line)
3686 gchar name[64] = {0}, value[256] = {0};
3688 log_write2("ARGS=\"%s\"", line);
3690 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3691 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3693 return send_error(ctx, set_unset_common(ctx, name, value));
3696 static gint rename_command(assuan_context_t ctx, gchar *line)
3698 struct client_s *client = assuan_get_pointer(ctx);
3699 gpg_error_t rc;
3700 gchar **req, **src, *dst;
3701 xmlNodePtr n, ndst;
3703 log_write2("ARGS=\"%s\"", line);
3704 req = split_input_line(line, " ", -1);
3706 if (!req || !req[0] || !req[1]) {
3707 g_strfreev(req);
3708 return send_error(ctx, GPG_ERR_SYNTAX);
3711 dst = req[1];
3712 is_literal_element(&dst);
3714 if (!valid_xml_element((xmlChar *)dst)) {
3715 g_strfreev(req);
3716 return GPG_ERR_INV_VALUE;
3719 if (strchr(req[0], '\t'))
3720 src = split_input_line(req[0], "\t", -1);
3721 else
3722 src = split_input_line(req[0], " ", -1);
3724 if (!src || !*src) {
3725 rc = GPG_ERR_SYNTAX;
3726 goto fail;
3729 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3731 if (src[1] && n)
3732 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3733 NULL, FALSE, 0, NULL, FALSE);
3735 if (!n)
3736 goto fail;
3739 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3741 if (!a) {
3742 rc = GPG_ERR_ENOMEM;
3743 goto fail;
3746 /* To prevent unwanted effects:
3748 * <root name="a"><b/></root>
3750 * RENAME a<TAB>b b
3752 if (xmlStrEqual(a, (xmlChar *)dst)) {
3753 xmlFree(a);
3754 rc = GPG_ERR_AMBIGUOUS_NAME;
3755 goto fail;
3758 xmlFree(a);
3759 gchar **tmp = NULL;
3761 if (src[1]) {
3762 gchar **p;
3764 for (p = src; *p; p++) {
3765 if (!*(p+1))
3766 break;
3768 strv_printf(&tmp, "%s", *p);
3772 strv_printf(&tmp, "!%s", dst);
3773 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3775 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3776 g_strfreev(tmp);
3777 goto fail;
3780 if (tmp[1] && ndst)
3781 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3782 NULL, NULL, FALSE, 0, NULL, FALSE);
3784 g_strfreev(tmp);
3786 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3787 goto fail;
3789 rc = 0;
3791 /* Target may exist:
3793 * <root name="a"/>
3794 * <root name="b" target="a"/>
3796 * RENAME b a
3798 * Would need to do:
3799 * RENAME !b a
3801 if (ndst == n) {
3802 rc = GPG_ERR_AMBIGUOUS_NAME;
3803 goto fail;
3806 if (ndst) {
3807 unlink_node(ndst);
3808 xmlFreeNodeList(ndst);
3811 rc = add_attribute(n, "_name", dst);
3813 fail:
3814 g_strfreev(req);
3815 g_strfreev(src);
3816 return send_error(ctx, rc);
3819 static gint copy_command(assuan_context_t ctx, gchar *line)
3821 struct client_s *client = assuan_get_pointer(ctx);
3822 gpg_error_t rc;
3823 gchar **req, **src = NULL, **dst = NULL;
3824 xmlNodePtr nsrc, ndst, new = NULL;
3826 log_write2("ARGS=\"%s\"", line);
3827 req = split_input_line(line, " ", -1);
3829 if (!req || !req[0] || !req[1]) {
3830 g_strfreev(req);
3831 return send_error(ctx, GPG_ERR_SYNTAX);
3834 if (strchr(req[0], '\t'))
3835 src = split_input_line(req[0], "\t", -1);
3836 else
3837 src = split_input_line(req[0], " ", -1);
3839 if (!src || !*src) {
3840 rc = GPG_ERR_SYNTAX;
3841 goto fail;
3844 if (strchr(req[1], '\t'))
3845 dst = split_input_line(req[1], "\t", -1);
3846 else
3847 dst = split_input_line(req[1], " ", -1);
3849 if (!dst || !*dst) {
3850 rc = GPG_ERR_SYNTAX;
3851 goto fail;
3854 if (!valid_element_path(dst, FALSE)) {
3855 rc = GPG_ERR_INV_VALUE;
3856 goto fail;
3859 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3860 if (nsrc && src[1])
3861 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3862 NULL, NULL, FALSE, 0, NULL, FALSE);
3864 if (!nsrc)
3865 goto fail;
3867 new = xmlCopyNodeList(nsrc);
3868 if (!new) {
3869 rc = GPG_ERR_ENOMEM;
3870 goto fail;
3873 gboolean create = FALSE;
3874 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3875 if (ndst && dst[1]) {
3876 if (ndst->children)
3877 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3878 NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
3879 else
3880 create = TRUE;
3882 else
3883 create = TRUE;
3885 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3886 goto fail;
3887 else if (create) {
3888 ndst = create_element_path(client, &dst, &rc, NULL);
3889 if (!ndst)
3890 goto fail;
3893 /* Merge any attributes from the src node to the initial dst node. */
3894 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3895 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3896 continue;
3898 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3899 if (a)
3900 xmlRemoveProp(a);
3902 xmlChar *tmp = xmlNodeGetContent(attr->children);
3903 xmlNewProp(ndst, attr->name, tmp);
3904 xmlFree(tmp);
3905 rc = add_attribute(ndst, NULL, NULL);
3908 xmlNodePtr n = ndst->children;
3909 xmlUnlinkNode(n);
3910 xmlFreeNodeList(n);
3911 ndst->children = NULL;
3913 if (new->children) {
3914 n = xmlCopyNodeList(new->children);
3915 if (!n) {
3916 rc = GPG_ERR_ENOMEM;
3917 goto fail;
3920 n = xmlAddChildList(ndst, n);
3921 if (!n) {
3922 rc = GPG_ERR_ENOMEM;
3923 goto fail;
3926 rc = update_element_mtime(xmlDocGetRootElement(client->doc) ==
3927 ndst->parent ? ndst : ndst->parent);
3930 fail:
3931 if (new) {
3932 xmlUnlinkNode(new);
3933 xmlFreeNodeList(new);
3936 if (req)
3937 g_strfreev(req);
3939 if (src)
3940 g_strfreev(src);
3942 if (dst)
3943 g_strfreev(dst);
3945 return send_error(ctx, rc);
3948 static gint move_command(assuan_context_t ctx, gchar *line)
3950 struct client_s *client = assuan_get_pointer(ctx);
3951 gpg_error_t rc;
3952 gchar **req, **src = NULL, **dst = NULL;
3953 xmlNodePtr nsrc, ndst = NULL;
3955 log_write2("ARGS=\"%s\"", line);
3956 req = split_input_line(line, " ", -1);
3958 if (!req || !req[0] || !req[1]) {
3959 g_strfreev(req);
3960 return send_error(ctx, GPG_ERR_SYNTAX);
3963 if (strchr(req[0], '\t'))
3964 src = split_input_line(req[0], "\t", -1);
3965 else
3966 src = split_input_line(req[0], " ", -1);
3968 if (!src || !*src) {
3969 rc = GPG_ERR_SYNTAX;
3970 goto fail;
3973 if (strchr(req[1], '\t'))
3974 dst = split_input_line(req[1], "\t", -1);
3975 else
3976 dst = split_input_line(req[1], " ", -1);
3978 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3980 if (nsrc && src[1])
3981 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3982 NULL, NULL, FALSE, 0, NULL, FALSE);
3984 if (!nsrc)
3985 goto fail;
3987 if (dst) {
3988 if (!valid_element_path(dst, FALSE)) {
3989 rc = GPG_ERR_INV_VALUE;
3990 goto fail;
3993 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3995 if (ndst && dst[1])
3996 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3997 NULL, NULL, FALSE, 0, NULL, FALSE);
3999 else
4000 ndst = xmlDocGetRootElement(client->doc);
4002 for (xmlNodePtr n = ndst; n; n = n->parent) {
4003 if (n == nsrc) {
4004 rc = GPG_ERR_CONFLICT;
4005 goto fail;
4009 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
4010 goto fail;
4012 rc = 0;
4014 if (ndst) {
4015 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
4016 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
4018 xmlFree(a);
4020 if (dup) {
4021 if (dup == nsrc)
4022 goto fail;
4024 if (ndst == xmlDocGetRootElement(client->doc)) {
4025 xmlNodePtr n = nsrc;
4026 gboolean match = FALSE;
4028 while (n->parent && n->parent != ndst)
4029 n = n->parent;
4031 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
4032 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
4034 if (xmlStrEqual(a, b)) {
4035 match = TRUE;
4036 xmlUnlinkNode(nsrc);
4037 xmlUnlinkNode(n);
4038 xmlFreeNodeList(n);
4041 xmlFree(a);
4042 xmlFree(b);
4044 if (!match) {
4045 xmlUnlinkNode(dup);
4046 xmlFreeNodeList(dup);
4049 else
4050 xmlUnlinkNode(dup);
4054 if (!ndst && dst) {
4055 xmlChar *name = node_has_attribute(nsrc, (xmlChar *)"_name");
4057 if (nsrc->parent == xmlDocGetRootElement(client->doc)
4058 && !g_strcmp0((gchar *)name, *dst)) {
4059 xmlFree(name);
4060 rc = GPG_ERR_CONFLICT;
4061 goto fail;
4064 xmlFree(name);
4065 ndst = create_element_path(client, &dst, &rc, nsrc);
4068 if (!ndst)
4069 goto fail;
4071 update_element_mtime(nsrc->parent);
4072 xmlUnlinkNode(nsrc);
4073 ndst = xmlAddChildList(ndst, nsrc);
4075 if (!ndst)
4076 rc = GPG_ERR_ENOMEM;
4078 update_element_mtime(ndst->parent);
4080 fail:
4081 if (req)
4082 g_strfreev(req);
4084 if (src)
4085 g_strfreev(src);
4087 if (dst)
4088 g_strfreev(dst);
4090 return send_error(ctx, rc);
4093 static int ls_command(assuan_context_t ctx, gchar *line)
4095 log_write2("ARGS=\"%s\"", line);
4096 gpg_error_t rc;
4097 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4098 gchar *dir = expand_homedir(tmp);
4099 DIR *d = opendir(dir);
4101 rc = gpg_error_from_syserror();
4102 g_free(tmp);
4104 if (!d) {
4105 g_free(dir);
4106 return send_error(ctx, rc);
4109 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4110 struct dirent *p = g_malloc(len), *cur = NULL;
4111 gchar *list = NULL;
4113 g_free(dir);
4114 rc = 0;
4116 while (!readdir_r(d, p, &cur) && cur) {
4117 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4118 continue;
4119 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4120 continue;
4122 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4124 if (!tmp) {
4125 if (list)
4126 g_free(list);
4128 rc = GPG_ERR_ENOMEM;
4129 break;
4132 g_free(list);
4133 list = tmp;
4136 closedir(d);
4137 g_free(p);
4139 if (rc)
4140 return send_error(ctx, rc);
4142 if (!list)
4143 return send_error(ctx, GPG_ERR_NO_VALUE);
4145 list[strlen(list)-1] = 0;
4146 rc = xfer_data(ctx, list, strlen(list));
4147 g_free(list);
4148 return send_error(ctx, rc);
4151 static void bye_notify(assuan_context_t ctx)
4153 struct client_s *cl = assuan_get_pointer(ctx);
4155 /* This will let assuan_process_next() return. */
4156 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4157 cl->last_rc = 0; // BYE command result
4160 static void reset_notify(assuan_context_t ctx)
4162 struct client_s *cl = assuan_get_pointer(ctx);
4164 if (cl)
4165 cleanup_client(cl);
4169 * This is called before every Assuan command.
4171 gint command_startup(assuan_context_t ctx, const gchar *name)
4173 struct client_s *cl = assuan_get_pointer(ctx);
4174 gpg_error_t rc;
4176 log_write1("%s", name);
4178 for (int i = 0; command_table[i]; i++) {
4179 if (!g_ascii_strcasecmp(name, command_table[i]->name) &&
4180 command_table[i]->ignore_startup)
4181 return 0;
4184 #ifdef WITH_PINENTRY
4185 if (!(cl->opts & OPT_PINENTRY))
4186 reset_pin_defaults(cl->pinentry);
4187 #endif
4189 cl->last_rc = rc = file_modified(cl);
4191 if (rc) {
4192 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4193 !g_ascii_strcasecmp(name, "OPEN"))
4194 rc = 0;
4197 return rc;
4201 * This is called after every Assuan command.
4203 void command_finalize(assuan_context_t ctx, gint rc)
4205 struct client_s *client = assuan_get_pointer(ctx);
4207 if (!client->is_lock_cmd)
4208 unlock_file_mutex(client);
4210 log_write1(_("command completed (rc=%u)"), client->last_rc);
4211 client->opts &= ~(OPT_INQUIRE);
4212 client->opts &= ~(OPT_BASE64);
4215 static gint help_command(assuan_context_t ctx, gchar *line)
4217 gpg_error_t rc;
4218 gint i;
4220 if (!line || !*line) {
4221 gchar *tmp;
4222 gchar *buf = g_strdup(_(
4223 "Usage: HELP [<COMMAND>]\n"
4224 " For commands that take an element path as an argument, each element is\n"
4225 " separated with an ASCII tab character (ASCII 0x09).\n"
4226 "\n"
4227 " Each element may contain a \"target\" attribute whose value is also an\n"
4228 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4229 " filesystem. When found, the element path of the \"target\" attribute will\n"
4230 " be used as a prefix for further elements in the current element path. To\n"
4231 " ignore any \"target\" attribute for the current element, prefix the element\n"
4232 " with an ! (ASCII 0x21).\n"
4233 "\n"
4234 " See pwmd(1) for configuration file options which may also set default\n"
4235 " options for specific data files.\n"
4236 "\n"
4237 "COMMANDS:"));
4239 for (i = 0; command_table[i]; i++) {
4240 gchar *p = strrchr(buf, '\n');
4241 gboolean newline = FALSE;
4243 if (!command_table[i]->help)
4244 continue;
4246 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4247 tmp = g_strdup_printf("%s\n", buf);
4248 g_free(buf);
4249 buf = tmp;
4250 newline = TRUE;
4253 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4254 command_table[i]->name);
4255 g_free(buf);
4256 buf = tmp;
4259 tmp = g_strdup_printf("%s\n", buf);
4260 g_free(buf);
4261 buf = tmp;
4262 rc = xfer_data(ctx, buf, strlen(buf));
4263 g_free(buf);
4264 return send_error(ctx, rc);
4267 for (i = 0; command_table[i]; i++) {
4268 if (!g_strcasecmp(line, command_table[i]->name)) {
4269 if (!command_table[i]->help)
4270 break;
4272 gchar *tmp = g_strdup_printf(_("Usage: %s"), command_table[i]->help);
4273 rc = xfer_data(ctx, tmp, strlen(tmp));
4274 g_free(tmp);
4275 return send_error(ctx, rc);
4279 return send_error(ctx, GPG_ERR_INV_NAME);
4282 void new_command(const gchar *name, gboolean ignore,
4283 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4285 gint i = 0;
4287 if (command_table)
4288 for (i = 0; command_table[i]; i++);
4290 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4291 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4292 command_table[i]->name = name;
4293 command_table[i]->handler = handler;
4294 command_table[i]->ignore_startup = ignore;
4295 command_table[i++]->help = help;
4296 command_table[i] = NULL;
4299 void deinit_commands()
4301 gint i;
4303 for (i = 0; command_table[i]; i++)
4304 g_free(command_table[i]);
4306 g_free(command_table);
4309 static gint sort_commands(const void *arg1, const void *arg2)
4311 struct command_table_s* const *a = arg1;
4312 struct command_table_s* const *b = arg2;
4314 if (!*a || !*b)
4315 return 0;
4316 else if (*a && !*b)
4317 return 1;
4318 else if (!*a && *b)
4319 return -1;
4321 return g_strcmp0((*a)->name, (*b)->name);
4324 void init_commands()
4326 /* !BEGIN-HELP-TEXT!
4328 * This comment is used as a marker to generate the offline documentation
4329 * for commands found in doc/COMMANDS.
4331 new_command("HELP", TRUE, help_command, _(
4332 "HELP [<COMMAND>]\n"
4333 " Show available commands or command specific help text.\n"
4336 new_command("OPEN", FALSE, open_command, _(
4337 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4338 " Opens <filename> using <key>. When the filename is not found on the\n"
4339 " file-system a new document will be created. If the file is found, it is\n"
4340 " looked for in the file cache for an existing key. When found and no key\n"
4341 " was specified, the cached key will be used for decryption (if encrypted).\n"
4342 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4343 " OPTIONS documentation).\n"
4344 "\n"
4345 " When the --lock option is passed then the file mutex will be locked as if\n"
4346 " the LOCK command had been sent after the file had been opened.\n"
4347 "\n"
4348 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4349 " retrieve the filename and key arguments.\n"
4350 "\n"
4351 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4352 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4353 " no value is specified then the configuration file value will be used. If\n"
4354 " the passphrase is invalid then it is up to the client whether to retry or\n"
4355 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4356 " pinentry dialog, use --pinentry=0.\n"
4357 "\n"
4358 " When a \"key_file\" configuration parameter has been set for the current\n"
4359 " file and there is no cache entry, then an --inquire must be used to\n"
4360 " retrieve the key.\n"
4361 "\n"
4362 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4363 " decoded before doing decryption. This allows for binary keys and may also\n"
4364 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4367 new_command("SAVE", FALSE, save_command, _(
4368 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4369 " [--iterations=[N]] [--base64] [<key>]\n"
4370 " Writes the XML document to disk. The file written to is the file that was\n"
4371 " opened using the OPEN command. If <key> is not specified then the\n"
4372 " currently cached key will be used. If the file is a new file or the file\n"
4373 " is not found in the file cache then <key> will be used. If both <key> is\n"
4374 " not specified and the file is not cached then pinentry(1) will be used to\n"
4375 " retrieve the key (see below) unless the configured number of iterations is\n"
4376 " 0 in which case the file will be saved unencrypted.\n"
4377 "\n"
4378 " Note that when both <key> is specified and the configured number of\n"
4379 " iterations is 0 the iterations for the current filename will be reset to\n"
4380 " 1. This is to be on the safe side and prevent misuse.\n"
4381 "\n"
4382 " The --iterations option can be used to change the number of encryption\n"
4383 " iterations for the opened file. When 0 no encryption will be performed.\n"
4384 " When this option is either not passed or is specified without a value then\n"
4385 " the previous setting obtained from the file header will be used.\n"
4386 "\n"
4387 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4388 " string with the --cipher option. Omitting the string uses the current\n"
4389 " cipher of the opened file or the default if the file is a new one. The\n"
4390 " default is specified in the configuration file. See pwmd(1) for available\n"
4391 " ciphers.\n"
4392 "\n"
4393 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4394 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4395 " no value is specified then the configuration file value will be used.\n"
4396 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4397 " is started over again until either the passphrases match or until the\n"
4398 " input is canceled by the user. To save with encryption and with an empty\n"
4399 " passphrase, use --pinentry=0.\n"
4400 "\n"
4401 " When --reset is specified then the cached passphrase for the opened file\n"
4402 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4403 " had been sent.\n"
4404 "\n"
4405 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4406 " retrieve the key.\n"
4407 "\n"
4408 " When a \"key_file\" configuration parameter has been set for the current\n"
4409 " file and there is no cache entry, then an --inquire must be used to\n"
4410 " retrieve the key.\n"
4411 "\n"
4412 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4413 " decoded before doing encryption. This allows for binary keys and may also\n"
4414 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4417 new_command("ISCACHED", TRUE, iscached_command, _(
4418 "ISCACHED <filename>\n"
4419 " An OK response is returned if the specified file is found in the file\n"
4420 " cache. If not found in the cache but exists on the filesystem,\n"
4421 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4424 new_command("CLEARCACHE", TRUE, clearcache_command, _(
4425 "CLEARCACHE [<filename>]\n"
4426 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4427 " the specified file. Always returns an OK response.\n"
4430 new_command("CACHETIMEOUT", TRUE, cachetimeout_command, _(
4431 "CACHETIMEOUT <filename> <seconds>\n"
4432 " Specify the number of seconds the specified file will be cached. -1 will\n"
4433 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4434 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4435 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4436 " invalid. OK otherwise.\n"
4439 new_command("LIST", FALSE, list_command, _(
4440 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4441 " If no element path is given then a newline separated list of root elements\n"
4442 " is returned with the data response. If given, then all reachable elements\n"
4443 " for the specified element path are returned unless the --no-recurse option\n"
4444 " is specified. If specified, only the child elements of the element path\n"
4445 " are returned without recursing into grandchildren. Each element in the\n"
4446 " path is prefixed with the literal '!' character when the element contains\n"
4447 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4448 "\n"
4449 " When the --verbose option is passed then each element path returned in the\n"
4450 " list will have a single space character followed by either a 0 or 1\n"
4451 " appended to it. When 0, the element path has no children, otherwise it\n"
4452 " does have children. When used with the --no-recurse option this may be\n"
4453 " useful to limit the amount of data transferred to the client.\n"
4456 new_command("REALPATH", FALSE, realpath_command, _(
4457 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4458 " Resolves all \"target\" attributes of the specified element path and returns\n"
4459 " the result with a data response.\n"
4462 new_command("STORE", FALSE, store_command, _(
4463 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4464 " Creates a new element path or modifies the content of an existing element\n"
4465 " path. If only a single element is specified, a new root element is\n"
4466 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4467 " to the last TAB delimited argument. If no content is specified after the\n"
4468 " last TAB then the content for the last specified element will be removed,\n"
4469 " or empty when creating a new element.\n"
4470 "\n"
4471 " The only restriction of an element name is that it not contain whitespace\n"
4472 " or begin with the literal element character '!' unless specifying a\n"
4473 " literal element. There is no whitespace between the TAB delimited\n"
4474 " elements. It is recommended that the value or content be base 64 encoded\n"
4475 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4476 " errors.\n"
4477 "\n"
4478 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4481 new_command("RENAME", FALSE, rename_command, _(
4482 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4483 " Renames the specified element to the new value. If an element of the same\n"
4484 " name as the value exists then it will be overwritten.\n"
4487 new_command("COPY", FALSE, copy_command, _(
4488 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4489 " Copies the entire element tree starting from the child node of the source\n"
4490 " element path, to the destination element path. If the destination element\n"
4491 " path does not exist then it will be created; otherwise it is overwritten.\n"
4492 "\n"
4493 " Note that attributes from the source element path are merged into the\n"
4494 " destination element path when the destination element path exists. When an\n"
4495 " attribute of the same name exists in both the source and destination\n"
4496 " element paths then the destination attribute will be updated to the source\n"
4497 " attribute value.\n"
4500 new_command("MOVE", FALSE, move_command, _(
4501 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4502 " Moves the source element path to the destination element path. If the\n"
4503 " destination is not specified then it will be moved to the root of the\n"
4504 " document. If the destination is specified and exists then it will be\n"
4505 " overwritten; otherwise it will be created.\n"
4508 new_command("DELETE", FALSE, delete_command, _(
4509 "DELETE [!]element[<TAB>[!]element[...]]\n"
4510 " Removes the specified element path and any children from the XML document.\n"
4513 new_command("GET", FALSE, get_command, _(
4514 "GET [!]element[<TAB>[!]element[...]]\n"
4515 " Retrieves the content or XML text node of the specified element path. The\n"
4516 " content is returned with a data response.\n"
4519 new_command("ATTR", FALSE, attr_command, _(
4520 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4521 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4522 " Stores or updates an attribute name and optional value of an element\n"
4523 " path.\n"
4524 "\n"
4525 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4526 " Removes an attribute from an element path.\n"
4527 "\n"
4528 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4529 " Retrieves a newline separated list of attributes names and values from\n"
4530 " the specified element path. The attribute names and values are space\n"
4531 " delimited.\n"
4532 "\n"
4533 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4534 " Retrieves the value of an attribute from an element path.\n"
4535 "\n"
4536 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4537 " if the element path is the root element. Although it can be SET to change\n"
4538 " the element name but only if the destination element name doesn't exist.\n"
4539 " Use the RENAME command for that instead.\n"
4540 "\n"
4541 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4542 " either storing content, editing attributes or by deleting a child element.\n"
4543 "\n"
4544 " Also see THE TARGET ATTRIBUTE.\n"
4547 new_command("XPATH", FALSE, xpath_command, _(
4548 "XPATH <expression>[<TAB>[value]]\n"
4549 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4550 " assumed the expression is a request to return a result. Otherwise, the\n"
4551 " result is set to the value argument and the document is updated. If there\n"
4552 " is no value after the <TAB> character, the value is assumed to be empty\n"
4553 " and the document is updated.\n"
4556 new_command("XPATHATTR", FALSE, xpathattr_command, _(
4557 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4558 " Like the XPATH command but operates on element attributes and won't return\n"
4559 " a result. For the SET operation the <value> is optional but the field is\n"
4560 " required in which case the value will be empty.\n"
4563 new_command("IMPORT", FALSE, import_command, _(
4564 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4565 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4566 " data. The content is created as a child of the specified element path. If\n"
4567 " an element of the element path does not exist then it is created. If no\n"
4568 " element path is specified then the content must begin with an pwmd DTD\n"
4569 " root element.\n"
4570 "\n"
4571 " Note that the new content must begin with an XML element node. Also note\n"
4572 " that an existing child node of the same element name as the root node of\n"
4573 " the imported content will be overwritten.\n"
4576 new_command("DUMP", FALSE, dump_command, _(
4577 "DUMP\n"
4578 " Shows the in memory XML document with indenting. To dump a specific\n"
4579 " element tree, use the XPATH command.\n"
4582 new_command("LOCK", FALSE, lock_command, _(
4583 "LOCK\n"
4584 " Locks the mutex associated with the opened file. This prevents other\n"
4585 " clients from sending commands to the same opened file until the client\n"
4586 " that sent this command either disconnects or sends the UNLOCK command.\n"
4589 new_command("UNLOCK", FALSE, unlock_command, _(
4590 "UNLOCK\n"
4591 " Unlocks the file mutex which was locked with the LOCK command.\n"
4594 new_command("GETPID", TRUE, getpid_command, _(
4595 "GETPID\n"
4596 " Retrieves the process id of the server.\n"
4599 new_command("GETCONFIG", TRUE, getconfig_command, _(
4600 "GETCONFIG [filename] <parameter>\n"
4601 " Returns the value of a pwmd configuration variable with a data response.\n"
4602 " If no file has been opened then the value for the specified file or the\n"
4603 " default from the \"global\" section will be returned. If a file has been\n"
4604 " opened and no filename is specified, the value previously set with the SET\n"
4605 " command, if any, will be returned.\n"
4606 "\n"
4607 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4608 " is returned.\n"
4611 new_command("VERSION", TRUE, version_command, _(
4612 "VERSION\n"
4613 " Returns the server version number and compile-time features with a data\n"
4614 " response with each being space delimited.\n"
4617 new_command("SET", TRUE, set_command, _(
4618 "SET <NAME>=<VALUE>\n"
4619 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4620 " option to its default value.\n"
4621 "\n"
4622 " NAME |VALUE |Description\n"
4623 " -----------------|----------|----------------------------------------------\n"
4624 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4625 " is 1.\n"
4626 "\n"
4627 " * Deprecated. Pass --pinentry to the OPEN and\n"
4628 " SAVE commands instead.\n"
4629 "\n"
4630 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4631 " process will terminate while waiting for a\n"
4632 " passphrase. The default is 20, 0 disables.\n"
4633 "\n"
4634 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4635 " is specified at compile time.\n"
4636 "\n"
4637 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4638 "\n"
4639 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4640 "\n"
4641 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4642 "\n"
4643 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4644 "\n"
4645 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4646 "\n"
4647 " DESC <string> Sets the error or description string of the\n"
4648 " pinentry dialog.\n"
4649 "\n"
4650 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4651 "\n"
4652 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4653 " pinentry(1).\n"
4654 "\n"
4655 " NAME <string> Associates the thread ID of the connection\n"
4656 " with the specified textual representation.\n"
4657 " Useful for debugging log messages.\n"
4658 "\n"
4659 " CIPHER <string> The cipher to use for the next SAVE.\n"
4660 "\n"
4661 " * Deprecated. Use --cipher instead.\n"
4662 "\n"
4663 " ITERATIONS <integer> The number of encryption iterations to do\n"
4664 " when the SAVE command is sent. An opened file\n"
4665 " is needed when setting this option. The\n"
4666 " CONFIG status message is sent after receiving\n"
4667 " this command.\n"
4668 "\n"
4669 " * Deprecated. Use --iterations instead.\n"
4670 "\n"
4671 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4672 " after a successful OPEN as if the LOCK\n"
4673 " command had been sent.\n"
4674 "\n"
4675 " * Deprecated. Use --lock instead.\n"
4676 "\n"
4677 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4678 " of a status message when the file mutex is\n"
4679 " locked by another client.\n"
4682 new_command("UNSET", TRUE, unset_command, _(
4683 "UNSET <NAME>\n"
4684 " Resets option NAME to the value specified in the server configuration\n"
4685 " file. Some options have no default and will be reset to NULL or 0\n"
4686 " depending on the value type. See the SET command for available options.\n"
4689 new_command("LS", TRUE, ls_command, _(
4690 "LS\n"
4691 " Lists the contents of the configured data_directory. The result is a\n"
4692 " newline separated list of filenames.\n"
4695 new_command("RESET", TRUE, NULL, _(
4696 "RESET\n"
4697 " Closes the currently opened file but keeps any previously set client\n"
4698 " options.\n"
4701 new_command("BYE", TRUE, NULL, _(
4702 "BYE\n"
4703 " Closes the connection discarding any unsaved changes.\n"
4706 new_command("NOP", TRUE, NULL, _(
4707 "NOP\n"
4708 " Does nothing. Always returns successfully.\n"
4711 /* !END-HELP-TEXT! */
4712 new_command("CANCEL", TRUE, NULL, NULL);
4713 new_command("END", TRUE, NULL, NULL);
4715 gint i;
4716 for (i = 0; command_table[i]; i++);
4717 qsort(command_table, i-1, sizeof(struct command_table_s *), sort_commands);
4720 gpg_error_t register_commands(assuan_context_t ctx)
4722 gint i = 0, rc;
4724 for (; command_table[i]; i++) {
4725 if (!command_table[i]->handler)
4726 continue;
4728 rc = assuan_register_command (ctx, command_table[i]->name,
4729 command_table[i]->handler);
4731 if (rc)
4732 return rc;
4735 rc = assuan_register_bye_notify(ctx, bye_notify);
4737 if (rc)
4738 return rc;
4740 rc = assuan_register_reset_notify(ctx, reset_notify);
4742 if (rc)
4743 return rc;
4745 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4747 if (rc)
4748 return rc;
4750 return assuan_register_post_cmd_notify(ctx, command_finalize);
4753 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4754 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4756 goffset insize, len;
4757 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4758 guint64 iter = 0, n_iter = 0, iter_progress = 0;
4759 gulong outsize = 0;
4760 gpg_error_t rc;
4761 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4762 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4763 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4765 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4766 insize = crypto->fh->st.st_size - fh_size;
4767 crypto->iv = gcry_malloc(crypto->blocksize);
4769 if (!crypto->iv) {
4770 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4771 return GPG_ERR_ENOMEM;
4774 if (crypto->fh->v1)
4775 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4776 else
4777 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4779 crypto->inbuf = gcry_malloc(insize);
4781 if (!crypto->inbuf) {
4782 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4783 return GPG_ERR_ENOMEM;
4786 crypto->insize = insize;
4787 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4789 if (len != crypto->insize)
4790 return GPG_ERR_INV_LENGTH;
4792 /* No encryption iterations. This is a plain (gzipped) file. */
4793 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4794 (!crypto->fh->v1 && fh_iter <= 0L)) {
4796 * cache_file_count() needs both .used == TRUE and a valid key in
4797 * order for it to count as a used cache entry. Fixes CACHE status
4798 * messages.
4800 memset(crypto->key, '!', hashlen);
4801 goto decompress;
4804 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4805 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4806 return rc;
4809 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4810 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4811 return rc;
4814 iter_progress = get_key_file_uint64(client && client->filename ?
4815 client->filename : "global", "iteration_progress");
4817 if (iter_progress > 0 && fh_iter >= iter_progress) {
4818 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4820 if (rc)
4821 return rc;
4824 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4826 if (rc)
4827 return rc;
4829 crypto->tkey = gcry_malloc(hashlen);
4831 if (!crypto->tkey) {
4832 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4833 return GPG_ERR_ENOMEM;
4836 memcpy(crypto->tkey, crypto->key, hashlen);
4837 guchar *tkey = crypto->tkey;
4838 tkey[0] ^= 1;
4840 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4841 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4842 return rc;
4845 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4846 if (iter_progress > 0ULL && iter >= iter_progress) {
4847 if (!(iter % iter_progress)) {
4848 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4849 ++n_iter * iter_progress, fh_iter);
4851 if (rc)
4852 return rc;
4856 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4857 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4858 return rc;
4861 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4863 if (rc) {
4864 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4865 return rc;
4868 iter++;
4871 if (iter_progress && fh_iter >= iter_progress) {
4872 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4874 if (rc)
4875 return rc;
4878 decompress:
4879 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4880 len = 0;
4882 if (crypto->fh->ver.fh2.iter > 0ULL) {
4883 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4884 return GPG_ERR_INV_PASSPHRASE;
4886 len = sizeof(crypto_magic);
4889 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4890 (gpointer *)&crypto->outbuf, &outsize);
4892 if (rc)
4893 return rc;
4895 else {
4896 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4897 (gpointer *)&crypto->outbuf, &outsize);
4899 if (rc == GPG_ERR_ENOMEM)
4900 return rc;
4901 else if (rc)
4902 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4904 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4905 gcry_free(crypto->outbuf);
4906 crypto->outbuf = NULL;
4907 return GPG_ERR_INV_PASSPHRASE;
4911 if (ctx) {
4912 client->xml = crypto->outbuf;
4913 client->len = outsize;
4914 crypto->outbuf = NULL;
4916 else if (dst) {
4917 *dst = crypto->outbuf;
4918 *dst_len = outsize;
4919 crypto->outbuf = NULL;
4922 /* The calling function should free the crypto struct. */
4923 return 0;