Oops. Fixed adding an extra element in COPY which happened in the
[pwmd.git] / src / commands.c
blobf06efb6ccc74944c412b7e4e58237c3d4005f4d6
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", 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 *p = NULL;
542 gchar *str = value;
543 gint n;
545 if (!str || !*str) {
546 client->pinentry->enable = -1;
547 client->opts &= ~(OPT_PINENTRY);
548 return 0;
551 n = atoi(str);
553 if (n < 0 || n > 1)
554 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
556 client->pinentry->enable = n ? TRUE : FALSE;
557 client->opts |= OPT_PINENTRY;
558 return 0;
559 #else
560 return GPG_ERR_NOT_IMPLEMENTED;
561 #endif
564 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
566 struct client_s *client = data;
568 (void)value;
569 client->opts |= OPT_INQUIRE;
570 return 0;
573 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
575 struct client_s *client = data;
577 (void)value;
578 client->opts |= OPT_BASE64;
579 return 0;
582 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
584 guchar *tmp;
585 gsize len;
587 if (client->opts & OPT_BASE64)
588 tmp = g_base64_decode(key, &len);
589 else {
590 tmp = (guchar *)g_strdup(key);
591 len = strlen(key);
594 if (!tmp)
595 return GPG_ERR_ENOMEM;
597 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
598 g_free(tmp);
599 return 0;
602 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
604 gboolean cached = FALSE;
605 gpg_error_t rc;
606 struct client_s *client = assuan_get_pointer(ctx);
607 gchar **req;
608 gchar *filename = NULL;
609 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
611 if ((req = split_input_line(line, " ", 2)) != NULL)
612 filename = req[0];
614 pth_cleanup_push(req_cleanup, req);
616 if (!filename || !*filename) {
617 pth_cleanup_pop(1);
618 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
621 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
623 if (valid_filename(filename) == FALSE) {
624 pth_cleanup_pop(1);
625 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
628 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
629 CACHE_LOCK(client->ctx);
631 if (cache_has_file(client->md5file) == FALSE) {
632 if (cache_add_file(client->md5file, NULL) == FALSE) {
633 pth_cleanup_pop(1);
634 CACHE_UNLOCK;
635 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
639 CACHE_UNLOCK;
640 rc = lock_file_mutex(client);
642 if (rc) {
643 pth_cleanup_pop(1);
644 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
647 client->freed = FALSE;
648 CACHE_LOCK(client->ctx);
649 cache_incr_refcount(client->md5file);
650 CACHE_UNLOCK;
651 client->crypto = init_client_crypto();
653 if (!client->crypto) {
654 pth_cleanup_pop(1);
655 cleanup_client(client);
656 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
659 client->crypto->key = gcry_malloc(hashlen);
661 if (!client->crypto->key) {
662 pth_cleanup_pop(1);
663 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
664 GPG_ERR_ENOMEM);
665 cleanup_client(client);
666 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
669 memset(client->crypto->key, 0, hashlen);
670 client->crypto->fh = read_file_header(filename, FALSE, &rc);
672 if (!client->crypto->fh) {
673 if (gpg_err_code_to_errno(rc) != ENOENT) {
674 log_write("%s: %s", filename, pwmd_strerror(rc));
675 pth_cleanup_pop(1);
676 cleanup_client(client);
677 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
681 * New files don't need a key.
683 if ((client->xml = new_document()) == NULL) {
684 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
685 pth_cleanup_pop(1);
686 cleanup_client(client);
687 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
690 client->len = xmlStrlen(client->xml);
691 client->new = TRUE;
692 client->filename = g_strdup(filename);
694 if (!client->filename) {
695 pth_cleanup_pop(1);
696 cleanup_client(client);
697 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
698 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
701 if (req[1] && *req[1]) {
702 rc = hash_key(client, req[1]);
704 if (rc) {
705 pth_cleanup_pop(1);
706 cleanup_client(client);
707 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
711 pth_cleanup_pop(1);
712 #ifdef WITH_PINENTRY
713 client->pinentry->filename = g_strdup(client->filename);
715 if (!client->pinentry->filename) {
716 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
717 cleanup_client(client);
718 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
720 #endif
721 return open_command_finalize(ctx, NULL, cached);
723 else {
724 if (!(client->opts & OPT_CIPHER))
725 g_key_file_set_string(keyfileh, filename, "cipher",
726 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
728 client->mtime = client->crypto->fh->st.st_mtime;
731 client->filename = g_strdup(filename);
733 if (!client->filename) {
734 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
735 pth_cleanup_pop(1);
736 cleanup_client(client);
737 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
740 #ifdef WITH_PINENTRY
741 if (client->pinentry->filename)
742 g_free(client->pinentry->filename);
744 client->pinentry->filename = g_strdup(client->filename);
746 if (!client->pinentry->filename) {
747 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
748 pth_cleanup_pop(1);
749 cleanup_client(client);
750 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
752 #endif
754 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
755 goto done;
757 CACHE_LOCK(client->ctx);
758 cached = cache_get_key(client->md5file, client->crypto->key);
759 CACHE_UNLOCK;
761 if (cached == FALSE) {
762 gchar *tmp = get_key_file_string(filename, "key_file");
764 if (tmp && !(client->opts & OPT_INQUIRE)) {
765 g_free(tmp);
766 pth_cleanup_pop(1);
767 cleanup_client(client);
768 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
771 if (tmp)
772 g_free(tmp);
775 * No key specified and no matching filename found in the cache. Use
776 * pinentry to retrieve the key. Cannot return assuan_process_done()
777 * here otherwise the command will be interrupted. The event loop in
778 * client_thread() will poll the file descriptor waiting for it to
779 * become ready to read a pinentry_key_s which will contain the
780 * entered key or an error code. It will then call
781 * open_command_finalize() to to finish the command.
783 if (!req[1] || !*req[1]) {
784 #ifdef WITH_PINENTRY
785 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
787 /* From set_pinentry_defaults(). */
788 if (client->opts & OPT_INQUIRE ||
789 client->pinentry->enable == FALSE ||
790 (client->pinentry->enable == -1 && b == FALSE)) {
791 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
792 goto done;
795 pth_cleanup_pop(1);
796 rc = lock_pin_mutex(client);
798 if (rc) {
799 unlock_pin_mutex(client->pinentry);
800 cleanup_client(client);
801 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
804 client->pinentry->which = PINENTRY_OPEN;
805 rc = pinentry_fork(ctx);
807 if (rc) {
808 unlock_pin_mutex(client->pinentry);
809 cleanup_client(client);
810 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
813 // Called from pinentry iterate.
814 client->pinentry->cb = open_command_finalize;
815 client->pinentry->status = PINENTRY_INIT;
816 return 0;
817 #else
818 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
819 goto done;
820 #endif
823 rc = hash_key(client, req[1]);
825 if (rc) {
826 pth_cleanup_pop(1);
827 cleanup_client(client);
828 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
831 else if (req && req[1] && *req[1]) {
832 rc = hash_key(client, req[1]);
834 if (rc) {
835 pth_cleanup_pop(1);
836 cleanup_client(client);
837 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
841 done:
842 pth_cleanup_pop(1);
843 return open_command_finalize(ctx, NULL, cached);
846 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
847 guchar *line, gsize len)
849 assuan_context_t ctx = data;
850 struct client_s *client = assuan_get_pointer(ctx);
851 gpg_error_t rc = file_modified(client);
853 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
854 if (line)
855 xfree(line);
857 return assuan_rc ? assuan_rc : rc;
860 rc = open_command_common(ctx, (gchar *)line);
862 if (line)
863 xfree(line);
865 client->inquire_status = INQUIRE_DONE;
866 return rc;
869 static gint open_command(assuan_context_t ctx, gchar *line)
871 gpg_error_t rc;
872 struct client_s *client = assuan_get_pointer(ctx);
873 struct argv_s *args[] = {
874 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
875 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
876 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
877 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
878 NULL
881 if (client->state == STATE_OPEN)
882 cleanup_client(client);
884 if (!(client->opts & OPT_LOCK))
885 client->lock_on_open = FALSE;
887 rc = parse_options(&line, args, client);
889 if (rc)
890 return send_error(ctx, rc);
892 if ((client->opts & OPT_INQUIRE)) {
893 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
894 ctx);
896 if (rc)
897 return send_error(ctx, rc);
899 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
900 client->inquire_status = INQUIRE_BUSY;
901 return 0;
904 return open_command_common(ctx, line);
907 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
908 guint size, gpointer *out, gulong *outsize)
910 struct gz_s *gz;
911 gz_header h;
912 gchar buf[17];
913 gint cmd = Z_NO_FLUSH;
914 gint zrc;
915 gpg_error_t rc;
917 gz = g_malloc0(sizeof(struct gz_s));
919 if (!gz)
920 return GPG_ERR_ENOMEM;
922 pth_cleanup_push(gz_cleanup, &gz);
923 gz->which = STATUS_COMPRESS;
924 gz->z.zalloc = z_alloc;
925 gz->z.zfree = z_free;
926 gz->z.next_in = data;
927 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
928 gz->z.avail_out = (uInt)zlib_bufsize;
929 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
931 if (!gz->out) {
932 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
933 pth_cleanup_pop(1);
934 return GPG_ERR_ENOMEM;
937 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
939 if (zrc != Z_OK) {
940 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
941 pth_cleanup_pop(1);
942 return GPG_ERR_COMPR_ALGO;
945 /* Rather than store the size of the uncompressed data in the file header,
946 * store it in the comment field of the gzip header. Don't give anyone too
947 * much information. Not sure why really, but it seems the right way. :)
949 memset(&h, 0, sizeof(gz_header));
950 g_snprintf(buf, sizeof(buf), "%u", size);
951 h.comment = (guchar *)buf;
952 zrc = deflateSetHeader(&gz->z, &h);
954 if (zrc != Z_OK) {
955 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
956 pth_cleanup_pop(1);
957 return GPG_ERR_COMPR_ALGO;
960 do {
961 gpointer p;
963 zrc = deflate(&gz->z, cmd);
965 switch (zrc) {
966 case Z_OK:
967 break;
968 case Z_BUF_ERROR:
969 if (!gz->z.avail_out) {
970 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
972 if (!p) {
973 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
974 rc = GPG_ERR_ENOMEM;
975 goto fail;
978 gz->out = p;
979 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
980 gz->z.avail_out = zlib_bufsize;
983 if (!gz->z.avail_in && gz->z.total_in < size) {
984 if (gz->z.total_in + zlib_bufsize > size)
985 gz->z.avail_in = size - gz->z.total_in;
986 else
987 gz->z.avail_in = zlib_bufsize;
989 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
990 gz->z.total_in, size);
992 if (rc)
993 goto fail;
996 if (gz->z.total_in >= size)
997 cmd = Z_FINISH;
999 break;
1000 case Z_STREAM_END:
1001 break;
1002 default:
1003 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
1004 rc = GPG_ERR_COMPR_ALGO;
1005 goto fail;
1007 } while (zrc != Z_STREAM_END);
1009 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1011 if (rc)
1012 goto fail;
1014 *out = gz->out;
1015 *outsize = gz->z.total_out;
1016 gz->done = TRUE;
1017 pth_cleanup_pop(1);
1018 return 0;
1020 fail:
1021 pth_cleanup_pop(1);
1022 return rc;
1025 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1028 * Useful for a large amount of data. Rather than doing all of the data in one
1029 * iteration do it in chunks. This lets the command be cancelable rather than
1030 * waiting for it to complete.
1032 static gpg_error_t iterate_crypto_once(struct client_s *client,
1033 struct crypto_s *crypto, status_msg_t which)
1035 gpg_error_t rc = 0;
1036 goffset len = CRYPTO_BLOCKSIZE(crypto);
1037 gpointer p = gcry_malloc(len);
1038 goffset total = 0;
1039 gpointer inbuf;
1041 if (!p)
1042 return GPG_ERR_ENOMEM;
1044 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1045 len = crypto->insize;
1047 pth_cleanup_push(gcry_free, p);
1049 for (;;) {
1050 inbuf = (guchar *)crypto->inbuf + total;
1051 guchar *tmp;
1053 if (len + total > crypto->insize)
1054 len = crypto->blocksize;
1056 if (which == STATUS_ENCRYPT)
1057 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1058 else
1059 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1061 if (rc)
1062 goto done;
1064 tmp = (guchar *)crypto->inbuf + total;
1065 memmove(tmp, p, len);
1066 total += len;
1068 if (total >= crypto->insize)
1069 break;
1071 pth_cancel_point();
1074 done:
1075 pth_cleanup_pop(1);
1076 return rc;
1079 /* The crypto struct must be setup for iterations and .key. */
1080 gpg_error_t do_xml_encrypt(struct client_s *client,
1081 struct crypto_s *crypto, const gchar *filename)
1083 goffset len = crypto->insize;
1084 gpointer inbuf;
1085 gchar *p;
1086 gpg_error_t rc;
1087 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
1088 gchar tmp[FILENAME_MAX];
1089 struct stat st;
1090 mode_t mode = 0;
1091 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1093 if (!crypto->fh->ver.fh2.iter) {
1095 * cache_file_count() needs both .used == TRUE and a valid key in
1096 * order for it to count as a used cache entry. Fixes CACHE status
1097 * messages.
1099 memset(crypto->key, '!', hashlen);
1100 goto write_file;
1104 * Resize the existing xml buffer to the block size required by gcrypt
1105 * rather than duplicating it and wasting memory.
1107 crypto->insize += sizeof(crypto_magic);
1108 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1110 if (crypto->insize % crypto->blocksize)
1111 len += crypto->blocksize;
1113 inbuf = gcry_realloc(crypto->inbuf, len);
1115 if (!inbuf) {
1116 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1117 return GPG_ERR_ENOMEM;
1120 guchar *tmpbuf = inbuf;
1121 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1122 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1123 crypto->inbuf = tmpbuf;
1124 crypto->insize = len;
1125 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1127 if (crypto->tkey)
1128 gcry_free(crypto->tkey);
1130 crypto->tkey = gcry_malloc(hashlen);
1132 if (!crypto->tkey) {
1133 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1134 return GPG_ERR_ENOMEM;
1137 memcpy(crypto->tkey, crypto->key, hashlen);
1138 guchar *tkey = crypto->tkey;
1139 tkey[0] ^= 1;
1141 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1142 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1143 return rc;
1146 iter_progress = get_key_file_uint64(
1147 client ? client->filename : "global", "iteration_progress");
1149 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1150 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1151 "0 %llu", crypto->fh->ver.fh2.iter);
1153 if (rc)
1154 return rc;
1157 while (xiter < crypto->fh->ver.fh2.iter-1) {
1158 if (iter_progress > 0ULL && xiter >= iter_progress) {
1159 if (!(xiter % iter_progress)) {
1160 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1161 "%llu %llu", ++n_iter * iter_progress,
1162 crypto->fh->ver.fh2.iter);
1164 if (rc)
1165 return rc;
1169 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1170 crypto->blocksize))) {
1171 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1172 return rc;
1175 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1177 if (rc) {
1178 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1179 return rc;
1182 xiter++;
1185 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1186 crypto->blocksize))) {
1187 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1188 return rc;
1191 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1192 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1193 return rc;
1196 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1198 if (rc)
1199 return rc;
1201 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1202 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1203 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1205 if (rc)
1206 return rc;
1209 write_file:
1210 tmp[0] = 0;
1212 if (filename) {
1213 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1214 crypto->fh->fd = STDOUT_FILENO;
1215 goto do_write_file;
1218 if (g_lstat(filename, &st) == 0) {
1219 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1221 if (!(mode & S_IWUSR))
1222 return GPG_ERR_EACCES;
1224 else if (errno != ENOENT)
1225 return gpg_error_from_syserror();
1227 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1228 #if GLIB_CHECK_VERSION(2, 22, 0)
1229 crypto->fh->fd = g_mkstemp_full(tmp, O_WRONLY, 0600);
1230 #else
1231 crypto->fh->fd = mkstemp(tmp);
1232 #endif
1234 if (crypto->fh->fd == -1) {
1235 rc = gpg_error_from_syserror();
1236 p = strrchr(tmp, '/');
1237 p++;
1238 log_write("%s: %s", p, pwmd_strerror(rc));
1239 return rc;
1242 pth_cleanup_push(cleanup_unlink_cb, tmp);
1244 else
1246 * xml_import() or convert_file() from command line.
1248 crypto->fh->fd = STDOUT_FILENO;
1250 do_write_file:
1251 crypto->fh->ver.fh2.magic[0] = '\177';
1252 crypto->fh->ver.fh2.magic[1] = 'P';
1253 crypto->fh->ver.fh2.magic[2] = 'W';
1254 crypto->fh->ver.fh2.magic[3] = 'M';
1255 crypto->fh->ver.fh2.magic[4] = 'D';
1256 crypto->fh->ver.fh2.version = VERSION_HEX;
1257 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1259 if (len != sizeof(crypto->fh->ver.fh2)) {
1260 rc = gpg_error_from_syserror();
1262 if (tmp[0])
1263 pth_cleanup_pop(1);
1265 return rc;
1268 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1270 if (len != crypto->insize) {
1271 rc = gpg_error_from_syserror();
1273 if (tmp[0])
1274 pth_cleanup_pop(1);
1276 return rc;
1279 if (fsync(crypto->fh->fd) == -1) {
1280 rc = gpg_error_from_syserror();
1282 if (tmp[0])
1283 pth_cleanup_pop(1);
1285 return rc;
1288 if (tmp[0]) {
1289 #ifdef WITH_LIBACL
1290 acl_t acl;
1291 #endif
1292 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1293 gchar tmp2[FILENAME_MAX];
1295 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1296 #ifdef WITH_LIBACL
1297 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1299 if (!acl)
1300 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1301 #endif
1303 if (rename(filename, tmp2) == -1) {
1304 rc = gpg_error_from_syserror();
1305 pth_cleanup_pop(1);
1306 #ifdef WITH_LIBACL
1307 if (acl)
1308 acl_free(acl);
1309 #endif
1310 return rc;
1313 #ifdef WITH_LIBACL
1314 else {
1315 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1317 if (!acl)
1318 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1320 #endif
1322 if (rename(tmp, filename) == -1) {
1323 rc = gpg_error_from_syserror();
1324 pth_cleanup_pop(1);
1325 #ifdef WITH_LIBACL
1326 if (acl)
1327 acl_free(acl);
1328 #endif
1329 return rc;
1332 pth_cleanup_pop(0);
1334 if (mode)
1335 chmod(filename, mode);
1337 #ifdef WITH_LIBACL
1338 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1339 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1341 if (acl)
1342 acl_free(acl);
1343 #endif
1346 if (client && g_lstat(filename, &st) == 0)
1347 client->mtime = st.st_mtime;
1349 return 0;
1352 gpg_error_t update_save_flags(const gchar *filename,
1353 struct crypto_s *crypto)
1355 gpg_error_t rc;
1357 /* New file? */
1358 if (!crypto->fh) {
1359 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1361 if (!crypto->fh)
1362 return GPG_ERR_ENOMEM;
1365 rc = init_client_crypto2(filename, crypto);
1367 if (rc)
1368 return rc;
1370 if (filename && !crypto->fh->v1)
1371 crypto->fh->ver.fh2.iter = get_key_file_uint64(filename, "iterations");
1373 return 0;
1376 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1377 gboolean cached)
1379 struct client_s *client = assuan_get_pointer(ctx);
1380 gpointer xmlbuf;
1381 gulong outsize = 0;
1382 guint len;
1383 gint clevel;
1384 gint timeout;
1385 gpointer outbuf;
1386 gpg_error_t rc;
1388 if (client->crypto->key && client->crypto->key != key)
1389 gcry_free(client->crypto->key);
1391 client->crypto->key = key;
1392 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1394 if (rc) {
1395 cleanup_crypto(&client->crypto);
1396 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1399 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1400 pth_cleanup_push(xmlFree, xmlbuf);
1401 clevel = get_key_file_integer(client->filename, "compression_level");
1403 if (clevel < 0)
1404 clevel = 0;
1406 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1408 if (rc) {
1409 pth_cleanup_pop(1);
1410 cleanup_crypto(&client->crypto);
1412 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1414 else {
1415 pth_cleanup_pop(1);
1416 xmlbuf = outbuf;
1417 len = outsize;
1420 client->crypto->inbuf = xmlbuf;
1421 client->crypto->insize = len;
1422 rc = update_save_flags(client->filename, client->crypto);
1424 if (rc) {
1425 cleanup_crypto(&client->crypto);
1426 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1427 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1430 rc = do_xml_encrypt(client, client->crypto, client->filename);
1432 if (rc) {
1433 cleanup_crypto(&client->crypto);
1434 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1437 timeout = get_key_file_integer(client->filename, "cache_timeout");
1438 CACHE_LOCK(client->ctx);
1440 if (cached) {
1441 cache_reset_timeout(client->md5file, timeout);
1442 CACHE_UNLOCK;
1444 if (client->new == TRUE)
1445 send_status_all(STATUS_CACHE);
1447 client->new = FALSE;
1448 cleanup_crypto(&client->crypto);
1449 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1452 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1453 CACHE_UNLOCK;
1454 cleanup_crypto(&client->crypto);
1455 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1458 client->new = FALSE;
1459 cache_reset_timeout(client->md5file, timeout);
1460 CACHE_UNLOCK;
1461 send_status_all(STATUS_CACHE);
1462 cleanup_crypto(&client->crypto);
1463 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1466 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1468 struct client_s *client = data;
1469 guint64 n;
1470 gchar *value = v;
1471 gchar *p = NULL;
1473 if (!client->filename)
1474 return EPWMD_NO_FILE;
1476 if (!value || !*value)
1477 return 0;
1479 errno = 0;
1480 n = g_ascii_strtoull(value, &p, 10);
1482 if (errno || (p && *p) || n == G_MAXUINT64)
1483 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1485 MUTEX_LOCK(&rcfile_mutex);
1486 p = g_strdup_printf("%llu", n);
1487 g_key_file_set_value(keyfileh,
1488 client->filename ? client->filename : "global", "iterations", p);
1489 g_free(p);
1490 MUTEX_UNLOCK(&rcfile_mutex);
1492 if (client->filename)
1493 client->opts |= OPT_ITERATIONS;
1495 return 0;
1498 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1500 struct client_s *client = data;
1501 const gchar *p = value;
1502 guint64 flags;
1504 if (!client->filename)
1505 return EPWMD_NO_FILE;
1507 if (!p || !*p)
1508 return 0;
1510 flags = pwmd_cipher_str_to_cipher(p);
1512 if (!flags)
1513 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1515 MUTEX_LOCK(&rcfile_mutex);
1516 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1517 MUTEX_UNLOCK(&rcfile_mutex);
1519 if (!value)
1520 g_free((gchar *)p);
1522 return 0;
1525 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1527 struct client_s *client = data;
1529 CACHE_LOCK(client->ctx);
1530 cache_clear(client->md5file, 1);
1531 CACHE_UNLOCK;
1532 return 0;
1535 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1537 struct client_s *client = assuan_get_pointer(ctx);
1538 gboolean cached = FALSE;
1539 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1541 CACHE_LOCK(ctx);
1542 cached = cache_iscached(client->md5file);
1543 CACHE_UNLOCK;
1546 * If a cache entry doesn't exist for this file and the file has a
1547 * "key_file" or "key" parameter, then it's an error. The reason is that
1548 * cache expiration would be useless. Unless this is an inquire, then its
1549 * fine.
1551 if (cached == FALSE) {
1552 gchar *tmp = get_key_file_string(client->filename, "key_file");
1554 if (tmp && !(client->opts & OPT_INQUIRE)) {
1555 g_free(tmp);
1556 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1559 if (tmp)
1560 g_free(tmp);
1563 cached = FALSE;
1565 /* New file? */
1566 if (!client->crypto) {
1567 client->crypto = init_client_crypto();
1569 if (!client->crypto) {
1570 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1571 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1575 client->crypto->key = gcry_malloc(hashlen);
1577 if (!client->crypto->key) {
1578 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1579 cleanup_crypto(&client->crypto);
1580 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1583 memset(client->crypto->key, '!', hashlen);
1585 if (!get_key_file_uint64(client->filename, "iterations") &&
1586 (!line || !*line))
1587 goto done;
1589 if (!line || !*line) {
1590 /* It doesn't make sense to use an --inquire with an empty
1591 * passphrase. This will prevent a pinentry dialog. */
1592 if (client->opts & OPT_INQUIRE) {
1593 cleanup_crypto(&client->crypto);
1594 return GPG_ERR_WRONG_KEY_USAGE;
1597 client->crypto->tkey = gcry_malloc(hashlen);
1599 if (!client->crypto->tkey) {
1600 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1601 cleanup_crypto(&client->crypto);
1602 return send_error(ctx, GPG_ERR_ENOMEM);
1605 memset(client->crypto->tkey, '!', hashlen);
1606 CACHE_LOCK(ctx);
1608 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1609 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1610 CACHE_UNLOCK;
1612 #ifdef WITH_PINENTRY
1613 gpg_error_t rc;
1615 if (client->pinentry->enable == FALSE ||
1616 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1617 /* Empty keys are allowed. */
1618 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1619 goto done;
1622 lock_pin_mutex(client);
1623 client->pinentry->which = PINENTRY_SAVE;
1624 rc = pinentry_fork(ctx);
1626 if (rc) {
1627 unlock_pin_mutex(client->pinentry);
1628 cleanup_crypto(&client->crypto);
1629 return send_error(ctx, rc);
1632 client->pinentry->cb = save_command_finalize;
1633 client->pinentry->status = PINENTRY_INIT;
1634 return 0;
1635 #else
1636 /* Empty keys are allowed. */
1637 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1638 goto done;
1639 #endif
1641 else {
1642 CACHE_UNLOCK;
1643 cached = TRUE;
1646 else {
1647 gpg_error_t rc;
1649 if (!get_key_file_uint64(client->filename, "iterations")) {
1650 guint64 iter = get_key_file_uint64(NULL, "iterations");
1651 gchar *p;
1653 if (!iter)
1654 iter = 1; // default? what about the "global" section?
1656 MUTEX_LOCK(&rcfile_mutex);
1657 p = g_strdup_printf("%llu", iter);
1658 g_key_file_set_value(keyfileh, client->filename, "iterations", p);
1659 g_free(p);
1660 MUTEX_UNLOCK(&rcfile_mutex);
1661 client->opts |= OPT_ITERATIONS;
1662 rc = send_status(ctx, STATUS_CONFIG, NULL);
1664 if (rc) {
1665 cleanup_crypto(&client->crypto);
1666 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1670 rc = hash_key(client, line);
1672 if (rc) {
1673 cleanup_crypto(&client->crypto);
1674 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1678 done:
1679 return save_command_finalize(ctx, client->crypto->key, cached);
1682 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1683 guchar *line, gsize len)
1685 assuan_context_t ctx = data;
1686 struct client_s *client = assuan_get_pointer(ctx);
1687 gpg_error_t rc = file_modified(client);
1689 if (assuan_rc || rc) {
1690 if (line)
1691 xfree(line);
1693 return assuan_rc ? assuan_rc : rc;
1696 rc = save_command_common(ctx, (gchar *)line);
1698 if (line)
1699 xfree(line);
1701 client->inquire_status = INQUIRE_DONE;
1702 return rc;
1705 static gint save_command(assuan_context_t ctx, gchar *line)
1707 struct stat st;
1708 struct client_s *client = assuan_get_pointer(ctx);
1709 gpg_error_t rc;
1710 struct argv_s *args[] = {
1711 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1712 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1713 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1714 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1715 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1716 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1717 NULL
1720 rc = parse_options(&line, args, client);
1722 if (rc)
1723 return send_error(ctx, rc);
1725 if (g_lstat(client->filename, &st) == -1 && errno != ENOENT)
1726 return send_error(ctx, gpg_error_from_syserror());
1728 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1729 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1730 return send_error(ctx, GPG_ERR_ENOANO);
1733 if ((client->opts & OPT_INQUIRE)) {
1734 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1735 ctx);
1737 if (rc)
1738 return send_error(ctx, rc);
1740 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1741 client->inquire_status = INQUIRE_BUSY;
1742 return 0;
1745 if (line && *line)
1746 log_write2("ARGS=%s", "<passphrase>");
1748 return save_command_common(ctx, line);
1751 static gint delete_command(assuan_context_t ctx, gchar *line)
1753 struct client_s *client = assuan_get_pointer(ctx);
1754 gchar **req;
1755 gpg_error_t rc;
1756 xmlNodePtr n;
1758 log_write2("ARGS=\"%s\"", line);
1760 if (strchr(line, '\t'))
1761 req = split_input_line(line, "\t", -1);
1762 else
1763 req = split_input_line(line, " ", -1);
1765 if (!req || !*req)
1766 return send_error(ctx, GPG_ERR_SYNTAX);
1768 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1770 if (!n) {
1771 g_strfreev(req);
1772 return send_error(ctx, rc);
1776 * No sub-node defined. Remove the entire node (root element).
1778 if (!req[1]) {
1779 if (n) {
1780 rc = unlink_node(n);
1781 xmlFreeNode(n);
1784 g_strfreev(req);
1785 return send_error(ctx, rc);
1788 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1789 g_strfreev(req);
1791 if (!n)
1792 return send_error(ctx, rc);
1794 if (n) {
1795 rc = unlink_node(n);
1796 xmlFreeNode(n);
1799 return send_error(ctx, rc);
1803 * Don't return with assuan_process_done() here. This has been called from
1804 * assuan_process_next() and the command should be finished in
1805 * client_thread().
1807 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1808 gsize len)
1810 assuan_context_t ctx = data;
1811 struct client_s *client = assuan_get_pointer(ctx);
1812 gchar **req;
1813 xmlNodePtr n;
1814 gpg_error_t rc = file_modified(client);
1816 if (assuan_rc || rc) {
1817 if (line)
1818 xfree(line);
1819 return assuan_rc ? assuan_rc : rc;
1822 req = split_input_line((gchar *)line, "\t", 0);
1823 xfree(line);
1825 if (!req || !*req)
1826 return GPG_ERR_SYNTAX;
1828 again:
1829 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1831 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1832 rc = new_root_element(client->doc, *req);
1834 if (rc) {
1835 g_strfreev(req);
1836 return rc;
1839 goto again;
1842 if (!n) {
1843 g_strfreev(req);
1844 return rc;
1847 if (req[1]) {
1848 if (!n->children)
1849 n = create_elements_cb(n, req+1, &rc, NULL);
1850 else
1851 n = find_elements(client->doc, n->children, req+1, &rc,
1852 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1855 g_strfreev(req);
1856 client->inquire_status = INQUIRE_DONE;
1858 if (!rc)
1859 rc = update_element_mtime(n);
1861 return rc;
1864 static gint store_command(assuan_context_t ctx, gchar *line)
1866 struct client_s *client = assuan_get_pointer(ctx);
1867 gpg_error_t rc;
1869 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1871 if (rc)
1872 return send_error(ctx, rc);
1874 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1875 client->inquire_status = INQUIRE_BUSY;
1876 return 0;
1879 static void *send_data_cb(void *arg)
1881 struct assuan_cmd_s *data = arg;
1882 gint old;
1883 gpg_error_t *rc;
1885 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1886 rc = g_malloc(sizeof(gpg_error_t));
1887 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1888 pth_cancel_state(old, NULL);
1889 pth_exit(rc);
1890 return NULL;
1893 /* For every assuan command that needs to be sent to the client, a timeout is
1894 * needed to determine if the client lost the connection. The timeout is the
1895 * same as the "keepalive" configuration parameter or a default if unset.
1897 gpg_error_t do_assuan_command(assuan_context_t ctx,
1898 void *(*cb)(void *data), void *data)
1900 pth_attr_t attr = pth_attr_new();
1901 pth_t tid;
1902 pth_event_t ev;
1903 pth_status_t st;
1904 gpg_error_t rc = 0;
1905 void *p;
1907 pth_attr_init(attr);
1908 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1909 tid = pth_spawn(attr, cb, data);
1910 rc = gpg_error_from_syserror();
1911 pth_attr_destroy(attr);
1913 if (!tid) {
1914 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1915 return rc;
1918 pth_cleanup_push(cleanup_cancel_cb, tid);
1919 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1920 pth_cleanup_push(cleanup_ev_cb, ev);
1921 pth_yield(tid);
1922 pth_wait(ev);
1924 st = pth_event_status(ev);
1926 if (st == PTH_STATUS_FAILED) {
1927 pth_cancel(tid);
1928 pth_join(tid, &p);
1929 g_free(p);
1930 rc = GPG_ERR_ASS_WRITE_ERROR;
1932 else if (st == PTH_STATUS_OCCURRED) {
1933 pth_join(tid, &p);
1934 rc = *(gpg_error_t *)p;
1935 g_free(p);
1938 pth_cleanup_pop(1);
1939 pth_cleanup_pop(0);
1940 return rc;
1943 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1944 gint total)
1946 gint to_send;
1947 gint sent = 0;
1948 gpg_error_t rc;
1949 struct assuan_cmd_s data;
1950 gint progress = get_key_file_integer("global", "xfer_progress");
1951 gint flush = 0;
1953 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1954 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1955 data.ctx = ctx;
1956 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1958 if (rc)
1959 return rc;
1961 again:
1962 do {
1963 if (sent + to_send > total)
1964 to_send = total - sent;
1966 data.line = flush ? NULL : (gchar *)line+sent;
1967 data.line_len = flush ? 0 : to_send;
1968 rc = do_assuan_command(ctx, send_data_cb, &data);
1970 if (!rc) {
1971 sent += flush ? 0 : to_send;
1973 if ((progress && !(sent % progress) && sent != total) ||
1974 (sent == total && flush))
1975 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1977 if (!flush && !rc && sent == total) {
1978 flush = 1;
1979 goto again;
1982 } while (!rc && sent < total);
1984 return rc;
1987 static gint get_command(assuan_context_t ctx, gchar *line)
1989 struct client_s *client = assuan_get_pointer(ctx);
1990 gchar **req;
1991 gpg_error_t rc;
1992 xmlNodePtr n;
1994 log_write2("ARGS=\"%s\"", line);
1995 req = split_input_line(line, "\t", -1);
1997 if (!req || !*req) {
1998 g_strfreev(req);
1999 return send_error(ctx, GPG_ERR_SYNTAX);
2002 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2004 if (!n) {
2005 g_strfreev(req);
2006 return send_error(ctx, rc);
2009 if (req[1])
2010 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2012 g_strfreev(req);
2014 if (rc)
2015 return send_error(ctx, rc);
2017 if (!n || !n->children)
2018 return send_error(ctx, GPG_ERR_NO_VALUE);
2020 n = find_text_node(n->children);
2022 if (!n || !n->content || !*n->content)
2023 return send_error(ctx, GPG_ERR_NO_VALUE);
2025 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2026 return send_error(ctx, rc);
2029 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2030 gpg_error_t *rc, gchar **req_orig, void *data)
2032 gchar *path = *(gchar **)data;
2033 gchar *tmp = NULL, *result;
2035 if (path) {
2036 g_free(path);
2037 *(gchar **)data = NULL;
2040 path = g_strjoinv("\t", target);
2042 if (!path) {
2043 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2044 *rc = GPG_ERR_ENOMEM;
2045 return NULL;
2048 if (req_orig) {
2049 tmp = g_strjoinv("\t", req_orig);
2051 if (!tmp) {
2052 g_free(path);
2053 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2054 *rc = GPG_ERR_ENOMEM;
2055 return NULL;
2059 if (tmp && *tmp)
2060 result = g_strdup_printf("%s\t%s", path, tmp);
2061 else
2062 result = g_strdup(path);
2064 if (!result) {
2065 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2066 *rc = GPG_ERR_ENOMEM;
2067 g_free(path);
2068 g_free(tmp);
2069 return NULL;
2072 g_free(path);
2073 g_free(tmp);
2074 *(gchar **)data = result;
2075 return node;
2078 static void list_command_cleanup1(void *arg);
2079 static gint realpath_command(assuan_context_t ctx, gchar *line)
2081 gpg_error_t rc;
2082 struct client_s *client = assuan_get_pointer(ctx);
2083 gchar **req;
2084 gchar *t;
2085 gint i;
2086 xmlNodePtr n;
2087 GString *string;
2088 gchar *rp = NULL;
2090 log_write2("ARGS=\"%s\"", line);
2092 if (strchr(line, '\t') != NULL) {
2093 if ((req = split_input_line(line, "\t", 0)) == NULL)
2094 return send_error(ctx, GPG_ERR_SYNTAX);
2096 else {
2097 if ((req = split_input_line(line, " ", 0)) == NULL)
2098 return send_error(ctx, GPG_ERR_SYNTAX);
2101 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2103 if (!n) {
2104 g_strfreev(req);
2105 return send_error(ctx, rc);
2108 rp = g_strjoinv("\t", req);
2110 if (!rp) {
2111 g_strfreev(req);
2112 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2113 return send_error(ctx, GPG_ERR_ENOMEM);
2116 if (req[1]) {
2117 n = find_elements(client->doc, n->children, req+1, &rc,
2118 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2120 if (!n) {
2121 g_free(rp);
2122 g_strfreev(req);
2123 return send_error(ctx, rc);
2127 string = g_string_new(rp);
2128 g_free(rp);
2129 g_strfreev(req);
2131 if (!string) {
2132 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2133 return send_error(ctx, GPG_ERR_ENOMEM);
2136 again:
2137 for (i = 0, t = string->str + i; *t; t++, i++) {
2138 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2139 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2140 goto again;
2144 pth_cleanup_push(list_command_cleanup1, string);
2145 rc = xfer_data(ctx, string->str, string->len);
2146 pth_cleanup_pop(1);
2147 return send_error(ctx, rc);
2150 static void list_command_cleanup1(void *arg)
2152 g_string_free((GString *)arg, TRUE);
2155 static void list_command_cleanup2(void *arg)
2157 struct element_list_s *elements = arg;
2159 if (elements) {
2160 if (elements->list) {
2161 gint total = g_slist_length(elements->list);
2162 gint i;
2164 for (i = 0; i < total; i++) {
2165 gchar *tmp = g_slist_nth_data(elements->list, i);
2166 g_free(tmp);
2169 g_slist_free(elements->list);
2172 if (elements->prefix)
2173 g_free(elements->prefix);
2175 if (elements->req)
2176 g_strfreev(elements->req);
2178 g_free(elements);
2182 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2184 struct element_list_s *elements = data;
2186 elements->recurse = FALSE;
2187 return 0;
2190 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2192 struct element_list_s *elements = data;
2194 elements->verbose = TRUE;
2195 return 0;
2198 static gint list_command(assuan_context_t ctx, gchar *line)
2200 struct client_s *client = assuan_get_pointer(ctx);
2201 gpg_error_t rc;
2202 struct element_list_s *elements = NULL;
2203 gchar *tmp;
2204 struct argv_s *args[] = {
2205 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2206 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2207 NULL
2210 if (disable_list_and_dump == TRUE)
2211 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2213 elements = g_malloc0(sizeof(struct element_list_s));
2215 if (!elements) {
2216 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2217 return GPG_ERR_ENOMEM;
2220 elements->recurse = TRUE; // default
2221 pth_cleanup_push(list_command_cleanup2, elements);
2222 rc = parse_options(&line, args, elements);
2224 if (rc)
2225 goto fail;
2227 if (!*line) {
2228 GString *str;
2230 rc = list_root_elements(client->doc, &str, elements->verbose);
2232 if (rc) {
2233 pth_cleanup_pop(1);
2234 return send_error(ctx, rc);
2237 pth_cleanup_push(list_command_cleanup1, str);
2238 rc = xfer_data(ctx, str->str, str->len);
2239 pth_cleanup_pop(1);
2240 pth_cleanup_pop(1);
2241 return send_error(ctx, rc);
2244 elements->req = split_input_line(line, " ", 0);
2246 if (!elements->req)
2247 strv_printf(&elements->req, "%s", line);
2249 rc = create_path_list(client->doc, elements, *elements->req);
2251 if (rc)
2252 goto fail;
2254 if (elements) {
2255 gint total = g_slist_length(elements->list);
2256 gint i;
2257 GString *str;
2259 if (!total) {
2260 rc = GPG_ERR_NO_VALUE;
2261 goto fail;
2264 str = g_string_new(NULL);
2266 if (!str) {
2267 rc = GPG_ERR_ENOMEM;
2268 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2269 goto fail;
2272 for (i = 0; i < total; i++) {
2273 tmp = g_slist_nth_data(elements->list, i);
2274 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2277 pth_cleanup_push(list_command_cleanup1, str);
2278 rc = xfer_data(ctx, str->str, str->len);
2279 pth_cleanup_pop(1);
2281 else
2282 rc = GPG_ERR_NO_VALUE;
2284 fail:
2285 pth_cleanup_pop(1);
2286 return send_error(ctx, rc);
2290 * req[0] - element path
2292 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2294 struct client_s *client = assuan_get_pointer(ctx);
2295 gchar **attrlist = NULL;
2296 gint i = 0;
2297 gchar **path = NULL;
2298 xmlAttrPtr a;
2299 xmlNodePtr n, an;
2300 gchar *line;
2301 gpg_error_t rc;
2303 if (!req || !req[0])
2304 return GPG_ERR_SYNTAX;
2306 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2308 * The first argument may be only a root element.
2310 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2311 return GPG_ERR_SYNTAX;
2314 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2316 if (!n) {
2317 g_strfreev(path);
2318 return rc;
2321 if (path[1]) {
2322 n = find_elements(client->doc, n->children, path+1, &rc,
2323 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2325 if (!n) {
2326 g_strfreev(path);
2327 return rc;
2331 g_strfreev(path);
2333 for (a = n->properties; a; a = a->next) {
2334 gchar **pa;
2336 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2337 if (attrlist)
2338 g_strfreev(attrlist);
2340 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2341 return GPG_ERR_ENOMEM;
2344 attrlist = pa;
2345 an = a->children;
2346 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2347 an && an->content ? (gchar *)an->content : "");
2349 if (!attrlist[i]) {
2350 g_strfreev(attrlist);
2351 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2352 return GPG_ERR_ENOMEM;
2355 attrlist[++i] = NULL;
2358 if (!attrlist)
2359 return GPG_ERR_NO_VALUE;
2361 line = g_strjoinv("\n", attrlist);
2363 if (!line) {
2364 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2365 g_strfreev(attrlist);
2366 return GPG_ERR_ENOMEM;
2369 pth_cleanup_push(g_free, line);
2370 pth_cleanup_push(req_cleanup, attrlist);
2371 rc = xfer_data(ctx, line, strlen(line));
2372 pth_cleanup_pop(1);
2373 pth_cleanup_pop(1);
2374 return rc;
2378 * req[0] - attribute
2379 * req[1] - element path
2381 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2383 xmlNodePtr n;
2384 gchar **path = NULL;
2385 gpg_error_t rc;
2387 if (!req || !req[0] || !req[1])
2388 return GPG_ERR_SYNTAX;
2390 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2392 * The first argument may be only a root element.
2394 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2395 return GPG_ERR_SYNTAX;
2399 * Don't remove the "_name" attribute for the root element. To remove an
2400 * root element use DELETE <name>.
2402 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2403 rc = GPG_ERR_SYNTAX;
2404 goto fail;
2407 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2409 if (!n)
2410 goto fail;
2412 if (path[1]) {
2413 n = find_elements(client->doc, n->children, path+1, &rc,
2414 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2416 if (!n)
2417 goto fail;
2420 rc = delete_attribute(n, (xmlChar *)req[0]);
2422 fail:
2423 g_strfreev(path);
2424 return rc;
2427 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2428 gpg_error_t *rc)
2430 gchar **src = *path;
2431 gchar **src_orig = g_strdupv(src);
2432 xmlNodePtr n = NULL;
2434 *rc = 0;
2436 if (!src_orig) {
2437 *rc = GPG_ERR_ENOMEM;
2438 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2439 goto fail;
2442 again:
2443 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2445 if (!n) {
2446 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2447 *rc = new_root_element(client->doc, src[0]);
2449 if (*rc)
2450 goto fail;
2452 goto again;
2454 else
2455 goto fail;
2458 if (src[1]) {
2459 if (!n->children)
2460 n = create_target_elements_cb(n, src+1, rc, NULL);
2461 else
2462 n = find_elements(client->doc, n->children, src+1, rc,
2463 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2465 if (!n)
2466 goto fail;
2469 * Reset the position of the element tree now that the elements
2470 * have been created.
2472 g_strfreev(src);
2473 src = src_orig;
2474 src_orig = NULL;
2475 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2477 if (!n)
2478 goto fail;
2480 n = find_elements(client->doc, n->children, src+1, rc,
2481 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2483 if (!n)
2484 goto fail;
2487 fail:
2488 if (src_orig)
2489 g_strfreev(src_orig);
2491 *path = src;
2492 return n;
2496 * Creates a "target" attribute. When other commands encounter an element with
2497 * this attribute, the element path is modified to the target value. If the
2498 * source element path doesn't exist when using 'ATTR SET target', it is
2499 * created, but the destination element path must exist.
2501 * req[0] - source element path
2502 * req[1] - destination element path
2504 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2506 gchar **src, **dst, *line = NULL, **odst = NULL;
2507 gpg_error_t rc;
2508 xmlNodePtr n;
2510 if (!req || !req[0] || !req[1])
2511 return GPG_ERR_SYNTAX;
2513 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2515 * The first argument may be only a root element.
2517 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2518 return GPG_ERR_SYNTAX;
2521 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2523 * The first argument may be only a root element.
2525 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2526 rc = GPG_ERR_SYNTAX;
2527 goto fail;
2531 odst = g_strdupv(dst);
2533 if (!odst) {
2534 rc = GPG_ERR_ENOMEM;
2535 goto fail;
2538 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2541 * Make sure the destination element path exists.
2543 if (!n)
2544 goto fail;
2546 if (dst[1]) {
2547 n = find_elements(client->doc, n->children, dst+1, &rc,
2548 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2550 if (!n)
2551 goto fail;
2554 n = create_element_path(client, &src, &rc);
2556 if (rc)
2557 goto fail;
2559 line = g_strjoinv("\t", odst);
2561 if (!line) {
2562 rc = GPG_ERR_ENOMEM;
2563 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2564 goto fail;
2567 rc = add_attribute(n, "target", line);
2569 fail:
2570 g_free(line);
2571 g_strfreev(src);
2572 g_strfreev(dst);
2573 g_strfreev(odst);
2574 return rc;
2578 * req[0] - name
2579 * req[1] - new name
2581 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2583 gpg_error_t rc;
2584 gchar **tmp;
2585 xmlNodePtr n;
2587 tmp = g_strdupv(req);
2589 if (!tmp) {
2590 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2591 return GPG_ERR_ENOMEM;
2594 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2595 g_strfreev(tmp);
2597 if (!n)
2598 return rc;
2600 if (g_utf8_collate(req[0], req[1]) == 0)
2601 return 0;
2604 * Will not overwrite an existing root.
2606 tmp = g_strdupv(req+1);
2608 if (!tmp) {
2609 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2610 return GPG_ERR_ENOMEM;
2613 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2614 g_strfreev(tmp);
2616 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2617 return rc;
2619 if (n)
2620 return GPG_ERR_AMBIGUOUS_NAME;
2622 if (!valid_xml_element((xmlChar *)req[1]))
2623 return GPG_ERR_SYNTAX;
2625 tmp = g_strdupv(req);
2627 if (!tmp) {
2628 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2629 return GPG_ERR_ENOMEM;
2632 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2633 g_strfreev(tmp);
2635 if (!n)
2636 return GPG_ERR_ELEMENT_NOT_FOUND;
2638 return add_attribute(n, "_name", req[1]);
2642 * req[0] - attribute
2643 * req[1] - element path
2645 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2647 struct client_s *client = assuan_get_pointer(ctx);
2648 xmlNodePtr n;
2649 xmlChar *a;
2650 gchar **path= NULL;
2651 gpg_error_t rc;
2653 if (!req || !req[0] || !req[1])
2654 return GPG_ERR_SYNTAX;
2656 if (strchr(req[1], '\t')) {
2657 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2658 return GPG_ERR_SYNTAX;
2660 else {
2661 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2662 return GPG_ERR_SYNTAX;
2665 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2667 if (!n)
2668 goto fail;
2670 if (path[1]) {
2671 n = find_elements(client->doc, n->children, path+1, &rc,
2672 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2674 if (!n)
2675 goto fail;
2678 g_strfreev(path);
2680 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2681 return GPG_ERR_NOT_FOUND;
2683 pth_cleanup_push(xmlFree, a);
2685 if (*a)
2686 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2687 else
2688 rc = GPG_ERR_NO_VALUE;
2690 pth_cleanup_pop(1);
2691 return rc;
2693 fail:
2694 g_strfreev(path);
2695 return rc;
2699 * req[0] - attribute
2700 * req[1] - element path
2701 * req[2] - value
2703 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2705 gchar **path = NULL;
2706 gpg_error_t rc;
2707 xmlNodePtr n;
2709 if (!req || !req[0] || !req[1])
2710 return GPG_ERR_SYNTAX;
2713 * Reserved attribute names.
2715 if (!g_strcmp0(req[0], "_name")) {
2717 * Only reserved for the root element. Not the rest of the
2718 * document.
2720 if (strchr(req[1], '\t') == NULL)
2721 return name_attribute(client, req + 1);
2723 else if (!g_strcmp0(req[0], "target"))
2724 return target_attribute(client, req + 1);
2726 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2728 * The first argument may be only a root element.
2730 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2731 return GPG_ERR_SYNTAX;
2734 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2736 if (!n)
2737 goto fail;
2739 if (path[1]) {
2740 n = find_elements(client->doc, n->children, path+1, &rc,
2741 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2743 if (!n)
2744 goto fail;
2747 rc = add_attribute(n, req[0], req[2]);
2749 fail:
2750 g_strfreev(path);
2751 return rc;
2755 * req[0] - command
2756 * req[1] - attribute name or element path if command is LIST
2757 * req[2] - element path
2758 * req[2] - element path or value
2760 static gint attr_command(assuan_context_t ctx, gchar *line)
2762 struct client_s *client = assuan_get_pointer(ctx);
2763 gchar **req;
2764 gpg_error_t rc = 0;
2766 log_write2("ARGS=\"%s\"", line);
2767 req = split_input_line(line, " ", 4);
2769 if (!req || !req[0] || !req[1]) {
2770 g_strfreev(req);
2771 return send_error(ctx, GPG_ERR_SYNTAX);
2774 pth_cleanup_push(req_cleanup, req);
2776 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2777 rc = attribute_set(client, req+1);
2778 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2779 rc = attribute_get(ctx, req+1);
2780 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2781 rc = attribute_delete(client, req+1);
2782 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2783 rc = attribute_list(ctx, req+1);
2784 else
2785 rc = GPG_ERR_SYNTAX;
2787 pth_cleanup_pop(1);
2788 return send_error(ctx, rc);
2791 static gint iscached_command(assuan_context_t ctx, gchar *line)
2793 gchar **req = split_input_line(line, " ", 0);
2794 guchar md5file[16];
2795 gchar *path, *tmp;
2797 if (!req || !*req) {
2798 g_strfreev(req);
2799 return send_error(ctx, GPG_ERR_SYNTAX);
2802 log_write2("ARGS=\"%s\"", line);
2804 if (!valid_filename(req[0])) {
2805 g_strfreev(req);
2806 return GPG_ERR_INV_VALUE;
2809 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2810 CACHE_LOCK(ctx);
2812 if (cache_iscached(md5file)) {
2813 g_strfreev(req);
2814 CACHE_UNLOCK;
2815 return send_error(ctx, 0);
2818 CACHE_UNLOCK;
2819 tmp = get_key_file_string("global", "data_directory");
2821 if (!tmp) {
2822 g_strfreev(req);
2823 return GPG_ERR_ENOMEM;
2826 path = expand_homedir(tmp);
2828 if (!path) {
2829 g_strfreev(req);
2830 g_free(tmp);
2831 return GPG_ERR_ENOMEM;
2834 g_free(tmp);
2835 tmp = path;
2836 path = g_strdup_printf("%s/%s", tmp, req[0]);
2837 g_free(tmp);
2839 if (!path) {
2840 g_strfreev(req);
2841 return GPG_ERR_ENOMEM;
2844 if (access(path, R_OK) == -1) {
2845 gpg_error_t rc = gpg_error_from_syserror();
2847 g_free(path);
2848 g_strfreev(req);
2849 return send_error(ctx, rc);
2852 g_free(path);
2853 return send_error(ctx, GPG_ERR_NOT_FOUND);
2856 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2858 gchar **req = split_input_line(line, " ", 0);
2859 guchar md5file[16];
2861 log_write2("ARGS=\"%s\"", line);
2862 CACHE_LOCK(ctx);
2864 if (!req || !*req) {
2865 g_strfreev(req);
2866 cache_clear(NULL, 2);
2867 CACHE_UNLOCK;
2868 return send_error(ctx, 0);
2871 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2872 g_strfreev(req);
2873 (void)cache_clear(md5file, 1);
2874 CACHE_UNLOCK;
2875 return send_error(ctx, 0);
2878 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2880 guchar md5file[16];
2881 glong timeout;
2882 gchar **req = split_input_line(line, " ", 0);
2883 gchar *p;
2885 if (!req || !*req || !req[1]) {
2886 g_strfreev(req);
2887 return send_error(ctx, GPG_ERR_SYNTAX);
2890 errno = 0;
2891 timeout = strtol(req[1], &p, 10);
2893 if (errno != 0 || *p != 0 || timeout < -1) {
2894 g_strfreev(req);
2895 return send_error(ctx, GPG_ERR_SYNTAX);
2898 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2899 CACHE_LOCK(client->ctx);
2901 if (cache_set_timeout(md5file, timeout) == FALSE) {
2902 CACHE_UNLOCK;
2903 return send_error(ctx, GPG_ERR_NOT_FOUND);
2906 CACHE_UNLOCK;
2907 return send_error(ctx, 0);
2910 static gint dump_command(assuan_context_t ctx, gchar *line)
2912 xmlChar *xml;
2913 gint len;
2914 struct client_s *client = assuan_get_pointer(ctx);
2915 gpg_error_t rc;
2917 if (disable_list_and_dump == TRUE)
2918 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2920 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2922 if (!xml) {
2923 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2924 return send_error(ctx, GPG_ERR_ENOMEM);
2927 pth_cleanup_push(xmlFree, xml);
2928 rc = xfer_data(ctx, (gchar *)xml, len);
2929 pth_cleanup_pop(1);
2930 return send_error(ctx, rc);
2933 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2935 struct client_s *client = assuan_get_pointer(ctx);
2936 gpg_error_t rc = 0;
2937 gchar filename[255]={0}, param[747]={0};
2938 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2940 log_write2("ARGS=\"%s\"", line);
2942 if (!line || !*line)
2943 return send_error(ctx, GPG_ERR_SYNTAX);
2945 if (strchr(line, ' ')) {
2946 sscanf(line, " %254[^ ] %746c", filename, param);
2947 paramp = param;
2948 fp = filename;
2951 if (fp && !valid_filename(fp))
2952 return send_error(ctx, GPG_ERR_INV_VALUE);
2954 paramp = g_ascii_strdown(paramp, -1);
2956 if (!paramp) {
2957 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2958 return send_error(ctx, GPG_ERR_ENOMEM);
2961 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2962 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2963 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2965 if (!fh && rc != GPG_ERR_ENOENT)
2966 return send_error(ctx, rc);
2968 if (!rc) {
2969 g_free(paramp);
2970 p = g_strdup_printf("%llu", fh->ver.fh2.iter);
2971 close_file_header(fh);
2973 if (!p) {
2974 log_write("%s(%i): %s", __FILE__, __LINE__,
2975 pwmd_strerror(GPG_ERR_ENOMEM));
2976 return send_error(ctx, GPG_ERR_ENOMEM);
2979 goto done;
2983 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2984 #ifdef WITH_PINENTRY
2985 gboolean n;
2987 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2988 n = client->pinentry->enable;
2989 else
2990 n = get_key_file_boolean(fp, "enable_pinentry");
2992 p = g_strdup_printf("%s", n ? "true" : "false");
2994 if (!p) {
2995 log_write("%s(%i): %s", __FILE__, __LINE__,
2996 pwmd_strerror(GPG_ERR_ENOMEM));
2997 return send_error(ctx, GPG_ERR_ENOMEM);
3000 goto done;
3001 #else
3002 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3003 #endif
3005 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3006 #ifdef WITH_PINENTRY
3007 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3009 if (!p) {
3010 log_write("%s(%i): %s", __FILE__, __LINE__,
3011 pwmd_strerror(GPG_ERR_ENOMEM));
3012 return send_error(ctx, GPG_ERR_ENOMEM);
3015 goto done;
3016 #else
3017 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3018 #endif
3021 p = get_key_file_string(fp ? fp : "global", paramp);
3022 g_free(paramp);
3024 if (!p)
3025 return send_error(ctx, GPG_ERR_UNKNOWN_OPTION);
3027 tmp = expand_homedir(p);
3028 g_free(p);
3030 if (!tmp) {
3031 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3032 return send_error(ctx, GPG_ERR_ENOMEM);
3035 p = tmp;
3036 done:
3037 pth_cleanup_push(g_free, p);
3038 rc = xfer_data(ctx, p, strlen(p));
3039 pth_cleanup_pop(1);
3040 return send_error(ctx, rc);
3043 struct xpath_s {
3044 xmlXPathContextPtr xp;
3045 xmlXPathObjectPtr result;
3046 xmlBufferPtr buf;
3047 gchar **req;
3050 static void xpath_command_cleanup(void *arg)
3052 struct xpath_s *xpath = arg;
3054 req_cleanup(xpath->req);
3056 if (xpath->buf)
3057 xmlBufferFree(xpath->buf);
3059 if (xpath->result)
3060 xmlXPathFreeObject(xpath->result);
3062 if (xpath->xp)
3063 xmlXPathFreeContext(xpath->xp);
3066 static gint xpath_command(assuan_context_t ctx, gchar *line)
3068 struct client_s *client = assuan_get_pointer(ctx);
3069 gpg_error_t rc;
3070 struct xpath_s xpath;
3072 log_write2("ARGS=\"%s\"", line);
3074 if (disable_list_and_dump == TRUE)
3075 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3077 if (!line || !*line)
3078 return send_error(ctx, GPG_ERR_SYNTAX);
3080 memset(&xpath, 0, sizeof(struct xpath_s));
3082 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3083 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3084 return send_error(ctx, GPG_ERR_ENOMEM);
3087 xpath.xp = xmlXPathNewContext(client->doc);
3089 if (!xpath.xp) {
3090 xpath_command_cleanup(&xpath);
3091 return send_error(ctx, EPWMD_LIBXML_ERROR);
3094 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3096 if (!xpath.result) {
3097 xpath_command_cleanup(&xpath);
3098 return send_error(ctx, EPWMD_LIBXML_ERROR);
3101 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3102 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3103 goto fail;
3106 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3107 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3109 if (rc)
3110 goto fail;
3111 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3112 rc = GPG_ERR_NO_VALUE;
3113 goto fail;
3115 else if (xpath.req[1])
3116 goto fail;
3118 pth_cleanup_push(xpath_command_cleanup, &xpath);
3119 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3120 xmlBufferLength(xpath.buf));
3121 pth_cleanup_pop(0);
3123 fail:
3124 xpath_command_cleanup(&xpath);
3125 return send_error(ctx, rc);
3128 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3129 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3131 struct client_s *client = assuan_get_pointer(ctx);
3132 gpg_error_t rc;
3133 struct xpath_s xpath;
3134 gchar **req = NULL;
3135 gboolean cmd = FALSE; //SET
3137 log_write2("ARGS=\"%s\"", line);
3139 if (disable_list_and_dump == TRUE)
3140 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3142 if (!line || !*line)
3143 return send_error(ctx, GPG_ERR_SYNTAX);
3145 memset(&xpath, 0, sizeof(struct xpath_s));
3147 if ((req = split_input_line(line, " ", 3)) == NULL)
3148 return send_error(ctx, GPG_ERR_ENOMEM);
3150 if (!req[0]) {
3151 rc = GPG_ERR_SYNTAX;
3152 goto fail;
3155 if (!g_ascii_strcasecmp(req[0], "SET"))
3156 cmd = FALSE;
3157 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3158 cmd = TRUE;
3159 else {
3160 rc = GPG_ERR_SYNTAX;
3161 goto fail;
3164 if (!req[1] || !req[2]) {
3165 rc = GPG_ERR_SYNTAX;
3166 goto fail;
3169 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3170 rc = GPG_ERR_ENOMEM;
3171 goto fail;
3174 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3175 rc = GPG_ERR_SYNTAX;
3176 goto fail;
3179 xpath.xp = xmlXPathNewContext(client->doc);
3181 if (!xpath.xp) {
3182 rc = EPWMD_LIBXML_ERROR;
3183 goto fail;
3186 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3188 if (!xpath.result) {
3189 rc = EPWMD_LIBXML_ERROR;
3190 goto fail;
3193 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3194 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3195 goto fail;
3198 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3199 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3201 fail:
3202 g_strfreev(req);
3203 xpath_command_cleanup(&xpath);
3204 return send_error(ctx, rc);
3207 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3208 gsize len)
3210 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3211 gpg_error_t rc = file_modified(client);
3212 gchar **req, **path = NULL, **path_orig = NULL, *content;
3213 xmlDocPtr doc = NULL;
3214 xmlNodePtr n, root, copy;
3216 if (assuan_rc || rc) {
3217 if (line)
3218 xfree(line);
3219 return assuan_rc ? assuan_rc : rc;
3222 req = split_input_line((gchar *)line, "\t", 2);
3223 xfree(line);
3225 if (!req || !*req)
3226 return GPG_ERR_SYNTAX;
3228 content = req[0];
3229 path = split_input_line(req[1], "\t", 0);
3231 if (!content || !*content) {
3232 rc = GPG_ERR_SYNTAX;
3233 goto fail;
3236 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3238 if (!doc) {
3239 rc = EPWMD_LIBXML_ERROR;
3240 goto fail;
3243 root = xmlDocGetRootElement(doc);
3244 rc = validate_import(root);
3246 if (rc)
3247 goto fail;
3249 if (path) {
3250 path_orig = g_strdupv(path);
3252 if (!path_orig) {
3253 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3254 rc = GPG_ERR_ENOMEM;
3255 goto fail;
3258 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3260 if (!a) {
3261 g_strfreev(path_orig);
3262 rc = GPG_ERR_ENOMEM;
3263 goto fail;
3266 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3267 xmlFree(a);
3268 g_strfreev(path_orig);
3269 rc = GPG_ERR_ENOMEM;
3270 goto fail;
3273 xmlFree(a);
3274 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3276 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3277 g_strfreev(path_orig);
3278 goto fail;
3281 if (!rc) {
3282 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3284 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3285 g_strfreev(path_orig);
3286 goto fail;
3288 else if (!rc) {
3289 xmlNodePtr parent = n->parent;
3291 xmlUnlinkNode(n);
3292 xmlFreeNode(n);
3293 n = parent;
3297 g_strfreev(path);
3298 path = path_orig;
3300 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3301 n = create_element_path(client, &path, &rc);
3303 if (rc)
3304 goto fail;
3307 copy = xmlCopyNodeList(root);
3308 n = xmlAddChildList(n, copy);
3310 if (!n)
3311 rc = EPWMD_LIBXML_ERROR;
3313 else {
3314 /* Check if the content root element can create a DTD root element. */
3315 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3316 rc = GPG_ERR_SYNTAX;
3317 goto fail;
3320 xmlChar *a;
3322 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3323 rc = GPG_ERR_SYNTAX;
3324 goto fail;
3327 gchar *tmp = g_strdup((gchar *)a);
3328 xmlFree(a);
3329 gboolean literal = is_literal_element(&tmp);
3331 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3332 g_free(tmp);
3333 rc = GPG_ERR_INV_VALUE;
3334 goto fail;
3337 if (strv_printf(&path, "%s", tmp) == FALSE) {
3338 g_free(tmp);
3339 rc = GPG_ERR_ENOMEM;
3340 goto fail;
3343 g_free(tmp);
3344 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3346 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3347 rc = EPWMD_LIBXML_ERROR;
3348 goto fail;
3351 /* Overwriting the existing tree. */
3352 if (!rc) {
3353 xmlUnlinkNode(n);
3354 xmlFreeNodeList(n);
3357 rc = 0;
3358 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3359 n = xmlCopyNode(root, 1);
3360 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3363 if (n && !rc)
3364 rc = update_element_mtime(n->parent);
3366 fail:
3367 if (doc)
3368 xmlFreeDoc(doc);
3370 if (path)
3371 g_strfreev(path);
3373 g_strfreev(req);
3374 client->inquire_status = INQUIRE_DONE;
3375 return rc;
3378 static gint import_command(assuan_context_t ctx, gchar *line)
3380 gpg_error_t rc;
3381 struct client_s *client = assuan_get_pointer(ctx);
3383 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3385 if (rc)
3386 return send_error(ctx, rc);
3388 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3389 client->inquire_status = INQUIRE_BUSY;
3390 return 0;
3393 static gpg_error_t do_lock_command(struct client_s *client)
3395 gpg_error_t rc = lock_file_mutex(client);
3397 if (!rc)
3398 client->is_lock_cmd = TRUE;
3400 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3403 static gint lock_command(assuan_context_t ctx, gchar *line)
3405 struct client_s *client = assuan_get_pointer(ctx);
3407 return do_lock_command(client);
3410 static gint unlock_command(assuan_context_t ctx, gchar *line)
3412 struct client_s *client = assuan_get_pointer(ctx);
3414 unlock_file_mutex(client);
3415 return send_error(ctx, 0);
3418 static gint getpid_command(assuan_context_t ctx, gchar *line)
3420 gpg_error_t rc;
3421 gchar buf[32];
3422 pid_t pid = getpid();
3424 print_fmt(buf, sizeof(buf), "%i", pid);
3425 rc = xfer_data(ctx, buf, strlen(buf));
3426 return send_error(ctx, rc);
3429 static gint version_command(assuan_context_t ctx, gchar *line)
3431 gpg_error_t rc;
3432 gchar *buf;
3434 buf = g_strdup_printf("0x%X %s", VERSION_HEX,
3435 #ifdef WITH_PINENTRY
3436 "PINENTRY "
3437 #endif
3438 #ifdef WITH_QUALITY
3439 "QUALITY "
3440 #endif
3441 #ifdef WITH_LIBACL
3442 "ACL "
3443 #endif
3444 "");
3445 rc = xfer_data(ctx, buf, strlen(buf));
3446 g_free(buf);
3447 return send_error(ctx, rc);
3450 #ifdef WITH_PINENTRY
3451 static void set_option_value(gchar **opt, const gchar *value)
3453 if (opt)
3454 g_free(*opt);
3456 *opt = NULL;
3458 if (value)
3459 *opt = g_strdup(value);
3461 #endif
3463 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3464 const gchar *value)
3466 struct client_s *client = assuan_get_pointer(ctx);
3467 gpg_error_t rc;
3469 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3470 gint n = 0;
3472 if (value) {
3473 n = atoi(value);
3475 if (n < 0 || n > 2)
3476 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3479 MUTEX_LOCK(&rcfile_mutex);
3480 g_key_file_set_integer(keyfileh, "global", "log_level", n);
3481 MUTEX_UNLOCK(&rcfile_mutex);
3482 goto done;
3484 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3485 gint n = 0;
3487 if (value) {
3488 n = atoi(value);
3490 if (n < 0 || n > 1)
3491 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3494 client->rc_on_locked = n ? TRUE : FALSE;
3495 goto done;
3497 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3498 rc = parse_open_opt_lock(client, (gpointer)value);
3500 if (rc)
3501 return rc;
3503 client->opts |= OPT_LOCK;
3505 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3506 if (!value) {
3507 client->opts &= ~(OPT_CIPHER);
3508 goto done;
3511 rc = parse_save_opt_cipher(client, (gpointer)value);
3513 if (rc)
3514 return rc;
3516 client->opts |= OPT_CIPHER;
3517 goto done;
3519 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3520 rc = parse_save_opt_iterations(client, (gpointer)value);
3522 if (rc)
3523 return rc;
3525 goto done;
3527 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3528 pth_attr_t attr = pth_attr_of(pth_self());
3529 gchar buf[41];
3531 if (!value) {
3532 pth_attr_destroy(attr);
3533 goto done;
3536 print_fmt(buf, sizeof(buf), "%s", value);
3537 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3538 pth_attr_destroy(attr);
3539 #ifdef WITH_PINENTRY
3540 if (client->pinentry->name)
3541 g_free(client->pinentry->name);
3543 client->pinentry->name = g_strdup(buf);
3545 if (!client->pinentry->name)
3546 return GPG_ERR_ENOMEM;
3547 #endif
3549 goto done;
3551 #ifdef WITH_PINENTRY
3552 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3553 set_option_value(&client->pinentry->lcmessages, value);
3554 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3555 set_option_value(&client->pinentry->lcctype, value);
3556 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3557 set_option_value(&client->pinentry->ttyname, value);
3558 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3559 set_option_value(&client->pinentry->ttytype, value);
3560 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3561 set_option_value(&client->pinentry->display, value);
3562 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3563 set_option_value(&client->pinentry->path, value);
3564 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3565 set_option_value(&client->pinentry->title, value);
3566 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3567 set_option_value(&client->pinentry->prompt, value);
3568 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3569 set_option_value(&client->pinentry->desc, value);
3570 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3571 gchar *p = NULL;
3572 gint n;
3574 if (!value)
3575 goto done;
3577 n = atoi(value);
3579 if (*p || n < 0)
3580 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3582 MUTEX_LOCK(&rcfile_mutex);
3583 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3584 "global", "pinentry_timeout", n);
3585 MUTEX_UNLOCK(&rcfile_mutex);
3586 goto done;
3588 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3589 rc = parse_opt_pinentry(client, (gpointer)value);
3591 if (rc)
3592 return rc;
3594 goto done;
3596 #else
3597 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3598 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3599 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3600 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3601 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3602 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3603 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3604 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3605 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3606 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3607 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3608 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3609 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3610 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3611 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3612 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3613 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3614 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3615 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3616 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3617 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3618 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3619 #endif
3620 else
3621 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3623 done:
3624 return 0;
3627 static gint unset_command(assuan_context_t ctx, gchar *line)
3629 log_write2("ARGS=\"%s\"", line);
3630 return send_error(ctx, set_unset_common(ctx, line, NULL));
3633 static gint set_command(assuan_context_t ctx, gchar *line)
3635 gchar name[64] = {0}, value[256] = {0};
3637 log_write2("ARGS=\"%s\"", line);
3639 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3640 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3642 return send_error(ctx, set_unset_common(ctx, name, value));
3645 static gint rename_command(assuan_context_t ctx, gchar *line)
3647 struct client_s *client = assuan_get_pointer(ctx);
3648 gpg_error_t rc;
3649 gchar **req, **src, *dst;
3650 xmlNodePtr n, ndst;
3652 log_write2("ARGS=\"%s\"", line);
3653 req = split_input_line(line, " ", -1);
3655 if (!req || !req[0] || !req[1]) {
3656 g_strfreev(req);
3657 return send_error(ctx, GPG_ERR_SYNTAX);
3660 dst = req[1];
3661 is_literal_element(&dst);
3663 if (!valid_xml_element((xmlChar *)dst)) {
3664 g_strfreev(req);
3665 return GPG_ERR_INV_VALUE;
3668 if (strchr(req[0], '\t'))
3669 src = split_input_line(req[0], "\t", -1);
3670 else
3671 src = split_input_line(req[0], " ", -1);
3673 if (!src || !*src) {
3674 rc = GPG_ERR_SYNTAX;
3675 goto fail;
3678 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3680 if (src[1] && n)
3681 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3682 NULL, FALSE, 0, NULL, FALSE);
3684 if (!n)
3685 goto fail;
3688 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3690 if (!a) {
3691 rc = GPG_ERR_ENOMEM;
3692 goto fail;
3695 /* To prevent unwanted effects:
3697 * <root name="a"><b/></root>
3699 * RENAME a<TAB>b b
3701 if (xmlStrEqual(a, (xmlChar *)dst)) {
3702 xmlFree(a);
3703 rc = GPG_ERR_AMBIGUOUS_NAME;
3704 goto fail;
3707 xmlFree(a);
3708 gchar **tmp = NULL;
3710 if (src[1]) {
3711 gchar **p;
3713 for (p = src; *p; p++) {
3714 if (!*(p+1))
3715 break;
3717 strv_printf(&tmp, "%s", *p);
3721 strv_printf(&tmp, "!%s", dst);
3722 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3724 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3725 g_strfreev(tmp);
3726 goto fail;
3729 if (tmp[1] && ndst)
3730 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3731 NULL, NULL, FALSE, 0, NULL, FALSE);
3733 g_strfreev(tmp);
3735 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3736 goto fail;
3738 rc = 0;
3740 /* Target may exist:
3742 * <root name="a"/>
3743 * <root name="b" target="a"/>
3745 * RENAME b a
3747 * Would need to do:
3748 * RENAME !b a
3750 if (ndst == n) {
3751 rc = GPG_ERR_AMBIGUOUS_NAME;
3752 goto fail;
3755 if (ndst) {
3756 unlink_node(ndst);
3757 xmlFreeNodeList(ndst);
3760 rc = add_attribute(n, "_name", dst);
3762 fail:
3763 g_strfreev(req);
3764 g_strfreev(src);
3765 return send_error(ctx, rc);
3768 static gint copy_command(assuan_context_t ctx, gchar *line)
3770 struct client_s *client = assuan_get_pointer(ctx);
3771 gpg_error_t rc;
3772 gchar **req, **src = NULL, **dst = NULL;
3773 xmlNodePtr nsrc, ndst, new;
3775 log_write2("ARGS=\"%s\"", line);
3776 req = split_input_line(line, " ", -1);
3778 if (!req || !req[0] || !req[1]) {
3779 g_strfreev(req);
3780 return send_error(ctx, GPG_ERR_SYNTAX);
3783 if (strchr(req[0], '\t'))
3784 src = split_input_line(req[0], "\t", -1);
3785 else
3786 src = split_input_line(req[0], " ", -1);
3788 if (!src || !*src) {
3789 rc = GPG_ERR_SYNTAX;
3790 goto fail;
3793 if (strchr(req[1], '\t'))
3794 dst = split_input_line(req[1], "\t", -1);
3795 else
3796 dst = split_input_line(req[1], " ", -1);
3798 if (!dst || !*dst) {
3799 rc = GPG_ERR_SYNTAX;
3800 goto fail;
3803 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3804 if (nsrc && src[1])
3805 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3806 NULL, NULL, FALSE, 0, NULL, FALSE);
3808 if (!nsrc)
3809 goto fail;
3811 gboolean create = FALSE;
3812 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3813 if (ndst && dst[1]) {
3814 if (ndst->children) {
3815 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3816 NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
3818 else {
3819 create = TRUE;
3822 else
3823 create = TRUE;
3825 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3826 goto fail;
3827 else if (create) {
3828 ndst = create_element_path(client, &dst, &rc);
3829 if (!ndst)
3830 goto fail;
3833 new = xmlCopyNodeList(nsrc);
3834 if (!new) {
3835 rc = GPG_ERR_ENOMEM;
3836 goto fail;
3839 /* Merge any attributes from the src node to the initial dst node. */
3840 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3841 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3842 continue;
3844 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3846 if (a)
3847 xmlRemoveProp(a);
3849 xmlChar *tmp = xmlNodeGetContent(attr->children);
3850 xmlNewProp(ndst, attr->name, tmp);
3851 xmlFree(tmp);
3852 rc = add_attribute(ndst, NULL, NULL);
3855 xmlNodePtr n = ndst->children;
3856 xmlUnlinkNode(n);
3857 xmlFreeNodeList(n);
3858 ndst->children = NULL;
3860 if (!new->children) {
3861 xmlUnlinkNode(new);
3862 xmlFreeNodeList(new);
3863 goto fail;
3866 n = xmlCopyNodeList(new->children);
3868 if (!n) {
3869 rc = GPG_ERR_ENOMEM;
3870 goto fail;
3873 xmlUnlinkNode(new);
3874 xmlFreeNodeList(new);
3875 n = xmlAddChildList(ndst, n);
3877 if (!n) {
3878 rc = GPG_ERR_ENOMEM;
3879 goto fail;
3882 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3884 fail:
3885 if (req)
3886 g_strfreev(req);
3888 if (src)
3889 g_strfreev(src);
3891 if (dst)
3892 g_strfreev(dst);
3894 return send_error(ctx, rc);
3897 static gint move_command(assuan_context_t ctx, gchar *line)
3899 struct client_s *client = assuan_get_pointer(ctx);
3900 gpg_error_t rc;
3901 gchar **req, **src = NULL, **dst = NULL;
3902 xmlNodePtr nsrc, ndst = NULL;
3904 log_write2("ARGS=\"%s\"", line);
3905 req = split_input_line(line, " ", -1);
3907 if (!req || !req[0] || !req[1]) {
3908 g_strfreev(req);
3909 return send_error(ctx, GPG_ERR_SYNTAX);
3912 if (strchr(req[0], '\t'))
3913 src = split_input_line(req[0], "\t", -1);
3914 else
3915 src = split_input_line(req[0], " ", -1);
3917 if (!src || !*src) {
3918 rc = GPG_ERR_SYNTAX;
3919 goto fail;
3922 if (strchr(req[1], '\t'))
3923 dst = split_input_line(req[1], "\t", -1);
3924 else
3925 dst = split_input_line(req[1], " ", -1);
3927 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3929 if (nsrc && src[1])
3930 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3931 NULL, NULL, FALSE, 0, NULL, FALSE);
3933 if (!nsrc)
3934 goto fail;
3936 if (dst) {
3937 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3939 if (ndst && dst[1])
3940 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3941 NULL, NULL, FALSE, 0, NULL, FALSE);
3943 else
3944 ndst = xmlDocGetRootElement(client->doc);
3946 for (xmlNodePtr n = ndst; n; n = n->parent) {
3947 if (n == nsrc) {
3948 rc = GPG_ERR_CONFLICT;
3949 goto fail;
3953 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3954 goto fail;
3956 rc = 0;
3958 if (ndst) {
3959 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3960 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3962 xmlFree(a);
3964 if (dup) {
3965 if (dup == nsrc)
3966 goto fail;
3968 if (ndst == xmlDocGetRootElement(client->doc)) {
3969 xmlNodePtr n = nsrc;
3970 gboolean match = FALSE;
3972 while (n->parent && n->parent != ndst)
3973 n = n->parent;
3975 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3976 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3978 if (xmlStrEqual(a, b)) {
3979 match = TRUE;
3980 xmlUnlinkNode(nsrc);
3981 xmlUnlinkNode(n);
3982 xmlFreeNodeList(n);
3985 xmlFree(a);
3986 xmlFree(b);
3988 if (!match) {
3989 xmlUnlinkNode(dup);
3990 xmlFreeNodeList(dup);
3993 else
3994 xmlUnlinkNode(dup);
3998 if (!ndst && dst)
3999 ndst = create_element_path(client, &dst, &rc);
4001 if (!ndst)
4002 goto fail;
4004 update_element_mtime(nsrc->parent);
4005 xmlUnlinkNode(nsrc);
4006 ndst = xmlAddChildList(ndst, nsrc);
4008 if (!ndst)
4009 rc = GPG_ERR_ENOMEM;
4011 update_element_mtime(ndst->parent);
4013 fail:
4014 if (req)
4015 g_strfreev(req);
4017 if (src)
4018 g_strfreev(src);
4020 if (dst)
4021 g_strfreev(dst);
4023 return send_error(ctx, rc);
4026 static int ls_command(assuan_context_t ctx, gchar *line)
4028 log_write2("ARGS=\"%s\"", line);
4029 gpg_error_t rc;
4030 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4031 gchar *dir = expand_homedir(tmp);
4032 DIR *d = opendir(dir);
4034 rc = gpg_error_from_syserror();
4035 g_free(tmp);
4037 if (!d) {
4038 g_free(dir);
4039 return send_error(ctx, rc);
4042 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4043 struct dirent *p = g_malloc(len), *cur = NULL;
4044 gchar *list = NULL;
4046 g_free(dir);
4047 rc = 0;
4049 while (!readdir_r(d, p, &cur) && cur) {
4050 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4051 continue;
4052 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4053 continue;
4055 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4057 if (!tmp) {
4058 if (list)
4059 g_free(list);
4061 rc = GPG_ERR_ENOMEM;
4062 break;
4065 g_free(list);
4066 list = tmp;
4069 closedir(d);
4070 g_free(p);
4072 if (rc)
4073 return send_error(ctx, rc);
4075 if (!list)
4076 return send_error(ctx, GPG_ERR_NO_VALUE);
4078 list[strlen(list)-1] = 0;
4079 rc = xfer_data(ctx, list, strlen(list));
4080 g_free(list);
4081 return send_error(ctx, rc);
4084 static void bye_notify(assuan_context_t ctx)
4086 struct client_s *cl = assuan_get_pointer(ctx);
4088 /* This will let assuan_process_next() return. */
4089 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4090 cl->last_rc = 0; // BYE command result
4093 static void reset_notify(assuan_context_t ctx)
4095 struct client_s *cl = assuan_get_pointer(ctx);
4097 if (cl)
4098 cleanup_client(cl);
4102 * This is called before every Assuan command.
4104 gint command_startup(assuan_context_t ctx, const gchar *name)
4106 struct client_s *cl = assuan_get_pointer(ctx);
4107 gpg_error_t rc;
4109 log_write1("%s", name);
4111 for (int i = 0; command_table[i]; i++) {
4112 if (!g_ascii_strcasecmp(name, command_table[i]->name) &&
4113 command_table[i]->ignore_startup)
4114 return 0;
4117 #ifdef WITH_PINENTRY
4118 if (!(cl->opts & OPT_PINENTRY))
4119 reset_pin_defaults(cl->pinentry);
4120 #endif
4122 cl->last_rc = rc = file_modified(cl);
4124 if (rc) {
4125 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4126 !g_ascii_strcasecmp(name, "OPEN"))
4127 rc = 0;
4130 return rc;
4134 * This is called after every Assuan command.
4136 void command_finalize(assuan_context_t ctx, gint rc)
4138 struct client_s *client = assuan_get_pointer(ctx);
4140 if (!client->is_lock_cmd)
4141 unlock_file_mutex(client);
4143 log_write1(_("command completed (rc=%u)"), client->last_rc);
4144 client->opts &= ~(OPT_INQUIRE);
4145 client->opts &= ~(OPT_BASE64);
4148 static gint help_command(assuan_context_t ctx, gchar *line)
4150 gpg_error_t rc;
4151 gint i;
4153 if (!line || !*line) {
4154 gchar *tmp;
4155 gchar *buf = g_strdup(_(
4156 "Usage: HELP [<COMMAND>]\n"
4157 " For commands that take an element path as an argument, each element is\n"
4158 " separated with an ASCII tab character (ASCII 0x09).\n"
4159 "\n"
4160 " Each element may contain a \"target\" attribute whose value is also an\n"
4161 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4162 " filesystem. When found, the element path of the \"target\" attribute will\n"
4163 " be used as a prefix for further elements in the current element path. To\n"
4164 " ignore any \"target\" attribute for the current element, prefix the element\n"
4165 " with an ! (ASCII 0x21).\n"
4166 "\n"
4167 " See pwmd(1) for configuration file options which may also set default\n"
4168 " options for specific data files.\n"
4169 "\n"
4170 "COMMANDS:"));
4172 for (i = 0; command_table[i]; i++) {
4173 gchar *p = strrchr(buf, '\n');
4174 gboolean newline = FALSE;
4176 if (!command_table[i]->help)
4177 continue;
4179 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4180 tmp = g_strdup_printf("%s\n", buf);
4181 g_free(buf);
4182 buf = tmp;
4183 newline = TRUE;
4186 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4187 command_table[i]->name);
4188 g_free(buf);
4189 buf = tmp;
4192 tmp = g_strdup_printf("%s\n", buf);
4193 g_free(buf);
4194 buf = tmp;
4195 rc = xfer_data(ctx, buf, strlen(buf));
4196 g_free(buf);
4197 return send_error(ctx, rc);
4200 for (i = 0; command_table[i]; i++) {
4201 if (!g_strcasecmp(line, command_table[i]->name)) {
4202 if (!command_table[i]->help)
4203 break;
4205 gchar *tmp = g_strdup_printf(_("Usage: %s"), command_table[i]->help);
4206 rc = xfer_data(ctx, tmp, strlen(tmp));
4207 g_free(tmp);
4208 return send_error(ctx, rc);
4212 return send_error(ctx, GPG_ERR_INV_NAME);
4215 void new_command(const gchar *name, gboolean ignore,
4216 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4218 gint i = 0;
4220 if (command_table)
4221 for (i = 0; command_table[i]; i++);
4223 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4224 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4225 command_table[i]->name = name;
4226 command_table[i]->handler = handler;
4227 command_table[i]->ignore_startup = ignore;
4228 command_table[i++]->help = help;
4229 command_table[i] = NULL;
4232 void deinit_commands()
4234 gint i;
4236 for (i = 0; command_table[i]; i++)
4237 g_free(command_table[i]);
4239 g_free(command_table);
4242 static gint sort_commands(const void *arg1, const void *arg2)
4244 struct command_table_s* const *a = arg1;
4245 struct command_table_s* const *b = arg2;
4247 if (!*a || !*b)
4248 return 0;
4249 else if (*a && !*b)
4250 return 1;
4251 else if (!*a && *b)
4252 return -1;
4254 return g_strcmp0((*a)->name, (*b)->name);
4257 void init_commands()
4259 /* !BEGIN-HELP-TEXT!
4261 * This comment is used as a marker to generate the offline documentation
4262 * for commands found in doc/COMMANDS.
4264 new_command("HELP", TRUE, help_command, _(
4265 "HELP [<COMMAND>]\n"
4266 " Show available commands or command specific help text.\n"
4269 new_command("OPEN", FALSE, open_command, _(
4270 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4271 " Opens <filename> using <key>. When the filename is not found on the\n"
4272 " file-system a new document will be created. If the file is found, it is\n"
4273 " looked for in the file cache for an existing key. When found and no key\n"
4274 " was specified, the cached key will be used for decryption (if encrypted).\n"
4275 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4276 " OPTIONS documentation).\n"
4277 "\n"
4278 " When the --lock option is passed then the file mutex will be locked as if\n"
4279 " the LOCK command had been sent after the file had been opened.\n"
4280 "\n"
4281 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4282 " retrieve the filename and key arguments.\n"
4283 "\n"
4284 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4285 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4286 " no value is specified then the configuration file value will be used. If\n"
4287 " the passphrase is invalid then it is up to the client whether to retry or\n"
4288 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4289 " pinentry dialog, use --pinentry=0.\n"
4290 "\n"
4291 " When a \"key_file\" configuration parameter has been set for the current\n"
4292 " file and there is no cache entry, then an --inquire must be used to\n"
4293 " retrieve the key.\n"
4294 "\n"
4295 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4296 " decoded before doing decryption. This allows for binary keys and may also\n"
4297 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4300 new_command("SAVE", FALSE, save_command, _(
4301 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4302 " [--iterations=[N]] [--base64] [<key>]\n"
4303 " Writes the XML document to disk. The file written to is the file that was\n"
4304 " opened using the OPEN command. If <key> is not specified then the\n"
4305 " currently cached key will be used. If the file is a new file or the file\n"
4306 " is not found in the file cache then <key> will be used. If both <key> is\n"
4307 " not specified and the file is not cached then pinentry(1) will be used to\n"
4308 " retrieve the key (see below) unless the configured number of iterations is\n"
4309 " 0 in which case the file will be saved unencrypted.\n"
4310 "\n"
4311 " Note that when both <key> is specified and the configured number of\n"
4312 " iterations is 0 the iterations for the current filename will be reset to\n"
4313 " 1. This is to be on the safe side and prevent misuse.\n"
4314 "\n"
4315 " The --iterations option can be used to change the number of encryption\n"
4316 " iterations for the opened file. When 0 no encryption will be performed.\n"
4317 " When this option is either not passed or is specified without a value then\n"
4318 " the previous setting obtained from the file header will be used.\n"
4319 "\n"
4320 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4321 " string with the --cipher option. Omitting the string uses the current\n"
4322 " cipher of the opened file or the default if the file is a new one. The\n"
4323 " default is specified in the configuration file. See pwmd(1) for available\n"
4324 " ciphers.\n"
4325 "\n"
4326 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4327 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4328 " no value is specified then the configuration file value will be used.\n"
4329 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4330 " is started over again until either the passphrases match or until the\n"
4331 " input is canceled by the user. To save with encryption and with an empty\n"
4332 " passphrase, use --pinentry=0.\n"
4333 "\n"
4334 " When --reset is specified then the cached passphrase for the opened file\n"
4335 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4336 " had been sent.\n"
4337 "\n"
4338 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4339 " retrieve the key.\n"
4340 "\n"
4341 " When a \"key_file\" configuration parameter has been set for the current\n"
4342 " file and there is no cache entry, then an --inquire must be used to\n"
4343 " retrieve the key.\n"
4344 "\n"
4345 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4346 " decoded before doing encryption. This allows for binary keys and may also\n"
4347 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4350 new_command("ISCACHED", TRUE, iscached_command, _(
4351 "ISCACHED <filename>\n"
4352 " An OK response is returned if the specified file is found in the file\n"
4353 " cache. If not found in the cache but exists on the filesystem,\n"
4354 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4357 new_command("CLEARCACHE", TRUE, clearcache_command, _(
4358 "CLEARCACHE [<filename>]\n"
4359 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4360 " the specified file. Always returns an OK response.\n"
4363 new_command("CACHETIMEOUT", TRUE, cachetimeout_command, _(
4364 "CACHETIMEOUT <filename> <seconds>\n"
4365 " Specify the number of seconds the specified file will be cached. -1 will\n"
4366 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4367 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4368 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4369 " invalid. OK otherwise.\n"
4372 new_command("LIST", FALSE, list_command, _(
4373 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4374 " If no element path is given then a newline separated list of root elements\n"
4375 " is returned with the data response. If given, then all reachable elements\n"
4376 " for the specified element path are returned unless the --no-recurse option\n"
4377 " is specified. If specified, only the child elements of the element path\n"
4378 " are returned without recursing into grandchildren. Each element in the\n"
4379 " path is prefixed with the literal '!' character when the element contains\n"
4380 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4381 "\n"
4382 " When the --verbose option is passed then each element path returned in the\n"
4383 " list will have a single space character followed by either a 0 or 1\n"
4384 " appended to it. When 0, the element path has no children, otherwise it\n"
4385 " does have children. When used with the --no-recurse option this may be\n"
4386 " useful to limit the amount of data transferred to the client.\n"
4389 new_command("REALPATH", FALSE, realpath_command, _(
4390 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4391 " Resolves all \"target\" attributes of the specified element path and returns\n"
4392 " the result with a data response.\n"
4395 new_command("STORE", FALSE, store_command, _(
4396 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4397 " Creates a new element path or modifies the content of an existing element\n"
4398 " path. If only a single element is specified, a new root element is\n"
4399 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4400 " to the last TAB delimited argument. If no content is specified after the\n"
4401 " last TAB then the content for the last specified element will be removed,\n"
4402 " or empty when creating a new element.\n"
4403 "\n"
4404 " The only restriction of an element name is that it not contain whitespace\n"
4405 " or begin with the literal element character '!' unless specifying a\n"
4406 " literal element. There is no whitespace between the TAB delimited\n"
4407 " elements. It is recommended that the value or content be base 64 encoded\n"
4408 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4409 " errors.\n"
4410 "\n"
4411 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4414 new_command("RENAME", FALSE, rename_command, _(
4415 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4416 " Renames the specified element to the new value. If an element of the same\n"
4417 " name as the value exists then it will be overwritten.\n"
4420 new_command("COPY", FALSE, copy_command, _(
4421 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4422 " Copies the entire element tree starting from the child node of the source\n"
4423 " element path, to the destination element path. If the destination element\n"
4424 " path does not exist then it will be created; otherwise it is overwritten.\n"
4425 "\n"
4426 " Note that attributes from the source element path are merged into the\n"
4427 " destination element path when the destination element path exists. When an\n"
4428 " attribute of the same name exists in both the source and destination\n"
4429 " element paths then the destination attribute will be updated to the source\n"
4430 " attribute value.\n"
4433 new_command("MOVE", FALSE, move_command, _(
4434 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4435 " Moves the source element path to the destination element path. If the\n"
4436 " destination is not specified then it will be moved to the root of the\n"
4437 " document. If the destination is specified and exists then it will be\n"
4438 " overwritten; otherwise it will be created.\n"
4441 new_command("DELETE", FALSE, delete_command, _(
4442 "DELETE [!]element[<TAB>[!]element[...]]\n"
4443 " Removes the specified element path and any children from the XML document.\n"
4446 new_command("GET", FALSE, get_command, _(
4447 "GET [!]element[<TAB>[!]element[...]]\n"
4448 " Retrieves the content or XML text node of the specified element path. The\n"
4449 " content is returned with a data response.\n"
4452 new_command("ATTR", FALSE, attr_command, _(
4453 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4454 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4455 " Stores or updates an attribute name and optional value of an element\n"
4456 " path.\n"
4457 "\n"
4458 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4459 " Removes an attribute from an element path.\n"
4460 "\n"
4461 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4462 " Retrieves a newline separated list of attributes names and values from\n"
4463 " the specified element path. The attribute names and values are space\n"
4464 " delimited.\n"
4465 "\n"
4466 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4467 " Retrieves the value of an attribute from an element path.\n"
4468 "\n"
4469 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4470 " if the element path is the root element. Although it can be SET to change\n"
4471 " the element name but only if the destination element name doesn't exist.\n"
4472 " Use the RENAME command for that instead.\n"
4473 "\n"
4474 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4475 " either storing content, editing attributes or by deleting a child element.\n"
4476 "\n"
4477 " Also see THE TARGET ATTRIBUTE.\n"
4480 new_command("XPATH", FALSE, xpath_command, _(
4481 "XPATH <expression>[<TAB>[value]]\n"
4482 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4483 " assumed the expression is a request to return a result. Otherwise, the\n"
4484 " result is set to the value argument and the document is updated. If there\n"
4485 " is no value after the <TAB> character, the value is assumed to be empty\n"
4486 " and the document is updated.\n"
4489 new_command("XPATHATTR", FALSE, xpathattr_command, _(
4490 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4491 " Like the XPATH command but operates on element attributes and won't return\n"
4492 " a result. For the SET operation the <value> is optional but the field is\n"
4493 " required in which case the value will be empty.\n"
4496 new_command("IMPORT", FALSE, import_command, _(
4497 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4498 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4499 " data. The content is created as a child of the specified element path. If\n"
4500 " an element of the element path does not exist then it is created. If no\n"
4501 " element path is specified then the content must begin with an pwmd DTD\n"
4502 " root element.\n"
4503 "\n"
4504 " Note that the new content must begin with an XML element node. Also note\n"
4505 " that an existing child node of the same element name as the root node of\n"
4506 " the imported content will be overwritten.\n"
4509 new_command("DUMP", FALSE, dump_command, _(
4510 "DUMP\n"
4511 " Shows the in memory XML document with indenting. To dump a specific\n"
4512 " element tree, use the XPATH command.\n"
4515 new_command("LOCK", FALSE, lock_command, _(
4516 "LOCK\n"
4517 " Locks the mutex associated with the opened file. This prevents other\n"
4518 " clients from sending commands to the same opened file until the client\n"
4519 " that sent this command either disconnects or sends the UNLOCK command.\n"
4522 new_command("UNLOCK", FALSE, unlock_command, _(
4523 "UNLOCK\n"
4524 " Unlocks the file mutex which was locked with the LOCK command.\n"
4527 new_command("GETPID", TRUE, getpid_command, _(
4528 "GETPID\n"
4529 " Retrieves the process id of the server.\n"
4532 new_command("GETCONFIG", TRUE, getconfig_command, _(
4533 "GETCONFIG [filename] <parameter>\n"
4534 " Returns the value of a pwmd configuration variable with a data response.\n"
4535 " If no file has been opened then the value for the specified file or the\n"
4536 " default from the \"global\" section will be returned. If a file has been\n"
4537 " opened and no filename is specified, the value previously set with the SET\n"
4538 " command, if any, will be returned.\n"
4539 "\n"
4540 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4541 " is returned.\n"
4544 new_command("VERSION", TRUE, version_command, _(
4545 "VERSION\n"
4546 " Returns the server version number and compile-time features with a data\n"
4547 " response with each being space delimited.\n"
4550 new_command("SET", TRUE, set_command, _(
4551 "SET <NAME>=<VALUE>\n"
4552 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4553 " option to its default value.\n"
4554 "\n"
4555 " NAME |VALUE |Description\n"
4556 " -----------------|----------|----------------------------------------------\n"
4557 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4558 " is 1.\n"
4559 "\n"
4560 " * Deprecated. Pass --pinentry to the OPEN and\n"
4561 " SAVE commands instead.\n"
4562 "\n"
4563 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4564 " process will terminate while waiting for a\n"
4565 " passphrase. The default is 20, 0 disables.\n"
4566 "\n"
4567 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4568 " is specified at compile time.\n"
4569 "\n"
4570 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4571 "\n"
4572 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4573 "\n"
4574 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4575 "\n"
4576 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4577 "\n"
4578 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4579 "\n"
4580 " DESC <string> Sets the error or description string of the\n"
4581 " pinentry dialog.\n"
4582 "\n"
4583 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4584 "\n"
4585 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4586 " pinentry(1).\n"
4587 "\n"
4588 " NAME <string> Associates the thread ID of the connection\n"
4589 " with the specified textual representation.\n"
4590 " Useful for debugging log messages.\n"
4591 "\n"
4592 " CIPHER <string> The cipher to use for the next SAVE.\n"
4593 "\n"
4594 " * Deprecated. Use --cipher instead.\n"
4595 "\n"
4596 " ITERATIONS <integer> The number of encryption iterations to do\n"
4597 " when the SAVE command is sent. An opened file\n"
4598 " is needed when setting this option. The\n"
4599 " CONFIG status message is sent after receiving\n"
4600 " this command.\n"
4601 "\n"
4602 " * Deprecated. Use --iterations instead.\n"
4603 "\n"
4604 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4605 " after a successful OPEN as if the LOCK\n"
4606 " command had been sent.\n"
4607 "\n"
4608 " * Deprecated. Use --lock instead.\n"
4609 "\n"
4610 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4611 " of a status message when the file mutex is\n"
4612 " locked by another client.\n"
4615 new_command("UNSET", TRUE, unset_command, _(
4616 "UNSET <NAME>\n"
4617 " Resets option NAME to the value specified in the server configuration\n"
4618 " file. Some options have no default and will be reset to NULL or 0\n"
4619 " depending on the value type. See the SET command for available options.\n"
4622 new_command("LS", TRUE, ls_command, _(
4623 "LS\n"
4624 " Lists the contents of the configured data_directory. The result is a\n"
4625 " newline separated list of filenames.\n"
4628 new_command("RESET", TRUE, NULL, _(
4629 "RESET\n"
4630 " Closes the currently opened file but keeps any previously set client\n"
4631 " options.\n"
4634 new_command("BYE", TRUE, NULL, _(
4635 "BYE\n"
4636 " Closes the connection discarding any unsaved changes.\n"
4639 new_command("NOP", TRUE, NULL, _(
4640 "NOP\n"
4641 " Does nothing. Always returns successfully.\n"
4644 /* !END-HELP-TEXT! */
4645 new_command("CANCEL", TRUE, NULL, NULL);
4646 new_command("END", TRUE, NULL, NULL);
4648 gint i;
4649 for (i = 0; command_table[i]; i++);
4650 qsort(command_table, i-1, sizeof(struct command_table_s *), sort_commands);
4653 gpg_error_t register_commands(assuan_context_t ctx)
4655 gint i = 0, rc;
4657 for (; command_table[i]; i++) {
4658 if (!command_table[i]->handler)
4659 continue;
4661 rc = assuan_register_command (ctx, command_table[i]->name,
4662 command_table[i]->handler);
4664 if (rc)
4665 return rc;
4668 rc = assuan_register_bye_notify(ctx, bye_notify);
4670 if (rc)
4671 return rc;
4673 rc = assuan_register_reset_notify(ctx, reset_notify);
4675 if (rc)
4676 return rc;
4678 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4680 if (rc)
4681 return rc;
4683 return assuan_register_post_cmd_notify(ctx, command_finalize);
4686 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4687 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4689 goffset insize, len;
4690 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4691 guint64 iter = 0, n_iter = 0, iter_progress = 0;
4692 gulong outsize = 0;
4693 gpg_error_t rc;
4694 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4695 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4696 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4698 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4699 insize = crypto->fh->st.st_size - fh_size;
4700 crypto->iv = gcry_malloc(crypto->blocksize);
4702 if (!crypto->iv) {
4703 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4704 return GPG_ERR_ENOMEM;
4707 if (crypto->fh->v1)
4708 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4709 else
4710 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4712 crypto->inbuf = gcry_malloc(insize);
4714 if (!crypto->inbuf) {
4715 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4716 return GPG_ERR_ENOMEM;
4719 crypto->insize = insize;
4720 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4722 if (len != crypto->insize)
4723 return GPG_ERR_INV_LENGTH;
4725 /* No encryption iterations. This is a plain (gzipped) file. */
4726 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4727 (!crypto->fh->v1 && fh_iter <= 0L)) {
4729 * cache_file_count() needs both .used == TRUE and a valid key in
4730 * order for it to count as a used cache entry. Fixes CACHE status
4731 * messages.
4733 memset(crypto->key, '!', hashlen);
4734 goto decompress;
4737 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4738 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4739 return rc;
4742 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4743 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4744 return rc;
4747 iter_progress = get_key_file_uint64(client && client->filename ?
4748 client->filename : "global", "iteration_progress");
4750 if (iter_progress > 0 && fh_iter >= iter_progress) {
4751 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4753 if (rc)
4754 return rc;
4757 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4759 if (rc)
4760 return rc;
4762 crypto->tkey = gcry_malloc(hashlen);
4764 if (!crypto->tkey) {
4765 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4766 return GPG_ERR_ENOMEM;
4769 memcpy(crypto->tkey, crypto->key, hashlen);
4770 guchar *tkey = crypto->tkey;
4771 tkey[0] ^= 1;
4773 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4774 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4775 return rc;
4778 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4779 if (iter_progress > 0ULL && iter >= iter_progress) {
4780 if (!(iter % iter_progress)) {
4781 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4782 ++n_iter * iter_progress, fh_iter);
4784 if (rc)
4785 return rc;
4789 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4790 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4791 return rc;
4794 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4796 if (rc) {
4797 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4798 return rc;
4801 iter++;
4804 if (iter_progress && fh_iter >= iter_progress) {
4805 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4807 if (rc)
4808 return rc;
4811 decompress:
4812 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4813 len = 0;
4815 if (crypto->fh->ver.fh2.iter > 0ULL) {
4816 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4817 return GPG_ERR_INV_PASSPHRASE;
4819 len = sizeof(crypto_magic);
4822 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4823 (gpointer *)&crypto->outbuf, &outsize);
4825 if (rc)
4826 return rc;
4828 else {
4829 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4830 (gpointer *)&crypto->outbuf, &outsize);
4832 if (rc == GPG_ERR_ENOMEM)
4833 return rc;
4834 else if (rc)
4835 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4837 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4838 gcry_free(crypto->outbuf);
4839 crypto->outbuf = NULL;
4840 return GPG_ERR_INV_PASSPHRASE;
4844 if (ctx) {
4845 client->xml = crypto->outbuf;
4846 client->len = outsize;
4847 crypto->outbuf = NULL;
4849 else if (dst) {
4850 *dst = crypto->outbuf;
4851 *dst_len = outsize;
4852 crypto->outbuf = NULL;
4855 /* The calling function should free the crypto struct. */
4856 return 0;