Use glib's command line option parser.
[pwmd.git] / src / commands.c
blob28c5d8f8b619d6843c810b1050d4eb3859bf6dd5
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 <gcrypt.h>
34 #include <zlib.h>
35 #include <dirent.h>
37 #ifdef WITH_LIBACL
38 #include <sys/acl.h>
39 #endif
41 #include "mem.h"
42 #include "xml.h"
43 #include "common.h"
45 #ifdef WITH_PINENTRY
46 #include "pinentry.h"
47 #endif
49 #include "pwmd_error.h"
50 #include "cache.h"
51 #include "misc.h"
52 #include "commands.h"
53 #include "mutex.h"
54 #include "rcfile.h"
56 struct gz_s {
57 z_stream z;
58 gpointer out;
59 gboolean done;
60 status_msg_t which;
63 struct command_table_s {
64 const gchar *name;
65 gint (*handler)(assuan_context_t, gchar *line);
66 const gchar *help;
67 gboolean ignore_startup;
70 static struct command_table_s **command_table;
71 static guchar crypto_magic[5] = "\177PWMD";
73 static gpg_error_t do_lock_command(struct client_s *client);
75 static void *z_alloc(void *data, unsigned items, unsigned size)
77 return gcry_calloc(items, size);
80 static void z_free(void *data, void *p)
82 gcry_free(p);
85 static gpg_error_t file_modified(struct client_s *client)
87 struct stat st;
88 gpg_error_t rc;
90 if (client->state != STATE_OPEN)
91 return EPWMD_NO_FILE;
93 rc = lock_file_mutex(client);
95 if (rc)
96 return rc;
98 if (lstat(client->filename, &st) == 0 && client->mtime) {
99 if (client->mtime != st.st_mtime)
100 return EPWMD_FILE_MODIFIED;
103 pth_cancel_point();
104 return 0;
107 static gpg_error_t parse_xml(assuan_context_t ctx)
109 struct client_s *client = assuan_get_pointer(ctx);
111 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
113 if (!client->doc)
114 return EPWMD_LIBXML_ERROR;
116 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
117 return 0;
119 return convert_elements(client->doc);
122 void unlock_file_mutex(struct client_s *client)
124 pth_mutex_t *m;
126 if (client->has_lock == FALSE)
127 return;
129 CACHE_LOCK(client->ctx);
131 if (cache_get_mutex(client->md5file, &m) == FALSE) {
132 CACHE_UNLOCK;
133 return;
136 CACHE_UNLOCK;
137 MUTEX_UNLOCK(m);
138 client->has_lock = client->is_lock_cmd = FALSE;
141 gpg_error_t lock_file_mutex(struct client_s *client)
143 pth_mutex_t *m;
144 gpg_error_t rc = 0;
146 if (client->has_lock == TRUE)
147 return 0;
149 CACHE_LOCK(client->ctx);
151 if (cache_get_mutex(client->md5file, &m) == FALSE) {
152 CACHE_UNLOCK;
153 return 0;
156 CACHE_UNLOCK;
158 if (client->rc_on_locked) {
159 if (!pth_mutex_acquire(m, TRUE, NULL))
160 return GPG_ERR_LOCKED;
161 #ifdef MUTEX_DEBUG
162 MUTEX_LOCK_DEBUG(m);
163 #endif
165 else
166 MUTEX_TRYLOCK(client, m, rc);
168 if (!rc)
169 client->has_lock = TRUE;
171 return rc;
174 void free_client(struct client_s *client)
176 if (client->doc)
177 xmlFreeDoc(client->doc);
179 if (client->xml)
180 gcry_free(client->xml);
182 if (client->filename)
183 g_free(client->filename);
185 if (client->crypto)
186 cleanup_crypto(&client->crypto);
188 if (client->xml_error)
189 xmlResetError(client->xml_error);
192 void cleanup_client(struct client_s *client)
194 assuan_context_t ctx = client->ctx;
195 struct client_thread_s *thd = client->thd;
196 gboolean rc_on_locked = client->rc_on_locked;
197 gboolean lock_on_open = client->lock_on_open;
198 #ifdef WITH_PINENTRY
199 struct pinentry_s *pin = client->pinentry;
200 #endif
202 unlock_file_mutex(client);
203 CACHE_LOCK(client->ctx);
204 cache_decr_refcount(client->md5file);
207 * This may be a new file so don't use a cache slot. save_command() will
208 * set this to FALSE on success.
210 if (client->new == TRUE)
211 cache_clear(client->md5file, 1);
213 CACHE_UNLOCK;
214 free_client(client);
215 memset(client, 0, sizeof(struct client_s));
216 client->state = STATE_CONNECTED;
217 client->ctx = ctx;
218 client->thd = thd;
219 client->freed = TRUE;
220 #ifdef WITH_PINENTRY
221 client->pinentry = pin;
222 #endif
223 client->rc_on_locked = rc_on_locked;
224 client->lock_on_open = lock_on_open;
227 static void gz_cleanup(void *arg)
229 struct gz_s **gz = (struct gz_s **)arg;
231 if (!gz)
232 return;
234 if (!(*gz)->done && (*gz)->out)
235 gcry_free((*gz)->out);
237 if ((*gz)->which == STATUS_COMPRESS) {
238 if ((*gz)->z.zalloc)
239 deflateEnd(&(*gz)->z);
241 else {
242 if ((*gz)->z.zalloc)
243 inflateEnd(&(*gz)->z);
246 g_free(*gz);
247 *gz = NULL;
250 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
251 gpointer *out, gulong *outsize)
253 struct gz_s *gz;
254 gz_header h;
255 gchar buf[17];
256 gpg_error_t rc;
257 gint zrc;
259 gz = g_malloc0(sizeof(struct gz_s));
261 if (!gz)
262 return GPG_ERR_ENOMEM;
264 pth_cleanup_push(gz_cleanup, &gz);
265 gz->which = STATUS_DECOMPRESS;
266 gz->z.zalloc = z_alloc;
267 gz->z.zfree = z_free;
268 gz->z.next_in = in;
269 gz->z.avail_in = (uInt)insize;
270 gz->z.avail_out = zlib_bufsize;
271 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
273 if (!gz->out) {
274 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
275 pth_cleanup_pop(1);
276 return GPG_ERR_ENOMEM;
279 zrc = inflateInit2(&gz->z, 47);
281 if (zrc != Z_OK) {
282 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
283 pth_cleanup_pop(1);
284 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
287 memset(&h, 0, sizeof(gz_header));
288 h.comment = (guchar *)buf;
289 h.comm_max = sizeof(buf);
290 zrc = inflateGetHeader(&gz->z, &h);
292 if (zrc != Z_OK) {
293 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
294 pth_cleanup_pop(1);
295 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
298 zrc = inflate(&gz->z, Z_BLOCK);
300 if (zrc != Z_OK) {
301 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
302 pth_cleanup_pop(1);
303 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
306 if (h.comment)
307 insize = strtoul((gchar *)h.comment, NULL, 10);
309 do {
310 gpointer p;
312 zrc = inflate(&gz->z, Z_FINISH);
314 switch (zrc) {
315 case Z_OK:
316 break;
317 case Z_BUF_ERROR:
318 if (!gz->z.avail_out) {
319 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
321 if (!p) {
322 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
323 rc = GPG_ERR_ENOMEM;
324 goto fail;
327 gz->out = p;
328 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
329 gz->z.avail_out = zlib_bufsize;
330 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
331 gz->z.total_out, insize);
333 if (rc)
334 goto fail;
336 break;
337 case Z_STREAM_END:
338 break;
339 default:
340 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
341 rc = GPG_ERR_COMPR_ALGO;
342 goto fail;
343 break;
345 } while (zrc != Z_STREAM_END);
347 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
348 insize);
350 if (rc)
351 goto fail;
353 *out = gz->out;
354 *outsize = gz->z.total_out;
355 gz->done = TRUE;
356 pth_cleanup_pop(1);
357 return 0;
359 fail:
360 pth_cleanup_pop(1);
361 return rc;
364 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
365 gpg_error_t *rc)
367 gint fd;
368 gsize len;
369 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
370 gsize fh_size;
371 gpointer p;
373 *rc = 0;
375 if (!fh) {
376 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
377 *rc = GPG_ERR_ENOMEM;
378 return NULL;
381 pth_cleanup_push(g_free, fh);
382 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
384 if (lstat(filename, &fh->st) == -1) {
385 *rc = gpg_error_from_syserror();
386 pth_cleanup_pop(1);
387 return NULL;
390 if (!S_ISREG(fh->st.st_mode)) {
391 *rc = GPG_ERR_ENOANO;
392 pth_cleanup_pop(1);
393 return NULL;
396 fd = open(filename, O_RDONLY);
398 if (fd == -1) {
399 *rc = gpg_error_from_syserror();
400 pth_cleanup_pop(1);
401 return NULL;
404 pth_cleanup_push(cleanup_fd_cb, &fd);
405 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
406 len = pth_read(fd, p, fh_size);
408 if (len != fh_size) {
409 *rc = gpg_error_from_syserror();
410 pth_cleanup_pop(1);
411 pth_cleanup_pop(1);
412 return NULL;
415 fh->v1 = v1;
416 fh->fd = fd;
417 pth_cleanup_pop(0);
418 pth_cleanup_pop(0);
419 return fh;
422 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
423 gboolean cached)
425 struct client_s *client = assuan_get_pointer(ctx);
426 gpg_error_t rc;
427 gint timeout;
428 guchar *key = client->crypto->key;
430 /* New file. */
431 if (!client->crypto->fh) {
432 if (key[0])
433 goto update_cache;
435 goto done;
438 rc = init_client_crypto2(client->filename, client->crypto);
440 if (rc) {
441 cleanup_client(client);
442 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
445 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
447 if (rc) {
448 cleanup_client(client);
449 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
452 update_cache:
453 CACHE_LOCK(client->ctx);
455 if (cached == FALSE) {
456 if (cache_update_key(client->md5file, key) == FALSE) {
457 cleanup_client(client);
458 CACHE_UNLOCK;
459 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
462 timeout = get_key_file_integer(client->filename, "cache_timeout");
463 cache_reset_timeout(client->md5file, timeout);
465 else
466 cache_set_timeout(client->md5file, -2);
468 CACHE_UNLOCK;
470 done:
471 rc = parse_xml(ctx);
473 if (client->xml) {
474 gcry_free(client->xml);
475 client->xml = NULL;
478 if (!rc) {
479 if (client->new == FALSE)
480 send_status_all(STATUS_CACHE);
482 client->state = STATE_OPEN;
485 if (!rc && client->new == FALSE &&
486 client->crypto->fh->ver.fh2.iter != get_key_file_uint64(client->filename, "iterations")) {
487 gchar *s = g_strdup_printf("%llu", client->crypto->fh->ver.fh2.iter);
489 MUTEX_LOCK(&rcfile_mutex);
490 g_key_file_set_value(keyfileh, client->filename, "iterations", s);
491 g_free(s);
492 MUTEX_UNLOCK(&rcfile_mutex);
493 send_status_all(STATUS_CONFIG);
496 cleanup_crypto(&client->crypto);
498 if (!rc && client->lock_on_open)
499 return do_lock_command(client);
501 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
504 static void req_cleanup(void *arg)
506 if (!arg)
507 return;
509 g_strfreev((gchar **)arg);
512 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
514 struct client_s *client = data;
515 const gchar *p = value;
517 if (p && *p) {
518 gint n = atoi(p);
520 if (n < 0 || n > 1)
521 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
523 client->lock_on_open = n ? TRUE : FALSE;
525 else if ((!p || !*p) && (client->opts & OPT_LOCK))
526 client->lock_on_open = FALSE;
527 else
528 client->lock_on_open = TRUE;
530 return 0;
533 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
535 #ifdef WITH_PINENTRY
536 struct client_s *client = data;
537 gchar *p = NULL;
538 gchar *str = value;
539 gint n;
541 if (!str || !*str) {
542 client->pinentry->enable = -1;
543 client->opts &= ~(OPT_PINENTRY);
544 return 0;
547 n = atoi(str);
549 if (*p || n < 0 || n > 1)
550 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
552 client->pinentry->enable = n ? TRUE : FALSE;
553 client->opts |= OPT_PINENTRY;
554 return 0;
555 #else
556 return GPG_ERR_NOT_IMPLEMENTED;
557 #endif
560 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
562 struct client_s *client = data;
564 (void)value;
565 client->opts |= OPT_INQUIRE;
566 return 0;
569 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
571 struct client_s *client = data;
573 (void)value;
574 client->opts |= OPT_BASE64;
575 return 0;
578 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
580 guchar *tmp;
581 gsize len;
583 if (client->opts & OPT_BASE64)
584 tmp = g_base64_decode(key, &len);
585 else {
586 tmp = (guchar *)g_strdup(key);
587 len = strlen(key);
590 if (!tmp)
591 return GPG_ERR_ENOMEM;
593 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
594 g_free(tmp);
595 return 0;
598 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
600 gboolean cached = FALSE;
601 gpg_error_t rc;
602 struct client_s *client = assuan_get_pointer(ctx);
603 gchar **req;
604 gchar *filename = NULL;
605 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
607 if ((req = split_input_line(line, " ", 2)) != NULL)
608 filename = req[0];
610 pth_cleanup_push(req_cleanup, req);
612 if (!filename || !*filename) {
613 pth_cleanup_pop(1);
614 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
617 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
619 if (valid_filename(filename) == FALSE) {
620 pth_cleanup_pop(1);
621 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
624 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
625 CACHE_LOCK(client->ctx);
627 if (cache_has_file(client->md5file) == FALSE) {
628 if (cache_add_file(client->md5file, NULL) == FALSE) {
629 pth_cleanup_pop(1);
630 CACHE_UNLOCK;
631 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
635 CACHE_UNLOCK;
636 rc = lock_file_mutex(client);
638 if (rc) {
639 pth_cleanup_pop(1);
640 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
643 client->freed = FALSE;
644 CACHE_LOCK(client->ctx);
645 cache_incr_refcount(client->md5file);
646 CACHE_UNLOCK;
647 client->crypto = init_client_crypto();
649 if (!client->crypto) {
650 pth_cleanup_pop(1);
651 cleanup_client(client);
652 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
655 client->crypto->key = gcry_malloc(hashlen);
657 if (!client->crypto->key) {
658 pth_cleanup_pop(1);
659 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
660 GPG_ERR_ENOMEM);
661 cleanup_client(client);
662 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
665 memset(client->crypto->key, 0, hashlen);
666 client->crypto->fh = read_file_header(filename, FALSE, &rc);
668 if (!client->crypto->fh) {
669 if (gpg_err_code_to_errno(rc) != ENOENT) {
670 log_write("%s: %s", filename, pwmd_strerror(rc));
671 pth_cleanup_pop(1);
672 cleanup_client(client);
673 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
677 * New files don't need a key.
679 if ((client->xml = new_document()) == NULL) {
680 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
681 pth_cleanup_pop(1);
682 cleanup_client(client);
683 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
686 client->len = xmlStrlen(client->xml);
687 client->new = TRUE;
688 client->filename = g_strdup(filename);
690 if (!client->filename) {
691 pth_cleanup_pop(1);
692 cleanup_client(client);
693 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
694 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
697 if (req[1] && *req[1]) {
698 rc = hash_key(client, req[1]);
700 if (rc) {
701 pth_cleanup_pop(1);
702 cleanup_client(client);
703 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
707 pth_cleanup_pop(1);
708 #ifdef WITH_PINENTRY
709 client->pinentry->filename = g_strdup(client->filename);
711 if (!client->pinentry->filename) {
712 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
713 cleanup_client(client);
714 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
716 #endif
717 return open_command_finalize(ctx, NULL, cached);
719 else {
720 if (!(client->opts & OPT_CIPHER))
721 g_key_file_set_string(keyfileh, filename, "cipher",
722 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
724 client->mtime = client->crypto->fh->st.st_mtime;
727 client->filename = g_strdup(filename);
729 if (!client->filename) {
730 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
731 pth_cleanup_pop(1);
732 cleanup_client(client);
733 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
736 #ifdef WITH_PINENTRY
737 if (client->pinentry->filename)
738 g_free(client->pinentry->filename);
740 client->pinentry->filename = g_strdup(client->filename);
742 if (!client->pinentry->filename) {
743 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
744 pth_cleanup_pop(1);
745 cleanup_client(client);
746 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
748 #endif
750 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
751 goto done;
753 CACHE_LOCK(client->ctx);
754 cached = cache_get_key(client->md5file, client->crypto->key);
755 CACHE_UNLOCK;
757 if (cached == FALSE) {
758 gchar *tmp = get_key_file_string(filename, "key_file");
760 if (tmp && !(client->opts & OPT_INQUIRE)) {
761 g_free(tmp);
762 pth_cleanup_pop(1);
763 cleanup_client(client);
764 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
767 if (tmp)
768 g_free(tmp);
771 * No key specified and no matching filename found in the cache. Use
772 * pinentry to retrieve the key. Cannot return assuan_process_done()
773 * here otherwise the command will be interrupted. The event loop in
774 * client_thread() will poll the file descriptor waiting for it to
775 * become ready to read a pinentry_key_s which will contain the
776 * entered key or an error code. It will then call
777 * open_command_finalize() to to finish the command.
779 if (!req[1] || !*req[1]) {
780 #ifdef WITH_PINENTRY
781 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
783 /* From set_pinentry_defaults(). */
784 if (client->opts & OPT_INQUIRE ||
785 client->pinentry->enable == FALSE ||
786 (client->pinentry->enable == -1 && b == FALSE)) {
787 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
788 goto done;
791 pth_cleanup_pop(1);
792 rc = lock_pin_mutex(client);
794 if (rc) {
795 unlock_pin_mutex(client->pinentry);
796 cleanup_client(client);
797 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
800 client->pinentry->which = PINENTRY_OPEN;
801 rc = pinentry_fork(ctx);
803 if (rc) {
804 unlock_pin_mutex(client->pinentry);
805 cleanup_client(client);
806 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
809 // Called from pinentry iterate.
810 client->pinentry->cb = open_command_finalize;
811 client->pinentry->status = PINENTRY_INIT;
812 return 0;
813 #else
814 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
815 goto done;
816 #endif
819 rc = hash_key(client, req[1]);
821 if (rc) {
822 pth_cleanup_pop(1);
823 cleanup_client(client);
824 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
827 else if (req && req[1] && *req[1]) {
828 rc = hash_key(client, req[1]);
830 if (rc) {
831 pth_cleanup_pop(1);
832 cleanup_client(client);
833 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
837 done:
838 pth_cleanup_pop(1);
839 return open_command_finalize(ctx, NULL, cached);
842 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
843 guchar *line, gsize len)
845 assuan_context_t ctx = data;
846 struct client_s *client = assuan_get_pointer(ctx);
847 gpg_error_t rc = file_modified(client);
849 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
850 if (line)
851 xfree(line);
853 return assuan_rc ? assuan_rc : rc;
856 rc = open_command_common(ctx, (gchar *)line);
858 if (line)
859 xfree(line);
861 client->inquire_status = INQUIRE_DONE;
862 return rc;
865 static gint open_command(assuan_context_t ctx, gchar *line)
867 gpg_error_t rc;
868 struct client_s *client = assuan_get_pointer(ctx);
869 struct argv_s *args[] = {
870 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
871 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
872 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
873 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
874 NULL
877 if (client->state == STATE_OPEN)
878 cleanup_client(client);
880 if (!(client->opts & OPT_LOCK))
881 client->lock_on_open = FALSE;
883 rc = parse_options(&line, args, client);
885 if (rc)
886 return send_error(ctx, rc);
888 if ((client->opts & OPT_INQUIRE)) {
889 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
890 ctx);
892 if (rc)
893 return send_error(ctx, rc);
895 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
896 client->inquire_status = INQUIRE_BUSY;
897 return 0;
900 return open_command_common(ctx, line);
903 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
904 guint size, gpointer *out, gulong *outsize)
906 struct gz_s *gz;
907 gz_header h;
908 gchar buf[17];
909 gint cmd = Z_NO_FLUSH;
910 gint zrc;
911 gpg_error_t rc;
913 gz = g_malloc0(sizeof(struct gz_s));
915 if (!gz)
916 return GPG_ERR_ENOMEM;
918 pth_cleanup_push(gz_cleanup, &gz);
919 gz->which = STATUS_COMPRESS;
920 gz->z.zalloc = z_alloc;
921 gz->z.zfree = z_free;
922 gz->z.next_in = data;
923 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
924 gz->z.avail_out = (uInt)zlib_bufsize;
925 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
927 if (!gz->out) {
928 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
929 pth_cleanup_pop(1);
930 return GPG_ERR_ENOMEM;
933 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
935 if (zrc != Z_OK) {
936 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
937 pth_cleanup_pop(1);
938 return GPG_ERR_COMPR_ALGO;
941 /* Rather than store the size of the uncompressed data in the file header,
942 * store it in the comment field of the gzip header. Don't give anyone too
943 * much information. Not sure why really, but it seems the right way. :)
945 memset(&h, 0, sizeof(gz_header));
946 g_snprintf(buf, sizeof(buf), "%u", size);
947 h.comment = (guchar *)buf;
948 zrc = deflateSetHeader(&gz->z, &h);
950 if (zrc != Z_OK) {
951 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
952 pth_cleanup_pop(1);
953 return GPG_ERR_COMPR_ALGO;
956 do {
957 gpointer p;
959 zrc = deflate(&gz->z, cmd);
961 switch (zrc) {
962 case Z_OK:
963 break;
964 case Z_BUF_ERROR:
965 if (!gz->z.avail_out) {
966 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
968 if (!p) {
969 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
970 rc = GPG_ERR_ENOMEM;
971 goto fail;
974 gz->out = p;
975 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
976 gz->z.avail_out = zlib_bufsize;
979 if (!gz->z.avail_in && gz->z.total_in < size) {
980 if (gz->z.total_in + zlib_bufsize > size)
981 gz->z.avail_in = size - gz->z.total_in;
982 else
983 gz->z.avail_in = zlib_bufsize;
985 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
986 gz->z.total_in, size);
988 if (rc)
989 goto fail;
992 if (gz->z.total_in >= size)
993 cmd = Z_FINISH;
995 break;
996 case Z_STREAM_END:
997 break;
998 default:
999 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
1000 rc = GPG_ERR_COMPR_ALGO;
1001 goto fail;
1003 } while (zrc != Z_STREAM_END);
1005 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1007 if (rc)
1008 goto fail;
1010 *out = gz->out;
1011 *outsize = gz->z.total_out;
1012 gz->done = TRUE;
1013 pth_cleanup_pop(1);
1014 return 0;
1016 fail:
1017 pth_cleanup_pop(1);
1018 return rc;
1021 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1024 * Useful for a large amount of data. Rather than doing all of the data in one
1025 * iteration do it in chunks. This lets the command be cancelable rather than
1026 * waiting for it to complete.
1028 static gpg_error_t iterate_crypto_once(struct client_s *client,
1029 struct crypto_s *crypto, status_msg_t which)
1031 gpg_error_t rc = 0;
1032 goffset len = CRYPTO_BLOCKSIZE(crypto);
1033 gpointer p = gcry_malloc(len);
1034 goffset total = 0;
1035 gpointer inbuf;
1037 if (!p)
1038 return GPG_ERR_ENOMEM;
1040 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1041 len = crypto->insize;
1043 pth_cleanup_push(gcry_free, p);
1045 for (;;) {
1046 inbuf = (guchar *)crypto->inbuf + total;
1047 guchar *tmp;
1049 if (len + total > crypto->insize)
1050 len = crypto->blocksize;
1052 if (which == STATUS_ENCRYPT)
1053 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1054 else
1055 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1057 if (rc)
1058 goto done;
1060 tmp = (guchar *)crypto->inbuf + total;
1061 memmove(tmp, p, len);
1062 total += len;
1064 if (total >= crypto->insize)
1065 break;
1067 pth_cancel_point();
1070 done:
1071 pth_cleanup_pop(1);
1072 return rc;
1075 /* The crypto struct must be setup for iterations and .key. */
1076 gpg_error_t do_xml_encrypt(struct client_s *client,
1077 struct crypto_s *crypto, const gchar *filename)
1079 goffset len = crypto->insize;
1080 gpointer inbuf;
1081 gchar *p;
1082 gpg_error_t rc;
1083 guint64 iter_progress = 0, n_iter = 0, xiter = 0;
1084 gchar tmp[FILENAME_MAX];
1085 struct stat st;
1086 mode_t mode = 0;
1087 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1089 if (!crypto->fh->ver.fh2.iter) {
1091 * cache_file_count() needs both .used == TRUE and a valid key in
1092 * order for it to count as a used cache entry. Fixes CACHE status
1093 * messages.
1095 memset(crypto->key, '!', hashlen);
1096 goto write_file;
1100 * Resize the existing xml buffer to the block size required by gcrypt
1101 * rather than duplicating it and wasting memory.
1103 crypto->insize += sizeof(crypto_magic);
1104 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1106 if (crypto->insize % crypto->blocksize)
1107 len += crypto->blocksize;
1109 inbuf = gcry_realloc(crypto->inbuf, len);
1111 if (!inbuf) {
1112 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1113 return GPG_ERR_ENOMEM;
1116 guchar *tmpbuf = inbuf;
1117 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1118 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1119 crypto->inbuf = tmpbuf;
1120 crypto->insize = len;
1121 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1123 if (crypto->tkey)
1124 gcry_free(crypto->tkey);
1126 crypto->tkey = gcry_malloc(hashlen);
1128 if (!crypto->tkey) {
1129 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1130 return GPG_ERR_ENOMEM;
1133 memcpy(crypto->tkey, crypto->key, hashlen);
1134 guchar *tkey = crypto->tkey;
1135 tkey[0] ^= 1;
1137 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1138 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1139 return rc;
1142 iter_progress = get_key_file_uint64(
1143 client ? client->filename : "global", "iteration_progress");
1145 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1146 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1147 "0 %llu", crypto->fh->ver.fh2.iter);
1149 if (rc)
1150 return rc;
1153 while (xiter < crypto->fh->ver.fh2.iter-1) {
1154 if (iter_progress > 0ULL && xiter >= iter_progress) {
1155 if (!(xiter % iter_progress)) {
1156 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1157 "%llu %llu", ++n_iter * iter_progress,
1158 crypto->fh->ver.fh2.iter);
1160 if (rc)
1161 return rc;
1165 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1166 crypto->blocksize))) {
1167 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1168 return rc;
1171 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1173 if (rc) {
1174 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1175 return rc;
1178 xiter++;
1181 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1182 crypto->blocksize))) {
1183 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1184 return rc;
1187 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1188 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1189 return rc;
1192 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1194 if (rc)
1195 return rc;
1197 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1198 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1199 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1201 if (rc)
1202 return rc;
1205 write_file:
1206 tmp[0] = 0;
1208 if (filename) {
1209 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1210 crypto->fh->fd = STDOUT_FILENO;
1211 goto do_write_file;
1214 if (lstat(filename, &st) == 0) {
1215 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1217 if (!(mode & S_IWUSR))
1218 return GPG_ERR_EACCES;
1220 else if (errno != ENOENT)
1221 return gpg_error_from_syserror();
1223 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1224 #if GLIB_CHECK_VERSION(2, 22, 0)
1225 crypto->fh->fd = g_mkstemp_full(tmp, O_WRONLY, 0600);
1226 #else
1227 crypto->fh->fd = mkstemp(tmp);
1228 #endif
1230 if (crypto->fh->fd == -1) {
1231 rc = gpg_error_from_syserror();
1232 p = strrchr(tmp, '/');
1233 p++;
1234 log_write("%s: %s", p, pwmd_strerror(rc));
1235 return rc;
1238 pth_cleanup_push(cleanup_unlink_cb, tmp);
1240 else
1242 * xml_import() or convert_file() from command line.
1244 crypto->fh->fd = STDOUT_FILENO;
1246 do_write_file:
1247 crypto->fh->ver.fh2.magic[0] = '\177';
1248 crypto->fh->ver.fh2.magic[1] = 'P';
1249 crypto->fh->ver.fh2.magic[2] = 'W';
1250 crypto->fh->ver.fh2.magic[3] = 'M';
1251 crypto->fh->ver.fh2.magic[4] = 'D';
1252 crypto->fh->ver.fh2.version = VERSION_HEX;
1253 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1255 if (len != sizeof(crypto->fh->ver.fh2)) {
1256 rc = gpg_error_from_syserror();
1258 if (tmp[0])
1259 pth_cleanup_pop(1);
1261 return rc;
1264 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1266 if (len != crypto->insize) {
1267 rc = gpg_error_from_syserror();
1269 if (tmp[0])
1270 pth_cleanup_pop(1);
1272 return rc;
1275 if (fsync(crypto->fh->fd) == -1) {
1276 rc = gpg_error_from_syserror();
1278 if (tmp[0])
1279 pth_cleanup_pop(1);
1281 return rc;
1284 if (tmp[0]) {
1285 #ifdef WITH_LIBACL
1286 acl_t acl;
1287 #endif
1288 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1289 gchar tmp2[FILENAME_MAX];
1291 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1292 #ifdef WITH_LIBACL
1293 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1295 if (!acl)
1296 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1297 #endif
1299 if (rename(filename, tmp2) == -1) {
1300 rc = gpg_error_from_syserror();
1301 pth_cleanup_pop(1);
1302 #ifdef WITH_LIBACL
1303 if (acl)
1304 acl_free(acl);
1305 #endif
1306 return rc;
1309 #ifdef WITH_LIBACL
1310 else {
1311 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1313 if (!acl)
1314 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1316 #endif
1318 if (rename(tmp, filename) == -1) {
1319 rc = gpg_error_from_syserror();
1320 pth_cleanup_pop(1);
1321 #ifdef WITH_LIBACL
1322 if (acl)
1323 acl_free(acl);
1324 #endif
1325 return rc;
1328 pth_cleanup_pop(0);
1330 if (mode)
1331 chmod(filename, mode);
1333 #ifdef WITH_LIBACL
1334 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1335 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1337 if (acl)
1338 acl_free(acl);
1339 #endif
1342 if (client && lstat(filename, &st) == 0)
1343 client->mtime = st.st_mtime;
1345 return 0;
1348 gpg_error_t update_save_flags(const gchar *filename,
1349 struct crypto_s *crypto)
1351 gpg_error_t rc;
1353 /* New file? */
1354 if (!crypto->fh) {
1355 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1357 if (!crypto->fh)
1358 return GPG_ERR_ENOMEM;
1361 rc = init_client_crypto2(filename, crypto);
1363 if (rc)
1364 return rc;
1366 if (filename && !crypto->fh->v1)
1367 crypto->fh->ver.fh2.iter = get_key_file_uint64(filename, "iterations");
1369 return 0;
1372 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1373 gboolean cached)
1375 struct client_s *client = assuan_get_pointer(ctx);
1376 gpointer xmlbuf;
1377 gulong outsize = 0;
1378 guint len;
1379 gint clevel;
1380 gint timeout;
1381 gpointer outbuf;
1382 gpg_error_t rc;
1384 if (client->crypto->key && client->crypto->key != key)
1385 gcry_free(client->crypto->key);
1387 client->crypto->key = key;
1388 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1390 if (rc) {
1391 cleanup_crypto(&client->crypto);
1392 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1395 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1396 pth_cleanup_push(xmlFree, xmlbuf);
1397 clevel = get_key_file_integer(client->filename, "compression_level");
1399 if (clevel < 0)
1400 clevel = 0;
1402 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1404 if (rc) {
1405 pth_cleanup_pop(1);
1406 cleanup_crypto(&client->crypto);
1408 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1410 else {
1411 pth_cleanup_pop(1);
1412 xmlbuf = outbuf;
1413 len = outsize;
1416 client->crypto->inbuf = xmlbuf;
1417 client->crypto->insize = len;
1418 rc = update_save_flags(client->filename, client->crypto);
1420 if (rc) {
1421 cleanup_crypto(&client->crypto);
1422 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1423 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1426 rc = do_xml_encrypt(client, client->crypto, client->filename);
1428 if (rc) {
1429 cleanup_crypto(&client->crypto);
1430 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1433 timeout = get_key_file_integer(client->filename, "cache_timeout");
1434 CACHE_LOCK(client->ctx);
1436 if (cached) {
1437 cache_reset_timeout(client->md5file, timeout);
1438 CACHE_UNLOCK;
1440 if (client->new == TRUE)
1441 send_status_all(STATUS_CACHE);
1443 client->new = FALSE;
1444 cleanup_crypto(&client->crypto);
1445 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1448 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1449 CACHE_UNLOCK;
1450 cleanup_crypto(&client->crypto);
1451 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1454 client->new = FALSE;
1455 cache_reset_timeout(client->md5file, timeout);
1456 CACHE_UNLOCK;
1457 send_status_all(STATUS_CACHE);
1458 cleanup_crypto(&client->crypto);
1459 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1462 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1464 struct client_s *client = data;
1465 guint64 n;
1466 gchar *value = v;
1467 gchar *p = NULL;
1469 if (!client->filename)
1470 return EPWMD_NO_FILE;
1472 if (!value || !*value)
1473 return 0;
1475 errno = 0;
1476 n = g_ascii_strtoull(value, &p, 10);
1478 if (errno || (p && *p) || n == G_MAXUINT64)
1479 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1481 MUTEX_LOCK(&rcfile_mutex);
1482 p = g_strdup_printf("%llu", n);
1483 g_key_file_set_value(keyfileh,
1484 client->filename ? client->filename : "global", "iterations", p);
1485 g_free(p);
1486 MUTEX_UNLOCK(&rcfile_mutex);
1488 if (client->filename)
1489 client->opts |= OPT_ITERATIONS;
1491 return 0;
1494 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1496 struct client_s *client = data;
1497 const gchar *p = value;
1498 guint64 flags;
1500 if (!client->filename)
1501 return EPWMD_NO_FILE;
1503 if (!p || !*p)
1504 return 0;
1506 flags = pwmd_cipher_str_to_cipher(p);
1508 if (!flags)
1509 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1511 MUTEX_LOCK(&rcfile_mutex);
1512 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1513 MUTEX_UNLOCK(&rcfile_mutex);
1515 if (!value)
1516 g_free((gchar *)p);
1518 return 0;
1521 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1523 struct client_s *client = data;
1525 CACHE_LOCK(client->ctx);
1526 cache_clear(client->md5file, 1);
1527 CACHE_UNLOCK;
1528 return 0;
1531 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1533 struct client_s *client = assuan_get_pointer(ctx);
1534 gboolean cached = FALSE;
1535 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1537 CACHE_LOCK(ctx);
1538 cached = cache_iscached(client->md5file);
1539 CACHE_UNLOCK;
1542 * If a cache entry doesn't exist for this file and the file has a
1543 * "key_file" or "key" parameter, then it's an error. The reason is that
1544 * cache expiration would be useless. Unless this is an inquire, then its
1545 * fine.
1547 if (cached == FALSE) {
1548 gchar *tmp = get_key_file_string(client->filename, "key_file");
1550 if (tmp && !(client->opts & OPT_INQUIRE)) {
1551 g_free(tmp);
1552 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1555 if (tmp)
1556 g_free(tmp);
1559 cached = FALSE;
1561 /* New file? */
1562 if (!client->crypto) {
1563 client->crypto = init_client_crypto();
1565 if (!client->crypto) {
1566 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1567 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1571 client->crypto->key = gcry_malloc(hashlen);
1573 if (!client->crypto->key) {
1574 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1575 cleanup_crypto(&client->crypto);
1576 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1579 memset(client->crypto->key, '!', hashlen);
1581 if (!get_key_file_uint64(client->filename, "iterations") &&
1582 (!line || !*line))
1583 goto done;
1585 if (!line || !*line) {
1586 /* It doesn't make sense to use an --inquire with an empty
1587 * passphrase. This will prevent a pinentry dialog. */
1588 if (client->opts & OPT_INQUIRE) {
1589 cleanup_crypto(&client->crypto);
1590 return GPG_ERR_WRONG_KEY_USAGE;
1593 client->crypto->tkey = gcry_malloc(hashlen);
1595 if (!client->crypto->tkey) {
1596 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1597 cleanup_crypto(&client->crypto);
1598 return send_error(ctx, GPG_ERR_ENOMEM);
1601 memset(client->crypto->tkey, '!', hashlen);
1602 CACHE_LOCK(ctx);
1604 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1605 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1606 CACHE_UNLOCK;
1608 #ifdef WITH_PINENTRY
1609 gpg_error_t rc;
1611 if (client->pinentry->enable == FALSE ||
1612 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1613 /* Empty keys are allowed. */
1614 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1615 goto done;
1618 lock_pin_mutex(client);
1619 client->pinentry->which = PINENTRY_SAVE;
1620 rc = pinentry_fork(ctx);
1622 if (rc) {
1623 unlock_pin_mutex(client->pinentry);
1624 cleanup_crypto(&client->crypto);
1625 return send_error(ctx, rc);
1628 client->pinentry->cb = save_command_finalize;
1629 client->pinentry->status = PINENTRY_INIT;
1630 return 0;
1631 #else
1632 /* Empty keys are allowed. */
1633 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1634 goto done;
1635 #endif
1637 else {
1638 CACHE_UNLOCK;
1639 cached = TRUE;
1642 else {
1643 gpg_error_t rc;
1645 if (!get_key_file_uint64(client->filename, "iterations")) {
1646 guint64 iter = get_key_file_uint64(NULL, "iterations");
1647 gchar *p;
1649 if (!iter)
1650 iter = 1; // default? what about the "global" section?
1652 MUTEX_LOCK(&rcfile_mutex);
1653 p = g_strdup_printf("%llu", iter);
1654 g_key_file_set_value(keyfileh, client->filename, "iterations", p);
1655 g_free(p);
1656 MUTEX_UNLOCK(&rcfile_mutex);
1657 client->opts |= OPT_ITERATIONS;
1658 rc = send_status(ctx, STATUS_CONFIG, NULL);
1660 if (rc) {
1661 cleanup_crypto(&client->crypto);
1662 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1666 rc = hash_key(client, line);
1668 if (rc) {
1669 cleanup_crypto(&client->crypto);
1670 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1674 done:
1675 return save_command_finalize(ctx, client->crypto->key, cached);
1678 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1679 guchar *line, gsize len)
1681 assuan_context_t ctx = data;
1682 struct client_s *client = assuan_get_pointer(ctx);
1683 gpg_error_t rc = file_modified(client);
1685 if (assuan_rc || rc) {
1686 if (line)
1687 xfree(line);
1689 return assuan_rc ? assuan_rc : rc;
1692 rc = save_command_common(ctx, (gchar *)line);
1694 if (line)
1695 xfree(line);
1697 client->inquire_status = INQUIRE_DONE;
1698 return rc;
1701 static gint save_command(assuan_context_t ctx, gchar *line)
1703 struct stat st;
1704 struct client_s *client = assuan_get_pointer(ctx);
1705 gpg_error_t rc;
1706 struct argv_s *args[] = {
1707 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1708 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1709 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1710 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1711 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1712 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1713 NULL
1716 rc = parse_options(&line, args, client);
1718 if (rc)
1719 return send_error(ctx, rc);
1721 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1722 return send_error(ctx, gpg_error_from_syserror());
1724 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1725 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1726 return send_error(ctx, GPG_ERR_ENOANO);
1729 if ((client->opts & OPT_INQUIRE)) {
1730 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1731 ctx);
1733 if (rc)
1734 return send_error(ctx, rc);
1736 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1737 client->inquire_status = INQUIRE_BUSY;
1738 return 0;
1741 if (line && *line)
1742 log_write2("ARGS=%s", "<passphrase>");
1744 return save_command_common(ctx, line);
1747 static gint delete_command(assuan_context_t ctx, gchar *line)
1749 struct client_s *client = assuan_get_pointer(ctx);
1750 gchar **req;
1751 gpg_error_t rc;
1752 xmlNodePtr n;
1754 log_write2("ARGS=\"%s\"", line);
1756 if (strchr(line, '\t'))
1757 req = split_input_line(line, "\t", -1);
1758 else
1759 req = split_input_line(line, " ", -1);
1761 if (!req || !*req)
1762 return send_error(ctx, GPG_ERR_SYNTAX);
1764 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1766 if (!n) {
1767 g_strfreev(req);
1768 return send_error(ctx, rc);
1772 * No sub-node defined. Remove the entire node (root element).
1774 if (!req[1]) {
1775 if (n) {
1776 rc = unlink_node(n);
1777 xmlFreeNode(n);
1780 g_strfreev(req);
1781 return send_error(ctx, rc);
1784 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1785 g_strfreev(req);
1787 if (!n)
1788 return send_error(ctx, rc);
1790 if (n) {
1791 rc = unlink_node(n);
1792 xmlFreeNode(n);
1795 return send_error(ctx, rc);
1799 * Don't return with assuan_process_done() here. This has been called from
1800 * assuan_process_next() and the command should be finished in
1801 * client_thread().
1803 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1804 gsize len)
1806 assuan_context_t ctx = data;
1807 struct client_s *client = assuan_get_pointer(ctx);
1808 gchar **req;
1809 xmlNodePtr n;
1810 gpg_error_t rc = file_modified(client);
1812 if (assuan_rc || rc) {
1813 if (line)
1814 xfree(line);
1815 return assuan_rc ? assuan_rc : rc;
1818 req = split_input_line((gchar *)line, "\t", 0);
1819 xfree(line);
1821 if (!req || !*req)
1822 return GPG_ERR_SYNTAX;
1824 again:
1825 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1827 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1828 rc = new_root_element(client->doc, *req);
1830 if (rc) {
1831 g_strfreev(req);
1832 return rc;
1835 goto again;
1838 if (!n) {
1839 g_strfreev(req);
1840 return rc;
1843 if (req[1]) {
1844 if (!n->children)
1845 n = create_elements_cb(n, req+1, &rc, NULL);
1846 else
1847 n = find_elements(client->doc, n->children, req+1, &rc,
1848 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1851 g_strfreev(req);
1852 client->inquire_status = INQUIRE_DONE;
1854 if (!rc)
1855 rc = update_element_mtime(n);
1857 return rc;
1860 static gint store_command(assuan_context_t ctx, gchar *line)
1862 struct client_s *client = assuan_get_pointer(ctx);
1863 gpg_error_t rc;
1865 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1867 if (rc)
1868 return send_error(ctx, rc);
1870 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1871 client->inquire_status = INQUIRE_BUSY;
1872 return 0;
1875 static void *send_data_cb(void *arg)
1877 struct assuan_cmd_s *data = arg;
1878 gint old;
1879 gpg_error_t *rc;
1881 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1882 rc = g_malloc(sizeof(gpg_error_t));
1883 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1884 pth_cancel_state(old, NULL);
1885 pth_exit(rc);
1886 return NULL;
1889 /* For every assuan command that needs to be sent to the client, a timeout is
1890 * needed to determine if the client lost the connection. The timeout is the
1891 * same as the "keepalive" configuration parameter or a default if unset.
1893 gpg_error_t do_assuan_command(assuan_context_t ctx,
1894 void *(*cb)(void *data), void *data)
1896 pth_attr_t attr = pth_attr_new();
1897 pth_t tid;
1898 gint to = get_key_file_integer("global", "keepalive");
1899 pth_event_t ev, tev;
1900 pth_status_t st;
1901 gpg_error_t rc = 0;
1902 void *p;
1904 pth_attr_init(attr);
1905 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1906 tid = pth_spawn(attr, cb, data);
1907 rc = gpg_error_from_syserror();
1908 pth_attr_destroy(attr);
1910 if (!tid) {
1911 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1912 return rc;
1915 pth_cleanup_push(cleanup_cancel_cb, tid);
1916 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1917 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1918 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1919 ev = pth_event_concat(ev, tev, NULL);
1920 pth_cleanup_push(cleanup_ev_cb, ev);
1921 pth_yield(tid);
1922 pth_wait(ev);
1924 if (tev) {
1925 st = pth_event_status(tev);
1927 if (st == PTH_STATUS_OCCURRED) {
1928 pth_cleanup_pop(1);
1929 pth_cleanup_pop(1);
1930 return GPG_ERR_TIMEOUT;
1934 st = pth_event_status(ev);
1936 if (st == PTH_STATUS_FAILED) {
1937 pth_cancel(tid);
1938 pth_join(tid, &p);
1939 g_free(p);
1940 rc = GPG_ERR_ASS_WRITE_ERROR;
1942 else if (st == PTH_STATUS_OCCURRED) {
1943 pth_join(tid, &p);
1944 rc = *(gpg_error_t *)p;
1945 g_free(p);
1948 pth_cleanup_pop(1);
1949 pth_cleanup_pop(0);
1950 return rc;
1953 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1954 gint total)
1956 gint to_send;
1957 gint sent = 0;
1958 gpg_error_t rc;
1959 struct assuan_cmd_s data;
1960 gint progress = get_key_file_integer("global", "xfer_progress");
1961 gint flush = 0;
1963 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1964 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1965 data.ctx = ctx;
1966 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1968 if (rc)
1969 return rc;
1971 again:
1972 do {
1973 if (sent + to_send > total)
1974 to_send = total - sent;
1976 data.line = flush ? NULL : (gchar *)line+sent;
1977 data.line_len = flush ? 0 : to_send;
1978 rc = do_assuan_command(ctx, send_data_cb, &data);
1980 if (!rc) {
1981 sent += flush ? 0 : to_send;
1983 if ((progress && !(sent % progress) && sent != total) ||
1984 (sent == total && flush))
1985 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1987 if (!flush && !rc && sent == total) {
1988 flush = 1;
1989 goto again;
1992 } while (!rc && sent < total);
1994 return rc;
1997 static gint get_command(assuan_context_t ctx, gchar *line)
1999 struct client_s *client = assuan_get_pointer(ctx);
2000 gchar **req;
2001 gpg_error_t rc;
2002 xmlNodePtr n;
2004 log_write2("ARGS=\"%s\"", line);
2005 req = split_input_line(line, "\t", -1);
2007 if (!req || !*req) {
2008 g_strfreev(req);
2009 return send_error(ctx, GPG_ERR_SYNTAX);
2012 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2014 if (!n) {
2015 g_strfreev(req);
2016 return send_error(ctx, rc);
2019 if (req[1])
2020 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2022 g_strfreev(req);
2024 if (rc)
2025 return send_error(ctx, rc);
2027 if (!n || !n->children)
2028 return send_error(ctx, GPG_ERR_NO_VALUE);
2030 n = find_text_node(n->children);
2032 if (!n || !n->content || !*n->content)
2033 return send_error(ctx, GPG_ERR_NO_VALUE);
2035 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2036 return send_error(ctx, rc);
2039 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2040 gpg_error_t *rc, gchar **req_orig, void *data)
2042 gchar *path = *(gchar **)data;
2043 gchar *tmp = NULL, *result;
2045 if (path) {
2046 g_free(path);
2047 *(gchar **)data = NULL;
2050 path = g_strjoinv("\t", target);
2052 if (!path) {
2053 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2054 *rc = GPG_ERR_ENOMEM;
2055 return NULL;
2058 if (req_orig) {
2059 tmp = g_strjoinv("\t", req_orig);
2061 if (!tmp) {
2062 g_free(path);
2063 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2064 *rc = GPG_ERR_ENOMEM;
2065 return NULL;
2069 if (tmp && *tmp)
2070 result = g_strdup_printf("%s\t%s", path, tmp);
2071 else
2072 result = g_strdup(path);
2074 if (!result) {
2075 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2076 *rc = GPG_ERR_ENOMEM;
2077 g_free(path);
2078 g_free(tmp);
2079 return NULL;
2082 g_free(path);
2083 g_free(tmp);
2084 *(gchar **)data = result;
2085 return node;
2088 static void list_command_cleanup1(void *arg);
2089 static gint realpath_command(assuan_context_t ctx, gchar *line)
2091 gpg_error_t rc;
2092 struct client_s *client = assuan_get_pointer(ctx);
2093 gchar **req;
2094 gchar *t;
2095 gint i;
2096 xmlNodePtr n;
2097 GString *string;
2098 gchar *rp = NULL;
2100 log_write2("ARGS=\"%s\"", line);
2102 if (strchr(line, '\t') != NULL) {
2103 if ((req = split_input_line(line, "\t", 0)) == NULL)
2104 return send_error(ctx, GPG_ERR_SYNTAX);
2106 else {
2107 if ((req = split_input_line(line, " ", 0)) == NULL)
2108 return send_error(ctx, GPG_ERR_SYNTAX);
2111 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2113 if (!n) {
2114 g_strfreev(req);
2115 return send_error(ctx, rc);
2118 rp = g_strjoinv("\t", req);
2120 if (!rp) {
2121 g_strfreev(req);
2122 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2123 return send_error(ctx, GPG_ERR_ENOMEM);
2126 if (req[1]) {
2127 n = find_elements(client->doc, n->children, req+1, &rc,
2128 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2130 if (!n) {
2131 g_free(rp);
2132 g_strfreev(req);
2133 return send_error(ctx, rc);
2137 string = g_string_new(rp);
2138 g_free(rp);
2139 g_strfreev(req);
2141 if (!string) {
2142 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2143 return send_error(ctx, GPG_ERR_ENOMEM);
2146 again:
2147 for (i = 0, t = string->str + i; *t; t++, i++) {
2148 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2149 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2150 goto again;
2154 pth_cleanup_push(list_command_cleanup1, string);
2155 rc = xfer_data(ctx, string->str, string->len);
2156 pth_cleanup_pop(1);
2157 return send_error(ctx, rc);
2160 static void list_command_cleanup1(void *arg)
2162 g_string_free((GString *)arg, TRUE);
2165 static void list_command_cleanup2(void *arg)
2167 struct element_list_s *elements = arg;
2169 if (elements) {
2170 if (elements->list) {
2171 gint total = g_slist_length(elements->list);
2172 gint i;
2174 for (i = 0; i < total; i++) {
2175 gchar *tmp = g_slist_nth_data(elements->list, i);
2176 g_free(tmp);
2179 g_slist_free(elements->list);
2182 if (elements->prefix)
2183 g_free(elements->prefix);
2185 if (elements->req)
2186 g_strfreev(elements->req);
2188 g_free(elements);
2192 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2194 struct element_list_s *elements = data;
2196 elements->recurse = FALSE;
2197 return 0;
2200 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2202 struct element_list_s *elements = data;
2204 elements->verbose = TRUE;
2205 return 0;
2208 static gint list_command(assuan_context_t ctx, gchar *line)
2210 struct client_s *client = assuan_get_pointer(ctx);
2211 gpg_error_t rc;
2212 struct element_list_s *elements = NULL;
2213 gchar *tmp;
2214 struct argv_s *args[] = {
2215 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2216 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2217 NULL
2220 if (disable_list_and_dump == TRUE)
2221 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2223 elements = g_malloc0(sizeof(struct element_list_s));
2225 if (!elements) {
2226 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2227 return GPG_ERR_ENOMEM;
2230 elements->recurse = TRUE; // default
2231 pth_cleanup_push(list_command_cleanup2, elements);
2232 rc = parse_options(&line, args, elements);
2234 if (rc)
2235 goto fail;
2237 if (!*line) {
2238 GString *str;
2240 rc = list_root_elements(client->doc, &str, elements->verbose);
2242 if (rc) {
2243 pth_cleanup_pop(1);
2244 return send_error(ctx, rc);
2247 pth_cleanup_push(list_command_cleanup1, str);
2248 rc = xfer_data(ctx, str->str, str->len);
2249 pth_cleanup_pop(1);
2250 pth_cleanup_pop(1);
2251 return send_error(ctx, rc);
2254 elements->req = split_input_line(line, " ", 0);
2256 if (!elements->req)
2257 strv_printf(&elements->req, "%s", line);
2259 rc = create_path_list(client->doc, elements, *elements->req);
2261 if (rc)
2262 goto fail;
2264 if (elements) {
2265 gint total = g_slist_length(elements->list);
2266 gint i;
2267 GString *str;
2269 if (!total) {
2270 rc = GPG_ERR_NO_VALUE;
2271 goto fail;
2274 str = g_string_new(NULL);
2276 if (!str) {
2277 rc = GPG_ERR_ENOMEM;
2278 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2279 goto fail;
2282 for (i = 0; i < total; i++) {
2283 tmp = g_slist_nth_data(elements->list, i);
2284 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2287 pth_cleanup_push(list_command_cleanup1, str);
2288 rc = xfer_data(ctx, str->str, str->len);
2289 pth_cleanup_pop(1);
2291 else
2292 rc = GPG_ERR_NO_VALUE;
2294 fail:
2295 pth_cleanup_pop(1);
2296 return send_error(ctx, rc);
2300 * req[0] - element path
2302 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2304 struct client_s *client = assuan_get_pointer(ctx);
2305 gchar **attrlist = NULL;
2306 gint i = 0;
2307 gchar **path = NULL;
2308 xmlAttrPtr a;
2309 xmlNodePtr n, an;
2310 gchar *line;
2311 gpg_error_t rc;
2313 if (!req || !req[0])
2314 return GPG_ERR_SYNTAX;
2316 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2318 * The first argument may be only a root element.
2320 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2321 return GPG_ERR_SYNTAX;
2324 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2326 if (!n) {
2327 g_strfreev(path);
2328 return rc;
2331 if (path[1]) {
2332 n = find_elements(client->doc, n->children, path+1, &rc,
2333 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2335 if (!n) {
2336 g_strfreev(path);
2337 return rc;
2341 g_strfreev(path);
2343 for (a = n->properties; a; a = a->next) {
2344 gchar **pa;
2346 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2347 if (attrlist)
2348 g_strfreev(attrlist);
2350 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2351 return GPG_ERR_ENOMEM;
2354 attrlist = pa;
2355 an = a->children;
2356 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2357 an && an->content ? (gchar *)an->content : "");
2359 if (!attrlist[i]) {
2360 g_strfreev(attrlist);
2361 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2362 return GPG_ERR_ENOMEM;
2365 attrlist[++i] = NULL;
2368 if (!attrlist)
2369 return GPG_ERR_NO_VALUE;
2371 line = g_strjoinv("\n", attrlist);
2373 if (!line) {
2374 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2375 g_strfreev(attrlist);
2376 return GPG_ERR_ENOMEM;
2379 pth_cleanup_push(g_free, line);
2380 pth_cleanup_push(req_cleanup, attrlist);
2381 rc = xfer_data(ctx, line, strlen(line));
2382 pth_cleanup_pop(1);
2383 pth_cleanup_pop(1);
2384 return rc;
2388 * req[0] - attribute
2389 * req[1] - element path
2391 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2393 xmlNodePtr n;
2394 gchar **path = NULL;
2395 gpg_error_t rc;
2397 if (!req || !req[0] || !req[1])
2398 return GPG_ERR_SYNTAX;
2400 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2402 * The first argument may be only a root element.
2404 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2405 return GPG_ERR_SYNTAX;
2409 * Don't remove the "_name" attribute for the root element. To remove an
2410 * root element use DELETE <name>.
2412 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2413 rc = GPG_ERR_SYNTAX;
2414 goto fail;
2417 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2419 if (!n)
2420 goto fail;
2422 if (path[1]) {
2423 n = find_elements(client->doc, n->children, path+1, &rc,
2424 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2426 if (!n)
2427 goto fail;
2430 rc = delete_attribute(n, (xmlChar *)req[0]);
2432 fail:
2433 g_strfreev(path);
2434 return rc;
2437 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2438 gpg_error_t *rc)
2440 gchar **src = *path;
2441 gchar **src_orig = g_strdupv(src);
2442 xmlNodePtr n = NULL;
2444 *rc = 0;
2446 if (!src_orig) {
2447 *rc = GPG_ERR_ENOMEM;
2448 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2449 goto fail;
2452 again:
2453 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2455 if (!n) {
2456 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2457 *rc = new_root_element(client->doc, src[0]);
2459 if (*rc)
2460 goto fail;
2462 goto again;
2464 else
2465 goto fail;
2468 if (src[1]) {
2469 if (!n->children)
2470 n = create_target_elements_cb(n, src+1, rc, NULL);
2471 else
2472 n = find_elements(client->doc, n->children, src+1, rc,
2473 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2475 if (!n)
2476 goto fail;
2479 * Reset the position of the element tree now that the elements
2480 * have been created.
2482 g_strfreev(src);
2483 src = src_orig;
2484 src_orig = NULL;
2485 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2487 if (!n)
2488 goto fail;
2490 n = find_elements(client->doc, n->children, src+1, rc,
2491 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2493 if (!n)
2494 goto fail;
2497 fail:
2498 if (src_orig)
2499 g_strfreev(src_orig);
2501 *path = src;
2502 return n;
2506 * Creates a "target" attribute. When other commands encounter an element with
2507 * this attribute, the element path is modified to the target value. If the
2508 * source element path doesn't exist when using 'ATTR SET target', it is
2509 * created, but the destination element path must exist.
2511 * req[0] - source element path
2512 * req[1] - destination element path
2514 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2516 gchar **src, **dst, *line = NULL, **odst = NULL;
2517 gpg_error_t rc;
2518 xmlNodePtr n;
2520 if (!req || !req[0] || !req[1])
2521 return GPG_ERR_SYNTAX;
2523 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2525 * The first argument may be only a root element.
2527 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2528 return GPG_ERR_SYNTAX;
2531 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2533 * The first argument may be only a root element.
2535 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2536 rc = GPG_ERR_SYNTAX;
2537 goto fail;
2541 odst = g_strdupv(dst);
2543 if (!odst) {
2544 rc = GPG_ERR_ENOMEM;
2545 goto fail;
2548 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2551 * Make sure the destination element path exists.
2553 if (!n)
2554 goto fail;
2556 if (dst[1]) {
2557 n = find_elements(client->doc, n->children, dst+1, &rc,
2558 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2560 if (!n)
2561 goto fail;
2564 n = create_element_path(client, &src, &rc);
2566 if (rc)
2567 goto fail;
2569 line = g_strjoinv("\t", odst);
2571 if (!line) {
2572 rc = GPG_ERR_ENOMEM;
2573 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2574 goto fail;
2577 rc = add_attribute(n, "target", line);
2579 fail:
2580 g_free(line);
2581 g_strfreev(src);
2582 g_strfreev(dst);
2583 g_strfreev(odst);
2584 return rc;
2588 * req[0] - name
2589 * req[1] - new name
2591 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2593 gpg_error_t rc;
2594 gchar **tmp;
2595 xmlNodePtr n;
2597 tmp = g_strdupv(req);
2599 if (!tmp) {
2600 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2601 return GPG_ERR_ENOMEM;
2604 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2605 g_strfreev(tmp);
2607 if (!n)
2608 return rc;
2610 if (g_utf8_collate(req[0], req[1]) == 0)
2611 return 0;
2614 * Will not overwrite an existing root.
2616 tmp = g_strdupv(req+1);
2618 if (!tmp) {
2619 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2620 return GPG_ERR_ENOMEM;
2623 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2624 g_strfreev(tmp);
2626 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2627 return rc;
2629 if (n)
2630 return GPG_ERR_AMBIGUOUS_NAME;
2632 if (!valid_xml_element((xmlChar *)req[1]))
2633 return GPG_ERR_SYNTAX;
2635 tmp = g_strdupv(req);
2637 if (!tmp) {
2638 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2639 return GPG_ERR_ENOMEM;
2642 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2643 g_strfreev(tmp);
2645 if (!n)
2646 return GPG_ERR_ELEMENT_NOT_FOUND;
2648 return add_attribute(n, "_name", req[1]);
2652 * req[0] - attribute
2653 * req[1] - element path
2655 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2657 struct client_s *client = assuan_get_pointer(ctx);
2658 xmlNodePtr n;
2659 xmlChar *a;
2660 gchar **path= NULL;
2661 gpg_error_t rc;
2663 if (!req || !req[0] || !req[1])
2664 return GPG_ERR_SYNTAX;
2666 if (strchr(req[1], '\t')) {
2667 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2668 return GPG_ERR_SYNTAX;
2670 else {
2671 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2672 return GPG_ERR_SYNTAX;
2675 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2677 if (!n)
2678 goto fail;
2680 if (path[1]) {
2681 n = find_elements(client->doc, n->children, path+1, &rc,
2682 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2684 if (!n)
2685 goto fail;
2688 g_strfreev(path);
2690 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2691 return GPG_ERR_NOT_FOUND;
2693 pth_cleanup_push(xmlFree, a);
2695 if (*a)
2696 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2697 else
2698 rc = GPG_ERR_NO_VALUE;
2700 pth_cleanup_pop(1);
2701 return rc;
2703 fail:
2704 g_strfreev(path);
2705 return rc;
2709 * req[0] - attribute
2710 * req[1] - element path
2711 * req[2] - value
2713 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2715 gchar **path = NULL;
2716 gpg_error_t rc;
2717 xmlNodePtr n;
2719 if (!req || !req[0] || !req[1])
2720 return GPG_ERR_SYNTAX;
2723 * Reserved attribute names.
2725 if (!strcmp(req[0], "_name")) {
2727 * Only reserved for the root element. Not the rest of the
2728 * document.
2730 if (strchr(req[1], '\t') == NULL)
2731 return name_attribute(client, req + 1);
2733 else if (!strcmp(req[0], "target"))
2734 return target_attribute(client, req + 1);
2736 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2738 * The first argument may be only a root element.
2740 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2741 return GPG_ERR_SYNTAX;
2744 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2746 if (!n)
2747 goto fail;
2749 if (path[1]) {
2750 n = find_elements(client->doc, n->children, path+1, &rc,
2751 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2753 if (!n)
2754 goto fail;
2757 rc = add_attribute(n, req[0], req[2]);
2759 fail:
2760 g_strfreev(path);
2761 return rc;
2765 * req[0] - command
2766 * req[1] - attribute name or element path if command is LIST
2767 * req[2] - element path
2768 * req[2] - element path or value
2770 static gint attr_command(assuan_context_t ctx, gchar *line)
2772 struct client_s *client = assuan_get_pointer(ctx);
2773 gchar **req;
2774 gpg_error_t rc = 0;
2776 log_write2("ARGS=\"%s\"", line);
2777 req = split_input_line(line, " ", 4);
2779 if (!req || !req[0] || !req[1]) {
2780 g_strfreev(req);
2781 return send_error(ctx, GPG_ERR_SYNTAX);
2784 pth_cleanup_push(req_cleanup, req);
2786 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2787 rc = attribute_set(client, req+1);
2788 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2789 rc = attribute_get(ctx, req+1);
2790 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2791 rc = attribute_delete(client, req+1);
2792 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2793 rc = attribute_list(ctx, req+1);
2794 else
2795 rc = GPG_ERR_SYNTAX;
2797 pth_cleanup_pop(1);
2798 return send_error(ctx, rc);
2801 static gint iscached_command(assuan_context_t ctx, gchar *line)
2803 gchar **req = split_input_line(line, " ", 0);
2804 guchar md5file[16];
2805 gchar *path, *tmp;
2807 if (!req || !*req) {
2808 g_strfreev(req);
2809 return send_error(ctx, GPG_ERR_SYNTAX);
2812 log_write2("ARGS=\"%s\"", line);
2814 if (!valid_filename(req[0])) {
2815 g_strfreev(req);
2816 return GPG_ERR_INV_VALUE;
2819 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2820 CACHE_LOCK(ctx);
2822 if (cache_iscached(md5file)) {
2823 g_strfreev(req);
2824 CACHE_UNLOCK;
2825 return send_error(ctx, 0);
2828 CACHE_UNLOCK;
2829 tmp = get_key_file_string("global", "data_directory");
2831 if (!tmp) {
2832 g_strfreev(req);
2833 return GPG_ERR_ENOMEM;
2836 path = expand_homedir(tmp);
2838 if (!path) {
2839 g_strfreev(req);
2840 g_free(tmp);
2841 return GPG_ERR_ENOMEM;
2844 g_free(tmp);
2845 tmp = path;
2846 path = g_strdup_printf("%s/%s", tmp, req[0]);
2847 g_free(tmp);
2849 if (!path) {
2850 g_strfreev(req);
2851 return GPG_ERR_ENOMEM;
2854 if (access(path, R_OK) == -1) {
2855 gpg_error_t rc = gpg_error_from_syserror();
2857 g_free(path);
2858 g_strfreev(req);
2859 return send_error(ctx, rc);
2862 g_free(path);
2863 return send_error(ctx, GPG_ERR_NOT_FOUND);
2866 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2868 gchar **req = split_input_line(line, " ", 0);
2869 guchar md5file[16];
2871 log_write2("ARGS=\"%s\"", line);
2872 CACHE_LOCK(ctx);
2874 if (!req || !*req) {
2875 g_strfreev(req);
2876 cache_clear(NULL, 2);
2877 CACHE_UNLOCK;
2878 return send_error(ctx, 0);
2881 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2882 g_strfreev(req);
2883 (void)cache_clear(md5file, 1);
2884 CACHE_UNLOCK;
2885 return send_error(ctx, 0);
2888 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2890 guchar md5file[16];
2891 glong timeout;
2892 gchar **req = split_input_line(line, " ", 0);
2893 gchar *p;
2895 if (!req || !*req || !req[1]) {
2896 g_strfreev(req);
2897 return send_error(ctx, GPG_ERR_SYNTAX);
2900 errno = 0;
2901 timeout = strtol(req[1], &p, 10);
2903 if (errno != 0 || *p != 0 || timeout < -1) {
2904 g_strfreev(req);
2905 return send_error(ctx, GPG_ERR_SYNTAX);
2908 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2909 CACHE_LOCK(client->ctx);
2911 if (cache_set_timeout(md5file, timeout) == FALSE) {
2912 CACHE_UNLOCK;
2913 return send_error(ctx, GPG_ERR_NOT_FOUND);
2916 CACHE_UNLOCK;
2917 return send_error(ctx, 0);
2920 static gint dump_command(assuan_context_t ctx, gchar *line)
2922 xmlChar *xml;
2923 gint len;
2924 struct client_s *client = assuan_get_pointer(ctx);
2925 gpg_error_t rc;
2927 if (disable_list_and_dump == TRUE)
2928 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2930 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2932 if (!xml) {
2933 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2934 return send_error(ctx, GPG_ERR_ENOMEM);
2937 pth_cleanup_push(xmlFree, xml);
2938 rc = xfer_data(ctx, (gchar *)xml, len);
2939 pth_cleanup_pop(1);
2940 return send_error(ctx, rc);
2943 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2945 struct client_s *client = assuan_get_pointer(ctx);
2946 gpg_error_t rc = 0;
2947 gchar filename[255]={0}, param[747]={0};
2948 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2950 log_write2("ARGS=\"%s\"", line);
2952 if (!line || !*line)
2953 return send_error(ctx, GPG_ERR_SYNTAX);
2955 if (strchr(line, ' ')) {
2956 sscanf(line, " %254[^ ] %746c", filename, param);
2957 paramp = param;
2958 fp = filename;
2961 if (fp && !valid_filename(fp))
2962 return send_error(ctx, GPG_ERR_INV_VALUE);
2964 paramp = g_ascii_strdown(paramp, -1);
2966 if (!paramp) {
2967 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2968 return send_error(ctx, GPG_ERR_ENOMEM);
2971 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2972 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2973 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2975 if (!fh && rc != GPG_ERR_ENOENT)
2976 return send_error(ctx, rc);
2978 if (!rc) {
2979 g_free(paramp);
2980 p = g_strdup_printf("%llu", fh->ver.fh2.iter);
2981 close_file_header(fh);
2983 if (!p) {
2984 log_write("%s(%i): %s", __FILE__, __LINE__,
2985 pwmd_strerror(GPG_ERR_ENOMEM));
2986 return send_error(ctx, GPG_ERR_ENOMEM);
2989 goto done;
2993 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2994 #ifdef WITH_PINENTRY
2995 gboolean n;
2997 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2998 n = client->pinentry->enable;
2999 else
3000 n = get_key_file_boolean(fp, "enable_pinentry");
3002 p = g_strdup_printf("%s", n ? "true" : "false");
3004 if (!p) {
3005 log_write("%s(%i): %s", __FILE__, __LINE__,
3006 pwmd_strerror(GPG_ERR_ENOMEM));
3007 return send_error(ctx, GPG_ERR_ENOMEM);
3010 goto done;
3011 #else
3012 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3013 #endif
3015 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3016 #ifdef WITH_PINENTRY
3017 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3019 if (!p) {
3020 log_write("%s(%i): %s", __FILE__, __LINE__,
3021 pwmd_strerror(GPG_ERR_ENOMEM));
3022 return send_error(ctx, GPG_ERR_ENOMEM);
3025 goto done;
3026 #else
3027 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3028 #endif
3031 p = get_key_file_string(fp ? fp : "global", paramp);
3032 g_free(paramp);
3034 if (!p)
3035 return send_error(ctx, GPG_ERR_UNKNOWN_OPTION);
3037 tmp = expand_homedir(p);
3038 g_free(p);
3040 if (!tmp) {
3041 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3042 return send_error(ctx, GPG_ERR_ENOMEM);
3045 p = tmp;
3046 done:
3047 pth_cleanup_push(g_free, p);
3048 rc = xfer_data(ctx, p, strlen(p));
3049 pth_cleanup_pop(1);
3050 return send_error(ctx, rc);
3053 struct xpath_s {
3054 xmlXPathContextPtr xp;
3055 xmlXPathObjectPtr result;
3056 xmlBufferPtr buf;
3057 gchar **req;
3060 static void xpath_command_cleanup(void *arg)
3062 struct xpath_s *xpath = arg;
3064 req_cleanup(xpath->req);
3066 if (xpath->buf)
3067 xmlBufferFree(xpath->buf);
3069 if (xpath->result)
3070 xmlXPathFreeObject(xpath->result);
3072 if (xpath->xp)
3073 xmlXPathFreeContext(xpath->xp);
3076 static gint xpath_command(assuan_context_t ctx, gchar *line)
3078 struct client_s *client = assuan_get_pointer(ctx);
3079 gpg_error_t rc;
3080 struct xpath_s xpath;
3082 log_write2("ARGS=\"%s\"", line);
3084 if (disable_list_and_dump == TRUE)
3085 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3087 if (!line || !*line)
3088 return send_error(ctx, GPG_ERR_SYNTAX);
3090 memset(&xpath, 0, sizeof(struct xpath_s));
3092 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3093 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3094 return send_error(ctx, GPG_ERR_ENOMEM);
3097 xpath.xp = xmlXPathNewContext(client->doc);
3099 if (!xpath.xp) {
3100 xpath_command_cleanup(&xpath);
3101 return send_error(ctx, EPWMD_LIBXML_ERROR);
3104 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3106 if (!xpath.result) {
3107 xpath_command_cleanup(&xpath);
3108 return send_error(ctx, EPWMD_LIBXML_ERROR);
3111 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3112 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3113 goto fail;
3116 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3117 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3119 if (rc)
3120 goto fail;
3121 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3122 rc = GPG_ERR_NO_VALUE;
3123 goto fail;
3125 else if (xpath.req[1])
3126 goto fail;
3128 pth_cleanup_push(xpath_command_cleanup, &xpath);
3129 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3130 xmlBufferLength(xpath.buf));
3131 pth_cleanup_pop(0);
3133 fail:
3134 xpath_command_cleanup(&xpath);
3135 return send_error(ctx, rc);
3138 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3139 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3141 struct client_s *client = assuan_get_pointer(ctx);
3142 gpg_error_t rc;
3143 struct xpath_s xpath;
3144 gchar **req = NULL;
3145 gboolean cmd = FALSE; //SET
3147 log_write2("ARGS=\"%s\"", line);
3149 if (disable_list_and_dump == TRUE)
3150 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3152 if (!line || !*line)
3153 return send_error(ctx, GPG_ERR_SYNTAX);
3155 memset(&xpath, 0, sizeof(struct xpath_s));
3157 if ((req = split_input_line(line, " ", 3)) == NULL)
3158 return send_error(ctx, GPG_ERR_ENOMEM);
3160 if (!req[0]) {
3161 rc = GPG_ERR_SYNTAX;
3162 goto fail;
3165 if (!g_ascii_strcasecmp(req[0], "SET"))
3166 cmd = FALSE;
3167 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3168 cmd = TRUE;
3169 else {
3170 rc = GPG_ERR_SYNTAX;
3171 goto fail;
3174 if (!req[1] || !req[2]) {
3175 rc = GPG_ERR_SYNTAX;
3176 goto fail;
3179 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3180 rc = GPG_ERR_ENOMEM;
3181 goto fail;
3184 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3185 rc = GPG_ERR_SYNTAX;
3186 goto fail;
3189 xpath.xp = xmlXPathNewContext(client->doc);
3191 if (!xpath.xp) {
3192 rc = EPWMD_LIBXML_ERROR;
3193 goto fail;
3196 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3198 if (!xpath.result) {
3199 rc = EPWMD_LIBXML_ERROR;
3200 goto fail;
3203 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3204 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3205 goto fail;
3208 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3209 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3211 fail:
3212 g_strfreev(req);
3213 xpath_command_cleanup(&xpath);
3214 return send_error(ctx, rc);
3217 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3218 gsize len)
3220 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3221 gpg_error_t rc = file_modified(client);
3222 gchar **req, **path = NULL, **path_orig = NULL, *content;
3223 xmlDocPtr doc = NULL;
3224 xmlNodePtr n, root, copy;
3226 if (assuan_rc || rc) {
3227 if (line)
3228 xfree(line);
3229 return assuan_rc ? assuan_rc : rc;
3232 req = split_input_line((gchar *)line, "\t", 2);
3233 xfree(line);
3235 if (!req || !*req)
3236 return GPG_ERR_SYNTAX;
3238 content = req[0];
3239 path = split_input_line(req[1], "\t", 0);
3241 if (!content || !*content) {
3242 rc = GPG_ERR_SYNTAX;
3243 goto fail;
3246 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3248 if (!doc) {
3249 rc = EPWMD_LIBXML_ERROR;
3250 goto fail;
3253 root = xmlDocGetRootElement(doc);
3254 rc = validate_import(root);
3256 if (rc)
3257 goto fail;
3259 if (path) {
3260 path_orig = g_strdupv(path);
3262 if (!path_orig) {
3263 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3264 rc = GPG_ERR_ENOMEM;
3265 goto fail;
3268 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3270 if (!a) {
3271 g_strfreev(path_orig);
3272 rc = GPG_ERR_ENOMEM;
3273 goto fail;
3276 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3277 xmlFree(a);
3278 g_strfreev(path_orig);
3279 rc = GPG_ERR_ENOMEM;
3280 goto fail;
3283 xmlFree(a);
3284 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3286 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3287 g_strfreev(path_orig);
3288 goto fail;
3291 if (!rc) {
3292 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3294 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3295 g_strfreev(path_orig);
3296 goto fail;
3298 else if (!rc) {
3299 xmlNodePtr parent = n->parent;
3301 xmlUnlinkNode(n);
3302 xmlFreeNode(n);
3303 n = parent;
3307 g_strfreev(path);
3308 path = path_orig;
3310 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3311 n = create_element_path(client, &path, &rc);
3313 if (rc)
3314 goto fail;
3317 copy = xmlCopyNodeList(root);
3318 n = xmlAddChildList(n, copy);
3320 if (!n)
3321 rc = EPWMD_LIBXML_ERROR;
3323 else {
3324 /* Check if the content root element can create a DTD root element. */
3325 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3326 rc = GPG_ERR_SYNTAX;
3327 goto fail;
3330 xmlChar *a;
3332 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3333 rc = GPG_ERR_SYNTAX;
3334 goto fail;
3337 gchar *tmp = g_strdup((gchar *)a);
3338 xmlFree(a);
3339 gboolean literal = is_literal_element(&tmp);
3341 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3342 g_free(tmp);
3343 rc = GPG_ERR_INV_VALUE;
3344 goto fail;
3347 if (strv_printf(&path, "%s", tmp) == FALSE) {
3348 g_free(tmp);
3349 rc = GPG_ERR_ENOMEM;
3350 goto fail;
3353 g_free(tmp);
3354 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3356 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3357 rc = EPWMD_LIBXML_ERROR;
3358 goto fail;
3361 /* Overwriting the existing tree. */
3362 if (!rc) {
3363 xmlUnlinkNode(n);
3364 xmlFreeNodeList(n);
3367 rc = 0;
3368 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3369 n = xmlCopyNode(root, 1);
3370 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3373 if (n && !rc)
3374 rc = update_element_mtime(n->parent);
3376 fail:
3377 if (doc)
3378 xmlFreeDoc(doc);
3380 if (path)
3381 g_strfreev(path);
3383 g_strfreev(req);
3384 client->inquire_status = INQUIRE_DONE;
3385 return rc;
3388 static gint import_command(assuan_context_t ctx, gchar *line)
3390 gpg_error_t rc;
3391 struct client_s *client = assuan_get_pointer(ctx);
3393 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3395 if (rc)
3396 return send_error(ctx, rc);
3398 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3399 client->inquire_status = INQUIRE_BUSY;
3400 return 0;
3403 static gpg_error_t do_lock_command(struct client_s *client)
3405 gpg_error_t rc = lock_file_mutex(client);
3407 if (!rc)
3408 client->is_lock_cmd = TRUE;
3410 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3413 static gint lock_command(assuan_context_t ctx, gchar *line)
3415 struct client_s *client = assuan_get_pointer(ctx);
3417 return do_lock_command(client);
3420 static gint unlock_command(assuan_context_t ctx, gchar *line)
3422 struct client_s *client = assuan_get_pointer(ctx);
3424 unlock_file_mutex(client);
3425 return send_error(ctx, 0);
3428 static gint getpid_command(assuan_context_t ctx, gchar *line)
3430 gpg_error_t rc;
3431 gchar buf[32];
3432 pid_t pid = getpid();
3434 print_fmt(buf, sizeof(buf), "%i", pid);
3435 rc = xfer_data(ctx, buf, strlen(buf));
3436 return send_error(ctx, rc);
3439 static gint version_command(assuan_context_t ctx, gchar *line)
3441 gpg_error_t rc;
3442 gchar *buf;
3444 buf = g_strdup_printf("0x%X %s", VERSION_HEX,
3445 #ifdef WITH_PINENTRY
3446 "PINENTRY "
3447 #endif
3448 #ifdef WITH_QUALITY
3449 "QUALITY "
3450 #endif
3451 #ifdef WITH_LIBACL
3452 "ACL "
3453 #endif
3454 "");
3455 rc = xfer_data(ctx, buf, strlen(buf));
3456 g_free(buf);
3457 return send_error(ctx, rc);
3460 #ifdef WITH_PINENTRY
3461 static void set_option_value(gchar **opt, const gchar *value)
3463 if (opt)
3464 g_free(*opt);
3466 *opt = NULL;
3468 if (value)
3469 *opt = g_strdup(value);
3471 #endif
3473 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3474 const gchar *value)
3476 struct client_s *client = assuan_get_pointer(ctx);
3477 gpg_error_t rc;
3479 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3480 gint n = 0;
3482 if (value) {
3483 n = atoi(value);
3485 if (n < 0 || n > 2)
3486 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3489 MUTEX_LOCK(&rcfile_mutex);
3490 g_key_file_set_integer(keyfileh, "global", "log_level", n);
3491 MUTEX_UNLOCK(&rcfile_mutex);
3492 goto done;
3494 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3495 gint n = 0;
3497 if (value) {
3498 n = atoi(value);
3500 if (n < 0 || n > 1)
3501 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3504 client->rc_on_locked = n ? TRUE : FALSE;
3505 goto done;
3507 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3508 rc = parse_open_opt_lock(client, (gpointer)value);
3510 if (rc)
3511 return rc;
3513 client->opts |= OPT_LOCK;
3515 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3516 if (!value) {
3517 client->opts &= ~(OPT_CIPHER);
3518 goto done;
3521 rc = parse_save_opt_cipher(client, (gpointer)value);
3523 if (rc)
3524 return rc;
3526 client->opts |= OPT_CIPHER;
3527 goto done;
3529 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3530 rc = parse_save_opt_iterations(client, (gpointer)value);
3532 if (rc)
3533 return rc;
3535 goto done;
3537 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3538 pth_attr_t attr = pth_attr_of(pth_self());
3539 gchar buf[41];
3541 if (!value) {
3542 pth_attr_destroy(attr);
3543 goto done;
3546 print_fmt(buf, sizeof(buf), "%s", value);
3547 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3548 pth_attr_destroy(attr);
3549 #ifdef WITH_PINENTRY
3550 if (client->pinentry->name)
3551 g_free(client->pinentry->name);
3553 client->pinentry->name = g_strdup(buf);
3555 if (!client->pinentry->name)
3556 return GPG_ERR_ENOMEM;
3557 #endif
3559 goto done;
3561 #ifdef WITH_PINENTRY
3562 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3563 set_option_value(&client->pinentry->lcmessages, value);
3564 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3565 set_option_value(&client->pinentry->lcctype, value);
3566 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3567 set_option_value(&client->pinentry->ttyname, value);
3568 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3569 set_option_value(&client->pinentry->ttytype, value);
3570 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3571 set_option_value(&client->pinentry->display, value);
3572 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3573 set_option_value(&client->pinentry->path, value);
3574 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3575 set_option_value(&client->pinentry->title, value);
3576 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3577 set_option_value(&client->pinentry->prompt, value);
3578 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3579 set_option_value(&client->pinentry->desc, value);
3580 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3581 gchar *p = NULL;
3582 gint n;
3584 if (!value)
3585 goto done;
3587 n = atoi(value);
3589 if (*p || n < 0)
3590 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3592 MUTEX_LOCK(&rcfile_mutex);
3593 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3594 "global", "pinentry_timeout", n);
3595 MUTEX_UNLOCK(&rcfile_mutex);
3596 goto done;
3598 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3599 rc = parse_opt_pinentry(client, (gpointer)value);
3601 if (rc)
3602 return rc;
3604 goto done;
3606 #else
3607 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3608 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3609 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3610 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3611 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3612 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3613 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3614 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3615 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3616 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3617 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3618 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3619 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3620 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3621 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3622 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3623 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3624 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3625 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3626 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3627 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3628 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3629 #endif
3630 else
3631 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3633 done:
3634 return 0;
3637 static gint unset_command(assuan_context_t ctx, gchar *line)
3639 log_write2("ARGS=\"%s\"", line);
3640 return send_error(ctx, set_unset_common(ctx, line, NULL));
3643 static gint set_command(assuan_context_t ctx, gchar *line)
3645 gchar name[64] = {0}, value[256] = {0};
3647 log_write2("ARGS=\"%s\"", line);
3649 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3650 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3652 return send_error(ctx, set_unset_common(ctx, name, value));
3655 static gint rename_command(assuan_context_t ctx, gchar *line)
3657 struct client_s *client = assuan_get_pointer(ctx);
3658 gpg_error_t rc;
3659 gchar **req, **src, *dst;
3660 xmlNodePtr n, ndst;
3662 log_write2("ARGS=\"%s\"", line);
3663 req = split_input_line(line, " ", -1);
3665 if (!req || !req[0] || !req[1]) {
3666 g_strfreev(req);
3667 return send_error(ctx, GPG_ERR_SYNTAX);
3670 dst = req[1];
3671 is_literal_element(&dst);
3673 if (!valid_xml_element((xmlChar *)dst)) {
3674 g_strfreev(req);
3675 return GPG_ERR_INV_VALUE;
3678 if (strchr(req[0], '\t'))
3679 src = split_input_line(req[0], "\t", -1);
3680 else
3681 src = split_input_line(req[0], " ", -1);
3683 if (!src || !*src) {
3684 rc = GPG_ERR_SYNTAX;
3685 goto fail;
3688 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3690 if (src[1] && n)
3691 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3692 NULL, FALSE, 0, NULL, FALSE);
3694 if (!n)
3695 goto fail;
3698 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3700 if (!a) {
3701 rc = GPG_ERR_ENOMEM;
3702 goto fail;
3705 /* To prevent unwanted effects:
3707 * <root name="a"><b/></root>
3709 * RENAME a<TAB>b b
3711 if (xmlStrEqual(a, (xmlChar *)dst)) {
3712 xmlFree(a);
3713 rc = GPG_ERR_AMBIGUOUS_NAME;
3714 goto fail;
3717 xmlFree(a);
3718 gchar **tmp = NULL;
3720 if (src[1]) {
3721 gchar **p;
3723 for (p = src; *p; p++) {
3724 if (!*(p+1))
3725 break;
3727 strv_printf(&tmp, "%s", *p);
3731 strv_printf(&tmp, "!%s", dst);
3732 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3734 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3735 g_strfreev(tmp);
3736 goto fail;
3739 if (tmp[1] && ndst)
3740 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3741 NULL, NULL, FALSE, 0, NULL, FALSE);
3743 g_strfreev(tmp);
3745 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3746 goto fail;
3748 rc = 0;
3750 /* Target may exist:
3752 * <root name="a"/>
3753 * <root name="b" target="a"/>
3755 * RENAME b a
3757 * Would need to do:
3758 * RENAME !b a
3760 if (ndst == n) {
3761 rc = GPG_ERR_AMBIGUOUS_NAME;
3762 goto fail;
3765 if (ndst) {
3766 unlink_node(ndst);
3767 xmlFreeNodeList(ndst);
3770 rc = add_attribute(n, "_name", dst);
3772 fail:
3773 g_strfreev(req);
3774 g_strfreev(src);
3775 return send_error(ctx, rc);
3778 static gint copy_command(assuan_context_t ctx, gchar *line)
3780 struct client_s *client = assuan_get_pointer(ctx);
3781 gpg_error_t rc;
3782 gchar **req, **src = NULL, **dst = NULL;
3783 xmlNodePtr nsrc, ndst, new;
3785 log_write2("ARGS=\"%s\"", line);
3786 req = split_input_line(line, " ", -1);
3788 if (!req || !req[0] || !req[1]) {
3789 g_strfreev(req);
3790 return send_error(ctx, GPG_ERR_SYNTAX);
3793 if (strchr(req[0], '\t'))
3794 src = split_input_line(req[0], "\t", -1);
3795 else
3796 src = split_input_line(req[0], " ", -1);
3798 if (!src || !*src) {
3799 rc = GPG_ERR_SYNTAX;
3800 goto fail;
3803 if (strchr(req[1], '\t'))
3804 dst = split_input_line(req[1], "\t", -1);
3805 else
3806 dst = split_input_line(req[1], " ", -1);
3808 if (!dst || !*dst) {
3809 rc = GPG_ERR_SYNTAX;
3810 goto fail;
3813 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3815 if (nsrc && src[1])
3816 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3817 NULL, NULL, FALSE, 0, NULL, FALSE);
3819 if (!nsrc)
3820 goto fail;
3822 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3824 if (ndst && dst[1])
3825 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3826 NULL, NULL, FALSE, 0, NULL, FALSE);
3828 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3829 goto fail;
3831 new = xmlCopyNodeList(nsrc);
3833 if (!new) {
3834 rc = GPG_ERR_ENOMEM;
3835 goto fail;
3838 if (!ndst)
3839 ndst = create_element_path(client, &dst, &rc);
3841 if (!ndst) {
3842 xmlUnlinkNode(new);
3843 xmlFreeNodeList(new);
3844 goto fail;
3847 /* Merge any attributes from the src node to the initial dst node. */
3848 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3849 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3850 continue;
3852 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3854 if (a)
3855 xmlRemoveProp(a);
3857 xmlChar *tmp = xmlNodeGetContent(attr->children);
3858 xmlNewProp(ndst, attr->name, tmp);
3859 xmlFree(tmp);
3860 rc = add_attribute(ndst, NULL, NULL);
3863 xmlNodePtr n = ndst->children;
3864 xmlUnlinkNode(n);
3865 xmlFreeNodeList(n);
3866 ndst->children = NULL;
3868 if (!new->children) {
3869 xmlUnlinkNode(new);
3870 xmlFreeNodeList(new);
3871 goto fail;
3874 n = xmlCopyNodeList(new->children);
3876 if (!n) {
3877 rc = GPG_ERR_ENOMEM;
3878 goto fail;
3881 xmlUnlinkNode(new);
3882 xmlFreeNodeList(new);
3883 n = xmlAddChildList(ndst, n);
3885 if (!n) {
3886 rc = GPG_ERR_ENOMEM;
3887 goto fail;
3890 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3892 fail:
3893 if (req)
3894 g_strfreev(req);
3896 if (src)
3897 g_strfreev(src);
3899 if (dst)
3900 g_strfreev(dst);
3902 return send_error(ctx, rc);
3905 static gint move_command(assuan_context_t ctx, gchar *line)
3907 struct client_s *client = assuan_get_pointer(ctx);
3908 gpg_error_t rc;
3909 gchar **req, **src = NULL, **dst = NULL;
3910 xmlNodePtr nsrc, ndst = NULL;
3912 log_write2("ARGS=\"%s\"", line);
3913 req = split_input_line(line, " ", -1);
3915 if (!req || !req[0] || !req[1]) {
3916 g_strfreev(req);
3917 return send_error(ctx, GPG_ERR_SYNTAX);
3920 if (strchr(req[0], '\t'))
3921 src = split_input_line(req[0], "\t", -1);
3922 else
3923 src = split_input_line(req[0], " ", -1);
3925 if (!src || !*src) {
3926 rc = GPG_ERR_SYNTAX;
3927 goto fail;
3930 if (strchr(req[1], '\t'))
3931 dst = split_input_line(req[1], "\t", -1);
3932 else
3933 dst = split_input_line(req[1], " ", -1);
3935 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3937 if (nsrc && src[1])
3938 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3939 NULL, NULL, FALSE, 0, NULL, FALSE);
3941 if (!nsrc)
3942 goto fail;
3944 if (dst) {
3945 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3947 if (ndst && dst[1])
3948 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3949 NULL, NULL, FALSE, 0, NULL, FALSE);
3951 else
3952 ndst = xmlDocGetRootElement(client->doc);
3954 for (xmlNodePtr n = ndst; n; n = n->parent) {
3955 if (n == nsrc) {
3956 rc = GPG_ERR_CONFLICT;
3957 goto fail;
3961 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3962 goto fail;
3964 rc = 0;
3966 if (ndst) {
3967 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3968 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3970 xmlFree(a);
3972 if (dup) {
3973 if (dup == nsrc)
3974 goto fail;
3976 if (ndst == xmlDocGetRootElement(client->doc)) {
3977 xmlNodePtr n = nsrc;
3978 gboolean match = FALSE;
3980 while (n->parent && n->parent != ndst)
3981 n = n->parent;
3983 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3984 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3986 if (xmlStrEqual(a, b)) {
3987 match = TRUE;
3988 xmlUnlinkNode(nsrc);
3989 xmlUnlinkNode(n);
3990 xmlFreeNodeList(n);
3993 xmlFree(a);
3994 xmlFree(b);
3996 if (!match) {
3997 xmlUnlinkNode(dup);
3998 xmlFreeNodeList(dup);
4001 else
4002 xmlUnlinkNode(dup);
4006 if (!ndst && dst)
4007 ndst = create_element_path(client, &dst, &rc);
4009 if (!ndst)
4010 goto fail;
4012 update_element_mtime(nsrc->parent);
4013 xmlUnlinkNode(nsrc);
4014 ndst = xmlAddChildList(ndst, nsrc);
4016 if (!ndst)
4017 rc = GPG_ERR_ENOMEM;
4019 update_element_mtime(ndst->parent);
4021 fail:
4022 if (req)
4023 g_strfreev(req);
4025 if (src)
4026 g_strfreev(src);
4028 if (dst)
4029 g_strfreev(dst);
4031 return send_error(ctx, rc);
4034 static int ls_command(assuan_context_t ctx, gchar *line)
4036 log_write2("ARGS=\"%s\"", line);
4037 gpg_error_t rc;
4038 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4039 gchar *dir = expand_homedir(tmp);
4040 DIR *d = opendir(dir);
4042 rc = gpg_error_from_syserror();
4043 g_free(tmp);
4045 if (!d) {
4046 g_free(dir);
4047 return send_error(ctx, rc);
4050 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4051 struct dirent *p = g_malloc(len), *cur = NULL;
4052 gchar *list = NULL;
4054 g_free(dir);
4055 rc = 0;
4057 while (!readdir_r(d, p, &cur) && cur) {
4058 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4059 continue;
4060 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4061 continue;
4063 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4065 if (!tmp) {
4066 if (list)
4067 g_free(list);
4069 rc = GPG_ERR_ENOMEM;
4070 break;
4073 g_free(list);
4074 list = tmp;
4077 closedir(d);
4078 g_free(p);
4080 if (rc)
4081 return send_error(ctx, rc);
4083 if (!list)
4084 return send_error(ctx, GPG_ERR_NO_VALUE);
4086 list[strlen(list)-1] = 0;
4087 rc = xfer_data(ctx, list, strlen(list));
4088 g_free(list);
4089 return send_error(ctx, rc);
4092 static void bye_notify(assuan_context_t ctx)
4094 struct client_s *cl = assuan_get_pointer(ctx);
4096 /* This will let assuan_process_next() return. */
4097 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4098 cl->last_rc = 0; // BYE command result
4101 static void reset_notify(assuan_context_t ctx)
4103 struct client_s *cl = assuan_get_pointer(ctx);
4105 if (cl)
4106 cleanup_client(cl);
4110 * This is called before every Assuan command.
4112 gint command_startup(assuan_context_t ctx, const gchar *name)
4114 struct client_s *cl = assuan_get_pointer(ctx);
4115 gpg_error_t rc;
4117 log_write1("%s", name);
4119 for (int i = 0; command_table[i]; i++) {
4120 if (!g_ascii_strcasecmp(name, command_table[i]->name) &&
4121 command_table[i]->ignore_startup)
4122 return 0;
4125 #ifdef WITH_PINENTRY
4126 if (!(cl->opts & OPT_PINENTRY))
4127 reset_pin_defaults(cl->pinentry);
4128 #endif
4130 cl->last_rc = rc = file_modified(cl);
4132 if (rc) {
4133 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4134 !g_ascii_strcasecmp(name, "OPEN"))
4135 rc = 0;
4138 return rc;
4142 * This is called after every Assuan command.
4144 void command_finalize(assuan_context_t ctx, gint rc)
4146 struct client_s *client = assuan_get_pointer(ctx);
4148 if (!client->is_lock_cmd)
4149 unlock_file_mutex(client);
4151 log_write1(N_("command completed (rc=%u)"), client->last_rc);
4152 client->opts &= ~(OPT_INQUIRE);
4153 client->opts &= ~(OPT_BASE64);
4156 static gint help_command(assuan_context_t ctx, gchar *line)
4158 gpg_error_t rc;
4159 gint i;
4161 if (!line || !*line) {
4162 gchar *tmp;
4163 gchar *buf = g_strdup(N_(
4164 "Usage: HELP [<COMMAND>]\n"
4165 " For commands that take an element path as an argument, each element is\n"
4166 " separated with an ASCII tab character (ASCII 0x09).\n"
4167 "\n"
4168 " Each element may contain a \"target\" attribute whose value is also an\n"
4169 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4170 " filesystem. When found, the element path of the \"target\" attribute will\n"
4171 " be used as a prefix for further elements in the current element path. To\n"
4172 " ignore any \"target\" attribute for the current element, prefix the element\n"
4173 " with an ! (ASCII 0x21).\n"
4174 "\n"
4175 " See pwmd(1) for configuration file options which may also set default\n"
4176 " options for specific data files.\n"
4177 "\n"
4178 "COMMANDS:"));
4180 for (i = 0; command_table[i]; i++) {
4181 gchar *p = strrchr(buf, '\n');
4182 gboolean newline = FALSE;
4184 if (!command_table[i]->help)
4185 continue;
4187 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4188 tmp = g_strdup_printf("%s\n", buf);
4189 g_free(buf);
4190 buf = tmp;
4191 newline = TRUE;
4194 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4195 command_table[i]->name);
4196 g_free(buf);
4197 buf = tmp;
4200 tmp = g_strdup_printf("%s\n", buf);
4201 g_free(buf);
4202 buf = tmp;
4203 rc = xfer_data(ctx, buf, strlen(buf));
4204 g_free(buf);
4205 return send_error(ctx, rc);
4208 for (i = 0; command_table[i]; i++) {
4209 if (!g_strcasecmp(line, command_table[i]->name)) {
4210 if (!command_table[i]->help)
4211 break;
4213 gchar *tmp = g_strdup_printf(N_("Usage: %s"), command_table[i]->help);
4214 rc = xfer_data(ctx, tmp, strlen(tmp));
4215 g_free(tmp);
4216 return send_error(ctx, rc);
4220 return send_error(ctx, GPG_ERR_INV_NAME);
4223 void new_command(const gchar *name, gboolean ignore,
4224 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4226 gint i = 0;
4228 if (command_table)
4229 for (i = 0; command_table[i]; i++);
4231 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4232 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4233 command_table[i]->name = name;
4234 command_table[i]->handler = handler;
4235 command_table[i]->ignore_startup = ignore;
4236 command_table[i++]->help = help;
4237 command_table[i] = NULL;
4240 void deinit_commands()
4242 gint i;
4244 for (i = 0; command_table[i]; i++)
4245 g_free(command_table[i]);
4247 g_free(command_table);
4250 static gint sort_commands(const void *arg1, const void *arg2)
4252 struct command_table_s* const *a = arg1;
4253 struct command_table_s* const *b = arg2;
4255 if (!*a || !*b)
4256 return 0;
4257 else if (*a && !*b)
4258 return 1;
4259 else if (!*a && *b)
4260 return -1;
4262 return strcmp((*a)->name, (*b)->name);
4265 void init_commands()
4267 /* !BEGIN-HELP-TEXT!
4269 * This comment is used as a marker to generate the offline documentation
4270 * for commands found in doc/COMMANDS.
4272 new_command("HELP", TRUE, help_command, N_(
4273 "HELP [<COMMAND>]\n"
4274 " Show available commands or command specific help text.\n"
4277 new_command("OPEN", FALSE, open_command, N_(
4278 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4279 " Opens <filename> using <key>. When the filename is not found on the\n"
4280 " file-system a new document will be created. If the file is found, it is\n"
4281 " looked for in the file cache for an existing key. When found and no key\n"
4282 " was specified, the cached key will be used for decryption (if encrypted).\n"
4283 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4284 " OPTIONS documentation).\n"
4285 "\n"
4286 " When the --lock option is passed then the file mutex will be locked as if\n"
4287 " the LOCK command had been sent after the file had been opened.\n"
4288 "\n"
4289 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4290 " retrieve the filename and key arguments.\n"
4291 "\n"
4292 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4293 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4294 " no value is specified then the configuration file value will be used. If\n"
4295 " the passphrase is invalid then it is up to the client whether to retry or\n"
4296 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4297 " pinentry dialog, use --pinentry=0.\n"
4298 "\n"
4299 " When a \"key_file\" configuration parameter has been set for the current\n"
4300 " file and there is no cache entry, then an --inquire must be used to\n"
4301 " retrieve the key.\n"
4302 "\n"
4303 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4304 " decoded before doing decryption. This allows for binary keys and may also\n"
4305 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4308 new_command("SAVE", FALSE, save_command, N_(
4309 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4310 " [--iterations=[N]] [--base64] [<key>]\n"
4311 " Writes the XML document to disk. The file written to is the file that was\n"
4312 " opened using the OPEN command. If <key> is not specified then the\n"
4313 " currently cached key will be used. If the file is a new file or the file\n"
4314 " is not found in the file cache then <key> will be used. If both <key> is\n"
4315 " not specified and the file is not cached then pinentry(1) will be used to\n"
4316 " retrieve the key (see below) unless the configured number of iterations is\n"
4317 " 0 in which case the file will be saved unencrypted.\n"
4318 "\n"
4319 " Note that when both <key> is specified and the configured number of\n"
4320 " iterations is 0 the iterations for the current filename will be reset to\n"
4321 " 1. This is to be on the safe side and prevent misuse.\n"
4322 "\n"
4323 " The --iterations option can be used to change the number of encryption\n"
4324 " iterations for the opened file. When 0 no encryption will be performed.\n"
4325 " When this option is either not passed or is specified without a value then\n"
4326 " the previous setting obtained from the file header will be used.\n"
4327 "\n"
4328 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4329 " string with the --cipher option. Omitting the string uses the current\n"
4330 " cipher of the opened file or the default if the file is a new one. The\n"
4331 " default is specified in the configuration file. See pwmd(1) for available\n"
4332 " ciphers.\n"
4333 "\n"
4334 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4335 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4336 " no value is specified then the configuration file value will be used.\n"
4337 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4338 " is started over again until either the passphrases match or until the\n"
4339 " input is canceled by the user. To save with encryption and with an empty\n"
4340 " passphrase, use --pinentry=0.\n"
4341 "\n"
4342 " When --reset is specified then the cached passphrase for the opened file\n"
4343 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4344 " had been sent.\n"
4345 "\n"
4346 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4347 " retrieve the key.\n"
4348 "\n"
4349 " When a \"key_file\" configuration parameter has been set for the current\n"
4350 " file and there is no cache entry, then an --inquire must be used to\n"
4351 " retrieve the key.\n"
4352 "\n"
4353 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4354 " decoded before doing encryption. This allows for binary keys and may also\n"
4355 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4358 new_command("ISCACHED", TRUE, iscached_command, N_(
4359 "ISCACHED <filename>\n"
4360 " An OK response is returned if the specified file is found in the file\n"
4361 " cache. If not found in the cache but exists on the filesystem,\n"
4362 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4365 new_command("CLEARCACHE", TRUE, clearcache_command, N_(
4366 "CLEARCACHE [<filename>]\n"
4367 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4368 " the specified file. Always returns an OK response.\n"
4371 new_command("CACHETIMEOUT", TRUE, cachetimeout_command, N_(
4372 "CACHETIMEOUT <filename> <seconds>\n"
4373 " Specify the number of seconds the specified file will be cached. -1 will\n"
4374 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4375 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4376 " parameter. Returns ERR if the filename is not cached or if the timeout is\n"
4377 " invalid. OK otherwise.\n"
4380 new_command("LIST", FALSE, list_command, N_(
4381 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4382 " If no element path is given then a newline separated list of root elements\n"
4383 " is returned with the data response. If given, then all reachable elements\n"
4384 " for the specified element path are returned unless the --no-recurse option\n"
4385 " is specified. If specified, only the child elements of the element path\n"
4386 " are returned without recursing into grandchildren. Each element in the\n"
4387 " path is prefixed with the literal '!' character when the element contains\n"
4388 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4389 "\n"
4390 " When the --verbose option is passed then each element path returned in the\n"
4391 " list will have a single space character followed by either a 0 or 1\n"
4392 " appended to it. When 0, the element path has no children, otherwise it\n"
4393 " does have children. When used with the --no-recurse option this may be\n"
4394 " useful to limit the amount of data transferred to the client.\n"
4397 new_command("REALPATH", FALSE, realpath_command, N_(
4398 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4399 " Resolves all \"target\" attributes of the specified element path and returns\n"
4400 " the result with a data response.\n"
4403 new_command("STORE", FALSE, store_command, N_(
4404 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4405 " Creates a new element path or modifies the content of an existing element\n"
4406 " path. If only a single element is specified, a new root element is\n"
4407 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4408 " to the last TAB delimited argument. If no content is specified after the\n"
4409 " last TAB then the content for the last specified element will be removed,\n"
4410 " or empty when creating a new element.\n"
4411 "\n"
4412 " The only restriction of an element name is that it not contain whitespace\n"
4413 " or begin with the literal element character '!' unless specifying a\n"
4414 " literal element. There is no whitespace between the TAB delimited\n"
4415 " elements. It is recommended that the value or content be base 64 encoded\n"
4416 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4417 " errors.\n"
4418 "\n"
4419 " This command uses a server INQUIRE to retrieve the data from the client.\n"
4422 new_command("RENAME", FALSE, rename_command, N_(
4423 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4424 " Renames the specified element to the new value. If an element of the same\n"
4425 " name as the value exists then it will be overwritten.\n"
4428 new_command("COPY", FALSE, copy_command, N_(
4429 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4430 " Copies the entire element tree starting from the child node of the source\n"
4431 " element path, to the destination element path. If the destination element\n"
4432 " path does not exist then it will be created; otherwise it is overwritten.\n"
4433 "\n"
4434 " Note that attributes from the source element path are merged into the\n"
4435 " destination element path when the destination element path exists. When an\n"
4436 " attribute of the same name exists in both the source and destination\n"
4437 " element paths then the destination attribute will be updated to the source\n"
4438 " attribute value.\n"
4441 new_command("MOVE", FALSE, move_command, N_(
4442 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4443 " Moves the source element path to the destination element path. If the\n"
4444 " destination is not specified then it will be moved to the root of the\n"
4445 " document. If the destination is specified and exists then it will be\n"
4446 " overwritten; otherwise it will be created.\n"
4449 new_command("DELETE", FALSE, delete_command, N_(
4450 "DELETE [!]element[<TAB>[!]element[...]]\n"
4451 " Removes the specified element path and any children from the XML document.\n"
4454 new_command("GET", FALSE, get_command, N_(
4455 "GET [!]element[<TAB>[!]element[...]]\n"
4456 " Retrieves the content or XML text node of the specified element path. The\n"
4457 " content is returned with a data response.\n"
4460 new_command("ATTR", FALSE, attr_command, N_(
4461 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4462 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4463 " Stores or updates an attribute name and optional value of an element\n"
4464 " path.\n"
4465 "\n"
4466 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4467 " Removes an attribute from an element path.\n"
4468 "\n"
4469 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4470 " Retrieves a newline separated list of attributes names and values from\n"
4471 " the specified element path. The attribute names and values are space\n"
4472 " delimited.\n"
4473 "\n"
4474 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4475 " Retrieves the value of an attribute from an element path.\n"
4476 "\n"
4477 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4478 " if the element path is the root element. Although it can be SET to change\n"
4479 " the element name but only if the destination element name doesn't exist.\n"
4480 " Use the RENAME command for that instead.\n"
4481 "\n"
4482 " The \"_mtime\" attribute is updated each time an element is modified by\n"
4483 " either storing content, editing attributes or by deleting a child element.\n"
4484 "\n"
4485 " Also see THE TARGET ATTRIBUTE.\n"
4488 new_command("XPATH", FALSE, xpath_command, N_(
4489 "XPATH <expression>[<TAB>[value]]\n"
4490 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4491 " assumed the expression is a request to return a result. Otherwise, the\n"
4492 " result is set to the value argument and the document is updated. If there\n"
4493 " is no value after the <TAB> character, the value is assumed to be empty\n"
4494 " and the document is updated.\n"
4497 new_command("XPATHATTR", FALSE, xpathattr_command, N_(
4498 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4499 " Like the XPATH command but operates on element attributes and won't return\n"
4500 " a result. For the SET operation the <value> is optional but the field is\n"
4501 " required in which case the value will be empty.\n"
4504 new_command("IMPORT", FALSE, import_command, N_(
4505 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4506 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4507 " data. The content is created as a child of the specified element path. If\n"
4508 " an element of the element path does not exist then it is created. If no\n"
4509 " element path is specified then the content must begin with an pwmd DTD\n"
4510 " root element.\n"
4511 "\n"
4512 " Note that the new content must begin with an XML element node. Also note\n"
4513 " that an existing child node of the same element name as the root node of\n"
4514 " the imported content will be overwritten.\n"
4517 new_command("DUMP", FALSE, dump_command, N_(
4518 "DUMP\n"
4519 " Shows the in memory XML document with indenting. To dump a specific\n"
4520 " element tree, use the XPATH command.\n"
4523 new_command("LOCK", FALSE, lock_command, N_(
4524 "LOCK\n"
4525 " Locks the mutex associated with the opened file. This prevents other\n"
4526 " clients from sending commands to the same opened file until the client\n"
4527 " that sent this command either disconnects or sends the UNLOCK command.\n"
4530 new_command("UNLOCK", FALSE, unlock_command, N_(
4531 "UNLOCK\n"
4532 " Unlocks the file mutex which was locked with the LOCK command.\n"
4535 new_command("GETPID", TRUE, getpid_command, N_(
4536 "GETPID\n"
4537 " Retrieves the process id of the server.\n"
4540 new_command("GETCONFIG", TRUE, getconfig_command, N_(
4541 "GETCONFIG [filename] <parameter>\n"
4542 " Returns the value of a pwmd configuration variable with a data response.\n"
4543 " If no file has been opened then the value for the specified file or the\n"
4544 " default from the \"global\" section will be returned. If a file has been\n"
4545 " opened and no filename is specified, the value previously set with the SET\n"
4546 " command, if any, will be returned.\n"
4547 "\n"
4548 " If there is no such configuration parameter defined, GPG_ERR_UNKNOWN_OPTION\n"
4549 " is returned.\n"
4552 new_command("VERSION", TRUE, version_command, N_(
4553 "VERSION\n"
4554 " Returns the server version number and compile-time features with a data\n"
4555 " response with each being space delimited.\n"
4558 new_command("SET", TRUE, set_command, N_(
4559 "SET <NAME>=<VALUE>\n"
4560 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4561 " option to its default value.\n"
4562 "\n"
4563 " NAME |VALUE |Description\n"
4564 " -----------------|----------|----------------------------------------------\n"
4565 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4566 " is 1.\n"
4567 "\n"
4568 " * Deprecated. Pass --pinentry to the OPEN and\n"
4569 " SAVE commands instead.\n"
4570 "\n"
4571 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4572 " process will terminate while waiting for a\n"
4573 " passphrase. The default is 20, 0 disables.\n"
4574 "\n"
4575 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4576 " is specified at compile time.\n"
4577 "\n"
4578 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4579 "\n"
4580 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4581 "\n"
4582 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4583 "\n"
4584 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4585 "\n"
4586 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4587 "\n"
4588 " DESC <string> Sets the error or description string of the\n"
4589 " pinentry dialog.\n"
4590 "\n"
4591 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4592 "\n"
4593 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4594 " pinentry(1).\n"
4595 "\n"
4596 " NAME <string> Associates the thread ID of the connection\n"
4597 " with the specified textual representation.\n"
4598 " Useful for debugging log messages.\n"
4599 "\n"
4600 " CIPHER <string> The cipher to use for the next SAVE.\n"
4601 "\n"
4602 " * Deprecated. Use --cipher instead.\n"
4603 "\n"
4604 " ITERATIONS <integer> The number of encryption iterations to do\n"
4605 " when the SAVE command is sent. An opened file\n"
4606 " is needed when setting this option. The\n"
4607 " CONFIG status message is sent after receiving\n"
4608 " this command.\n"
4609 "\n"
4610 " * Deprecated. Use --iterations instead.\n"
4611 "\n"
4612 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4613 " after a successful OPEN as if the LOCK\n"
4614 " command had been sent.\n"
4615 "\n"
4616 " * Deprecated. Use --lock instead.\n"
4617 "\n"
4618 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4619 " of a status message when the file mutex is\n"
4620 " locked by another client.\n"
4623 new_command("UNSET", TRUE, unset_command, N_(
4624 "UNSET <NAME>\n"
4625 " Resets option NAME to the value specified in the server configuration\n"
4626 " file. Some options have no default and will be reset to NULL or 0\n"
4627 " depending on the value type. See the SET command for available options.\n"
4630 new_command("LS", TRUE, ls_command, N_(
4631 "LS\n"
4632 " Lists the contents of the configured data_directory. The result is a\n"
4633 " newline separated list of filenames.\n"
4636 new_command("RESET", TRUE, NULL, N_(
4637 "RESET\n"
4638 " Closes the currently opened file but keeps any previously set client\n"
4639 " options.\n"
4642 new_command("BYE", TRUE, NULL, N_(
4643 "BYE\n"
4644 " Closes the connection discarding any unsaved changes.\n"
4647 new_command("NOP", TRUE, NULL, N_(
4648 "NOP\n"
4649 " Does nothing. Always returns successfully.\n"
4652 /* !END-HELP-TEXT! */
4653 new_command("CANCEL", TRUE, NULL, NULL);
4654 new_command("END", TRUE, NULL, NULL);
4656 gint i;
4657 for (i = 0; command_table[i]; i++);
4658 qsort(command_table, i-1, sizeof(struct command_table_s *), sort_commands);
4661 gpg_error_t register_commands(assuan_context_t ctx)
4663 gint i = 0, rc;
4665 for (; command_table[i]; i++) {
4666 if (!command_table[i]->handler)
4667 continue;
4669 rc = assuan_register_command (ctx, command_table[i]->name,
4670 command_table[i]->handler);
4672 if (rc)
4673 return rc;
4676 rc = assuan_register_bye_notify(ctx, bye_notify);
4678 if (rc)
4679 return rc;
4681 rc = assuan_register_reset_notify(ctx, reset_notify);
4683 if (rc)
4684 return rc;
4686 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4688 if (rc)
4689 return rc;
4691 return assuan_register_post_cmd_notify(ctx, command_finalize);
4694 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4695 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4697 goffset insize, len;
4698 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4699 guint64 iter = 0, n_iter = 0, iter_progress = 0;
4700 gulong outsize = 0;
4701 gpg_error_t rc;
4702 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4703 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4704 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4706 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4707 insize = crypto->fh->st.st_size - fh_size;
4708 crypto->iv = gcry_malloc(crypto->blocksize);
4710 if (!crypto->iv) {
4711 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4712 return GPG_ERR_ENOMEM;
4715 if (crypto->fh->v1)
4716 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4717 else
4718 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4720 crypto->inbuf = gcry_malloc(insize);
4722 if (!crypto->inbuf) {
4723 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4724 return GPG_ERR_ENOMEM;
4727 crypto->insize = insize;
4728 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4730 if (len != crypto->insize)
4731 return GPG_ERR_INV_LENGTH;
4733 /* No encryption iterations. This is a plain (gzipped) file. */
4734 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4735 (!crypto->fh->v1 && fh_iter <= 0L)) {
4737 * cache_file_count() needs both .used == TRUE and a valid key in
4738 * order for it to count as a used cache entry. Fixes CACHE status
4739 * messages.
4741 memset(crypto->key, '!', hashlen);
4742 goto decompress;
4745 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4746 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4747 return rc;
4750 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4751 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4752 return rc;
4755 iter_progress = get_key_file_uint64(client && client->filename ?
4756 client->filename : "global", "iteration_progress");
4758 if (iter_progress > 0 && fh_iter >= iter_progress) {
4759 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4761 if (rc)
4762 return rc;
4765 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4767 if (rc)
4768 return rc;
4770 crypto->tkey = gcry_malloc(hashlen);
4772 if (!crypto->tkey) {
4773 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4774 return GPG_ERR_ENOMEM;
4777 memcpy(crypto->tkey, crypto->key, hashlen);
4778 guchar *tkey = crypto->tkey;
4779 tkey[0] ^= 1;
4781 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4782 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4783 return rc;
4786 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4787 if (iter_progress > 0ULL && iter >= iter_progress) {
4788 if (!(iter % iter_progress)) {
4789 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4790 ++n_iter * iter_progress, fh_iter);
4792 if (rc)
4793 return rc;
4797 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4798 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4799 return rc;
4802 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4804 if (rc) {
4805 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4806 return rc;
4809 iter++;
4812 if (iter_progress && fh_iter >= iter_progress) {
4813 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4815 if (rc)
4816 return rc;
4819 decompress:
4820 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4821 len = 0;
4823 if (crypto->fh->ver.fh2.iter > 0ULL) {
4824 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4825 return GPG_ERR_INV_PASSPHRASE;
4827 len = sizeof(crypto_magic);
4830 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4831 (gpointer *)&crypto->outbuf, &outsize);
4833 if (rc)
4834 return rc;
4836 else {
4837 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4838 (gpointer *)&crypto->outbuf, &outsize);
4840 if (rc == GPG_ERR_ENOMEM)
4841 return rc;
4842 else if (rc)
4843 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4845 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4846 gcry_free(crypto->outbuf);
4847 crypto->outbuf = NULL;
4848 return GPG_ERR_INV_PASSPHRASE;
4852 if (ctx) {
4853 client->xml = crypto->outbuf;
4854 client->len = outsize;
4855 crypto->outbuf = NULL;
4857 else if (dst) {
4858 *dst = crypto->outbuf;
4859 *dst_len = outsize;
4860 crypto->outbuf = NULL;
4863 /* The calling function should free the crypto struct. */
4864 return 0;