Do as the documentation says and let CLEARCACHE always return 0 even when
[pwmd.git] / src / commands.c
blob6c7666b5d5a7b3c36e385212f8910873cec484a0
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2010 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #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"
55 struct gz_s {
56 z_stream z;
57 gpointer out;
58 gboolean done;
59 status_msg_t which;
62 struct command_table_s {
63 const gchar *name;
64 gint (*handler)(assuan_context_t, gchar *line);
65 const gchar *help;
66 gboolean ignore_startup;
69 static struct command_table_s **command_table;
70 static guchar crypto_magic[5] = "\177PWMD";
72 static gpg_error_t do_lock_command(struct client_s *client);
74 static void *z_alloc(void *data, unsigned items, unsigned size)
76 return gcry_calloc(items, size);
79 static void z_free(void *data, void *p)
81 gcry_free(p);
84 static gpg_error_t file_modified(struct client_s *client)
86 struct stat st;
87 gpg_error_t rc;
89 if (client->state != STATE_OPEN)
90 return EPWMD_NO_FILE;
92 rc = lock_file_mutex(client);
94 if (rc)
95 return rc;
97 if (lstat(client->filename, &st) == 0 && client->mtime) {
98 if (client->mtime != st.st_mtime)
99 return EPWMD_FILE_MODIFIED;
102 pth_cancel_point();
103 return 0;
106 static gpg_error_t parse_xml(assuan_context_t ctx)
108 struct client_s *client = assuan_get_pointer(ctx);
110 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
112 if (!client->doc)
113 return EPWMD_LIBXML_ERROR;
115 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
116 return 0;
118 return convert_elements(client->doc);
121 void unlock_file_mutex(struct client_s *client)
123 pth_mutex_t *m;
125 if (client->has_lock == FALSE)
126 return;
128 CACHE_LOCK(client->ctx);
130 if (cache_get_mutex(client->md5file, &m) == FALSE) {
131 CACHE_UNLOCK;
132 return;
135 CACHE_UNLOCK;
136 MUTEX_UNLOCK(m);
137 client->has_lock = client->is_lock_cmd = FALSE;
140 gpg_error_t lock_file_mutex(struct client_s *client)
142 pth_mutex_t *m;
143 gpg_error_t rc = 0;
145 if (client->has_lock == TRUE)
146 return 0;
148 CACHE_LOCK(client->ctx);
150 if (cache_get_mutex(client->md5file, &m) == FALSE) {
151 CACHE_UNLOCK;
152 return 0;
155 CACHE_UNLOCK;
157 if (client->rc_on_locked) {
158 if (!pth_mutex_acquire(m, TRUE, NULL))
159 return GPG_ERR_LOCKED;
160 #ifdef MUTEX_DEBUG
161 MUTEX_LOCK_DEBUG(m);
162 #endif
164 else
165 MUTEX_TRYLOCK(client, m, rc);
167 if (!rc)
168 client->has_lock = TRUE;
170 return rc;
173 void free_client(struct client_s *client)
175 if (client->doc)
176 xmlFreeDoc(client->doc);
178 if (client->xml)
179 gcry_free(client->xml);
181 if (client->filename)
182 g_free(client->filename);
184 if (client->crypto)
185 cleanup_crypto(&client->crypto);
187 if (client->xml_error)
188 xmlResetError(client->xml_error);
191 void cleanup_client(struct client_s *client)
193 assuan_context_t ctx = client->ctx;
194 struct client_thread_s *thd = client->thd;
195 gboolean rc_on_locked = client->rc_on_locked;
196 gboolean lock_on_open = client->lock_on_open;
197 #ifdef WITH_PINENTRY
198 struct pinentry_s *pin = client->pinentry;
199 #endif
201 unlock_file_mutex(client);
202 CACHE_LOCK(client->ctx);
203 cache_decr_refcount(client->md5file);
206 * This may be a new file so don't use a cache slot. save_command() will
207 * set this to FALSE on success.
209 if (client->new == TRUE)
210 cache_clear(client->md5file, 1);
212 CACHE_UNLOCK;
213 free_client(client);
214 memset(client, 0, sizeof(struct client_s));
215 client->state = STATE_CONNECTED;
216 client->ctx = ctx;
217 client->thd = thd;
218 client->freed = TRUE;
219 #ifdef WITH_PINENTRY
220 client->pinentry = pin;
221 #endif
222 client->rc_on_locked = rc_on_locked;
223 client->lock_on_open = lock_on_open;
226 static void gz_cleanup(void *arg)
228 struct gz_s **gz = (struct gz_s **)arg;
230 if (!gz)
231 return;
233 if (!(*gz)->done && (*gz)->out)
234 gcry_free((*gz)->out);
236 if ((*gz)->which == STATUS_COMPRESS) {
237 if ((*gz)->z.zalloc)
238 deflateEnd(&(*gz)->z);
240 else {
241 if ((*gz)->z.zalloc)
242 inflateEnd(&(*gz)->z);
245 g_free(*gz);
246 *gz = NULL;
249 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
250 gpointer *out, gulong *outsize)
252 struct gz_s *gz;
253 gz_header h;
254 gchar buf[17];
255 gpg_error_t rc;
256 gint zrc;
258 gz = g_malloc0(sizeof(struct gz_s));
260 if (!gz)
261 return GPG_ERR_ENOMEM;
263 pth_cleanup_push(gz_cleanup, &gz);
264 gz->which = STATUS_DECOMPRESS;
265 gz->z.zalloc = z_alloc;
266 gz->z.zfree = z_free;
267 gz->z.next_in = in;
268 gz->z.avail_in = (uInt)insize;
269 gz->z.avail_out = zlib_bufsize;
270 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
272 if (!gz->out) {
273 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
274 pth_cleanup_pop(1);
275 return GPG_ERR_ENOMEM;
278 zrc = inflateInit2(&gz->z, 47);
280 if (zrc != Z_OK) {
281 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
282 pth_cleanup_pop(1);
283 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
286 memset(&h, 0, sizeof(gz_header));
287 h.comment = (guchar *)buf;
288 h.comm_max = sizeof(buf);
289 zrc = inflateGetHeader(&gz->z, &h);
291 if (zrc != Z_OK) {
292 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
293 pth_cleanup_pop(1);
294 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
297 zrc = inflate(&gz->z, Z_BLOCK);
299 if (zrc != Z_OK) {
300 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
301 pth_cleanup_pop(1);
302 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
305 if (h.comment)
306 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
308 do {
309 gpointer p;
311 zrc = inflate(&gz->z, Z_FINISH);
313 switch (zrc) {
314 case Z_OK:
315 break;
316 case Z_BUF_ERROR:
317 if (!gz->z.avail_out) {
318 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
320 if (!p) {
321 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
322 rc = GPG_ERR_ENOMEM;
323 goto fail;
326 gz->out = p;
327 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
328 gz->z.avail_out = zlib_bufsize;
329 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
330 gz->z.total_out, insize);
332 if (rc)
333 goto fail;
335 break;
336 case Z_STREAM_END:
337 break;
338 default:
339 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
340 rc = GPG_ERR_COMPR_ALGO;
341 goto fail;
342 break;
344 } while (zrc != Z_STREAM_END);
346 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
347 insize);
349 if (rc)
350 goto fail;
352 *out = gz->out;
353 *outsize = gz->z.total_out;
354 gz->done = TRUE;
355 pth_cleanup_pop(1);
356 return 0;
358 fail:
359 pth_cleanup_pop(1);
360 return rc;
363 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
364 gpg_error_t *rc)
366 gint fd;
367 gsize len;
368 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
369 gsize fh_size;
370 gpointer p;
372 *rc = 0;
374 if (!fh) {
375 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
376 *rc = GPG_ERR_ENOMEM;
377 return NULL;
380 pth_cleanup_push(g_free, fh);
381 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
383 if (lstat(filename, &fh->st) == -1) {
384 *rc = gpg_error_from_syserror();
385 pth_cleanup_pop(1);
386 return NULL;
389 if (!S_ISREG(fh->st.st_mode)) {
390 *rc = GPG_ERR_ENOANO;
391 pth_cleanup_pop(1);
392 return NULL;
395 fd = open(filename, O_RDONLY);
397 if (fd == -1) {
398 *rc = gpg_error_from_syserror();
399 pth_cleanup_pop(1);
400 return NULL;
403 pth_cleanup_push(cleanup_fd_cb, &fd);
404 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
405 len = pth_read(fd, p, fh_size);
407 if (len != fh_size) {
408 *rc = gpg_error_from_syserror();
409 pth_cleanup_pop(1);
410 pth_cleanup_pop(1);
411 return NULL;
414 fh->v1 = v1;
415 fh->fd = fd;
416 pth_cleanup_pop(0);
417 pth_cleanup_pop(0);
418 return fh;
421 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
422 gboolean cached)
424 struct client_s *client = assuan_get_pointer(ctx);
425 gpg_error_t rc;
426 gint timeout;
427 guchar *key = client->crypto->key;
429 /* New file. */
430 if (!client->crypto->fh) {
431 if (key[0])
432 goto update_cache;
434 goto done;
437 rc = init_client_crypto2(client->filename, client->crypto);
439 if (rc) {
440 cleanup_client(client);
441 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
444 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
446 if (rc) {
447 cleanup_client(client);
448 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
451 update_cache:
452 CACHE_LOCK(client->ctx);
454 if (cached == FALSE) {
455 if (cache_update_key(client->md5file, key) == FALSE) {
456 cleanup_client(client);
457 CACHE_UNLOCK;
458 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
461 timeout = get_key_file_integer(client->filename, "cache_timeout");
462 cache_reset_timeout(client->md5file, timeout);
464 else
465 cache_set_timeout(client->md5file, -2);
467 CACHE_UNLOCK;
469 done:
470 rc = parse_xml(ctx);
472 if (client->xml) {
473 gcry_free(client->xml);
474 client->xml = NULL;
477 if (!rc) {
478 if (client->new == FALSE)
479 send_status_all(STATUS_CACHE);
481 client->state = STATE_OPEN;
484 if (!rc && client->new == FALSE &&
485 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
486 MUTEX_LOCK(&rcfile_mutex);
487 g_key_file_set_double(keyfileh, client->filename, "iterations",
488 client->crypto->fh->ver.fh2.iter);
489 MUTEX_UNLOCK(&rcfile_mutex);
490 send_status_all(STATUS_CONFIG);
493 cleanup_crypto(&client->crypto);
495 if (!rc && client->lock_on_open)
496 return do_lock_command(client);
498 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
501 static void req_cleanup(void *arg)
503 if (!arg)
504 return;
506 g_strfreev((gchar **)arg);
509 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
511 struct client_s *client = data;
512 const gchar *p = value;
514 if (p && *p) {
515 long l = strtol(p, NULL, 10);
517 if (l < 0 || l > 1)
518 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
520 client->lock_on_open = l ? TRUE : FALSE;
522 else if ((!p || !*p) && (client->opts & OPT_LOCK))
523 client->lock_on_open = FALSE;
524 else
525 client->lock_on_open = TRUE;
527 return 0;
530 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
532 #ifdef WITH_PINENTRY
533 struct client_s *client = data;
534 gchar *p = NULL;
535 gchar *str = value;
536 gint n;
538 if (!str || !*str) {
539 client->pinentry->enable = -1;
540 client->opts &= ~(OPT_PINENTRY);
541 return 0;
544 n = strtol(str, &p, 10);
546 if (*p || n < 0 || n > 1)
547 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
549 client->pinentry->enable = n ? TRUE : FALSE;
550 client->opts |= OPT_PINENTRY;
551 return 0;
552 #else
553 return GPG_ERR_NOT_IMPLEMENTED;
554 #endif
557 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
559 struct client_s *client = data;
561 (void)value;
562 client->opts |= OPT_INQUIRE;
563 return 0;
566 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
568 struct client_s *client = data;
570 (void)value;
571 client->opts |= OPT_BASE64;
572 return 0;
575 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
577 guchar *tmp;
578 gsize len;
580 if (client->opts & OPT_BASE64)
581 tmp = g_base64_decode(key, &len);
582 else {
583 tmp = (guchar *)g_strdup(key);
584 len = strlen(key);
587 if (!tmp)
588 return GPG_ERR_ENOMEM;
590 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
591 g_free(tmp);
592 return 0;
595 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
597 gboolean cached = FALSE;
598 gpg_error_t rc;
599 struct client_s *client = assuan_get_pointer(ctx);
600 gchar **req;
601 gchar *filename = NULL;
602 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
604 if ((req = split_input_line(line, " ", 2)) != NULL)
605 filename = req[0];
607 pth_cleanup_push(req_cleanup, req);
609 if (!filename || !*filename) {
610 pth_cleanup_pop(1);
611 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
614 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
616 if (valid_filename(filename) == FALSE) {
617 pth_cleanup_pop(1);
618 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
621 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
622 CACHE_LOCK(client->ctx);
624 if (cache_has_file(client->md5file) == FALSE) {
625 if (cache_add_file(client->md5file, NULL) == FALSE) {
626 pth_cleanup_pop(1);
627 CACHE_UNLOCK;
628 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
632 CACHE_UNLOCK;
633 rc = lock_file_mutex(client);
635 if (rc) {
636 pth_cleanup_pop(1);
637 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
640 client->freed = FALSE;
641 CACHE_LOCK(client->ctx);
642 cache_incr_refcount(client->md5file);
643 CACHE_UNLOCK;
644 client->crypto = init_client_crypto();
646 if (!client->crypto) {
647 pth_cleanup_pop(1);
648 cleanup_client(client);
649 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
652 client->crypto->key = gcry_malloc(hashlen);
654 if (!client->crypto->key) {
655 pth_cleanup_pop(1);
656 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
657 GPG_ERR_ENOMEM);
658 cleanup_client(client);
659 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
662 memset(client->crypto->key, 0, hashlen);
663 client->crypto->fh = read_file_header(filename, FALSE, &rc);
665 if (!client->crypto->fh) {
666 if (gpg_err_code_to_errno(rc) != ENOENT) {
667 log_write("%s: %s", filename, pwmd_strerror(rc));
668 pth_cleanup_pop(1);
669 cleanup_client(client);
670 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
674 * New files don't need a key.
676 if ((client->xml = new_document()) == NULL) {
677 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
678 pth_cleanup_pop(1);
679 cleanup_client(client);
680 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
683 client->len = xmlStrlen(client->xml);
684 client->new = TRUE;
685 client->filename = g_strdup(filename);
687 if (!client->filename) {
688 pth_cleanup_pop(1);
689 cleanup_client(client);
690 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
691 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
694 if (req[1] && *req[1]) {
695 rc = hash_key(client, req[1]);
697 if (rc) {
698 pth_cleanup_pop(1);
699 cleanup_client(client);
700 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
704 pth_cleanup_pop(1);
705 #ifdef WITH_PINENTRY
706 client->pinentry->filename = g_strdup(client->filename);
708 if (!client->pinentry->filename) {
709 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
710 cleanup_client(client);
711 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
713 #endif
714 return open_command_finalize(ctx, NULL, cached);
716 else {
717 if (!(client->opts & OPT_CIPHER))
718 g_key_file_set_string(keyfileh, filename, "cipher",
719 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
721 client->mtime = client->crypto->fh->st.st_mtime;
724 client->filename = g_strdup(filename);
726 if (!client->filename) {
727 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
728 pth_cleanup_pop(1);
729 cleanup_client(client);
730 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
733 #ifdef WITH_PINENTRY
734 if (client->pinentry->filename)
735 g_free(client->pinentry->filename);
737 client->pinentry->filename = g_strdup(client->filename);
739 if (!client->pinentry->filename) {
740 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
741 pth_cleanup_pop(1);
742 cleanup_client(client);
743 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
745 #endif
747 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
748 goto done;
750 CACHE_LOCK(client->ctx);
751 cached = cache_get_key(client->md5file, client->crypto->key);
752 CACHE_UNLOCK;
754 if (cached == FALSE) {
755 gchar *tmp = get_key_file_string(filename, "key_file");
757 if (tmp && !(client->opts & OPT_INQUIRE)) {
758 g_free(tmp);
759 pth_cleanup_pop(1);
760 cleanup_client(client);
761 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
764 if (tmp)
765 g_free(tmp);
768 * No key specified and no matching filename found in the cache. Use
769 * pinentry to retrieve the key. Cannot return assuan_process_done()
770 * here otherwise the command will be interrupted. The event loop in
771 * client_thread() will poll the file descriptor waiting for it to
772 * become ready to read a pinentry_key_s which will contain the
773 * entered key or an error code. It will then call
774 * open_command_finalize() to to finish the command.
776 if (!req[1] || !*req[1]) {
777 #ifdef WITH_PINENTRY
778 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
780 /* From set_pinentry_defaults(). */
781 if (client->opts & OPT_INQUIRE ||
782 client->pinentry->enable == FALSE ||
783 (client->pinentry->enable == -1 && b == FALSE)) {
784 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
785 goto done;
788 pth_cleanup_pop(1);
789 rc = lock_pin_mutex(client);
791 if (rc) {
792 unlock_pin_mutex(client->pinentry);
793 cleanup_client(client);
794 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
797 client->pinentry->which = PINENTRY_OPEN;
798 rc = pinentry_fork(ctx);
800 if (rc) {
801 unlock_pin_mutex(client->pinentry);
802 cleanup_client(client);
803 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
806 // Called from pinentry iterate.
807 client->pinentry->cb = open_command_finalize;
808 client->pinentry->status = PINENTRY_INIT;
809 return 0;
810 #else
811 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
812 goto done;
813 #endif
816 rc = hash_key(client, req[1]);
818 if (rc) {
819 pth_cleanup_pop(1);
820 cleanup_client(client);
821 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
824 else if (req && req[1] && *req[1]) {
825 rc = hash_key(client, req[1]);
827 if (rc) {
828 pth_cleanup_pop(1);
829 cleanup_client(client);
830 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
834 done:
835 pth_cleanup_pop(1);
836 return open_command_finalize(ctx, NULL, cached);
839 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
840 guchar *line, gsize len)
842 assuan_context_t ctx = data;
843 struct client_s *client = assuan_get_pointer(ctx);
844 gpg_error_t rc = file_modified(client);
846 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
847 if (line)
848 xfree(line);
850 return assuan_rc ? assuan_rc : rc;
853 rc = open_command_common(ctx, (gchar *)line);
855 if (line)
856 xfree(line);
858 client->inquire_status = INQUIRE_DONE;
859 return rc;
862 static gint open_command(assuan_context_t ctx, gchar *line)
864 gpg_error_t rc;
865 struct client_s *client = assuan_get_pointer(ctx);
866 struct argv_s *args[] = {
867 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
868 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
869 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
870 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
871 NULL
874 if (client->state == STATE_OPEN)
875 cleanup_client(client);
877 if (!(client->opts & OPT_LOCK))
878 client->lock_on_open = FALSE;
880 rc = parse_options(&line, args, client);
882 if (rc)
883 return send_error(ctx, rc);
885 if ((client->opts & OPT_INQUIRE)) {
886 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
887 ctx);
889 if (rc)
890 return send_error(ctx, rc);
892 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
893 client->inquire_status = INQUIRE_BUSY;
894 return 0;
897 return open_command_common(ctx, line);
900 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
901 guint size, gpointer *out, gulong *outsize)
903 struct gz_s *gz;
904 gz_header h;
905 gchar buf[17];
906 gint cmd = Z_NO_FLUSH;
907 gint zrc;
908 gpg_error_t rc;
910 gz = g_malloc0(sizeof(struct gz_s));
912 if (!gz)
913 return GPG_ERR_ENOMEM;
915 pth_cleanup_push(gz_cleanup, &gz);
916 gz->which = STATUS_COMPRESS;
917 gz->z.zalloc = z_alloc;
918 gz->z.zfree = z_free;
919 gz->z.next_in = data;
920 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
921 gz->z.avail_out = (uInt)zlib_bufsize;
922 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
924 if (!gz->out) {
925 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
926 pth_cleanup_pop(1);
927 return GPG_ERR_ENOMEM;
930 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
932 if (zrc != Z_OK) {
933 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
934 pth_cleanup_pop(1);
935 return GPG_ERR_COMPR_ALGO;
938 /* Rather than store the size of the uncompressed data in the file header,
939 * store it in the comment field of the gzip header. Don't give anyone too
940 * much information. Not sure why really, but it seems the right way. :)
942 memset(&h, 0, sizeof(gz_header));
943 g_snprintf(buf, sizeof(buf), "%u", size);
944 h.comment = (guchar *)buf;
945 zrc = deflateSetHeader(&gz->z, &h);
947 if (zrc != Z_OK) {
948 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
949 pth_cleanup_pop(1);
950 return GPG_ERR_COMPR_ALGO;
953 do {
954 gpointer p;
956 zrc = deflate(&gz->z, cmd);
958 switch (zrc) {
959 case Z_OK:
960 break;
961 case Z_BUF_ERROR:
962 if (!gz->z.avail_out) {
963 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
965 if (!p) {
966 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
967 rc = GPG_ERR_ENOMEM;
968 goto fail;
971 gz->out = p;
972 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
973 gz->z.avail_out = zlib_bufsize;
976 if (!gz->z.avail_in && gz->z.total_in < size) {
977 if (gz->z.total_in + zlib_bufsize > size)
978 gz->z.avail_in = size - gz->z.total_in;
979 else
980 gz->z.avail_in = zlib_bufsize;
982 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
983 gz->z.total_in, size);
985 if (rc)
986 goto fail;
989 if (gz->z.total_in >= size)
990 cmd = Z_FINISH;
992 break;
993 case Z_STREAM_END:
994 break;
995 default:
996 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
997 rc = GPG_ERR_COMPR_ALGO;
998 goto fail;
1000 } while (zrc != Z_STREAM_END);
1002 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1004 if (rc)
1005 goto fail;
1007 *out = gz->out;
1008 *outsize = gz->z.total_out;
1009 gz->done = TRUE;
1010 pth_cleanup_pop(1);
1011 return 0;
1013 fail:
1014 pth_cleanup_pop(1);
1015 return rc;
1018 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1021 * Useful for a large amount of data. Rather than doing all of the data in one
1022 * iteration do it in chunks. This lets the command be cancelable rather than
1023 * waiting for it to complete.
1025 static gpg_error_t iterate_crypto_once(struct client_s *client,
1026 struct crypto_s *crypto, status_msg_t which)
1028 gpg_error_t rc = 0;
1029 goffset len = CRYPTO_BLOCKSIZE(crypto);
1030 gpointer p = gcry_malloc(len);
1031 goffset total = 0;
1032 gpointer inbuf;
1034 if (!p)
1035 return GPG_ERR_ENOMEM;
1037 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1038 len = crypto->insize;
1040 pth_cleanup_push(gcry_free, p);
1042 for (;;) {
1043 inbuf = (guchar *)crypto->inbuf + total;
1044 guchar *tmp;
1046 if (len + total > crypto->insize)
1047 len = crypto->blocksize;
1049 if (which == STATUS_ENCRYPT)
1050 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1051 else
1052 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1054 if (rc)
1055 goto done;
1057 tmp = (guchar *)crypto->inbuf + total;
1058 memmove(tmp, p, len);
1059 total += len;
1061 if (total >= crypto->insize)
1062 break;
1064 pth_cancel_point();
1067 done:
1068 pth_cleanup_pop(1);
1069 return rc;
1072 /* The crypto struct must be setup for iterations and .key. */
1073 gpg_error_t do_xml_encrypt(struct client_s *client,
1074 struct crypto_s *crypto, const gchar *filename)
1076 goffset len = crypto->insize;
1077 gpointer inbuf;
1078 gchar *p;
1079 gpg_error_t rc;
1080 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
1081 gchar tmp[FILENAME_MAX];
1082 struct stat st;
1083 mode_t mode = 0;
1084 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1086 if (!crypto->fh->ver.fh2.iter) {
1088 * cache_file_count() needs both .used == TRUE and a valid key in
1089 * order for it to count as a used cache entry. Fixes CACHE status
1090 * messages.
1092 memset(crypto->key, '!', hashlen);
1093 goto write_file;
1097 * Resize the existing xml buffer to the block size required by gcrypt
1098 * rather than duplicating it and wasting memory.
1100 crypto->insize += sizeof(crypto_magic);
1101 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1103 if (crypto->insize % crypto->blocksize)
1104 len += crypto->blocksize;
1106 inbuf = gcry_realloc(crypto->inbuf, len);
1108 if (!inbuf) {
1109 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1110 return GPG_ERR_ENOMEM;
1113 guchar *tmpbuf = inbuf;
1114 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1115 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1116 crypto->inbuf = tmpbuf;
1117 crypto->insize = len;
1118 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1120 if (crypto->tkey)
1121 gcry_free(crypto->tkey);
1123 crypto->tkey = gcry_malloc(hashlen);
1125 if (!crypto->tkey) {
1126 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1127 return GPG_ERR_ENOMEM;
1130 memcpy(crypto->tkey, crypto->key, hashlen);
1131 guchar *tkey = crypto->tkey;
1132 tkey[0] ^= 1;
1134 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1135 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1136 return rc;
1139 iter_progress = (guint64)get_key_file_double(
1140 client ? client->filename : "global", "iteration_progress");
1142 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1143 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1144 "0 %llu", crypto->fh->ver.fh2.iter);
1146 if (rc)
1147 return rc;
1150 while (xiter < crypto->fh->ver.fh2.iter-1) {
1151 if (iter_progress > 0ULL && xiter >= iter_progress) {
1152 if (!(xiter % iter_progress)) {
1153 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1154 "%llu %llu", ++n_iter * iter_progress,
1155 crypto->fh->ver.fh2.iter);
1157 if (rc)
1158 return rc;
1162 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1163 crypto->blocksize))) {
1164 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1165 return rc;
1168 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1170 if (rc) {
1171 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1172 return rc;
1175 xiter++;
1178 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1179 crypto->blocksize))) {
1180 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1181 return rc;
1184 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1185 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1186 return rc;
1189 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1191 if (rc)
1192 return rc;
1194 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1195 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1196 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1198 if (rc)
1199 return rc;
1202 write_file:
1203 tmp[0] = 0;
1205 if (filename) {
1206 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1207 crypto->fh->fd = STDOUT_FILENO;
1208 goto do_write_file;
1211 if (lstat(filename, &st) == 0) {
1212 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1214 if (!(mode & S_IWUSR))
1215 return GPG_ERR_EACCES;
1217 else if (errno != ENOENT)
1218 return gpg_error_from_syserror();
1220 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1221 crypto->fh->fd = mkstemp(tmp);
1223 if (crypto->fh->fd == -1) {
1224 rc = gpg_error_from_syserror();
1225 p = strrchr(tmp, '/');
1226 p++;
1227 log_write("%s: %s", p, pwmd_strerror(rc));
1228 return rc;
1231 pth_cleanup_push(cleanup_unlink_cb, tmp);
1233 else
1235 * xml_import() or convert_file() from command line.
1237 crypto->fh->fd = STDOUT_FILENO;
1239 do_write_file:
1240 crypto->fh->ver.fh2.magic[0] = '\177';
1241 crypto->fh->ver.fh2.magic[1] = 'P';
1242 crypto->fh->ver.fh2.magic[2] = 'W';
1243 crypto->fh->ver.fh2.magic[3] = 'M';
1244 crypto->fh->ver.fh2.magic[4] = 'D';
1245 crypto->fh->ver.fh2.version = VERSION_HEX;
1246 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1248 if (len != sizeof(crypto->fh->ver.fh2)) {
1249 rc = gpg_error_from_syserror();
1251 if (tmp[0])
1252 pth_cleanup_pop(1);
1254 return rc;
1257 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1259 if (len != crypto->insize) {
1260 rc = gpg_error_from_syserror();
1262 if (tmp[0])
1263 pth_cleanup_pop(1);
1265 return rc;
1268 if (fsync(crypto->fh->fd) == -1) {
1269 rc = gpg_error_from_syserror();
1271 if (tmp[0])
1272 pth_cleanup_pop(1);
1274 return rc;
1277 if (tmp[0]) {
1278 #ifdef WITH_LIBACL
1279 acl_t acl;
1280 #endif
1281 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1282 gchar tmp2[FILENAME_MAX];
1284 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1285 #ifdef WITH_LIBACL
1286 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1288 if (!acl)
1289 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1290 #endif
1292 if (rename(filename, tmp2) == -1) {
1293 rc = gpg_error_from_syserror();
1294 pth_cleanup_pop(1);
1295 #ifdef WITH_LIBACL
1296 if (acl)
1297 acl_free(acl);
1298 #endif
1299 return rc;
1302 #ifdef WITH_LIBACL
1303 else {
1304 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1306 if (!acl)
1307 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1309 #endif
1311 if (rename(tmp, filename) == -1) {
1312 rc = gpg_error_from_syserror();
1313 pth_cleanup_pop(1);
1314 #ifdef WITH_LIBACL
1315 if (acl)
1316 acl_free(acl);
1317 #endif
1318 return rc;
1321 pth_cleanup_pop(0);
1323 if (mode)
1324 chmod(filename, mode);
1326 #ifdef WITH_LIBACL
1327 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1328 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1330 if (acl)
1331 acl_free(acl);
1332 #endif
1335 if (client && lstat(filename, &st) == 0)
1336 client->mtime = st.st_mtime;
1338 return 0;
1341 gpg_error_t update_save_flags(const gchar *filename,
1342 struct crypto_s *crypto)
1344 gpg_error_t rc;
1345 guint64 iter;
1347 /* New file? */
1348 if (!crypto->fh) {
1349 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1351 if (!crypto->fh)
1352 return GPG_ERR_ENOMEM;
1355 rc = init_client_crypto2(filename, crypto);
1357 if (rc)
1358 return rc;
1360 if (filename && !crypto->fh->v1) {
1361 iter = (guint64)get_key_file_double(filename, "iterations");
1362 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1365 return 0;
1368 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1369 gboolean cached)
1371 struct client_s *client = assuan_get_pointer(ctx);
1372 gpointer xmlbuf;
1373 gulong outsize = 0;
1374 guint len;
1375 gint clevel;
1376 gint timeout;
1377 gpointer outbuf;
1378 gpg_error_t rc;
1380 if (client->crypto->key && client->crypto->key != key)
1381 gcry_free(client->crypto->key);
1383 client->crypto->key = key;
1384 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1386 if (rc) {
1387 cleanup_crypto(&client->crypto);
1388 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1391 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1392 pth_cleanup_push(xmlFree, xmlbuf);
1393 clevel = get_key_file_integer(client->filename, "compression_level");
1395 if (clevel < 0)
1396 clevel = 0;
1398 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1400 if (rc) {
1401 pth_cleanup_pop(1);
1402 cleanup_crypto(&client->crypto);
1404 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1406 else {
1407 pth_cleanup_pop(1);
1408 xmlbuf = outbuf;
1409 len = outsize;
1412 client->crypto->inbuf = xmlbuf;
1413 client->crypto->insize = len;
1414 rc = update_save_flags(client->filename, client->crypto);
1416 if (rc) {
1417 cleanup_crypto(&client->crypto);
1418 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1419 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1422 rc = do_xml_encrypt(client, client->crypto, client->filename);
1424 if (rc) {
1425 cleanup_crypto(&client->crypto);
1426 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1429 timeout = get_key_file_integer(client->filename, "cache_timeout");
1430 CACHE_LOCK(client->ctx);
1432 if (cached) {
1433 cache_reset_timeout(client->md5file, timeout);
1434 CACHE_UNLOCK;
1436 if (client->new == TRUE)
1437 send_status_all(STATUS_CACHE);
1439 client->new = FALSE;
1440 cleanup_crypto(&client->crypto);
1441 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1444 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1445 CACHE_UNLOCK;
1446 cleanup_crypto(&client->crypto);
1447 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1450 client->new = FALSE;
1451 cache_reset_timeout(client->md5file, timeout);
1452 CACHE_UNLOCK;
1453 send_status_all(STATUS_CACHE);
1454 cleanup_crypto(&client->crypto);
1455 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1458 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1460 struct client_s *client = data;
1461 guint64 n;
1462 gchar *value = v;
1463 gchar *p = NULL;
1465 if (!client->filename)
1466 return EPWMD_NO_FILE;
1468 if (!value || !*value)
1469 return 0;
1471 errno = 0;
1472 n = strtoul(value, &p, 10);
1474 if (errno || (p && *p) || n == G_MAXULONG)
1475 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1477 MUTEX_LOCK(&rcfile_mutex);
1478 g_key_file_set_double(keyfileh,
1479 client->filename ? client->filename : "global", "iterations", n);
1480 MUTEX_UNLOCK(&rcfile_mutex);
1482 if (client->filename)
1483 client->opts |= OPT_ITERATIONS;
1485 return 0;
1488 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1490 struct client_s *client = data;
1491 const gchar *p = value;
1492 guint64 flags;
1494 if (!client->filename)
1495 return EPWMD_NO_FILE;
1497 if (!p || !*p)
1498 return 0;
1500 flags = pwmd_cipher_str_to_cipher(p);
1502 if (!flags)
1503 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1505 MUTEX_LOCK(&rcfile_mutex);
1506 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1507 MUTEX_UNLOCK(&rcfile_mutex);
1509 if (!value)
1510 g_free((gchar *)p);
1512 return 0;
1515 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1517 struct client_s *client = data;
1519 CACHE_LOCK(client->ctx);
1520 cache_clear(client->md5file, 1);
1521 CACHE_UNLOCK;
1522 return 0;
1525 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1527 struct client_s *client = assuan_get_pointer(ctx);
1528 gboolean cached = FALSE;
1529 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1531 CACHE_LOCK(ctx);
1532 cached = cache_iscached(client->md5file);
1533 CACHE_UNLOCK;
1536 * If a cache entry doesn't exist for this file and the file has a
1537 * "key_file" or "key" parameter, then it's an error. The reason is that
1538 * cache expiration would be useless. Unless this is an inquire, then its
1539 * fine.
1541 if (cached == FALSE) {
1542 gchar *tmp = get_key_file_string(client->filename, "key_file");
1544 if (tmp && !(client->opts & OPT_INQUIRE)) {
1545 g_free(tmp);
1546 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1549 if (tmp)
1550 g_free(tmp);
1553 cached = FALSE;
1555 /* New file? */
1556 if (!client->crypto) {
1557 client->crypto = init_client_crypto();
1559 if (!client->crypto) {
1560 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1561 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1565 client->crypto->key = gcry_malloc(hashlen);
1567 if (!client->crypto->key) {
1568 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1569 cleanup_crypto(&client->crypto);
1570 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1573 memset(client->crypto->key, '!', hashlen);
1575 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1576 (!line || !*line))
1577 goto done;
1579 if (!line || !*line) {
1580 /* It doesn't make sense to use an --inquire with an empty
1581 * passphrase. This will prevent a pinentry dialog. */
1582 if (client->opts & OPT_INQUIRE) {
1583 cleanup_crypto(&client->crypto);
1584 return GPG_ERR_WRONG_KEY_USAGE;
1587 client->crypto->tkey = gcry_malloc(hashlen);
1589 if (!client->crypto->tkey) {
1590 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1591 cleanup_crypto(&client->crypto);
1592 return send_error(ctx, GPG_ERR_ENOMEM);
1595 memset(client->crypto->tkey, '!', hashlen);
1596 CACHE_LOCK(ctx);
1598 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1599 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1600 CACHE_UNLOCK;
1602 #ifdef WITH_PINENTRY
1603 gpg_error_t rc;
1605 if (client->pinentry->enable == FALSE ||
1606 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1607 /* Empty keys are allowed. */
1608 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1609 goto done;
1612 lock_pin_mutex(client);
1613 client->pinentry->which = PINENTRY_SAVE;
1614 rc = pinentry_fork(ctx);
1616 if (rc) {
1617 unlock_pin_mutex(client->pinentry);
1618 cleanup_crypto(&client->crypto);
1619 return send_error(ctx, rc);
1622 client->pinentry->cb = save_command_finalize;
1623 client->pinentry->status = PINENTRY_INIT;
1624 return 0;
1625 #else
1626 /* Empty keys are allowed. */
1627 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1628 goto done;
1629 #endif
1631 else {
1632 CACHE_UNLOCK;
1633 cached = TRUE;
1636 else {
1637 gpg_error_t rc;
1639 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1640 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1642 if (iter <= 0L)
1643 iter = 1;
1645 MUTEX_LOCK(&rcfile_mutex);
1646 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1647 MUTEX_UNLOCK(&rcfile_mutex);
1648 client->opts |= OPT_ITERATIONS;
1649 rc = send_status(ctx, STATUS_CONFIG, NULL);
1651 if (rc) {
1652 cleanup_crypto(&client->crypto);
1653 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1657 rc = hash_key(client, line);
1659 if (rc) {
1660 cleanup_crypto(&client->crypto);
1661 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1665 done:
1666 return save_command_finalize(ctx, client->crypto->key, cached);
1669 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1670 guchar *line, gsize len)
1672 assuan_context_t ctx = data;
1673 struct client_s *client = assuan_get_pointer(ctx);
1674 gpg_error_t rc = file_modified(client);
1676 if (assuan_rc || rc) {
1677 if (line)
1678 xfree(line);
1680 return assuan_rc ? assuan_rc : rc;
1683 rc = save_command_common(ctx, (gchar *)line);
1685 if (line)
1686 xfree(line);
1688 client->inquire_status = INQUIRE_DONE;
1689 return rc;
1692 static gint save_command(assuan_context_t ctx, gchar *line)
1694 struct stat st;
1695 struct client_s *client = assuan_get_pointer(ctx);
1696 gpg_error_t rc;
1697 struct argv_s *args[] = {
1698 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1699 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1700 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1701 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1702 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1703 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1704 NULL
1707 rc = parse_options(&line, args, client);
1709 if (rc)
1710 return send_error(ctx, rc);
1712 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1713 return send_error(ctx, gpg_error_from_syserror());
1715 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1716 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1717 return send_error(ctx, GPG_ERR_ENOANO);
1720 if ((client->opts & OPT_INQUIRE)) {
1721 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1722 ctx);
1724 if (rc)
1725 return send_error(ctx, rc);
1727 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1728 client->inquire_status = INQUIRE_BUSY;
1729 return 0;
1732 if (line && *line)
1733 log_write2("ARGS=%s", "<passphrase>");
1735 return save_command_common(ctx, line);
1738 static gint delete_command(assuan_context_t ctx, gchar *line)
1740 struct client_s *client = assuan_get_pointer(ctx);
1741 gchar **req;
1742 gpg_error_t rc;
1743 xmlNodePtr n;
1745 log_write2("ARGS=\"%s\"", line);
1747 if (strchr(line, '\t'))
1748 req = split_input_line(line, "\t", -1);
1749 else
1750 req = split_input_line(line, " ", -1);
1752 if (!req || !*req)
1753 return send_error(ctx, GPG_ERR_SYNTAX);
1755 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1757 if (!n) {
1758 g_strfreev(req);
1759 return send_error(ctx, rc);
1763 * No sub-node defined. Remove the entire node (root element).
1765 if (!req[1]) {
1766 if (n) {
1767 rc = unlink_node(n);
1768 xmlFreeNode(n);
1771 g_strfreev(req);
1772 return send_error(ctx, rc);
1775 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1776 g_strfreev(req);
1778 if (!n)
1779 return send_error(ctx, rc);
1781 if (n) {
1782 rc = unlink_node(n);
1783 xmlFreeNode(n);
1786 return send_error(ctx, rc);
1790 * Don't return with assuan_process_done() here. This has been called from
1791 * assuan_process_next() and the command should be finished in
1792 * client_thread().
1794 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1795 gsize len)
1797 assuan_context_t ctx = data;
1798 struct client_s *client = assuan_get_pointer(ctx);
1799 gchar **req;
1800 xmlNodePtr n;
1801 gpg_error_t rc = file_modified(client);
1803 if (assuan_rc || rc) {
1804 if (line)
1805 xfree(line);
1806 return assuan_rc ? assuan_rc : rc;
1809 req = split_input_line((gchar *)line, "\t", 0);
1810 xfree(line);
1812 if (!req || !*req)
1813 return GPG_ERR_SYNTAX;
1815 again:
1816 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1818 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1819 rc = new_root_element(client->doc, *req);
1821 if (rc) {
1822 g_strfreev(req);
1823 return rc;
1826 goto again;
1829 if (!n) {
1830 g_strfreev(req);
1831 return rc;
1834 if (req[1]) {
1835 if (!n->children)
1836 n = create_elements_cb(n, req+1, &rc, NULL);
1837 else
1838 n = find_elements(client->doc, n->children, req+1, &rc,
1839 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1842 g_strfreev(req);
1843 client->inquire_status = INQUIRE_DONE;
1845 if (!rc)
1846 rc = update_element_mtime(n);
1848 return rc;
1851 static gint store_command(assuan_context_t ctx, gchar *line)
1853 struct client_s *client = assuan_get_pointer(ctx);
1854 gpg_error_t rc;
1856 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1858 if (rc)
1859 return send_error(ctx, rc);
1861 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1862 client->inquire_status = INQUIRE_BUSY;
1863 return 0;
1866 static void *send_data_cb(void *arg)
1868 struct assuan_cmd_s *data = arg;
1869 gint old;
1870 gpg_error_t *rc;
1872 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1873 rc = g_malloc(sizeof(gpg_error_t));
1874 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1875 pth_cancel_state(old, NULL);
1876 pth_exit(rc);
1877 return NULL;
1880 /* For every assuan command that needs to be sent to the client, a timeout is
1881 * needed to determine if the client lost the connection. The timeout is the
1882 * same as the "keepalive" configuration parameter or a default if unset.
1884 gpg_error_t do_assuan_command(assuan_context_t ctx,
1885 void *(*cb)(void *data), void *data)
1887 pth_attr_t attr = pth_attr_new();
1888 pth_t tid;
1889 gint to = get_key_file_integer("global", "keepalive");
1890 pth_event_t ev, tev;
1891 pth_status_t st;
1892 gpg_error_t rc = 0;
1893 void *p;
1895 pth_attr_init(attr);
1896 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1897 tid = pth_spawn(attr, cb, data);
1898 rc = gpg_error_from_syserror();
1899 pth_attr_destroy(attr);
1901 if (!tid) {
1902 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1903 return rc;
1906 pth_cleanup_push(cleanup_cancel_cb, tid);
1907 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1908 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1909 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1910 ev = pth_event_concat(ev, tev, NULL);
1911 pth_cleanup_push(cleanup_ev_cb, ev);
1912 pth_yield(tid);
1913 pth_wait(ev);
1915 if (tev) {
1916 st = pth_event_status(tev);
1918 if (st == PTH_STATUS_OCCURRED) {
1919 pth_cleanup_pop(1);
1920 pth_cleanup_pop(1);
1921 return GPG_ERR_TIMEOUT;
1925 st = pth_event_status(ev);
1927 if (st == PTH_STATUS_FAILED) {
1928 pth_cancel(tid);
1929 pth_join(tid, &p);
1930 g_free(p);
1931 rc = GPG_ERR_ASS_WRITE_ERROR;
1933 else if (st == PTH_STATUS_OCCURRED) {
1934 pth_join(tid, &p);
1935 rc = *(gpg_error_t *)p;
1936 g_free(p);
1939 pth_cleanup_pop(1);
1940 pth_cleanup_pop(0);
1941 return rc;
1944 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1945 gint total)
1947 gint to_send;
1948 gint sent = 0;
1949 gpg_error_t rc;
1950 struct assuan_cmd_s data;
1951 gint progress = get_key_file_integer("global", "xfer_progress");
1952 gint flush = 0;
1954 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1955 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1956 data.ctx = ctx;
1957 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1959 if (rc)
1960 return rc;
1962 again:
1963 do {
1964 if (sent + to_send > total)
1965 to_send = total - sent;
1967 data.line = flush ? NULL : (gchar *)line+sent;
1968 data.line_len = flush ? 0 : to_send;
1969 rc = do_assuan_command(ctx, send_data_cb, &data);
1971 if (!rc) {
1972 sent += flush ? 0 : to_send;
1974 if ((progress && !(sent % progress) && sent != total) ||
1975 (sent == total && flush))
1976 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1978 if (!flush && !rc && sent == total) {
1979 flush = 1;
1980 goto again;
1983 } while (!rc && sent < total);
1985 return rc;
1988 static gint get_command(assuan_context_t ctx, gchar *line)
1990 struct client_s *client = assuan_get_pointer(ctx);
1991 gchar **req;
1992 gpg_error_t rc;
1993 xmlNodePtr n;
1995 log_write2("ARGS=\"%s\"", line);
1996 req = split_input_line(line, "\t", -1);
1998 if (!req || !*req) {
1999 g_strfreev(req);
2000 return send_error(ctx, GPG_ERR_SYNTAX);
2003 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2005 if (!n) {
2006 g_strfreev(req);
2007 return send_error(ctx, rc);
2010 if (req[1])
2011 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2013 g_strfreev(req);
2015 if (rc)
2016 return send_error(ctx, rc);
2018 if (!n || !n->children)
2019 return send_error(ctx, GPG_ERR_NO_VALUE);
2021 n = find_text_node(n->children);
2023 if (!n || !n->content || !*n->content)
2024 return send_error(ctx, GPG_ERR_NO_VALUE);
2026 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2027 return send_error(ctx, rc);
2030 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2031 gpg_error_t *rc, gchar **req_orig, void *data)
2033 gchar *path = *(gchar **)data;
2034 gchar *tmp = NULL, *result;
2036 if (path) {
2037 g_free(path);
2038 *(gchar **)data = NULL;
2041 path = g_strjoinv("\t", target);
2043 if (!path) {
2044 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2045 *rc = GPG_ERR_ENOMEM;
2046 return NULL;
2049 if (req_orig) {
2050 tmp = g_strjoinv("\t", req_orig);
2052 if (!tmp) {
2053 g_free(path);
2054 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2055 *rc = GPG_ERR_ENOMEM;
2056 return NULL;
2060 if (tmp && *tmp)
2061 result = g_strdup_printf("%s\t%s", path, tmp);
2062 else
2063 result = g_strdup(path);
2065 if (!result) {
2066 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2067 *rc = GPG_ERR_ENOMEM;
2068 g_free(path);
2069 g_free(tmp);
2070 return NULL;
2073 g_free(path);
2074 g_free(tmp);
2075 *(gchar **)data = result;
2076 return node;
2079 static void list_command_cleanup1(void *arg);
2080 static gint realpath_command(assuan_context_t ctx, gchar *line)
2082 gpg_error_t rc;
2083 struct client_s *client = assuan_get_pointer(ctx);
2084 gchar **req;
2085 gchar *t;
2086 gint i;
2087 xmlNodePtr n;
2088 GString *string;
2089 gchar *rp = NULL;
2091 log_write2("ARGS=\"%s\"", line);
2093 if (strchr(line, '\t') != NULL) {
2094 if ((req = split_input_line(line, "\t", 0)) == NULL)
2095 return send_error(ctx, GPG_ERR_SYNTAX);
2097 else {
2098 if ((req = split_input_line(line, " ", 0)) == NULL)
2099 return send_error(ctx, GPG_ERR_SYNTAX);
2102 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2104 if (!n) {
2105 g_strfreev(req);
2106 return send_error(ctx, rc);
2109 rp = g_strjoinv("\t", req);
2111 if (!rp) {
2112 g_strfreev(req);
2113 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2114 return send_error(ctx, GPG_ERR_ENOMEM);
2117 if (req[1]) {
2118 n = find_elements(client->doc, n->children, req+1, &rc,
2119 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2121 if (!n) {
2122 g_free(rp);
2123 g_strfreev(req);
2124 return send_error(ctx, rc);
2128 string = g_string_new(rp);
2129 g_free(rp);
2130 g_strfreev(req);
2132 if (!string) {
2133 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2134 return send_error(ctx, GPG_ERR_ENOMEM);
2137 again:
2138 for (i = 0, t = string->str + i; *t; t++, i++) {
2139 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2140 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2141 goto again;
2145 pth_cleanup_push(list_command_cleanup1, string);
2146 rc = xfer_data(ctx, string->str, string->len);
2147 pth_cleanup_pop(1);
2148 return send_error(ctx, rc);
2151 static void list_command_cleanup1(void *arg)
2153 g_string_free((GString *)arg, TRUE);
2156 static void list_command_cleanup2(void *arg)
2158 struct element_list_s *elements = arg;
2160 if (elements) {
2161 if (elements->list) {
2162 gint total = g_slist_length(elements->list);
2163 gint i;
2165 for (i = 0; i < total; i++) {
2166 gchar *tmp = g_slist_nth_data(elements->list, i);
2167 g_free(tmp);
2170 g_slist_free(elements->list);
2173 if (elements->prefix)
2174 g_free(elements->prefix);
2176 if (elements->req)
2177 g_strfreev(elements->req);
2179 g_free(elements);
2183 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2185 struct element_list_s *elements = data;
2187 elements->recurse = FALSE;
2188 return 0;
2191 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2193 struct element_list_s *elements = data;
2195 elements->verbose = TRUE;
2196 return 0;
2199 static gint list_command(assuan_context_t ctx, gchar *line)
2201 struct client_s *client = assuan_get_pointer(ctx);
2202 gpg_error_t rc;
2203 struct element_list_s *elements = NULL;
2204 gchar *tmp;
2205 struct argv_s *args[] = {
2206 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2207 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2208 NULL
2211 if (disable_list_and_dump == TRUE)
2212 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2214 elements = g_malloc0(sizeof(struct element_list_s));
2216 if (!elements) {
2217 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2218 return GPG_ERR_ENOMEM;
2221 elements->recurse = TRUE; // default
2222 pth_cleanup_push(list_command_cleanup2, elements);
2223 rc = parse_options(&line, args, elements);
2225 if (rc)
2226 goto fail;
2228 if (!*line) {
2229 GString *str;
2231 rc = list_root_elements(client->doc, &str, elements->verbose);
2233 if (rc) {
2234 pth_cleanup_pop(1);
2235 return send_error(ctx, rc);
2238 pth_cleanup_push(list_command_cleanup1, str);
2239 rc = xfer_data(ctx, str->str, str->len);
2240 pth_cleanup_pop(1);
2241 pth_cleanup_pop(1);
2242 return send_error(ctx, rc);
2245 elements->req = split_input_line(line, " ", 0);
2247 if (!elements->req)
2248 strv_printf(&elements->req, "%s", line);
2250 rc = create_path_list(client->doc, elements, *elements->req);
2252 if (rc)
2253 goto fail;
2255 if (elements) {
2256 gint total = g_slist_length(elements->list);
2257 gint i;
2258 GString *str;
2260 if (!total) {
2261 rc = GPG_ERR_NO_VALUE;
2262 goto fail;
2265 str = g_string_new(NULL);
2267 if (!str) {
2268 rc = GPG_ERR_ENOMEM;
2269 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2270 goto fail;
2273 for (i = 0; i < total; i++) {
2274 tmp = g_slist_nth_data(elements->list, i);
2275 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2278 pth_cleanup_push(list_command_cleanup1, str);
2279 rc = xfer_data(ctx, str->str, str->len);
2280 pth_cleanup_pop(1);
2282 else
2283 rc = GPG_ERR_NO_VALUE;
2285 fail:
2286 pth_cleanup_pop(1);
2287 return send_error(ctx, rc);
2291 * req[0] - element path
2293 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2295 struct client_s *client = assuan_get_pointer(ctx);
2296 gchar **attrlist = NULL;
2297 gint i = 0;
2298 gchar **path = NULL;
2299 xmlAttrPtr a;
2300 xmlNodePtr n, an;
2301 gchar *line;
2302 gpg_error_t rc;
2304 if (!req || !req[0])
2305 return GPG_ERR_SYNTAX;
2307 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2309 * The first argument may be only a root element.
2311 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2312 return GPG_ERR_SYNTAX;
2315 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2317 if (!n) {
2318 g_strfreev(path);
2319 return rc;
2322 if (path[1]) {
2323 n = find_elements(client->doc, n->children, path+1, &rc,
2324 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2326 if (!n) {
2327 g_strfreev(path);
2328 return rc;
2332 g_strfreev(path);
2334 for (a = n->properties; a; a = a->next) {
2335 gchar **pa;
2337 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2338 if (attrlist)
2339 g_strfreev(attrlist);
2341 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2342 return GPG_ERR_ENOMEM;
2345 attrlist = pa;
2346 an = a->children;
2347 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2348 an && an->content ? (gchar *)an->content : "");
2350 if (!attrlist[i]) {
2351 g_strfreev(attrlist);
2352 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2353 return GPG_ERR_ENOMEM;
2356 attrlist[++i] = NULL;
2359 if (!attrlist)
2360 return GPG_ERR_NO_VALUE;
2362 line = g_strjoinv("\n", attrlist);
2364 if (!line) {
2365 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2366 g_strfreev(attrlist);
2367 return GPG_ERR_ENOMEM;
2370 pth_cleanup_push(g_free, line);
2371 pth_cleanup_push(req_cleanup, attrlist);
2372 rc = xfer_data(ctx, line, strlen(line));
2373 pth_cleanup_pop(1);
2374 pth_cleanup_pop(1);
2375 return rc;
2379 * req[0] - attribute
2380 * req[1] - element path
2382 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2384 xmlNodePtr n;
2385 gchar **path = NULL;
2386 gpg_error_t rc;
2388 if (!req || !req[0] || !req[1])
2389 return GPG_ERR_SYNTAX;
2391 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2393 * The first argument may be only a root element.
2395 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2396 return GPG_ERR_SYNTAX;
2400 * Don't remove the "_name" attribute for the root element. To remove an
2401 * root element use DELETE <name>.
2403 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2404 rc = GPG_ERR_SYNTAX;
2405 goto fail;
2408 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2410 if (!n)
2411 goto fail;
2413 if (path[1]) {
2414 n = find_elements(client->doc, n->children, path+1, &rc,
2415 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2417 if (!n)
2418 goto fail;
2421 rc = delete_attribute(n, (xmlChar *)req[0]);
2423 fail:
2424 g_strfreev(path);
2425 return rc;
2428 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2429 gpg_error_t *rc)
2431 gchar **src = *path;
2432 gchar **src_orig = g_strdupv(src);
2433 xmlNodePtr n = NULL;
2435 *rc = 0;
2437 if (!src_orig) {
2438 *rc = GPG_ERR_ENOMEM;
2439 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2440 goto fail;
2443 again:
2444 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2446 if (!n) {
2447 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2448 *rc = new_root_element(client->doc, src[0]);
2450 if (*rc)
2451 goto fail;
2453 goto again;
2455 else
2456 goto fail;
2459 if (src[1]) {
2460 if (!n->children)
2461 n = create_target_elements_cb(n, src+1, rc, NULL);
2462 else
2463 n = find_elements(client->doc, n->children, src+1, rc,
2464 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2466 if (!n)
2467 goto fail;
2470 * Reset the position of the element tree now that the elements
2471 * have been created.
2473 g_strfreev(src);
2474 src = src_orig;
2475 src_orig = NULL;
2476 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2478 if (!n)
2479 goto fail;
2481 n = find_elements(client->doc, n->children, src+1, rc,
2482 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2484 if (!n)
2485 goto fail;
2488 fail:
2489 if (src_orig)
2490 g_strfreev(src_orig);
2492 *path = src;
2493 return n;
2497 * Creates a "target" attribute. When other commands encounter an element with
2498 * this attribute, the element path is modified to the target value. If the
2499 * source element path doesn't exist when using 'ATTR SET target', it is
2500 * created, but the destination element path must exist.
2502 * req[0] - source element path
2503 * req[1] - destination element path
2505 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2507 gchar **src, **dst, *line = NULL, **odst = NULL;
2508 gpg_error_t rc;
2509 xmlNodePtr n;
2511 if (!req || !req[0] || !req[1])
2512 return GPG_ERR_SYNTAX;
2514 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2516 * The first argument may be only a root element.
2518 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2519 return GPG_ERR_SYNTAX;
2522 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2524 * The first argument may be only a root element.
2526 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2527 rc = GPG_ERR_SYNTAX;
2528 goto fail;
2532 odst = g_strdupv(dst);
2534 if (!odst) {
2535 rc = GPG_ERR_ENOMEM;
2536 goto fail;
2539 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2542 * Make sure the destination element path exists.
2544 if (!n)
2545 goto fail;
2547 if (dst[1]) {
2548 n = find_elements(client->doc, n->children, dst+1, &rc,
2549 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2551 if (!n)
2552 goto fail;
2555 n = create_element_path(client, &src, &rc);
2557 if (rc)
2558 goto fail;
2560 line = g_strjoinv("\t", odst);
2562 if (!line) {
2563 rc = GPG_ERR_ENOMEM;
2564 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2565 goto fail;
2568 rc = add_attribute(n, "target", line);
2570 fail:
2571 g_free(line);
2572 g_strfreev(src);
2573 g_strfreev(dst);
2574 g_strfreev(odst);
2575 return rc;
2579 * req[0] - name
2580 * req[1] - new name
2582 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2584 gpg_error_t rc;
2585 gchar **tmp;
2586 xmlNodePtr n;
2588 tmp = g_strdupv(req);
2590 if (!tmp) {
2591 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2592 return GPG_ERR_ENOMEM;
2595 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2596 g_strfreev(tmp);
2598 if (!n)
2599 return rc;
2601 if (g_utf8_collate(req[0], req[1]) == 0)
2602 return 0;
2605 * Will not overwrite an existing root.
2607 tmp = g_strdupv(req+1);
2609 if (!tmp) {
2610 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2611 return GPG_ERR_ENOMEM;
2614 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2615 g_strfreev(tmp);
2617 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2618 return rc;
2620 if (n)
2621 return GPG_ERR_AMBIGUOUS_NAME;
2623 if (!valid_xml_element((xmlChar *)req[1]))
2624 return GPG_ERR_SYNTAX;
2626 tmp = g_strdupv(req);
2628 if (!tmp) {
2629 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2630 return GPG_ERR_ENOMEM;
2633 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2634 g_strfreev(tmp);
2636 if (!n)
2637 return GPG_ERR_ELEMENT_NOT_FOUND;
2639 return add_attribute(n, "_name", req[1]);
2643 * req[0] - attribute
2644 * req[1] - element path
2646 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2648 struct client_s *client = assuan_get_pointer(ctx);
2649 xmlNodePtr n;
2650 xmlChar *a;
2651 gchar **path= NULL;
2652 gpg_error_t rc;
2654 if (!req || !req[0] || !req[1])
2655 return GPG_ERR_SYNTAX;
2657 if (strchr(req[1], '\t')) {
2658 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2659 return GPG_ERR_SYNTAX;
2661 else {
2662 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2663 return GPG_ERR_SYNTAX;
2666 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2668 if (!n)
2669 goto fail;
2671 if (path[1]) {
2672 n = find_elements(client->doc, n->children, path+1, &rc,
2673 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2675 if (!n)
2676 goto fail;
2679 g_strfreev(path);
2681 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2682 return GPG_ERR_NOT_FOUND;
2684 pth_cleanup_push(xmlFree, a);
2686 if (*a)
2687 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2688 else
2689 rc = GPG_ERR_NO_VALUE;
2691 pth_cleanup_pop(1);
2692 return rc;
2694 fail:
2695 g_strfreev(path);
2696 return rc;
2700 * req[0] - attribute
2701 * req[1] - element path
2702 * req[2] - value
2704 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2706 gchar **path = NULL;
2707 gpg_error_t rc;
2708 xmlNodePtr n;
2710 if (!req || !req[0] || !req[1])
2711 return GPG_ERR_SYNTAX;
2714 * Reserved attribute names.
2716 if (!strcmp(req[0], "_name")) {
2718 * Only reserved for the root element. Not the rest of the
2719 * document.
2721 if (strchr(req[1], '\t') == NULL)
2722 return name_attribute(client, req + 1);
2724 else if (!strcmp(req[0], "target"))
2725 return target_attribute(client, req + 1);
2727 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2729 * The first argument may be only a root element.
2731 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2732 return GPG_ERR_SYNTAX;
2735 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2737 if (!n)
2738 goto fail;
2740 if (path[1]) {
2741 n = find_elements(client->doc, n->children, path+1, &rc,
2742 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2744 if (!n)
2745 goto fail;
2748 rc = add_attribute(n, req[0], req[2]);
2750 fail:
2751 g_strfreev(path);
2752 return rc;
2756 * req[0] - command
2757 * req[1] - attribute name or element path if command is LIST
2758 * req[2] - element path
2759 * req[2] - element path or value
2761 static gint attr_command(assuan_context_t ctx, gchar *line)
2763 struct client_s *client = assuan_get_pointer(ctx);
2764 gchar **req;
2765 gpg_error_t rc = 0;
2767 log_write2("ARGS=\"%s\"", line);
2768 req = split_input_line(line, " ", 4);
2770 if (!req || !req[0] || !req[1]) {
2771 g_strfreev(req);
2772 return send_error(ctx, GPG_ERR_SYNTAX);
2775 pth_cleanup_push(req_cleanup, req);
2777 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2778 rc = attribute_set(client, req+1);
2779 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2780 rc = attribute_get(ctx, req+1);
2781 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2782 rc = attribute_delete(client, req+1);
2783 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2784 rc = attribute_list(ctx, req+1);
2785 else
2786 rc = GPG_ERR_SYNTAX;
2788 pth_cleanup_pop(1);
2789 return send_error(ctx, rc);
2792 static gint iscached_command(assuan_context_t ctx, gchar *line)
2794 gchar **req = split_input_line(line, " ", 0);
2795 guchar md5file[16];
2796 gchar *path, *tmp;
2798 if (!req || !*req) {
2799 g_strfreev(req);
2800 return send_error(ctx, GPG_ERR_SYNTAX);
2803 log_write2("ARGS=\"%s\"", line);
2805 if (!valid_filename(req[0])) {
2806 g_strfreev(req);
2807 return GPG_ERR_INV_VALUE;
2810 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2811 CACHE_LOCK(ctx);
2813 if (cache_iscached(md5file)) {
2814 g_strfreev(req);
2815 CACHE_UNLOCK;
2816 return send_error(ctx, 0);
2819 CACHE_UNLOCK;
2820 tmp = get_key_file_string("global", "data_directory");
2822 if (!tmp) {
2823 g_strfreev(req);
2824 return GPG_ERR_ENOMEM;
2827 path = expand_homedir(tmp);
2829 if (!path) {
2830 g_strfreev(req);
2831 g_free(tmp);
2832 return GPG_ERR_ENOMEM;
2835 g_free(tmp);
2836 tmp = path;
2837 path = g_strdup_printf("%s/%s", tmp, req[0]);
2838 g_free(tmp);
2840 if (!path) {
2841 g_strfreev(req);
2842 return GPG_ERR_ENOMEM;
2845 if (access(path, R_OK) == -1) {
2846 gpg_error_t rc = gpg_error_from_syserror();
2848 g_free(path);
2849 g_strfreev(req);
2850 return send_error(ctx, rc);
2853 g_free(path);
2854 return send_error(ctx, GPG_ERR_NOT_FOUND);
2857 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2859 gchar **req = split_input_line(line, " ", 0);
2860 guchar md5file[16];
2862 log_write2("ARGS=\"%s\"", line);
2863 CACHE_LOCK(ctx);
2865 if (!req || !*req) {
2866 g_strfreev(req);
2867 cache_clear(NULL, 2);
2868 CACHE_UNLOCK;
2869 return send_error(ctx, 0);
2872 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2873 g_strfreev(req);
2874 (void)cache_clear(md5file, 1);
2875 CACHE_UNLOCK;
2876 return send_error(ctx, 0);
2879 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2881 guchar md5file[16];
2882 glong timeout;
2883 gchar **req = split_input_line(line, " ", 0);
2884 gchar *p;
2886 if (!req || !*req || !req[1]) {
2887 g_strfreev(req);
2888 return send_error(ctx, GPG_ERR_SYNTAX);
2891 errno = 0;
2892 timeout = strtol(req[1], &p, 10);
2894 if (errno != 0 || *p != 0 || timeout < -1) {
2895 g_strfreev(req);
2896 return send_error(ctx, GPG_ERR_SYNTAX);
2899 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2900 CACHE_LOCK(client->ctx);
2902 if (cache_set_timeout(md5file, timeout) == FALSE) {
2903 CACHE_UNLOCK;
2904 return send_error(ctx, GPG_ERR_NOT_FOUND);
2907 CACHE_UNLOCK;
2908 return send_error(ctx, 0);
2911 static gint dump_command(assuan_context_t ctx, gchar *line)
2913 xmlChar *xml;
2914 gint len;
2915 struct client_s *client = assuan_get_pointer(ctx);
2916 gpg_error_t rc;
2918 if (disable_list_and_dump == TRUE)
2919 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2921 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2923 if (!xml) {
2924 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2925 return send_error(ctx, GPG_ERR_ENOMEM);
2928 pth_cleanup_push(xmlFree, xml);
2929 rc = xfer_data(ctx, (gchar *)xml, len);
2930 pth_cleanup_pop(1);
2931 return send_error(ctx, rc);
2934 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2936 struct client_s *client = assuan_get_pointer(ctx);
2937 gpg_error_t rc = 0;
2938 gchar filename[255]={0}, param[747]={0};
2939 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2941 log_write2("ARGS=\"%s\"", line);
2943 if (!line || !*line)
2944 return send_error(ctx, GPG_ERR_SYNTAX);
2946 if (strchr(line, ' ')) {
2947 sscanf(line, " %254[^ ] %746c", filename, param);
2948 paramp = param;
2949 fp = filename;
2952 if (fp && !valid_filename(fp))
2953 return send_error(ctx, GPG_ERR_INV_VALUE);
2955 paramp = g_ascii_strdown(paramp, -1);
2957 if (!paramp) {
2958 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2959 return send_error(ctx, GPG_ERR_ENOMEM);
2962 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2963 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2964 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2966 if (!fh && rc != GPG_ERR_ENOENT)
2967 return send_error(ctx, rc);
2969 if (!rc) {
2970 g_free(paramp);
2971 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2972 close_file_header(fh);
2974 if (!p) {
2975 log_write("%s(%i): %s", __FILE__, __LINE__,
2976 pwmd_strerror(GPG_ERR_ENOMEM));
2977 return send_error(ctx, GPG_ERR_ENOMEM);
2980 goto done;
2984 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2985 #ifdef WITH_PINENTRY
2986 gboolean n;
2988 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2989 n = client->pinentry->enable;
2990 else
2991 n = get_key_file_boolean(fp, "enable_pinentry");
2993 p = g_strdup_printf("%s", n ? "true" : "false");
2995 if (!p) {
2996 log_write("%s(%i): %s", __FILE__, __LINE__,
2997 pwmd_strerror(GPG_ERR_ENOMEM));
2998 return send_error(ctx, GPG_ERR_ENOMEM);
3001 goto done;
3002 #else
3003 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3004 #endif
3006 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3007 #ifdef WITH_PINENTRY
3008 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3010 if (!p) {
3011 log_write("%s(%i): %s", __FILE__, __LINE__,
3012 pwmd_strerror(GPG_ERR_ENOMEM));
3013 return send_error(ctx, GPG_ERR_ENOMEM);
3016 goto done;
3017 #else
3018 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3019 #endif
3022 p = get_key_file_string(fp ? fp : "global", paramp);
3023 g_free(paramp);
3025 if (!p)
3026 return send_error(ctx, GPG_ERR_UNKNOWN_OPTION);
3028 tmp = expand_homedir(p);
3029 g_free(p);
3031 if (!tmp) {
3032 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3033 return send_error(ctx, GPG_ERR_ENOMEM);
3036 p = tmp;
3037 done:
3038 pth_cleanup_push(g_free, p);
3039 rc = xfer_data(ctx, p, strlen(p));
3040 pth_cleanup_pop(1);
3041 return send_error(ctx, rc);
3044 struct xpath_s {
3045 xmlXPathContextPtr xp;
3046 xmlXPathObjectPtr result;
3047 xmlBufferPtr buf;
3048 gchar **req;
3051 static void xpath_command_cleanup(void *arg)
3053 struct xpath_s *xpath = arg;
3055 req_cleanup(xpath->req);
3057 if (xpath->buf)
3058 xmlBufferFree(xpath->buf);
3060 if (xpath->result)
3061 xmlXPathFreeObject(xpath->result);
3063 if (xpath->xp)
3064 xmlXPathFreeContext(xpath->xp);
3067 static gint xpath_command(assuan_context_t ctx, gchar *line)
3069 struct client_s *client = assuan_get_pointer(ctx);
3070 gpg_error_t rc;
3071 struct xpath_s xpath;
3073 log_write2("ARGS=\"%s\"", line);
3075 if (disable_list_and_dump == TRUE)
3076 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3078 if (!line || !*line)
3079 return send_error(ctx, GPG_ERR_SYNTAX);
3081 memset(&xpath, 0, sizeof(struct xpath_s));
3083 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3084 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3085 return send_error(ctx, GPG_ERR_ENOMEM);
3088 xpath.xp = xmlXPathNewContext(client->doc);
3090 if (!xpath.xp) {
3091 xpath_command_cleanup(&xpath);
3092 return send_error(ctx, EPWMD_LIBXML_ERROR);
3095 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3097 if (!xpath.result) {
3098 xpath_command_cleanup(&xpath);
3099 return send_error(ctx, EPWMD_LIBXML_ERROR);
3102 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3103 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3104 goto fail;
3107 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3108 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3110 if (rc)
3111 goto fail;
3112 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3113 rc = GPG_ERR_NO_VALUE;
3114 goto fail;
3116 else if (xpath.req[1])
3117 goto fail;
3119 pth_cleanup_push(xpath_command_cleanup, &xpath);
3120 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3121 xmlBufferLength(xpath.buf));
3122 pth_cleanup_pop(0);
3124 fail:
3125 xpath_command_cleanup(&xpath);
3126 return send_error(ctx, rc);
3129 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3130 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3132 struct client_s *client = assuan_get_pointer(ctx);
3133 gpg_error_t rc;
3134 struct xpath_s xpath;
3135 gchar **req = NULL;
3136 gboolean cmd = FALSE; //SET
3138 log_write2("ARGS=\"%s\"", line);
3140 if (disable_list_and_dump == TRUE)
3141 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3143 if (!line || !*line)
3144 return send_error(ctx, GPG_ERR_SYNTAX);
3146 memset(&xpath, 0, sizeof(struct xpath_s));
3148 if ((req = split_input_line(line, " ", 3)) == NULL)
3149 return send_error(ctx, GPG_ERR_ENOMEM);
3151 if (!req[0]) {
3152 rc = GPG_ERR_SYNTAX;
3153 goto fail;
3156 if (!g_ascii_strcasecmp(req[0], "SET"))
3157 cmd = FALSE;
3158 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3159 cmd = TRUE;
3160 else {
3161 rc = GPG_ERR_SYNTAX;
3162 goto fail;
3165 if (!req[1] || !req[2]) {
3166 rc = GPG_ERR_SYNTAX;
3167 goto fail;
3170 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3171 rc = GPG_ERR_ENOMEM;
3172 goto fail;
3175 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3176 rc = GPG_ERR_SYNTAX;
3177 goto fail;
3180 xpath.xp = xmlXPathNewContext(client->doc);
3182 if (!xpath.xp) {
3183 rc = EPWMD_LIBXML_ERROR;
3184 goto fail;
3187 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3189 if (!xpath.result) {
3190 rc = EPWMD_LIBXML_ERROR;
3191 goto fail;
3194 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3195 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3196 goto fail;
3199 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3200 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3202 fail:
3203 g_strfreev(req);
3204 xpath_command_cleanup(&xpath);
3205 return send_error(ctx, rc);
3208 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3209 gsize len)
3211 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3212 gpg_error_t rc = file_modified(client);
3213 gchar **req, **path = NULL, **path_orig = NULL, *content;
3214 xmlDocPtr doc = NULL;
3215 xmlNodePtr n, root, copy;
3217 if (assuan_rc || rc) {
3218 if (line)
3219 xfree(line);
3220 return assuan_rc ? assuan_rc : rc;
3223 req = split_input_line((gchar *)line, "\t", 2);
3224 xfree(line);
3226 if (!req || !*req)
3227 return GPG_ERR_SYNTAX;
3229 content = req[0];
3230 path = split_input_line(req[1], "\t", 0);
3232 if (!content || !*content) {
3233 rc = GPG_ERR_SYNTAX;
3234 goto fail;
3237 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3239 if (!doc) {
3240 rc = EPWMD_LIBXML_ERROR;
3241 goto fail;
3244 root = xmlDocGetRootElement(doc);
3245 rc = validate_import(root);
3247 if (rc)
3248 goto fail;
3250 if (path) {
3251 path_orig = g_strdupv(path);
3253 if (!path_orig) {
3254 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3255 rc = GPG_ERR_ENOMEM;
3256 goto fail;
3259 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3261 if (!a) {
3262 g_strfreev(path_orig);
3263 rc = GPG_ERR_ENOMEM;
3264 goto fail;
3267 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3268 xmlFree(a);
3269 g_strfreev(path_orig);
3270 rc = GPG_ERR_ENOMEM;
3271 goto fail;
3274 xmlFree(a);
3275 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3277 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3278 g_strfreev(path_orig);
3279 goto fail;
3282 if (!rc) {
3283 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3285 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3286 g_strfreev(path_orig);
3287 goto fail;
3289 else if (!rc) {
3290 xmlNodePtr parent = n->parent;
3292 xmlUnlinkNode(n);
3293 xmlFreeNode(n);
3294 n = parent;
3298 g_strfreev(path);
3299 path = path_orig;
3301 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3302 n = create_element_path(client, &path, &rc);
3304 if (rc)
3305 goto fail;
3308 copy = xmlCopyNodeList(root);
3309 n = xmlAddChildList(n, copy);
3311 if (!n)
3312 rc = EPWMD_LIBXML_ERROR;
3314 else {
3315 /* Check if the content root element can create a DTD root element. */
3316 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3317 rc = GPG_ERR_SYNTAX;
3318 goto fail;
3321 xmlChar *a;
3323 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3324 rc = GPG_ERR_SYNTAX;
3325 goto fail;
3328 gchar *tmp = g_strdup((gchar *)a);
3329 xmlFree(a);
3330 gboolean literal = is_literal_element(&tmp);
3332 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3333 g_free(tmp);
3334 rc = GPG_ERR_INV_VALUE;
3335 goto fail;
3338 if (strv_printf(&path, "%s", tmp) == FALSE) {
3339 g_free(tmp);
3340 rc = GPG_ERR_ENOMEM;
3341 goto fail;
3344 g_free(tmp);
3345 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3347 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3348 rc = EPWMD_LIBXML_ERROR;
3349 goto fail;
3352 /* Overwriting the existing tree. */
3353 if (!rc) {
3354 xmlUnlinkNode(n);
3355 xmlFreeNodeList(n);
3358 rc = 0;
3359 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3360 n = xmlCopyNode(root, 1);
3361 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3364 if (n && !rc)
3365 rc = update_element_mtime(n->parent);
3367 fail:
3368 if (doc)
3369 xmlFreeDoc(doc);
3371 if (path)
3372 g_strfreev(path);
3374 g_strfreev(req);
3375 client->inquire_status = INQUIRE_DONE;
3376 return rc;
3379 static gint import_command(assuan_context_t ctx, gchar *line)
3381 gpg_error_t rc;
3382 struct client_s *client = assuan_get_pointer(ctx);
3384 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3386 if (rc)
3387 return send_error(ctx, rc);
3389 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3390 client->inquire_status = INQUIRE_BUSY;
3391 return 0;
3394 static gpg_error_t do_lock_command(struct client_s *client)
3396 gpg_error_t rc = lock_file_mutex(client);
3398 if (!rc)
3399 client->is_lock_cmd = TRUE;
3401 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3404 static gint lock_command(assuan_context_t ctx, gchar *line)
3406 struct client_s *client = assuan_get_pointer(ctx);
3408 return do_lock_command(client);
3411 static gint unlock_command(assuan_context_t ctx, gchar *line)
3413 struct client_s *client = assuan_get_pointer(ctx);
3415 unlock_file_mutex(client);
3416 return send_error(ctx, 0);
3419 static gint getpid_command(assuan_context_t ctx, gchar *line)
3421 gpg_error_t rc;
3422 gchar buf[32];
3423 pid_t pid = getpid();
3425 print_fmt(buf, sizeof(buf), "%i", pid);
3426 rc = xfer_data(ctx, buf, strlen(buf));
3427 return send_error(ctx, rc);
3430 static gint version_command(assuan_context_t ctx, gchar *line)
3432 gpg_error_t rc;
3433 gchar buf[32];
3435 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3436 rc = xfer_data(ctx, buf, strlen(buf));
3437 return send_error(ctx, rc);
3440 #ifdef WITH_PINENTRY
3441 static void set_option_value(gchar **opt, const gchar *value)
3443 if (opt)
3444 g_free(*opt);
3446 *opt = NULL;
3448 if (value)
3449 *opt = g_strdup(value);
3451 #endif
3453 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3454 const gchar *value)
3456 struct client_s *client = assuan_get_pointer(ctx);
3457 gpg_error_t rc;
3459 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3460 glong l = 0;
3462 if (value) {
3463 l = strtol(value, NULL, 10);
3465 if (l < 0 || l > 2)
3466 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3469 MUTEX_LOCK(&rcfile_mutex);
3470 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3471 MUTEX_UNLOCK(&rcfile_mutex);
3472 goto done;
3474 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3475 glong l = 0;
3477 if (value) {
3478 l = strtol(value, NULL, 10);
3480 if (l < 0 || l > 1)
3481 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3484 client->rc_on_locked = l ? TRUE : FALSE;
3485 goto done;
3487 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3488 rc = parse_open_opt_lock(client, (gpointer)value);
3490 if (rc)
3491 return rc;
3493 client->opts |= OPT_LOCK;
3495 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3496 if (!value) {
3497 client->opts &= ~(OPT_CIPHER);
3498 goto done;
3501 rc = parse_save_opt_cipher(client, (gpointer)value);
3503 if (rc)
3504 return rc;
3506 client->opts |= OPT_CIPHER;
3507 goto done;
3509 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3510 rc = parse_save_opt_iterations(client, (gpointer)value);
3512 if (rc)
3513 return rc;
3515 goto done;
3517 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3518 pth_attr_t attr = pth_attr_of(pth_self());
3519 gchar buf[41];
3521 if (!value) {
3522 pth_attr_destroy(attr);
3523 goto done;
3526 print_fmt(buf, sizeof(buf), "%s", value);
3527 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3528 pth_attr_destroy(attr);
3529 #ifdef WITH_PINENTRY
3530 if (client->pinentry->name)
3531 g_free(client->pinentry->name);
3533 client->pinentry->name = g_strdup(buf);
3535 if (!client->pinentry->name)
3536 return GPG_ERR_ENOMEM;
3537 #endif
3539 goto done;
3541 #ifdef WITH_PINENTRY
3542 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3543 set_option_value(&client->pinentry->lcmessages, value);
3544 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3545 set_option_value(&client->pinentry->lcctype, value);
3546 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3547 set_option_value(&client->pinentry->ttyname, value);
3548 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3549 set_option_value(&client->pinentry->ttytype, value);
3550 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3551 set_option_value(&client->pinentry->display, value);
3552 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3553 set_option_value(&client->pinentry->path, value);
3554 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3555 set_option_value(&client->pinentry->title, value);
3556 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3557 set_option_value(&client->pinentry->prompt, value);
3558 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3559 set_option_value(&client->pinentry->desc, value);
3560 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3561 gchar *p = NULL;
3562 gint n;
3564 if (!value)
3565 goto done;
3567 n = strtol(value, &p, 10);
3569 if (*p || n < 0)
3570 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3572 MUTEX_LOCK(&rcfile_mutex);
3573 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3574 "global", "pinentry_timeout", n);
3575 MUTEX_UNLOCK(&rcfile_mutex);
3576 goto done;
3578 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3579 rc = parse_opt_pinentry(client, (gpointer)value);
3581 if (rc)
3582 return rc;
3584 goto done;
3586 #else
3587 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3588 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3589 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3590 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3591 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3592 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3593 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3594 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3595 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3596 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3597 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3598 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3599 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3600 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3601 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3602 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3603 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3604 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3605 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3606 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3607 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3608 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3609 #endif
3610 else
3611 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3613 done:
3614 return 0;
3617 static gint unset_command(assuan_context_t ctx, gchar *line)
3619 log_write2("ARGS=\"%s\"", line);
3620 return send_error(ctx, set_unset_common(ctx, line, NULL));
3623 static gint set_command(assuan_context_t ctx, gchar *line)
3625 gchar name[64] = {0}, value[256] = {0};
3627 log_write2("ARGS=\"%s\"", line);
3629 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3630 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3632 return send_error(ctx, set_unset_common(ctx, name, value));
3635 static gint rename_command(assuan_context_t ctx, gchar *line)
3637 struct client_s *client = assuan_get_pointer(ctx);
3638 gpg_error_t rc;
3639 gchar **req, **src, *dst;
3640 xmlNodePtr n, ndst;
3642 log_write2("ARGS=\"%s\"", line);
3643 req = split_input_line(line, " ", -1);
3645 if (!req || !req[0] || !req[1]) {
3646 g_strfreev(req);
3647 return send_error(ctx, GPG_ERR_SYNTAX);
3650 dst = req[1];
3651 is_literal_element(&dst);
3653 if (!valid_xml_element((xmlChar *)dst)) {
3654 g_strfreev(req);
3655 return GPG_ERR_INV_VALUE;
3658 if (strchr(req[0], '\t'))
3659 src = split_input_line(req[0], "\t", -1);
3660 else
3661 src = split_input_line(req[0], " ", -1);
3663 if (!src || !*src) {
3664 rc = GPG_ERR_SYNTAX;
3665 goto fail;
3668 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3670 if (src[1] && n)
3671 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3672 NULL, FALSE, 0, NULL, FALSE);
3674 if (!n)
3675 goto fail;
3678 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3680 if (!a) {
3681 rc = GPG_ERR_ENOMEM;
3682 goto fail;
3685 /* To prevent unwanted effects:
3687 * <root name="a"><b/></root>
3689 * RENAME a<TAB>b b
3691 if (xmlStrEqual(a, (xmlChar *)dst)) {
3692 xmlFree(a);
3693 rc = GPG_ERR_AMBIGUOUS_NAME;
3694 goto fail;
3697 xmlFree(a);
3698 gchar **tmp = NULL;
3700 if (src[1]) {
3701 gchar **p;
3703 for (p = src; *p; p++) {
3704 if (!*(p+1))
3705 break;
3707 strv_printf(&tmp, "%s", *p);
3711 strv_printf(&tmp, "!%s", dst);
3712 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3714 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3715 g_strfreev(tmp);
3716 goto fail;
3719 if (tmp[1] && ndst)
3720 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3721 NULL, NULL, FALSE, 0, NULL, FALSE);
3723 g_strfreev(tmp);
3725 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3726 goto fail;
3728 rc = 0;
3730 /* Target may exist:
3732 * <root name="a"/>
3733 * <root name="b" target="a"/>
3735 * RENAME b a
3737 * Would need to do:
3738 * RENAME !b a
3740 if (ndst == n) {
3741 rc = GPG_ERR_AMBIGUOUS_NAME;
3742 goto fail;
3745 if (ndst) {
3746 unlink_node(ndst);
3747 xmlFreeNodeList(ndst);
3750 rc = add_attribute(n, "_name", dst);
3752 fail:
3753 g_strfreev(req);
3754 g_strfreev(src);
3755 return send_error(ctx, rc);
3758 static gint copy_command(assuan_context_t ctx, gchar *line)
3760 struct client_s *client = assuan_get_pointer(ctx);
3761 gpg_error_t rc;
3762 gchar **req, **src = NULL, **dst = NULL;
3763 xmlNodePtr nsrc, ndst, new;
3765 log_write2("ARGS=\"%s\"", line);
3766 req = split_input_line(line, " ", -1);
3768 if (!req || !req[0] || !req[1]) {
3769 g_strfreev(req);
3770 return send_error(ctx, GPG_ERR_SYNTAX);
3773 if (strchr(req[0], '\t'))
3774 src = split_input_line(req[0], "\t", -1);
3775 else
3776 src = split_input_line(req[0], " ", -1);
3778 if (!src || !*src) {
3779 rc = GPG_ERR_SYNTAX;
3780 goto fail;
3783 if (strchr(req[1], '\t'))
3784 dst = split_input_line(req[1], "\t", -1);
3785 else
3786 dst = split_input_line(req[1], " ", -1);
3788 if (!dst || !*dst) {
3789 rc = GPG_ERR_SYNTAX;
3790 goto fail;
3793 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3795 if (nsrc && src[1])
3796 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3797 NULL, NULL, FALSE, 0, NULL, FALSE);
3799 if (!nsrc)
3800 goto fail;
3802 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3804 if (ndst && dst[1])
3805 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3806 NULL, NULL, FALSE, 0, NULL, FALSE);
3808 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3809 goto fail;
3811 new = xmlCopyNodeList(nsrc);
3813 if (!new) {
3814 rc = GPG_ERR_ENOMEM;
3815 goto fail;
3818 if (!ndst)
3819 ndst = create_element_path(client, &dst, &rc);
3821 if (!ndst) {
3822 xmlUnlinkNode(new);
3823 xmlFreeNodeList(new);
3824 goto fail;
3827 /* Merge any attributes from the src node to the initial dst node. */
3828 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3829 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3830 continue;
3832 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3834 if (a)
3835 xmlRemoveProp(a);
3837 xmlChar *tmp = xmlNodeGetContent(attr->children);
3838 xmlNewProp(ndst, attr->name, tmp);
3839 xmlFree(tmp);
3840 rc = add_attribute(ndst, NULL, NULL);
3843 xmlNodePtr n = ndst->children;
3844 xmlUnlinkNode(n);
3845 xmlFreeNodeList(n);
3846 ndst->children = NULL;
3848 if (!new->children) {
3849 xmlUnlinkNode(new);
3850 xmlFreeNodeList(new);
3851 goto fail;
3854 n = xmlCopyNodeList(new->children);
3856 if (!n) {
3857 rc = GPG_ERR_ENOMEM;
3858 goto fail;
3861 xmlUnlinkNode(new);
3862 xmlFreeNodeList(new);
3863 n = xmlAddChildList(ndst, n);
3865 if (!n) {
3866 rc = GPG_ERR_ENOMEM;
3867 goto fail;
3870 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3872 fail:
3873 if (req)
3874 g_strfreev(req);
3876 if (src)
3877 g_strfreev(src);
3879 if (dst)
3880 g_strfreev(dst);
3882 return send_error(ctx, rc);
3885 static gint move_command(assuan_context_t ctx, gchar *line)
3887 struct client_s *client = assuan_get_pointer(ctx);
3888 gpg_error_t rc;
3889 gchar **req, **src = NULL, **dst = NULL;
3890 xmlNodePtr nsrc, ndst = NULL;
3892 log_write2("ARGS=\"%s\"", line);
3893 req = split_input_line(line, " ", -1);
3895 if (!req || !req[0] || !req[1]) {
3896 g_strfreev(req);
3897 return send_error(ctx, GPG_ERR_SYNTAX);
3900 if (strchr(req[0], '\t'))
3901 src = split_input_line(req[0], "\t", -1);
3902 else
3903 src = split_input_line(req[0], " ", -1);
3905 if (!src || !*src) {
3906 rc = GPG_ERR_SYNTAX;
3907 goto fail;
3910 if (strchr(req[1], '\t'))
3911 dst = split_input_line(req[1], "\t", -1);
3912 else
3913 dst = split_input_line(req[1], " ", -1);
3915 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3917 if (nsrc && src[1])
3918 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3919 NULL, NULL, FALSE, 0, NULL, FALSE);
3921 if (!nsrc)
3922 goto fail;
3924 if (dst) {
3925 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3927 if (ndst && dst[1])
3928 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3929 NULL, NULL, FALSE, 0, NULL, FALSE);
3931 else
3932 ndst = xmlDocGetRootElement(client->doc);
3934 for (xmlNodePtr n = ndst; n; n = n->parent) {
3935 if (n == nsrc) {
3936 rc = GPG_ERR_CONFLICT;
3937 goto fail;
3941 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3942 goto fail;
3944 rc = 0;
3946 if (ndst) {
3947 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3948 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3950 xmlFree(a);
3952 if (dup) {
3953 if (dup == nsrc)
3954 goto fail;
3956 if (ndst == xmlDocGetRootElement(client->doc)) {
3957 xmlNodePtr n = nsrc;
3958 gboolean match = FALSE;
3960 while (n->parent && n->parent != ndst)
3961 n = n->parent;
3963 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3964 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3966 if (xmlStrEqual(a, b)) {
3967 match = TRUE;
3968 xmlUnlinkNode(nsrc);
3969 xmlUnlinkNode(n);
3970 xmlFreeNodeList(n);
3973 xmlFree(a);
3974 xmlFree(b);
3976 if (!match) {
3977 xmlUnlinkNode(dup);
3978 xmlFreeNodeList(dup);
3981 else
3982 xmlUnlinkNode(dup);
3986 if (!ndst && dst)
3987 ndst = create_element_path(client, &dst, &rc);
3989 if (!ndst)
3990 goto fail;
3992 update_element_mtime(nsrc->parent);
3993 xmlUnlinkNode(nsrc);
3994 ndst = xmlAddChildList(ndst, nsrc);
3996 if (!ndst)
3997 rc = GPG_ERR_ENOMEM;
3999 update_element_mtime(ndst->parent);
4001 fail:
4002 if (req)
4003 g_strfreev(req);
4005 if (src)
4006 g_strfreev(src);
4008 if (dst)
4009 g_strfreev(dst);
4011 return send_error(ctx, rc);
4014 static int ls_command(assuan_context_t ctx, gchar *line)
4016 log_write2("ARGS=\"%s\"", line);
4017 gpg_error_t rc;
4018 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4019 gchar *dir = expand_homedir(tmp);
4020 DIR *d = opendir(dir);
4022 rc = gpg_error_from_syserror();
4023 g_free(tmp);
4025 if (!d) {
4026 g_free(dir);
4027 return send_error(ctx, rc);
4030 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4031 struct dirent *p = g_malloc(len), *cur = NULL;
4032 gchar *list = NULL;
4034 g_free(dir);
4035 rc = 0;
4037 while (!readdir_r(d, p, &cur) && cur) {
4038 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4039 continue;
4040 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4041 continue;
4043 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4045 if (!tmp) {
4046 if (list)
4047 g_free(list);
4049 rc = GPG_ERR_ENOMEM;
4050 break;
4053 g_free(list);
4054 list = tmp;
4057 closedir(d);
4058 g_free(p);
4060 if (rc)
4061 return send_error(ctx, rc);
4063 if (!list)
4064 return send_error(ctx, GPG_ERR_NO_VALUE);
4066 list[strlen(list)-1] = 0;
4067 rc = xfer_data(ctx, list, strlen(list));
4068 g_free(list);
4069 return send_error(ctx, rc);
4072 static void bye_notify(assuan_context_t ctx)
4074 struct client_s *cl = assuan_get_pointer(ctx);
4076 /* This will let assuan_process_next() return. */
4077 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4078 cl->last_rc = 0; // BYE command result
4081 static void reset_notify(assuan_context_t ctx)
4083 struct client_s *cl = assuan_get_pointer(ctx);
4085 if (cl)
4086 cleanup_client(cl);
4090 * This is called before every Assuan command.
4092 gint command_startup(assuan_context_t ctx, const gchar *name)
4094 struct client_s *cl = assuan_get_pointer(ctx);
4095 gpg_error_t rc;
4097 log_write1("%s", name);
4099 for (int i = 0; command_table[i]; i++) {
4100 if (!g_ascii_strcasecmp(name, command_table[i]->name) &&
4101 command_table[i]->ignore_startup)
4102 return 0;
4105 #ifdef WITH_PINENTRY
4106 if (!(cl->opts & OPT_PINENTRY))
4107 reset_pin_defaults(cl->pinentry);
4108 #endif
4110 cl->last_rc = rc = file_modified(cl);
4112 if (rc) {
4113 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4114 !g_ascii_strcasecmp(name, "OPEN"))
4115 rc = 0;
4118 return rc;
4122 * This is called after every Assuan command.
4124 void command_finalize(assuan_context_t ctx, gint rc)
4126 struct client_s *client = assuan_get_pointer(ctx);
4128 if (!client->is_lock_cmd)
4129 unlock_file_mutex(client);
4131 log_write1(N_("command completed (rc=%u)"), client->last_rc);
4132 client->opts &= ~(OPT_INQUIRE);
4133 client->opts &= ~(OPT_BASE64);
4136 static gint help_command(assuan_context_t ctx, gchar *line)
4138 gpg_error_t rc;
4139 gint i;
4141 if (!line || !*line) {
4142 gchar *tmp;
4143 gchar *buf = g_strdup(N_(
4144 "Usage: HELP [<COMMAND>]\n"
4145 " For commands that take an element path as an argument, each element is\n"
4146 " separated with an ASCII tab character (ASCII 0x09).\n"
4147 "\n"
4148 " Each element may contain a \"target\" attribute whose value is also an\n"
4149 " element path. Think of a \"target\" attribute like a symbolic link on a\n"
4150 " filesystem. When found, the element path of the \"target\" attribute will\n"
4151 " be used as a prefix for further elements in the current element path. To\n"
4152 " ignore any \"target\" attribute for the current element, prefix the element\n"
4153 " with an ! (ASCII 0x21).\n"
4154 "\n"
4155 " See pwmd(1) for configuration file options which may also set default\n"
4156 " options for specific data files.\n"
4157 "\n"
4158 "COMMANDS:"));
4160 for (i = 0; command_table[i]; i++) {
4161 gchar *p = strrchr(buf, '\n');
4162 gboolean newline = FALSE;
4164 if (!command_table[i]->help)
4165 continue;
4167 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4168 tmp = g_strdup_printf("%s\n", buf);
4169 g_free(buf);
4170 buf = tmp;
4171 newline = TRUE;
4174 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4175 command_table[i]->name);
4176 g_free(buf);
4177 buf = tmp;
4180 tmp = g_strdup_printf("%s\n", buf);
4181 g_free(buf);
4182 buf = tmp;
4183 rc = xfer_data(ctx, buf, strlen(buf));
4184 g_free(buf);
4185 return send_error(ctx, rc);
4188 for (i = 0; command_table[i]; i++) {
4189 if (!g_strcasecmp(line, command_table[i]->name)) {
4190 if (!command_table[i]->help)
4191 break;
4193 gchar *tmp = g_strdup_printf(N_("Usage: %s"), command_table[i]->help);
4194 rc = xfer_data(ctx, tmp, strlen(tmp));
4195 g_free(tmp);
4196 return send_error(ctx, rc);
4200 return send_error(ctx, GPG_ERR_INV_NAME);
4203 void new_command(const gchar *name, gboolean ignore,
4204 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4206 gint i = 0;
4208 if (command_table)
4209 for (i = 0; command_table[i]; i++);
4211 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4212 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4213 command_table[i]->name = name;
4214 command_table[i]->handler = handler;
4215 command_table[i]->ignore_startup = ignore;
4216 command_table[i++]->help = help;
4217 command_table[i] = NULL;
4220 void deinit_commands()
4222 gint i;
4224 for (i = 0; command_table[i]; i++)
4225 g_free(command_table[i]);
4227 g_free(command_table);
4230 void init_commands()
4232 /* !BEGIN-HELP-TEXT!
4234 * This comment is used as a marker to generate the offline documentation
4235 * for commands found in doc/COMMANDS.
4237 new_command("HELP", TRUE, help_command, N_(
4238 "HELP [<COMMAND>]\n"
4239 " Show available commands or command specific help text.\n"
4242 new_command("OPEN", FALSE, open_command, N_(
4243 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4244 " Opens <filename> using <key>. When the filename is not found on the\n"
4245 " file-system a new document will be created. If the file is found, it is\n"
4246 " looked for in the file cache for an existing key. When found and no key\n"
4247 " was specified, the cached key will be used for decryption (if encrypted).\n"
4248 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4249 " OPTIONS documentation).\n"
4250 "\n"
4251 " When the --lock option is passed then the file mutex will be locked as if\n"
4252 " the LOCK command had been sent after the file had been opened.\n"
4253 "\n"
4254 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4255 " retrieve the filename and key arguments.\n"
4256 "\n"
4257 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4258 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4259 " no value is specified then the configuration file value will be used. If\n"
4260 " the passphrase is invalid then it is up to the client whether to retry or\n"
4261 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4262 " pinentry dialog, use --pinentry=0.\n"
4263 "\n"
4264 " When a \"key_file\" configuration parameter has been set for the current\n"
4265 " file and there is no cache entry, then an --inquire must be used to\n"
4266 " retrieve the key.\n"
4267 "\n"
4268 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4269 " decoded before doing decryption. This allows for binary keys and may also\n"
4270 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4273 new_command("SAVE", FALSE, save_command, N_(
4274 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4275 " [--iterations=[N]] [--base64] [<key>]\n"
4276 " Writes the XML document to disk. The file written to is the file that was\n"
4277 " opened using the OPEN command. If <key> is not specified then the\n"
4278 " currently cached key will be used. If the file is a new file or the file\n"
4279 " isn't found in the file cache then <key> will be used. If both <key> is\n"
4280 " not specified and the file is not cached then pinentry(1) will be used to\n"
4281 " retrieve the key (see below) unless the configured number of iterations is\n"
4282 " 0 in which case the file will be saved unencrypted.\n"
4283 "\n"
4284 " Note that when both <key> is specified and the configured number of\n"
4285 " iterations is 0 the iterations for the current filename will be reset to\n"
4286 " 1. This is to be on the safe side and prevent misuse.\n"
4287 "\n"
4288 " The --iterations option can be used to change the number of encryption\n"
4289 " iterations for the opened file. When 0 no encryption will be performed.\n"
4290 " When this option is either not passed or is specified without a value then\n"
4291 " previous setting obtained from the file header will be used.\n"
4292 "\n"
4293 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4294 " string with the --cipher option. Omitting the string uses the current\n"
4295 " cipher of the opened file or the default if the file is a new one. The\n"
4296 " default is specified in the configuration file. See pwmd(1) for available\n"
4297 " ciphers.\n"
4298 "\n"
4299 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4300 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4301 " no value is specified then the configuration file value will be used.\n"
4302 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4303 " is started over again until either the passphrases match or until the\n"
4304 " input is canceled by the user. To save with encryption and with an empty\n"
4305 " passphrase, use --pinentry=0.\n"
4306 "\n"
4307 " When --reset is specified then the cached passphrase for the opened file\n"
4308 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4309 " had been sent.\n"
4310 "\n"
4311 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4312 " retrieve the key.\n"
4313 "\n"
4314 " When a \"key_file\" configuration parameter has been set for the current\n"
4315 " file and there is no cache entry, then an --inquire must be used to\n"
4316 " retrieve the key.\n"
4317 "\n"
4318 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4319 " decoded before doing encryption. This allows for binary keys and may also\n"
4320 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4323 new_command("ISCACHED", TRUE, iscached_command, N_(
4324 "ISCACHED <filename>\n"
4325 " An OK response is returned if the specified file is found in the file\n"
4326 " cache. If not found in the cache but exists on the filesystem,\n"
4327 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4330 new_command("CLEARCACHE", TRUE, clearcache_command, N_(
4331 "CLEARCACHE [<filename>]\n"
4332 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4333 " the specified file. Always returns an OK response.\n"
4336 new_command("CACHETIMEOUT", TRUE, cachetimeout_command, N_(
4337 "CACHETIMEOUT <filename> <seconds>\n"
4338 " Specify the number of seconds the specified file will be cached. -1 will\n"
4339 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4340 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4341 " parameter. Returns ERR if the filename isn't cached or if the timeout is\n"
4342 " invalid. OK otherwise.\n"
4345 new_command("LIST", FALSE, list_command, N_(
4346 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4347 " If no element path is given then a newline separated list of root elements\n"
4348 " is returned with the data response. If given, then all reachable elements\n"
4349 " for the specified element path are returned unless the --no-recurse option\n"
4350 " is specified. If specified, only the child elements of the element path\n"
4351 " are returned without recursing into grandchildren. Each element in the\n"
4352 " path is prefixed with the literal '!' character when the element contains\n"
4353 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4354 "\n"
4355 " When the --verbose option is passed then each element path returned in the\n"
4356 " list will have a single space character followed by either a 0 or 1\n"
4357 " appended to it. When 0, the element path has no children, otherwise it\n"
4358 " does have children. When used with the --no-recurse option this may be\n"
4359 " useful to limit the amount of data transferred to the client.\n"
4362 new_command("REALPATH", FALSE, realpath_command, N_(
4363 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4364 " Resolves all \"target\" attributes of the specified element path and returns\n"
4365 " the result with a data response.\n"
4368 new_command("STORE", FALSE, store_command, N_(
4369 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4370 " Creates a new element tree or modifies the content of an existing element\n"
4371 " path. If only a single element is specified, a new root element is\n"
4372 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4373 " to the last TAB delimited argument. If no content is specified after the\n"
4374 " last TAB then the content for the last specified element will be removed\n"
4375 " or empty when creating a new element.\n"
4376 "\n"
4377 " The only restriction of an element name is that it not contain whitespace\n"
4378 " or begin with the literal element character '!' unless specifying a\n"
4379 " literal element. There is no whitespace between the TAB delimited\n"
4380 " elements. It is recommended that the value or content be base 64 encoded\n"
4381 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4382 " errors.\n"
4383 "\n"
4384 " PWMD reads the element path from the client via the Assuan INQUIRE\n"
4385 " protocol response: the STORE command is sent by itself without arguments,\n"
4386 " then the server responds with INQUIRE. The client then sends the element\n"
4387 " path prefixed with a \"D \" data response. The element path may extend\n"
4388 " multiple lines but each must be prefixed with the data \"D \" response. When\n"
4389 " finished, the client sends \"END\" on an empty line. This is needed so an\n"
4390 " element path and value can be more than 1000 bytes long, the Assuan\n"
4391 " protocol line limit.\n"
4394 new_command("RENAME", FALSE, rename_command, N_(
4395 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4396 " Renames the specified element to the new value. If an element of the same\n"
4397 " name as the value exists then it will be overwritten.\n"
4400 new_command("COPY", FALSE, copy_command, N_(
4401 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4402 " Copies the entire element tree starting from the child node of the source\n"
4403 " element path, to the destination element path. If the destination element\n"
4404 " path doesn't exist then it is created; otherwise it is overwritten.\n"
4405 "\n"
4406 " Note that attributes from the source element path are merged into the\n"
4407 " destination element path when the destination element path exists. When an\n"
4408 " attribute of the same name exists in both the source and destination\n"
4409 " element paths then the destination attribute will be updated to the source\n"
4410 " attribute value.\n"
4413 new_command("MOVE", FALSE, move_command, N_(
4414 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4415 " Moves the source element path to the destination element path. If the\n"
4416 " destination is not specified then it will be moved to the root of the\n"
4417 " document. If the destination is specified and exists then it will be\n"
4418 " overwritten; otherwise it will be created.\n"
4421 new_command("DELETE", FALSE, delete_command, N_(
4422 "DELETE [!]element[<TAB>[!]element[...]]\n"
4423 " Removes the specified element path from the XML document.\n"
4426 new_command("GET", FALSE, get_command, N_(
4427 "GET [!]element[<TAB>[!]element[...]]\n"
4428 " Retrieves the content or XML text node of the specified element path. The\n"
4429 " data is returned with a data response.\n"
4432 new_command("ATTR", FALSE, attr_command, N_(
4433 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4434 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4435 " Stores or updates an attribute name and optional value of an element\n"
4436 " path.\n"
4437 "\n"
4438 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4439 " Removes an attribute from an element path.\n"
4440 "\n"
4441 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4442 " Gets a newline separated list of attributes from an element path.\n"
4443 "\n"
4444 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4445 " Gets the value of an attribute from an element path.\n"
4446 "\n"
4447 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4448 " if the element path is the root element. Although it can be SET to change\n"
4449 " the element name but only if the destination element name doesn't exist.\n"
4450 " Use the RENAME command for that instead.\n"
4451 "\n"
4452 " There is another special attribute \"_mtime\" which is updated each time an\n"
4453 " element is modified: either by storing content, editing attributes or\n"
4454 " deleting a child element.\n"
4455 "\n"
4456 " Also see THE TARGET ATTRIBUTE.\n"
4459 new_command("XPATH", FALSE, xpath_command, N_(
4460 "XPATH <expression>[<TAB>[value]]\n"
4461 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4462 " assumed the expression is a request to return a result. Otherwise, the\n"
4463 " result is set to the value argument and the document is updated. If there\n"
4464 " is no value after the <TAB> character, the value is assumed to be empty\n"
4465 " and the document is updated.\n"
4468 new_command("XPATHATTR", FALSE, xpathattr_command, N_(
4469 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4470 " Like the XPATH command but operates on element attributes and won't return\n"
4471 " a result. For the SET operation the <value> is optional but the field is\n"
4472 " required in which case the value will be empty.\n"
4475 new_command("IMPORT", FALSE, import_command, N_(
4476 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4477 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4478 " data. The content is created as a child of the specified element path. If\n"
4479 " an element of the element path does not exist then it is created. If no\n"
4480 " element path is specified then the content must begin with an pwmd DTD\n"
4481 " root element.\n"
4482 "\n"
4483 " Note that the new content must begin with an XML element node. Also note\n"
4484 " that an existing child node of the same element name as the root node of\n"
4485 " the imported content will be overwritten.\n"
4488 new_command("DUMP", FALSE, dump_command, N_(
4489 "DUMP\n"
4490 " Shows the in memory XML document with indenting. To dump a specific\n"
4491 " element tree, use the XPATH command.\n"
4494 new_command("LOCK", FALSE, lock_command, N_(
4495 "LOCK\n"
4496 " Locks the mutex associated with the opened file. This prevents other\n"
4497 " clients from sending commands to the same opened file until the client\n"
4498 " that sent this command either disconnects or sends the UNLOCK command.\n"
4501 new_command("UNLOCK", FALSE, unlock_command, N_(
4502 "UNLOCK\n"
4503 " Unlocks the file mutex which was locked with the LOCK command.\n"
4506 new_command("GETPID", TRUE, getpid_command, N_(
4507 "GETPID\n"
4508 " Retrieves the process id of the server.\n"
4511 new_command("GETCONFIG", TRUE, getconfig_command, N_(
4512 "GETCONFIG [filename] <parameter>\n"
4513 " Returns the value of a pwmd configuration variable with a data response.\n"
4514 " If no file has been opened then the value for the specified file or the\n"
4515 " default from the \"global\" section will be returned. If a file has been\n"
4516 " opened and no filename is specified, the value previously set with the SET\n"
4517 " command, if any, will be returned.\n"
4518 "\n"
4519 " If there is no such configuration parameter defined, GPG_ERR_NO_VALUE is\n"
4520 " returned.\n"
4523 new_command("VERSION", TRUE, version_command, N_(
4524 "VERSION\n"
4525 " Returns the server version number with a data response.\n"
4528 new_command("SET", TRUE, set_command, N_(
4529 "SET <NAME>=<VALUE>\n"
4530 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4531 " option to its default value.\n"
4532 "\n"
4533 " NAME |VALUE |Description\n"
4534 " -----------------|----------|----------------------------------------------\n"
4535 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4536 " is 1.\n"
4537 "\n"
4538 " * Deprecated. Pass --pinentry to the OPEN and\n"
4539 " SAVE commands instead.\n"
4540 "\n"
4541 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4542 " process will terminate while waiting for a\n"
4543 " passphrase. The default is 20, 0 disables.\n"
4544 "\n"
4545 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4546 " is specified at compile time.\n"
4547 "\n"
4548 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4549 "\n"
4550 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4551 "\n"
4552 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4553 "\n"
4554 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4555 "\n"
4556 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4557 "\n"
4558 " DESC <string> Sets the error or description string of the\n"
4559 " pinentry dialog.\n"
4560 "\n"
4561 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4562 "\n"
4563 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4564 " pinentry(1).\n"
4565 "\n"
4566 " NAME <string> Associates the thread ID of the connection\n"
4567 " with the specified textual representation.\n"
4568 " Useful for debugging log messages.\n"
4569 "\n"
4570 " CIPHER <string> The cipher to use for the next SAVE.\n"
4571 "\n"
4572 " * Deprecated. Use --cipher instead.\n"
4573 "\n"
4574 " ITERATIONS <integer> The number of encryption iterations to do\n"
4575 " when the SAVE command is sent. An opened file\n"
4576 " is needed when setting this option. The\n"
4577 " CONFIG status message is sent after receiving\n"
4578 " this command.\n"
4579 "\n"
4580 " * Deprecated. Use --iterations instead.\n"
4581 "\n"
4582 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4583 " after a successful OPEN as if the LOCK\n"
4584 " command had been sent.\n"
4585 "\n"
4586 " * Deprecated. Use --lock instead.\n"
4587 "\n"
4588 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4589 " of a status message when the file mutex is\n"
4590 " locked by another thread.\n"
4593 new_command("UNSET", TRUE, unset_command, N_(
4594 "UNSET <NAME>\n"
4595 " Resets option NAME to the value specified in the server configuration\n"
4596 " file. Some options have no default and will be reset to NULL or 0\n"
4597 " depending on the value type. See the SET command for available options.\n"
4600 new_command("LS", TRUE, ls_command, N_(
4601 "LS\n"
4602 " Lists the contents of the configured data_directory. The result is a\n"
4603 " newline separated list of filenames.\n"
4606 new_command("RESET", TRUE, NULL, N_(
4607 "RESET\n"
4608 " Closes the currently opened file but keeps any previously set client\n"
4609 " options.\n"
4612 new_command("BYE", TRUE, NULL, N_(
4613 "BYE\n"
4614 " Closes the connection discarding any unsaved changes.\n"
4617 new_command("NOP", TRUE, NULL, N_(
4618 "NOP\n"
4619 " Does nothing. Always returns successfully.\n"
4622 /* !END-HELP-TEXT! */
4623 new_command("CANCEL", TRUE, NULL, NULL);
4624 new_command("END", TRUE, NULL, NULL);
4627 gpg_error_t register_commands(assuan_context_t ctx)
4629 gint i = 0, rc;
4631 for (; command_table[i]; i++) {
4632 if (!command_table[i]->handler)
4633 continue;
4635 rc = assuan_register_command (ctx, command_table[i]->name,
4636 command_table[i]->handler);
4638 if (rc)
4639 return rc;
4642 rc = assuan_register_bye_notify(ctx, bye_notify);
4644 if (rc)
4645 return rc;
4647 rc = assuan_register_reset_notify(ctx, reset_notify);
4649 if (rc)
4650 return rc;
4652 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4654 if (rc)
4655 return rc;
4657 return assuan_register_post_cmd_notify(ctx, command_finalize);
4660 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4661 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4663 goffset insize, len;
4664 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4665 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
4666 gulong outsize = 0;
4667 gpg_error_t rc;
4668 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4669 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4670 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4672 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4673 insize = crypto->fh->st.st_size - fh_size;
4674 crypto->iv = gcry_malloc(crypto->blocksize);
4676 if (!crypto->iv) {
4677 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4678 return GPG_ERR_ENOMEM;
4681 if (crypto->fh->v1)
4682 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4683 else
4684 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4686 crypto->inbuf = gcry_malloc(insize);
4688 if (!crypto->inbuf) {
4689 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4690 return GPG_ERR_ENOMEM;
4693 crypto->insize = insize;
4694 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4696 if (len != crypto->insize)
4697 return GPG_ERR_INV_LENGTH;
4699 /* No encryption iterations. This is a plain (gzipped) file. */
4700 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4701 (!crypto->fh->v1 && fh_iter <= 0L)) {
4703 * cache_file_count() needs both .used == TRUE and a valid key in
4704 * order for it to count as a used cache entry. Fixes CACHE status
4705 * messages.
4707 memset(crypto->key, '!', hashlen);
4708 goto decompress;
4711 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4712 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4713 return rc;
4716 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4717 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4718 return rc;
4721 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4722 client->filename : "global", "iteration_progress");
4724 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4725 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4727 if (rc)
4728 return rc;
4731 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4733 if (rc)
4734 return rc;
4736 crypto->tkey = gcry_malloc(hashlen);
4738 if (!crypto->tkey) {
4739 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4740 return GPG_ERR_ENOMEM;
4743 memcpy(crypto->tkey, crypto->key, hashlen);
4744 guchar *tkey = crypto->tkey;
4745 tkey[0] ^= 1;
4747 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4748 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4749 return rc;
4752 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4753 if (iter_progress > 0ULL && iter >= iter_progress) {
4754 if (!(iter % iter_progress)) {
4755 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4756 ++n_iter * iter_progress, fh_iter);
4758 if (rc)
4759 return rc;
4763 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4764 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4765 return rc;
4768 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4770 if (rc) {
4771 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4772 return rc;
4775 iter++;
4778 if (iter_progress && fh_iter >= iter_progress) {
4779 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4781 if (rc)
4782 return rc;
4785 decompress:
4786 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4787 len = 0;
4789 if (crypto->fh->ver.fh2.iter > 0ULL) {
4790 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4791 return GPG_ERR_INV_PASSPHRASE;
4793 len = sizeof(crypto_magic);
4796 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4797 (gpointer *)&crypto->outbuf, &outsize);
4799 if (rc)
4800 return rc;
4802 else {
4803 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4804 (gpointer *)&crypto->outbuf, &outsize);
4806 if (rc == GPG_ERR_ENOMEM)
4807 return rc;
4808 else if (rc)
4809 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4811 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4812 gcry_free(crypto->outbuf);
4813 crypto->outbuf = NULL;
4814 return GPG_ERR_INV_PASSPHRASE;
4818 if (ctx) {
4819 client->xml = crypto->outbuf;
4820 client->len = outsize;
4821 crypto->outbuf = NULL;
4823 else if (dst) {
4824 *dst = crypto->outbuf;
4825 *dst_len = outsize;
4826 crypto->outbuf = NULL;
4829 /* The calling function should free the crypto struct. */
4830 return 0;