Added the client options set with the SET command to the online help.
[pwmd.git] / src / commands.c
blob050dabe621635002628dbe461f8de9f396ad6726
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;
68 static struct command_table_s **command_table;
69 static guchar crypto_magic[5] = "\177PWMD";
71 static gpg_error_t do_lock_command(struct client_s *client);
73 static void *z_alloc(void *data, unsigned items, unsigned size)
75 return gcry_calloc(items, size);
78 static void z_free(void *data, void *p)
80 gcry_free(p);
83 static gpg_error_t file_modified(struct client_s *client)
85 struct stat st;
86 gpg_error_t rc;
88 if (client->state != STATE_OPEN)
89 return EPWMD_NO_FILE;
91 rc = lock_file_mutex(client);
93 if (rc)
94 return rc;
96 if (lstat(client->filename, &st) == 0 && client->mtime) {
97 if (client->mtime != st.st_mtime)
98 return EPWMD_FILE_MODIFIED;
101 pth_cancel_point();
102 return 0;
105 static gpg_error_t parse_xml(assuan_context_t ctx)
107 struct client_s *client = assuan_get_pointer(ctx);
109 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
111 if (!client->doc)
112 return EPWMD_LIBXML_ERROR;
114 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
115 return 0;
117 return convert_elements(client->doc);
120 void unlock_file_mutex(struct client_s *client)
122 pth_mutex_t *m;
124 if (client->has_lock == FALSE)
125 return;
127 CACHE_LOCK(client->ctx);
129 if (cache_get_mutex(client->md5file, &m) == FALSE) {
130 CACHE_UNLOCK;
131 return;
134 CACHE_UNLOCK;
135 MUTEX_UNLOCK(m);
136 client->has_lock = client->is_lock_cmd = FALSE;
139 gpg_error_t lock_file_mutex(struct client_s *client)
141 pth_mutex_t *m;
142 gpg_error_t rc = 0;
144 if (client->has_lock == TRUE)
145 return 0;
147 CACHE_LOCK(client->ctx);
149 if (cache_get_mutex(client->md5file, &m) == FALSE) {
150 CACHE_UNLOCK;
151 return 0;
154 CACHE_UNLOCK;
156 if (client->rc_on_locked) {
157 if (!pth_mutex_acquire(m, TRUE, NULL))
158 return GPG_ERR_LOCKED;
159 #ifdef MUTEX_DEBUG
160 MUTEX_LOCK_DEBUG(m);
161 #endif
163 else
164 MUTEX_TRYLOCK(client, m, rc);
166 if (!rc)
167 client->has_lock = TRUE;
169 return rc;
172 void free_client(struct client_s *client)
174 if (client->doc)
175 xmlFreeDoc(client->doc);
177 if (client->xml)
178 gcry_free(client->xml);
180 if (client->filename)
181 g_free(client->filename);
183 if (client->crypto)
184 cleanup_crypto(&client->crypto);
186 if (client->xml_error)
187 xmlResetError(client->xml_error);
190 void cleanup_client(struct client_s *client)
192 assuan_context_t ctx = client->ctx;
193 struct client_thread_s *thd = client->thd;
194 gboolean rc_on_locked = client->rc_on_locked;
195 gboolean lock_on_open = client->lock_on_open;
196 #ifdef WITH_PINENTRY
197 struct pinentry_s *pin = client->pinentry;
198 #endif
200 unlock_file_mutex(client);
201 CACHE_LOCK(client->ctx);
202 cache_decr_refcount(client->md5file);
205 * This may be a new file so don't use a cache slot. save_command() will
206 * set this to FALSE on success.
208 if (client->new == TRUE)
209 cache_clear(client->md5file, 1);
211 CACHE_UNLOCK;
212 free_client(client);
213 memset(client, 0, sizeof(struct client_s));
214 client->state = STATE_CONNECTED;
215 client->ctx = ctx;
216 client->thd = thd;
217 client->freed = TRUE;
218 #ifdef WITH_PINENTRY
219 client->pinentry = pin;
220 #endif
221 client->rc_on_locked = rc_on_locked;
222 client->lock_on_open = lock_on_open;
225 static void gz_cleanup(void *arg)
227 struct gz_s **gz = (struct gz_s **)arg;
229 if (!gz)
230 return;
232 if (!(*gz)->done && (*gz)->out)
233 gcry_free((*gz)->out);
235 if ((*gz)->which == STATUS_COMPRESS) {
236 if ((*gz)->z.zalloc)
237 deflateEnd(&(*gz)->z);
239 else {
240 if ((*gz)->z.zalloc)
241 inflateEnd(&(*gz)->z);
244 g_free(*gz);
245 *gz = NULL;
248 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
249 gpointer *out, gulong *outsize)
251 struct gz_s *gz;
252 gz_header h;
253 gchar buf[17];
254 gpg_error_t rc;
255 gint zrc;
257 gz = g_malloc0(sizeof(struct gz_s));
259 if (!gz)
260 return GPG_ERR_ENOMEM;
262 pth_cleanup_push(gz_cleanup, &gz);
263 gz->which = STATUS_DECOMPRESS;
264 gz->z.zalloc = z_alloc;
265 gz->z.zfree = z_free;
266 gz->z.next_in = in;
267 gz->z.avail_in = (uInt)insize;
268 gz->z.avail_out = zlib_bufsize;
269 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
271 if (!gz->out) {
272 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
273 pth_cleanup_pop(1);
274 return GPG_ERR_ENOMEM;
277 zrc = inflateInit2(&gz->z, 47);
279 if (zrc != Z_OK) {
280 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
281 pth_cleanup_pop(1);
282 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
285 memset(&h, 0, sizeof(gz_header));
286 h.comment = (guchar *)buf;
287 h.comm_max = sizeof(buf);
288 zrc = inflateGetHeader(&gz->z, &h);
290 if (zrc != Z_OK) {
291 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
292 pth_cleanup_pop(1);
293 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
296 zrc = inflate(&gz->z, Z_BLOCK);
298 if (zrc != Z_OK) {
299 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
300 pth_cleanup_pop(1);
301 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
304 if (h.comment)
305 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
307 do {
308 gpointer p;
310 zrc = inflate(&gz->z, Z_FINISH);
312 switch (zrc) {
313 case Z_OK:
314 break;
315 case Z_BUF_ERROR:
316 if (!gz->z.avail_out) {
317 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
319 if (!p) {
320 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
321 rc = GPG_ERR_ENOMEM;
322 goto fail;
325 gz->out = p;
326 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
327 gz->z.avail_out = zlib_bufsize;
328 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
329 gz->z.total_out, insize);
331 if (rc)
332 goto fail;
334 break;
335 case Z_STREAM_END:
336 break;
337 default:
338 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
339 rc = GPG_ERR_COMPR_ALGO;
340 goto fail;
341 break;
343 } while (zrc != Z_STREAM_END);
345 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
346 insize);
348 if (rc)
349 goto fail;
351 *out = gz->out;
352 *outsize = gz->z.total_out;
353 gz->done = TRUE;
354 pth_cleanup_pop(1);
355 return 0;
357 fail:
358 pth_cleanup_pop(1);
359 return rc;
362 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
363 gpg_error_t *rc)
365 gint fd;
366 gsize len;
367 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
368 gsize fh_size;
369 gpointer p;
371 *rc = 0;
373 if (!fh) {
374 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
375 *rc = GPG_ERR_ENOMEM;
376 return NULL;
379 pth_cleanup_push(g_free, fh);
380 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
382 if (lstat(filename, &fh->st) == -1) {
383 *rc = gpg_error_from_syserror();
384 pth_cleanup_pop(1);
385 return NULL;
388 if (!S_ISREG(fh->st.st_mode)) {
389 *rc = GPG_ERR_ENOANO;
390 pth_cleanup_pop(1);
391 return NULL;
394 fd = open(filename, O_RDONLY);
396 if (fd == -1) {
397 *rc = gpg_error_from_syserror();
398 pth_cleanup_pop(1);
399 return NULL;
402 pth_cleanup_push(cleanup_fd_cb, &fd);
403 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
404 len = pth_read(fd, p, fh_size);
406 if (len != fh_size) {
407 *rc = gpg_error_from_syserror();
408 pth_cleanup_pop(1);
409 pth_cleanup_pop(1);
410 return NULL;
413 fh->v1 = v1;
414 fh->fd = fd;
415 pth_cleanup_pop(0);
416 pth_cleanup_pop(0);
417 return fh;
420 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
421 gboolean cached)
423 struct client_s *client = assuan_get_pointer(ctx);
424 gpg_error_t rc;
425 gint timeout;
426 guchar *key = client->crypto->key;
428 /* New file. */
429 if (!client->crypto->fh) {
430 if (key[0])
431 goto update_cache;
433 goto done;
436 rc = init_client_crypto2(client->filename, client->crypto);
438 if (rc) {
439 cleanup_client(client);
440 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
443 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
445 if (rc) {
446 cleanup_client(client);
447 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
450 update_cache:
451 CACHE_LOCK(client->ctx);
453 if (cached == FALSE) {
454 if (cache_update_key(client->md5file, key) == FALSE) {
455 cleanup_client(client);
456 CACHE_UNLOCK;
457 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
460 timeout = get_key_file_integer(client->filename, "cache_timeout");
461 cache_reset_timeout(client->md5file, timeout);
463 else
464 cache_set_timeout(client->md5file, -2);
466 CACHE_UNLOCK;
468 done:
469 rc = parse_xml(ctx);
471 if (client->xml) {
472 gcry_free(client->xml);
473 client->xml = NULL;
476 if (!rc) {
477 if (client->new == FALSE)
478 send_status_all(STATUS_CACHE);
480 client->state = STATE_OPEN;
483 if (!rc && client->new == FALSE &&
484 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
485 MUTEX_LOCK(&rcfile_mutex);
486 g_key_file_set_double(keyfileh, client->filename, "iterations",
487 client->crypto->fh->ver.fh2.iter);
488 MUTEX_UNLOCK(&rcfile_mutex);
489 send_status_all(STATUS_CONFIG);
492 cleanup_crypto(&client->crypto);
494 if (!rc && client->lock_on_open)
495 return do_lock_command(client);
497 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
500 static void req_cleanup(void *arg)
502 if (!arg)
503 return;
505 g_strfreev((gchar **)arg);
508 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
510 struct client_s *client = data;
511 const gchar *p = value;
513 if (p && *p) {
514 long l = strtol(p, NULL, 10);
516 if (l < 0 || l > 1)
517 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
519 client->lock_on_open = l ? TRUE : FALSE;
521 else if ((!p || !*p) && (client->opts & OPT_LOCK))
522 client->lock_on_open = FALSE;
523 else
524 client->lock_on_open = TRUE;
526 return 0;
529 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
531 #ifdef WITH_PINENTRY
532 struct client_s *client = data;
533 gchar *p = NULL;
534 gchar *str = value;
535 gint n;
537 if (!str || !*str) {
538 client->pinentry->enable = -1;
539 client->opts &= ~(OPT_PINENTRY);
540 return 0;
543 n = strtol(str, &p, 10);
545 if (*p || n < 0 || n > 1)
546 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
548 client->pinentry->enable = n ? TRUE : FALSE;
549 client->opts |= OPT_PINENTRY;
550 return 0;
551 #else
552 return GPG_ERR_NOT_IMPLEMENTED;
553 #endif
556 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
558 struct client_s *client = data;
560 (void)value;
561 client->opts |= OPT_INQUIRE;
562 return 0;
565 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
567 struct client_s *client = data;
569 (void)value;
570 client->opts |= OPT_BASE64;
571 return 0;
574 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
576 guchar *tmp;
577 gsize len;
579 if (client->opts & OPT_BASE64)
580 tmp = g_base64_decode(key, &len);
581 else {
582 tmp = (guchar *)g_strdup(key);
583 len = strlen(key);
586 if (!tmp)
587 return GPG_ERR_ENOMEM;
589 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
590 g_free(tmp);
591 return 0;
594 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
596 gboolean cached = FALSE;
597 gpg_error_t rc;
598 struct client_s *client = assuan_get_pointer(ctx);
599 gchar **req;
600 gchar *filename = NULL;
601 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
603 if ((req = split_input_line(line, " ", 2)) != NULL)
604 filename = req[0];
606 pth_cleanup_push(req_cleanup, req);
608 if (!filename || !*filename) {
609 pth_cleanup_pop(1);
610 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
613 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
615 if (valid_filename(filename) == FALSE) {
616 pth_cleanup_pop(1);
617 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
620 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
621 CACHE_LOCK(client->ctx);
623 if (cache_has_file(client->md5file) == FALSE) {
624 if (cache_add_file(client->md5file, NULL) == FALSE) {
625 pth_cleanup_pop(1);
626 CACHE_UNLOCK;
627 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
631 CACHE_UNLOCK;
632 rc = lock_file_mutex(client);
634 if (rc) {
635 pth_cleanup_pop(1);
636 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
639 client->freed = FALSE;
640 CACHE_LOCK(client->ctx);
641 cache_incr_refcount(client->md5file);
642 CACHE_UNLOCK;
643 client->crypto = init_client_crypto();
645 if (!client->crypto) {
646 pth_cleanup_pop(1);
647 cleanup_client(client);
648 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
651 client->crypto->key = gcry_malloc(hashlen);
653 if (!client->crypto->key) {
654 pth_cleanup_pop(1);
655 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
656 GPG_ERR_ENOMEM);
657 cleanup_client(client);
658 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
661 memset(client->crypto->key, 0, hashlen);
662 client->crypto->fh = read_file_header(filename, FALSE, &rc);
664 if (!client->crypto->fh) {
665 if (gpg_err_code_to_errno(rc) != ENOENT) {
666 log_write("%s: %s", filename, pwmd_strerror(rc));
667 pth_cleanup_pop(1);
668 cleanup_client(client);
669 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
673 * New files don't need a key.
675 if ((client->xml = new_document()) == NULL) {
676 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
677 pth_cleanup_pop(1);
678 cleanup_client(client);
679 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
682 client->len = xmlStrlen(client->xml);
683 client->new = TRUE;
684 client->filename = g_strdup(filename);
686 if (!client->filename) {
687 pth_cleanup_pop(1);
688 cleanup_client(client);
689 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
690 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
693 if (req[1] && *req[1]) {
694 rc = hash_key(client, req[1]);
696 if (rc) {
697 pth_cleanup_pop(1);
698 cleanup_client(client);
699 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
703 pth_cleanup_pop(1);
704 #ifdef WITH_PINENTRY
705 client->pinentry->filename = g_strdup(client->filename);
707 if (!client->pinentry->filename) {
708 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
709 cleanup_client(client);
710 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
712 #endif
713 return open_command_finalize(ctx, NULL, cached);
715 else {
716 if (!(client->opts & OPT_CIPHER))
717 g_key_file_set_string(keyfileh, filename, "cipher",
718 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
720 client->mtime = client->crypto->fh->st.st_mtime;
723 client->filename = g_strdup(filename);
725 if (!client->filename) {
726 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
727 pth_cleanup_pop(1);
728 cleanup_client(client);
729 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
732 #ifdef WITH_PINENTRY
733 if (client->pinentry->filename)
734 g_free(client->pinentry->filename);
736 client->pinentry->filename = g_strdup(client->filename);
738 if (!client->pinentry->filename) {
739 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
740 pth_cleanup_pop(1);
741 cleanup_client(client);
742 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
744 #endif
746 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
747 goto done;
749 CACHE_LOCK(client->ctx);
750 cached = cache_get_key(client->md5file, client->crypto->key);
751 CACHE_UNLOCK;
753 if (cached == FALSE) {
754 gchar *tmp = get_key_file_string(filename, "key_file");
756 if (tmp && !(client->opts & OPT_INQUIRE)) {
757 g_free(tmp);
758 pth_cleanup_pop(1);
759 cleanup_client(client);
760 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
763 if (tmp)
764 g_free(tmp);
767 * No key specified and no matching filename found in the cache. Use
768 * pinentry to retrieve the key. Cannot return assuan_process_done()
769 * here otherwise the command will be interrupted. The event loop in
770 * client_thread() will poll the file descriptor waiting for it to
771 * become ready to read a pinentry_key_s which will contain the
772 * entered key or an error code. It will then call
773 * open_command_finalize() to to finish the command.
775 if (!req[1] || !*req[1]) {
776 #ifdef WITH_PINENTRY
777 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
779 /* From set_pinentry_defaults(). */
780 if (client->opts & OPT_INQUIRE ||
781 client->pinentry->enable == FALSE ||
782 (client->pinentry->enable == -1 && b == FALSE)) {
783 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
784 goto done;
787 pth_cleanup_pop(1);
788 rc = lock_pin_mutex(client);
790 if (rc) {
791 unlock_pin_mutex(client->pinentry);
792 cleanup_client(client);
793 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
796 client->pinentry->which = PINENTRY_OPEN;
797 rc = pinentry_fork(ctx);
799 if (rc) {
800 unlock_pin_mutex(client->pinentry);
801 cleanup_client(client);
802 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
805 // Called from pinentry iterate.
806 client->pinentry->cb = open_command_finalize;
807 client->pinentry->status = PINENTRY_INIT;
808 return 0;
809 #else
810 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
811 goto done;
812 #endif
815 rc = hash_key(client, req[1]);
817 if (rc) {
818 pth_cleanup_pop(1);
819 cleanup_client(client);
820 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
823 else if (req && req[1] && *req[1]) {
824 rc = hash_key(client, req[1]);
826 if (rc) {
827 pth_cleanup_pop(1);
828 cleanup_client(client);
829 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
833 done:
834 pth_cleanup_pop(1);
835 return open_command_finalize(ctx, NULL, cached);
838 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
839 guchar *line, gsize len)
841 assuan_context_t ctx = data;
842 struct client_s *client = assuan_get_pointer(ctx);
843 gpg_error_t rc = file_modified(client);
845 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
846 if (line)
847 xfree(line);
849 return assuan_rc ? assuan_rc : rc;
852 rc = open_command_common(ctx, (gchar *)line);
854 if (line)
855 xfree(line);
857 client->inquire_status = INQUIRE_DONE;
858 return rc;
861 static gint open_command(assuan_context_t ctx, gchar *line)
863 gpg_error_t rc;
864 struct client_s *client = assuan_get_pointer(ctx);
865 struct argv_s *args[] = {
866 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
867 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
868 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
869 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
870 NULL
873 if (client->state == STATE_OPEN)
874 cleanup_client(client);
876 if (!(client->opts & OPT_LOCK))
877 client->lock_on_open = FALSE;
879 rc = parse_options(&line, args, client);
881 if (rc)
882 return send_error(ctx, rc);
884 if ((client->opts & OPT_INQUIRE)) {
885 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
886 ctx);
888 if (rc)
889 return send_error(ctx, rc);
891 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
892 client->inquire_status = INQUIRE_BUSY;
893 return 0;
896 return open_command_common(ctx, line);
899 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
900 guint size, gpointer *out, gulong *outsize)
902 struct gz_s *gz;
903 gz_header h;
904 gchar buf[17];
905 gint cmd = Z_NO_FLUSH;
906 gint zrc;
907 gpg_error_t rc;
909 gz = g_malloc0(sizeof(struct gz_s));
911 if (!gz)
912 return GPG_ERR_ENOMEM;
914 pth_cleanup_push(gz_cleanup, &gz);
915 gz->which = STATUS_COMPRESS;
916 gz->z.zalloc = z_alloc;
917 gz->z.zfree = z_free;
918 gz->z.next_in = data;
919 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
920 gz->z.avail_out = (uInt)zlib_bufsize;
921 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
923 if (!gz->out) {
924 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
925 pth_cleanup_pop(1);
926 return GPG_ERR_ENOMEM;
929 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
931 if (zrc != Z_OK) {
932 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
933 pth_cleanup_pop(1);
934 return GPG_ERR_COMPR_ALGO;
937 /* Rather than store the size of the uncompressed data in the file header,
938 * store it in the comment field of the gzip header. Don't give anyone too
939 * much information. Not sure why really, but it seems the right way. :)
941 memset(&h, 0, sizeof(gz_header));
942 g_snprintf(buf, sizeof(buf), "%u", size);
943 h.comment = (guchar *)buf;
944 zrc = deflateSetHeader(&gz->z, &h);
946 if (zrc != Z_OK) {
947 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
948 pth_cleanup_pop(1);
949 return GPG_ERR_COMPR_ALGO;
952 do {
953 gpointer p;
955 zrc = deflate(&gz->z, cmd);
957 switch (zrc) {
958 case Z_OK:
959 break;
960 case Z_BUF_ERROR:
961 if (!gz->z.avail_out) {
962 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
964 if (!p) {
965 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
966 rc = GPG_ERR_ENOMEM;
967 goto fail;
970 gz->out = p;
971 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
972 gz->z.avail_out = zlib_bufsize;
975 if (!gz->z.avail_in && gz->z.total_in < size) {
976 if (gz->z.total_in + zlib_bufsize > size)
977 gz->z.avail_in = size - gz->z.total_in;
978 else
979 gz->z.avail_in = zlib_bufsize;
981 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
982 gz->z.total_in, size);
984 if (rc)
985 goto fail;
988 if (gz->z.total_in >= size)
989 cmd = Z_FINISH;
991 break;
992 case Z_STREAM_END:
993 break;
994 default:
995 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
996 rc = GPG_ERR_COMPR_ALGO;
997 goto fail;
999 } while (zrc != Z_STREAM_END);
1001 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
1003 if (rc)
1004 goto fail;
1006 *out = gz->out;
1007 *outsize = gz->z.total_out;
1008 gz->done = TRUE;
1009 pth_cleanup_pop(1);
1010 return 0;
1012 fail:
1013 pth_cleanup_pop(1);
1014 return rc;
1017 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1020 * Useful for a large amount of data. Rather than doing all of the data in one
1021 * iteration do it in chunks. This lets the command be cancelable rather than
1022 * waiting for it to complete.
1024 static gpg_error_t iterate_crypto_once(struct client_s *client,
1025 struct crypto_s *crypto, status_msg_t which)
1027 gpg_error_t rc = 0;
1028 goffset len = CRYPTO_BLOCKSIZE(crypto);
1029 gpointer p = gcry_malloc(len);
1030 goffset total = 0;
1031 gpointer inbuf;
1033 if (!p)
1034 return GPG_ERR_ENOMEM;
1036 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1037 len = crypto->insize;
1039 pth_cleanup_push(gcry_free, p);
1041 for (;;) {
1042 inbuf = (guchar *)crypto->inbuf + total;
1043 guchar *tmp;
1045 if (len + total > crypto->insize)
1046 len = crypto->blocksize;
1048 if (which == STATUS_ENCRYPT)
1049 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1050 else
1051 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1053 if (rc)
1054 goto done;
1056 tmp = (guchar *)crypto->inbuf + total;
1057 memmove(tmp, p, len);
1058 total += len;
1060 if (total >= crypto->insize)
1061 break;
1063 pth_cancel_point();
1066 done:
1067 pth_cleanup_pop(1);
1068 return rc;
1071 /* The crypto struct must be setup for iterations and .key. */
1072 gpg_error_t do_xml_encrypt(struct client_s *client,
1073 struct crypto_s *crypto, const gchar *filename)
1075 goffset len = crypto->insize;
1076 gpointer inbuf;
1077 gchar *p;
1078 gpg_error_t rc;
1079 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
1080 gchar tmp[FILENAME_MAX];
1081 struct stat st;
1082 mode_t mode = 0;
1083 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1085 if (!crypto->fh->ver.fh2.iter) {
1087 * cache_file_count() needs both .used == TRUE and a valid key in
1088 * order for it to count as a used cache entry. Fixes CACHE status
1089 * messages.
1091 memset(crypto->key, '!', hashlen);
1092 goto write_file;
1096 * Resize the existing xml buffer to the block size required by gcrypt
1097 * rather than duplicating it and wasting memory.
1099 crypto->insize += sizeof(crypto_magic);
1100 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1102 if (crypto->insize % crypto->blocksize)
1103 len += crypto->blocksize;
1105 inbuf = gcry_realloc(crypto->inbuf, len);
1107 if (!inbuf) {
1108 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1109 return GPG_ERR_ENOMEM;
1112 guchar *tmpbuf = inbuf;
1113 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1114 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1115 crypto->inbuf = tmpbuf;
1116 crypto->insize = len;
1117 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1119 if (crypto->tkey)
1120 gcry_free(crypto->tkey);
1122 crypto->tkey = gcry_malloc(hashlen);
1124 if (!crypto->tkey) {
1125 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1126 return GPG_ERR_ENOMEM;
1129 memcpy(crypto->tkey, crypto->key, hashlen);
1130 guchar *tkey = crypto->tkey;
1131 tkey[0] ^= 1;
1133 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1134 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1135 return rc;
1138 iter_progress = (guint64)get_key_file_double(
1139 client ? client->filename : "global", "iteration_progress");
1141 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1142 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1143 "0 %llu", crypto->fh->ver.fh2.iter);
1145 if (rc)
1146 return rc;
1149 while (xiter < crypto->fh->ver.fh2.iter-1) {
1150 if (iter_progress > 0ULL && xiter >= iter_progress) {
1151 if (!(xiter % iter_progress)) {
1152 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1153 "%llu %llu", ++n_iter * iter_progress,
1154 crypto->fh->ver.fh2.iter);
1156 if (rc)
1157 return rc;
1161 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1162 crypto->blocksize))) {
1163 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1164 return rc;
1167 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1169 if (rc) {
1170 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1171 return rc;
1174 xiter++;
1177 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1178 crypto->blocksize))) {
1179 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1180 return rc;
1183 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1184 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1185 return rc;
1188 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1190 if (rc)
1191 return rc;
1193 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1194 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1195 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1197 if (rc)
1198 return rc;
1201 write_file:
1202 tmp[0] = 0;
1204 if (filename) {
1205 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1206 crypto->fh->fd = STDOUT_FILENO;
1207 goto do_write_file;
1210 if (lstat(filename, &st) == 0) {
1211 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1213 if (!(mode & S_IWUSR))
1214 return GPG_ERR_EACCES;
1216 else if (errno != ENOENT)
1217 return gpg_error_from_syserror();
1219 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1220 crypto->fh->fd = mkstemp(tmp);
1222 if (crypto->fh->fd == -1) {
1223 rc = gpg_error_from_syserror();
1224 p = strrchr(tmp, '/');
1225 p++;
1226 log_write("%s: %s", p, pwmd_strerror(rc));
1227 return rc;
1230 pth_cleanup_push(cleanup_unlink_cb, tmp);
1232 else
1234 * xml_import() or convert_file() from command line.
1236 crypto->fh->fd = STDOUT_FILENO;
1238 do_write_file:
1239 crypto->fh->ver.fh2.magic[0] = '\177';
1240 crypto->fh->ver.fh2.magic[1] = 'P';
1241 crypto->fh->ver.fh2.magic[2] = 'W';
1242 crypto->fh->ver.fh2.magic[3] = 'M';
1243 crypto->fh->ver.fh2.magic[4] = 'D';
1244 crypto->fh->ver.fh2.version = VERSION_HEX;
1245 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1247 if (len != sizeof(crypto->fh->ver.fh2)) {
1248 rc = gpg_error_from_syserror();
1250 if (tmp[0])
1251 pth_cleanup_pop(1);
1253 return rc;
1256 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1258 if (len != crypto->insize) {
1259 rc = gpg_error_from_syserror();
1261 if (tmp[0])
1262 pth_cleanup_pop(1);
1264 return rc;
1267 if (fsync(crypto->fh->fd) == -1) {
1268 rc = gpg_error_from_syserror();
1270 if (tmp[0])
1271 pth_cleanup_pop(1);
1273 return rc;
1276 if (tmp[0]) {
1277 #ifdef WITH_LIBACL
1278 acl_t acl;
1279 #endif
1280 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1281 gchar tmp2[FILENAME_MAX];
1283 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1284 #ifdef WITH_LIBACL
1285 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1287 if (!acl)
1288 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1289 #endif
1291 if (rename(filename, tmp2) == -1) {
1292 rc = gpg_error_from_syserror();
1293 pth_cleanup_pop(1);
1294 #ifdef WITH_LIBACL
1295 if (acl)
1296 acl_free(acl);
1297 #endif
1298 return rc;
1301 #ifdef WITH_LIBACL
1302 else {
1303 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1305 if (!acl)
1306 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1308 #endif
1310 if (rename(tmp, filename) == -1) {
1311 rc = gpg_error_from_syserror();
1312 pth_cleanup_pop(1);
1313 #ifdef WITH_LIBACL
1314 if (acl)
1315 acl_free(acl);
1316 #endif
1317 return rc;
1320 pth_cleanup_pop(0);
1322 if (mode)
1323 chmod(filename, mode);
1325 #ifdef WITH_LIBACL
1326 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1327 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1329 if (acl)
1330 acl_free(acl);
1331 #endif
1334 if (client && lstat(filename, &st) == 0)
1335 client->mtime = st.st_mtime;
1337 return 0;
1340 gpg_error_t update_save_flags(const gchar *filename,
1341 struct crypto_s *crypto)
1343 gpg_error_t rc;
1344 guint64 iter;
1346 /* New file? */
1347 if (!crypto->fh) {
1348 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1350 if (!crypto->fh)
1351 return GPG_ERR_ENOMEM;
1354 rc = init_client_crypto2(filename, crypto);
1356 if (rc)
1357 return rc;
1359 if (filename && !crypto->fh->v1) {
1360 iter = (guint64)get_key_file_double(filename, "iterations");
1361 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1364 return 0;
1367 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1368 gboolean cached)
1370 struct client_s *client = assuan_get_pointer(ctx);
1371 gpointer xmlbuf;
1372 gulong outsize = 0;
1373 guint len;
1374 gint clevel;
1375 gint timeout;
1376 gpointer outbuf;
1377 gpg_error_t rc;
1379 if (client->crypto->key && client->crypto->key != key)
1380 gcry_free(client->crypto->key);
1382 client->crypto->key = key;
1383 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1385 if (rc) {
1386 cleanup_crypto(&client->crypto);
1387 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1390 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1391 pth_cleanup_push(xmlFree, xmlbuf);
1392 clevel = get_key_file_integer(client->filename, "compression_level");
1394 if (clevel < 0)
1395 clevel = 0;
1397 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1399 if (rc) {
1400 pth_cleanup_pop(1);
1401 cleanup_crypto(&client->crypto);
1403 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1405 else {
1406 pth_cleanup_pop(1);
1407 xmlbuf = outbuf;
1408 len = outsize;
1411 client->crypto->inbuf = xmlbuf;
1412 client->crypto->insize = len;
1413 rc = update_save_flags(client->filename, client->crypto);
1415 if (rc) {
1416 cleanup_crypto(&client->crypto);
1417 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1418 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1421 rc = do_xml_encrypt(client, client->crypto, client->filename);
1423 if (rc) {
1424 cleanup_crypto(&client->crypto);
1425 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1428 timeout = get_key_file_integer(client->filename, "cache_timeout");
1429 CACHE_LOCK(client->ctx);
1431 if (cached) {
1432 cache_reset_timeout(client->md5file, timeout);
1433 CACHE_UNLOCK;
1435 if (client->new == TRUE)
1436 send_status_all(STATUS_CACHE);
1438 client->new = FALSE;
1439 cleanup_crypto(&client->crypto);
1440 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1443 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1444 CACHE_UNLOCK;
1445 cleanup_crypto(&client->crypto);
1446 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1449 client->new = FALSE;
1450 cache_reset_timeout(client->md5file, timeout);
1451 CACHE_UNLOCK;
1452 send_status_all(STATUS_CACHE);
1453 cleanup_crypto(&client->crypto);
1454 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1457 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1459 struct client_s *client = data;
1460 guint64 n;
1461 gchar *value = v;
1462 gchar *p = NULL;
1464 if (!client->filename)
1465 return EPWMD_NO_FILE;
1467 if (!value || !*value)
1468 return 0;
1470 errno = 0;
1471 n = strtoul(value, &p, 10);
1473 if (errno || (p && *p) || n == G_MAXULONG)
1474 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1476 MUTEX_LOCK(&rcfile_mutex);
1477 g_key_file_set_double(keyfileh,
1478 client->filename ? client->filename : "global", "iterations", n);
1479 MUTEX_UNLOCK(&rcfile_mutex);
1481 if (client->filename)
1482 client->opts |= OPT_ITERATIONS;
1484 return 0;
1487 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1489 struct client_s *client = data;
1490 const gchar *p = value;
1491 guint64 flags;
1493 if (!client->filename)
1494 return EPWMD_NO_FILE;
1496 if (!p || !*p)
1497 return 0;
1499 flags = pwmd_cipher_str_to_cipher(p);
1501 if (!flags)
1502 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1504 MUTEX_LOCK(&rcfile_mutex);
1505 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1506 MUTEX_UNLOCK(&rcfile_mutex);
1508 if (!value)
1509 g_free((gchar *)p);
1511 return 0;
1514 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1516 struct client_s *client = data;
1518 CACHE_LOCK(client->ctx);
1519 cache_clear(client->md5file, 1);
1520 CACHE_UNLOCK;
1521 return 0;
1524 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1526 struct client_s *client = assuan_get_pointer(ctx);
1527 gboolean cached = FALSE;
1528 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1530 CACHE_LOCK(ctx);
1531 cached = cache_iscached(client->md5file);
1532 CACHE_UNLOCK;
1535 * If a cache entry doesn't exist for this file and the file has a
1536 * "key_file" or "key" parameter, then it's an error. The reason is that
1537 * cache expiration would be useless. Unless this is an inquire, then its
1538 * fine.
1540 if (cached == FALSE) {
1541 gchar *tmp = get_key_file_string(client->filename, "key_file");
1543 if (tmp && !(client->opts & OPT_INQUIRE)) {
1544 g_free(tmp);
1545 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1548 if (tmp)
1549 g_free(tmp);
1552 cached = FALSE;
1554 /* New file? */
1555 if (!client->crypto) {
1556 client->crypto = init_client_crypto();
1558 if (!client->crypto) {
1559 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1560 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1564 client->crypto->key = gcry_malloc(hashlen);
1566 if (!client->crypto->key) {
1567 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1568 cleanup_crypto(&client->crypto);
1569 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1572 memset(client->crypto->key, '!', hashlen);
1574 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1575 (!line || !*line))
1576 goto done;
1578 if (!line || !*line) {
1579 /* It doesn't make sense to use an --inquire with an empty
1580 * passphrase. This will prevent a pinentry dialog. */
1581 if (client->opts & OPT_INQUIRE) {
1582 cleanup_crypto(&client->crypto);
1583 return GPG_ERR_WRONG_KEY_USAGE;
1586 client->crypto->tkey = gcry_malloc(hashlen);
1588 if (!client->crypto->tkey) {
1589 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1590 cleanup_crypto(&client->crypto);
1591 return send_error(ctx, GPG_ERR_ENOMEM);
1594 memset(client->crypto->tkey, '!', hashlen);
1595 CACHE_LOCK(ctx);
1597 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1598 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1599 CACHE_UNLOCK;
1601 #ifdef WITH_PINENTRY
1602 gpg_error_t rc;
1604 if (client->pinentry->enable == FALSE ||
1605 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1606 /* Empty keys are allowed. */
1607 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1608 goto done;
1611 lock_pin_mutex(client);
1612 client->pinentry->which = PINENTRY_SAVE;
1613 rc = pinentry_fork(ctx);
1615 if (rc) {
1616 unlock_pin_mutex(client->pinentry);
1617 cleanup_crypto(&client->crypto);
1618 return send_error(ctx, rc);
1621 client->pinentry->cb = save_command_finalize;
1622 client->pinentry->status = PINENTRY_INIT;
1623 return 0;
1624 #else
1625 /* Empty keys are allowed. */
1626 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1627 goto done;
1628 #endif
1630 else {
1631 CACHE_UNLOCK;
1632 cached = TRUE;
1635 else {
1636 gpg_error_t rc;
1638 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1639 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1641 if (iter <= 0L)
1642 iter = 1;
1644 MUTEX_LOCK(&rcfile_mutex);
1645 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1646 MUTEX_UNLOCK(&rcfile_mutex);
1647 client->opts |= OPT_ITERATIONS;
1648 rc = send_status(ctx, STATUS_CONFIG, NULL);
1650 if (rc) {
1651 cleanup_crypto(&client->crypto);
1652 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1656 rc = hash_key(client, line);
1658 if (rc) {
1659 cleanup_crypto(&client->crypto);
1660 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1664 done:
1665 return save_command_finalize(ctx, client->crypto->key, cached);
1668 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1669 guchar *line, gsize len)
1671 assuan_context_t ctx = data;
1672 struct client_s *client = assuan_get_pointer(ctx);
1673 gpg_error_t rc = file_modified(client);
1675 if (assuan_rc || rc) {
1676 if (line)
1677 xfree(line);
1679 return assuan_rc ? assuan_rc : rc;
1682 rc = save_command_common(ctx, (gchar *)line);
1684 if (line)
1685 xfree(line);
1687 client->inquire_status = INQUIRE_DONE;
1688 return rc;
1691 static gint save_command(assuan_context_t ctx, gchar *line)
1693 struct stat st;
1694 struct client_s *client = assuan_get_pointer(ctx);
1695 gpg_error_t rc;
1696 struct argv_s *args[] = {
1697 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1698 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1699 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1700 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1701 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1702 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1703 NULL
1706 rc = parse_options(&line, args, client);
1708 if (rc)
1709 return send_error(ctx, rc);
1711 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1712 return send_error(ctx, gpg_error_from_syserror());
1714 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1715 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1716 return send_error(ctx, GPG_ERR_ENOANO);
1719 if ((client->opts & OPT_INQUIRE)) {
1720 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1721 ctx);
1723 if (rc)
1724 return send_error(ctx, rc);
1726 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1727 client->inquire_status = INQUIRE_BUSY;
1728 return 0;
1731 if (line && *line)
1732 log_write2("ARGS=%s", "<passphrase>");
1734 return save_command_common(ctx, line);
1737 static gint delete_command(assuan_context_t ctx, gchar *line)
1739 struct client_s *client = assuan_get_pointer(ctx);
1740 gchar **req;
1741 gpg_error_t rc;
1742 xmlNodePtr n;
1744 log_write2("ARGS=\"%s\"", line);
1746 if (strchr(line, '\t'))
1747 req = split_input_line(line, "\t", -1);
1748 else
1749 req = split_input_line(line, " ", -1);
1751 if (!req || !*req)
1752 return send_error(ctx, GPG_ERR_SYNTAX);
1754 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1756 if (!n) {
1757 g_strfreev(req);
1758 return send_error(ctx, rc);
1762 * No sub-node defined. Remove the entire node (root element).
1764 if (!req[1]) {
1765 if (n) {
1766 rc = unlink_node(n);
1767 xmlFreeNode(n);
1770 g_strfreev(req);
1771 return send_error(ctx, rc);
1774 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1775 g_strfreev(req);
1777 if (!n)
1778 return send_error(ctx, rc);
1780 if (n) {
1781 rc = unlink_node(n);
1782 xmlFreeNode(n);
1785 return send_error(ctx, rc);
1789 * Don't return with assuan_process_done() here. This has been called from
1790 * assuan_process_next() and the command should be finished in
1791 * client_thread().
1793 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1794 gsize len)
1796 assuan_context_t ctx = data;
1797 struct client_s *client = assuan_get_pointer(ctx);
1798 gchar **req;
1799 xmlNodePtr n;
1800 gpg_error_t rc = file_modified(client);
1802 if (assuan_rc || rc) {
1803 if (line)
1804 xfree(line);
1805 return assuan_rc ? assuan_rc : rc;
1808 req = split_input_line((gchar *)line, "\t", 0);
1809 xfree(line);
1811 if (!req || !*req)
1812 return GPG_ERR_SYNTAX;
1814 again:
1815 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1817 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1818 rc = new_root_element(client->doc, *req);
1820 if (rc) {
1821 g_strfreev(req);
1822 return rc;
1825 goto again;
1828 if (!n) {
1829 g_strfreev(req);
1830 return rc;
1833 if (req[1]) {
1834 if (!n->children)
1835 n = create_elements_cb(n, req+1, &rc, NULL);
1836 else
1837 n = find_elements(client->doc, n->children, req+1, &rc,
1838 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1841 g_strfreev(req);
1842 client->inquire_status = INQUIRE_DONE;
1844 if (!rc)
1845 rc = update_element_mtime(n);
1847 return rc;
1850 static gint store_command(assuan_context_t ctx, gchar *line)
1852 struct client_s *client = assuan_get_pointer(ctx);
1853 gpg_error_t rc;
1855 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1857 if (rc)
1858 return send_error(ctx, rc);
1860 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1861 client->inquire_status = INQUIRE_BUSY;
1862 return 0;
1865 static void *send_data_cb(void *arg)
1867 struct assuan_cmd_s *data = arg;
1868 gint old;
1869 gpg_error_t *rc;
1871 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1872 rc = g_malloc(sizeof(gpg_error_t));
1873 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1874 pth_cancel_state(old, NULL);
1875 pth_exit(rc);
1876 return NULL;
1879 /* For every assuan command that needs to be sent to the client, a timeout is
1880 * needed to determine if the client lost the connection. The timeout is the
1881 * same as the "keepalive" configuration parameter or a default if unset.
1883 gpg_error_t do_assuan_command(assuan_context_t ctx,
1884 void *(*cb)(void *data), void *data)
1886 pth_attr_t attr = pth_attr_new();
1887 pth_t tid;
1888 gint to = get_key_file_integer("global", "keepalive");
1889 pth_event_t ev, tev;
1890 pth_status_t st;
1891 gpg_error_t rc = 0;
1892 void *p;
1894 pth_attr_init(attr);
1895 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1896 tid = pth_spawn(attr, cb, data);
1897 rc = gpg_error_from_syserror();
1898 pth_attr_destroy(attr);
1900 if (!tid) {
1901 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1902 return rc;
1905 pth_cleanup_push(cleanup_cancel_cb, tid);
1906 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1907 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1908 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1909 ev = pth_event_concat(ev, tev, NULL);
1910 pth_cleanup_push(cleanup_ev_cb, ev);
1911 pth_yield(tid);
1912 pth_wait(ev);
1914 if (tev) {
1915 st = pth_event_status(tev);
1917 if (st == PTH_STATUS_OCCURRED) {
1918 pth_cleanup_pop(1);
1919 pth_cleanup_pop(1);
1920 return GPG_ERR_TIMEOUT;
1924 st = pth_event_status(ev);
1926 if (st == PTH_STATUS_FAILED) {
1927 pth_cancel(tid);
1928 pth_join(tid, &p);
1929 g_free(p);
1930 rc = GPG_ERR_ASS_WRITE_ERROR;
1932 else if (st == PTH_STATUS_OCCURRED) {
1933 pth_join(tid, &p);
1934 rc = *(gpg_error_t *)p;
1935 g_free(p);
1938 pth_cleanup_pop(1);
1939 pth_cleanup_pop(0);
1940 return rc;
1943 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1944 gint total)
1946 gint to_send;
1947 gint sent = 0;
1948 gpg_error_t rc;
1949 struct assuan_cmd_s data;
1950 gint progress = get_key_file_integer("global", "xfer_progress");
1951 gint flush = 0;
1953 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1954 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1955 data.ctx = ctx;
1956 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1958 if (rc)
1959 return rc;
1961 again:
1962 do {
1963 if (sent + to_send > total)
1964 to_send = total - sent;
1966 data.line = flush ? NULL : (gchar *)line+sent;
1967 data.line_len = flush ? 0 : to_send;
1968 rc = do_assuan_command(ctx, send_data_cb, &data);
1970 if (!rc) {
1971 sent += flush ? 0 : to_send;
1973 if ((progress && !(sent % progress) && sent != total) ||
1974 (sent == total && flush))
1975 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1977 if (!flush && !rc && sent == total) {
1978 flush = 1;
1979 goto again;
1982 } while (!rc && sent < total);
1984 return rc;
1987 static gint get_command(assuan_context_t ctx, gchar *line)
1989 struct client_s *client = assuan_get_pointer(ctx);
1990 gchar **req;
1991 gpg_error_t rc;
1992 xmlNodePtr n;
1994 log_write2("ARGS=\"%s\"", line);
1995 req = split_input_line(line, "\t", -1);
1997 if (!req || !*req) {
1998 g_strfreev(req);
1999 return send_error(ctx, GPG_ERR_SYNTAX);
2002 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2004 if (!n) {
2005 g_strfreev(req);
2006 return send_error(ctx, rc);
2009 if (req[1])
2010 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2012 g_strfreev(req);
2014 if (rc)
2015 return send_error(ctx, rc);
2017 if (!n || !n->children)
2018 return send_error(ctx, GPG_ERR_NO_VALUE);
2020 n = find_text_node(n->children);
2022 if (!n || !n->content || !*n->content)
2023 return send_error(ctx, GPG_ERR_NO_VALUE);
2025 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2026 return send_error(ctx, rc);
2029 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2030 gpg_error_t *rc, gchar **req_orig, void *data)
2032 gchar *path = *(gchar **)data;
2033 gchar *tmp = NULL, *result;
2035 if (path) {
2036 g_free(path);
2037 *(gchar **)data = NULL;
2040 path = g_strjoinv("\t", target);
2042 if (!path) {
2043 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2044 *rc = GPG_ERR_ENOMEM;
2045 return NULL;
2048 if (req_orig) {
2049 tmp = g_strjoinv("\t", req_orig);
2051 if (!tmp) {
2052 g_free(path);
2053 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2054 *rc = GPG_ERR_ENOMEM;
2055 return NULL;
2059 if (tmp && *tmp)
2060 result = g_strdup_printf("%s\t%s", path, tmp);
2061 else
2062 result = g_strdup(path);
2064 if (!result) {
2065 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2066 *rc = GPG_ERR_ENOMEM;
2067 g_free(path);
2068 g_free(tmp);
2069 return NULL;
2072 g_free(path);
2073 g_free(tmp);
2074 *(gchar **)data = result;
2075 return node;
2078 static void list_command_cleanup1(void *arg);
2079 static gint realpath_command(assuan_context_t ctx, gchar *line)
2081 gpg_error_t rc;
2082 struct client_s *client = assuan_get_pointer(ctx);
2083 gchar **req;
2084 gchar *t;
2085 gint i;
2086 xmlNodePtr n;
2087 GString *string;
2088 gchar *rp = NULL;
2090 log_write2("ARGS=\"%s\"", line);
2092 if (strchr(line, '\t') != NULL) {
2093 if ((req = split_input_line(line, "\t", 0)) == NULL)
2094 return send_error(ctx, GPG_ERR_SYNTAX);
2096 else {
2097 if ((req = split_input_line(line, " ", 0)) == NULL)
2098 return send_error(ctx, GPG_ERR_SYNTAX);
2101 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2103 if (!n) {
2104 g_strfreev(req);
2105 return send_error(ctx, rc);
2108 rp = g_strjoinv("\t", req);
2110 if (!rp) {
2111 g_strfreev(req);
2112 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2113 return send_error(ctx, GPG_ERR_ENOMEM);
2116 if (req[1]) {
2117 n = find_elements(client->doc, n->children, req+1, &rc,
2118 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2120 if (!n) {
2121 g_free(rp);
2122 g_strfreev(req);
2123 return send_error(ctx, rc);
2127 string = g_string_new(rp);
2128 g_free(rp);
2129 g_strfreev(req);
2131 if (!string) {
2132 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2133 return send_error(ctx, GPG_ERR_ENOMEM);
2136 again:
2137 for (i = 0, t = string->str + i; *t; t++, i++) {
2138 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2139 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2140 goto again;
2144 pth_cleanup_push(list_command_cleanup1, string);
2145 rc = xfer_data(ctx, string->str, string->len);
2146 pth_cleanup_pop(1);
2147 return send_error(ctx, rc);
2150 static void list_command_cleanup1(void *arg)
2152 g_string_free((GString *)arg, TRUE);
2155 static void list_command_cleanup2(void *arg)
2157 struct element_list_s *elements = arg;
2159 if (elements) {
2160 if (elements->list) {
2161 gint total = g_slist_length(elements->list);
2162 gint i;
2164 for (i = 0; i < total; i++) {
2165 gchar *tmp = g_slist_nth_data(elements->list, i);
2166 g_free(tmp);
2169 g_slist_free(elements->list);
2172 if (elements->prefix)
2173 g_free(elements->prefix);
2175 if (elements->req)
2176 g_strfreev(elements->req);
2178 g_free(elements);
2182 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2184 struct element_list_s *elements = data;
2186 elements->recurse = FALSE;
2187 return 0;
2190 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2192 struct element_list_s *elements = data;
2194 elements->verbose = TRUE;
2195 return 0;
2198 static gint list_command(assuan_context_t ctx, gchar *line)
2200 struct client_s *client = assuan_get_pointer(ctx);
2201 gpg_error_t rc;
2202 struct element_list_s *elements = NULL;
2203 gchar *tmp;
2204 struct argv_s *args[] = {
2205 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2206 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2207 NULL
2210 if (disable_list_and_dump == TRUE)
2211 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2213 elements = g_malloc0(sizeof(struct element_list_s));
2215 if (!elements) {
2216 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2217 return GPG_ERR_ENOMEM;
2220 elements->recurse = TRUE; // default
2221 pth_cleanup_push(list_command_cleanup2, elements);
2222 rc = parse_options(&line, args, elements);
2224 if (rc)
2225 goto fail;
2227 if (!*line) {
2228 GString *str;
2230 rc = list_root_elements(client->doc, &str, elements->verbose);
2232 if (rc) {
2233 pth_cleanup_pop(1);
2234 return send_error(ctx, rc);
2237 pth_cleanup_push(list_command_cleanup1, str);
2238 rc = xfer_data(ctx, str->str, str->len);
2239 pth_cleanup_pop(1);
2240 pth_cleanup_pop(1);
2241 return send_error(ctx, rc);
2244 elements->req = split_input_line(line, " ", 0);
2246 if (!elements->req)
2247 strv_printf(&elements->req, "%s", line);
2249 rc = create_path_list(client->doc, elements, *elements->req);
2251 if (rc)
2252 goto fail;
2254 if (elements) {
2255 gint total = g_slist_length(elements->list);
2256 gint i;
2257 GString *str;
2259 if (!total) {
2260 rc = GPG_ERR_NO_VALUE;
2261 goto fail;
2264 str = g_string_new(NULL);
2266 if (!str) {
2267 rc = GPG_ERR_ENOMEM;
2268 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2269 goto fail;
2272 for (i = 0; i < total; i++) {
2273 tmp = g_slist_nth_data(elements->list, i);
2274 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2277 pth_cleanup_push(list_command_cleanup1, str);
2278 rc = xfer_data(ctx, str->str, str->len);
2279 pth_cleanup_pop(1);
2281 else
2282 rc = GPG_ERR_NO_VALUE;
2284 fail:
2285 pth_cleanup_pop(1);
2286 return send_error(ctx, rc);
2290 * req[0] - element path
2292 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2294 struct client_s *client = assuan_get_pointer(ctx);
2295 gchar **attrlist = NULL;
2296 gint i = 0;
2297 gchar **path = NULL;
2298 xmlAttrPtr a;
2299 xmlNodePtr n, an;
2300 gchar *line;
2301 gpg_error_t rc;
2303 if (!req || !req[0])
2304 return GPG_ERR_SYNTAX;
2306 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2308 * The first argument may be only a root element.
2310 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2311 return GPG_ERR_SYNTAX;
2314 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2316 if (!n) {
2317 g_strfreev(path);
2318 return rc;
2321 if (path[1]) {
2322 n = find_elements(client->doc, n->children, path+1, &rc,
2323 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2325 if (!n) {
2326 g_strfreev(path);
2327 return rc;
2331 g_strfreev(path);
2333 for (a = n->properties; a; a = a->next) {
2334 gchar **pa;
2336 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2337 if (attrlist)
2338 g_strfreev(attrlist);
2340 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2341 return GPG_ERR_ENOMEM;
2344 attrlist = pa;
2345 an = a->children;
2346 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2347 an && an->content ? (gchar *)an->content : "");
2349 if (!attrlist[i]) {
2350 g_strfreev(attrlist);
2351 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2352 return GPG_ERR_ENOMEM;
2355 attrlist[++i] = NULL;
2358 if (!attrlist)
2359 return GPG_ERR_NO_VALUE;
2361 line = g_strjoinv("\n", attrlist);
2363 if (!line) {
2364 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2365 g_strfreev(attrlist);
2366 return GPG_ERR_ENOMEM;
2369 pth_cleanup_push(g_free, line);
2370 pth_cleanup_push(req_cleanup, attrlist);
2371 rc = xfer_data(ctx, line, strlen(line));
2372 pth_cleanup_pop(1);
2373 pth_cleanup_pop(1);
2374 return rc;
2378 * req[0] - attribute
2379 * req[1] - element path
2381 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2383 xmlNodePtr n;
2384 gchar **path = NULL;
2385 gpg_error_t rc;
2387 if (!req || !req[0] || !req[1])
2388 return GPG_ERR_SYNTAX;
2390 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2392 * The first argument may be only a root element.
2394 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2395 return GPG_ERR_SYNTAX;
2399 * Don't remove the "_name" attribute for the root element. To remove an
2400 * root element use DELETE <name>.
2402 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2403 rc = GPG_ERR_SYNTAX;
2404 goto fail;
2407 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2409 if (!n)
2410 goto fail;
2412 if (path[1]) {
2413 n = find_elements(client->doc, n->children, path+1, &rc,
2414 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2416 if (!n)
2417 goto fail;
2420 rc = delete_attribute(n, (xmlChar *)req[0]);
2422 fail:
2423 g_strfreev(path);
2424 return rc;
2427 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2428 gpg_error_t *rc)
2430 gchar **src = *path;
2431 gchar **src_orig = g_strdupv(src);
2432 xmlNodePtr n = NULL;
2434 *rc = 0;
2436 if (!src_orig) {
2437 *rc = GPG_ERR_ENOMEM;
2438 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2439 goto fail;
2442 again:
2443 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2445 if (!n) {
2446 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2447 *rc = new_root_element(client->doc, src[0]);
2449 if (*rc)
2450 goto fail;
2452 goto again;
2454 else
2455 goto fail;
2458 if (src[1]) {
2459 if (!n->children)
2460 n = create_target_elements_cb(n, src+1, rc, NULL);
2461 else
2462 n = find_elements(client->doc, n->children, src+1, rc,
2463 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2465 if (!n)
2466 goto fail;
2469 * Reset the position of the element tree now that the elements
2470 * have been created.
2472 g_strfreev(src);
2473 src = src_orig;
2474 src_orig = NULL;
2475 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2477 if (!n)
2478 goto fail;
2480 n = find_elements(client->doc, n->children, src+1, rc,
2481 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2483 if (!n)
2484 goto fail;
2487 fail:
2488 if (src_orig)
2489 g_strfreev(src_orig);
2491 *path = src;
2492 return n;
2496 * Creates a "target" attribute. When other commands encounter an element with
2497 * this attribute, the element path is modified to the target value. If the
2498 * source element path doesn't exist when using 'ATTR SET target', it is
2499 * created, but the destination element path must exist.
2501 * req[0] - source element path
2502 * req[1] - destination element path
2504 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2506 gchar **src, **dst, *line = NULL, **odst = NULL;
2507 gpg_error_t rc;
2508 xmlNodePtr n;
2510 if (!req || !req[0] || !req[1])
2511 return GPG_ERR_SYNTAX;
2513 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2515 * The first argument may be only a root element.
2517 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2518 return GPG_ERR_SYNTAX;
2521 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2523 * The first argument may be only a root element.
2525 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2526 rc = GPG_ERR_SYNTAX;
2527 goto fail;
2531 odst = g_strdupv(dst);
2533 if (!odst) {
2534 rc = GPG_ERR_ENOMEM;
2535 goto fail;
2538 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2541 * Make sure the destination element path exists.
2543 if (!n)
2544 goto fail;
2546 if (dst[1]) {
2547 n = find_elements(client->doc, n->children, dst+1, &rc,
2548 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2550 if (!n)
2551 goto fail;
2554 n = create_element_path(client, &src, &rc);
2556 if (rc)
2557 goto fail;
2559 line = g_strjoinv("\t", odst);
2561 if (!line) {
2562 rc = GPG_ERR_ENOMEM;
2563 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2564 goto fail;
2567 rc = add_attribute(n, "target", line);
2569 fail:
2570 g_free(line);
2571 g_strfreev(src);
2572 g_strfreev(dst);
2573 g_strfreev(odst);
2574 return rc;
2578 * req[0] - name
2579 * req[1] - new name
2581 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2583 gpg_error_t rc;
2584 gchar **tmp;
2585 xmlNodePtr n;
2587 tmp = g_strdupv(req);
2589 if (!tmp) {
2590 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2591 return GPG_ERR_ENOMEM;
2594 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2595 g_strfreev(tmp);
2597 if (!n)
2598 return rc;
2600 if (g_utf8_collate(req[0], req[1]) == 0)
2601 return 0;
2604 * Will not overwrite an existing root.
2606 tmp = g_strdupv(req+1);
2608 if (!tmp) {
2609 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2610 return GPG_ERR_ENOMEM;
2613 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2614 g_strfreev(tmp);
2616 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2617 return rc;
2619 if (n)
2620 return GPG_ERR_AMBIGUOUS_NAME;
2622 if (!valid_xml_element((xmlChar *)req[1]))
2623 return GPG_ERR_SYNTAX;
2625 tmp = g_strdupv(req);
2627 if (!tmp) {
2628 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2629 return GPG_ERR_ENOMEM;
2632 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2633 g_strfreev(tmp);
2635 if (!n)
2636 return GPG_ERR_ELEMENT_NOT_FOUND;
2638 return add_attribute(n, "_name", req[1]);
2642 * req[0] - attribute
2643 * req[1] - element path
2645 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2647 struct client_s *client = assuan_get_pointer(ctx);
2648 xmlNodePtr n;
2649 xmlChar *a;
2650 gchar **path= NULL;
2651 gpg_error_t rc;
2653 if (!req || !req[0] || !req[1])
2654 return GPG_ERR_SYNTAX;
2656 if (strchr(req[1], '\t')) {
2657 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2658 return GPG_ERR_SYNTAX;
2660 else {
2661 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2662 return GPG_ERR_SYNTAX;
2665 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2667 if (!n)
2668 goto fail;
2670 if (path[1]) {
2671 n = find_elements(client->doc, n->children, path+1, &rc,
2672 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2674 if (!n)
2675 goto fail;
2678 g_strfreev(path);
2680 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2681 return GPG_ERR_NOT_FOUND;
2683 pth_cleanup_push(xmlFree, a);
2685 if (*a)
2686 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2687 else
2688 rc = GPG_ERR_NO_VALUE;
2690 pth_cleanup_pop(1);
2691 return rc;
2693 fail:
2694 g_strfreev(path);
2695 return rc;
2699 * req[0] - attribute
2700 * req[1] - element path
2701 * req[2] - value
2703 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2705 gchar **path = NULL;
2706 gpg_error_t rc;
2707 xmlNodePtr n;
2709 if (!req || !req[0] || !req[1])
2710 return GPG_ERR_SYNTAX;
2713 * Reserved attribute names.
2715 if (!strcmp(req[0], "_name")) {
2717 * Only reserved for the root element. Not the rest of the
2718 * document.
2720 if (strchr(req[1], '\t') == NULL)
2721 return name_attribute(client, req + 1);
2723 else if (!strcmp(req[0], "target"))
2724 return target_attribute(client, req + 1);
2726 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2728 * The first argument may be only a root element.
2730 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2731 return GPG_ERR_SYNTAX;
2734 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2736 if (!n)
2737 goto fail;
2739 if (path[1]) {
2740 n = find_elements(client->doc, n->children, path+1, &rc,
2741 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2743 if (!n)
2744 goto fail;
2747 rc = add_attribute(n, req[0], req[2]);
2749 fail:
2750 g_strfreev(path);
2751 return rc;
2755 * req[0] - command
2756 * req[1] - attribute name or element path if command is LIST
2757 * req[2] - element path
2758 * req[2] - element path or value
2760 static gint attr_command(assuan_context_t ctx, gchar *line)
2762 struct client_s *client = assuan_get_pointer(ctx);
2763 gchar **req;
2764 gpg_error_t rc = 0;
2766 log_write2("ARGS=\"%s\"", line);
2767 req = split_input_line(line, " ", 4);
2769 if (!req || !req[0] || !req[1]) {
2770 g_strfreev(req);
2771 return send_error(ctx, GPG_ERR_SYNTAX);
2774 pth_cleanup_push(req_cleanup, req);
2776 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2777 rc = attribute_set(client, req+1);
2778 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2779 rc = attribute_get(ctx, req+1);
2780 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2781 rc = attribute_delete(client, req+1);
2782 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2783 rc = attribute_list(ctx, req+1);
2784 else
2785 rc = GPG_ERR_SYNTAX;
2787 pth_cleanup_pop(1);
2788 return send_error(ctx, rc);
2791 static gint iscached_command(assuan_context_t ctx, gchar *line)
2793 gchar **req = split_input_line(line, " ", 0);
2794 guchar md5file[16];
2795 gchar *path, *tmp;
2797 if (!req || !*req) {
2798 g_strfreev(req);
2799 return send_error(ctx, GPG_ERR_SYNTAX);
2802 log_write2("ARGS=\"%s\"", line);
2804 if (!valid_filename(req[0])) {
2805 g_strfreev(req);
2806 return GPG_ERR_INV_VALUE;
2809 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2810 CACHE_LOCK(ctx);
2812 if (cache_iscached(md5file)) {
2813 g_strfreev(req);
2814 CACHE_UNLOCK;
2815 return send_error(ctx, 0);
2818 CACHE_UNLOCK;
2819 tmp = get_key_file_string("global", "data_directory");
2821 if (!tmp) {
2822 g_strfreev(req);
2823 return GPG_ERR_ENOMEM;
2826 path = expand_homedir(tmp);
2828 if (!path) {
2829 g_strfreev(req);
2830 g_free(tmp);
2831 return GPG_ERR_ENOMEM;
2834 g_free(tmp);
2835 tmp = path;
2836 path = g_strdup_printf("%s/%s", tmp, req[0]);
2837 g_free(tmp);
2839 if (!path) {
2840 g_strfreev(req);
2841 return GPG_ERR_ENOMEM;
2844 if (access(path, R_OK) == -1) {
2845 gpg_error_t rc = gpg_error_from_syserror();
2847 g_free(path);
2848 g_strfreev(req);
2849 return send_error(ctx, rc);
2852 g_free(path);
2853 return send_error(ctx, GPG_ERR_NOT_FOUND);
2856 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2858 gchar **req = split_input_line(line, " ", 0);
2859 guchar md5file[16];
2861 log_write2("ARGS=\"%s\"", line);
2862 CACHE_LOCK(ctx);
2864 if (!req || !*req) {
2865 g_strfreev(req);
2866 cache_clear(NULL, 2);
2867 CACHE_UNLOCK;
2868 return send_error(ctx, 0);
2871 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2872 g_strfreev(req);
2874 if (cache_clear(md5file, 1) == FALSE) {
2875 CACHE_UNLOCK;
2876 return send_error(ctx, GPG_ERR_NOT_FOUND);
2879 CACHE_UNLOCK;
2880 return send_error(ctx, 0);
2883 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2885 guchar md5file[16];
2886 glong timeout;
2887 gchar **req = split_input_line(line, " ", 0);
2888 gchar *p;
2890 if (!req || !*req || !req[1]) {
2891 g_strfreev(req);
2892 return send_error(ctx, GPG_ERR_SYNTAX);
2895 errno = 0;
2896 timeout = strtol(req[1], &p, 10);
2898 if (errno != 0 || *p != 0 || timeout < -1) {
2899 g_strfreev(req);
2900 return send_error(ctx, GPG_ERR_SYNTAX);
2903 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2904 CACHE_LOCK(client->ctx);
2906 if (cache_set_timeout(md5file, timeout) == FALSE) {
2907 CACHE_UNLOCK;
2908 return send_error(ctx, GPG_ERR_NOT_FOUND);
2911 CACHE_UNLOCK;
2912 return send_error(ctx, 0);
2915 static gint dump_command(assuan_context_t ctx, gchar *line)
2917 xmlChar *xml;
2918 gint len;
2919 struct client_s *client = assuan_get_pointer(ctx);
2920 gpg_error_t rc;
2922 if (disable_list_and_dump == TRUE)
2923 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2925 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2927 if (!xml) {
2928 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2929 return send_error(ctx, GPG_ERR_ENOMEM);
2932 pth_cleanup_push(xmlFree, xml);
2933 rc = xfer_data(ctx, (gchar *)xml, len);
2934 pth_cleanup_pop(1);
2935 return send_error(ctx, rc);
2938 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2940 struct client_s *client = assuan_get_pointer(ctx);
2941 gpg_error_t rc = 0;
2942 gchar filename[255]={0}, param[747]={0};
2943 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2945 log_write2("ARGS=\"%s\"", line);
2947 if (strchr(line, ' ')) {
2948 sscanf(line, " %254[^ ] %746c", filename, param);
2949 paramp = param;
2950 fp = filename;
2953 if (fp && !valid_filename(fp))
2954 return send_error(ctx, GPG_ERR_INV_VALUE);
2956 paramp = g_ascii_strdown(paramp, -1);
2958 if (!paramp) {
2959 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2960 return send_error(ctx, GPG_ERR_ENOMEM);
2963 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2964 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2965 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2967 if (!fh && rc != GPG_ERR_ENOENT)
2968 return send_error(ctx, rc);
2970 if (!rc) {
2971 g_free(paramp);
2972 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2973 close_file_header(fh);
2975 if (!p) {
2976 log_write("%s(%i): %s", __FILE__, __LINE__,
2977 pwmd_strerror(GPG_ERR_ENOMEM));
2978 return send_error(ctx, GPG_ERR_ENOMEM);
2981 goto done;
2985 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2986 #ifdef WITH_PINENTRY
2987 gboolean n;
2989 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2990 n = client->pinentry->enable;
2991 else
2992 n = get_key_file_boolean(fp, "enable_pinentry");
2994 p = g_strdup_printf("%s", n ? "true" : "false");
2996 if (!p) {
2997 log_write("%s(%i): %s", __FILE__, __LINE__,
2998 pwmd_strerror(GPG_ERR_ENOMEM));
2999 return send_error(ctx, GPG_ERR_ENOMEM);
3002 goto done;
3003 #else
3004 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3005 #endif
3007 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3008 #ifdef WITH_PINENTRY
3009 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3011 if (!p) {
3012 log_write("%s(%i): %s", __FILE__, __LINE__,
3013 pwmd_strerror(GPG_ERR_ENOMEM));
3014 return send_error(ctx, GPG_ERR_ENOMEM);
3017 goto done;
3018 #else
3019 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3020 #endif
3023 p = get_key_file_string(fp ? fp : "global", paramp);
3024 g_free(paramp);
3026 if (!p)
3027 return send_error(ctx, GPG_ERR_NO_VALUE);
3029 tmp = expand_homedir(p);
3030 g_free(p);
3032 if (!tmp) {
3033 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3034 return send_error(ctx, GPG_ERR_ENOMEM);
3037 p = tmp;
3038 done:
3039 pth_cleanup_push(g_free, p);
3040 rc = xfer_data(ctx, p, strlen(p));
3041 pth_cleanup_pop(1);
3042 return send_error(ctx, rc);
3045 struct xpath_s {
3046 xmlXPathContextPtr xp;
3047 xmlXPathObjectPtr result;
3048 xmlBufferPtr buf;
3049 gchar **req;
3052 static void xpath_command_cleanup(void *arg)
3054 struct xpath_s *xpath = arg;
3056 req_cleanup(xpath->req);
3058 if (xpath->buf)
3059 xmlBufferFree(xpath->buf);
3061 if (xpath->result)
3062 xmlXPathFreeObject(xpath->result);
3064 if (xpath->xp)
3065 xmlXPathFreeContext(xpath->xp);
3068 static gint xpath_command(assuan_context_t ctx, gchar *line)
3070 struct client_s *client = assuan_get_pointer(ctx);
3071 gpg_error_t rc;
3072 struct xpath_s xpath;
3074 log_write2("ARGS=\"%s\"", line);
3076 if (disable_list_and_dump == TRUE)
3077 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3079 if (!line || !*line)
3080 return send_error(ctx, GPG_ERR_SYNTAX);
3082 memset(&xpath, 0, sizeof(struct xpath_s));
3084 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3085 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3086 return send_error(ctx, GPG_ERR_ENOMEM);
3089 xpath.xp = xmlXPathNewContext(client->doc);
3091 if (!xpath.xp) {
3092 xpath_command_cleanup(&xpath);
3093 return send_error(ctx, EPWMD_LIBXML_ERROR);
3096 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3098 if (!xpath.result) {
3099 xpath_command_cleanup(&xpath);
3100 return send_error(ctx, EPWMD_LIBXML_ERROR);
3103 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3104 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3105 goto fail;
3108 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3109 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3111 if (rc)
3112 goto fail;
3113 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3114 rc = GPG_ERR_NO_VALUE;
3115 goto fail;
3117 else if (xpath.req[1])
3118 goto fail;
3120 pth_cleanup_push(xpath_command_cleanup, &xpath);
3121 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3122 xmlBufferLength(xpath.buf));
3123 pth_cleanup_pop(0);
3125 fail:
3126 xpath_command_cleanup(&xpath);
3127 return send_error(ctx, rc);
3130 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3131 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3133 struct client_s *client = assuan_get_pointer(ctx);
3134 gpg_error_t rc;
3135 struct xpath_s xpath;
3136 gchar **req = NULL;
3137 gboolean cmd = FALSE; //SET
3139 log_write2("ARGS=\"%s\"", line);
3141 if (disable_list_and_dump == TRUE)
3142 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3144 if (!line || !*line)
3145 return send_error(ctx, GPG_ERR_SYNTAX);
3147 memset(&xpath, 0, sizeof(struct xpath_s));
3149 if ((req = split_input_line(line, " ", 3)) == NULL)
3150 return send_error(ctx, GPG_ERR_ENOMEM);
3152 if (!req[0]) {
3153 rc = GPG_ERR_SYNTAX;
3154 goto fail;
3157 if (!g_ascii_strcasecmp(req[0], "SET"))
3158 cmd = FALSE;
3159 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3160 cmd = TRUE;
3161 else {
3162 rc = GPG_ERR_SYNTAX;
3163 goto fail;
3166 if (!req[1] || !req[2]) {
3167 rc = GPG_ERR_SYNTAX;
3168 goto fail;
3171 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3172 rc = GPG_ERR_ENOMEM;
3173 goto fail;
3176 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3177 rc = GPG_ERR_SYNTAX;
3178 goto fail;
3181 xpath.xp = xmlXPathNewContext(client->doc);
3183 if (!xpath.xp) {
3184 rc = EPWMD_LIBXML_ERROR;
3185 goto fail;
3188 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3190 if (!xpath.result) {
3191 rc = EPWMD_LIBXML_ERROR;
3192 goto fail;
3195 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3196 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3197 goto fail;
3200 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3201 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3203 fail:
3204 g_strfreev(req);
3205 xpath_command_cleanup(&xpath);
3206 return send_error(ctx, rc);
3209 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3210 gsize len)
3212 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3213 gpg_error_t rc = file_modified(client);
3214 gchar **req, **path = NULL, **path_orig = NULL, *content;
3215 xmlDocPtr doc = NULL;
3216 xmlNodePtr n, root, copy;
3218 if (assuan_rc || rc) {
3219 if (line)
3220 xfree(line);
3221 return assuan_rc ? assuan_rc : rc;
3224 req = split_input_line((gchar *)line, "\t", 2);
3225 xfree(line);
3227 if (!req || !*req)
3228 return GPG_ERR_SYNTAX;
3230 content = req[0];
3231 path = split_input_line(req[1], "\t", 0);
3233 if (!content || !*content) {
3234 rc = GPG_ERR_SYNTAX;
3235 goto fail;
3238 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3240 if (!doc) {
3241 rc = EPWMD_LIBXML_ERROR;
3242 goto fail;
3245 root = xmlDocGetRootElement(doc);
3246 rc = validate_import(root);
3248 if (rc)
3249 goto fail;
3251 if (path) {
3252 path_orig = g_strdupv(path);
3254 if (!path_orig) {
3255 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3256 rc = GPG_ERR_ENOMEM;
3257 goto fail;
3260 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3262 if (!a) {
3263 g_strfreev(path_orig);
3264 rc = GPG_ERR_ENOMEM;
3265 goto fail;
3268 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3269 xmlFree(a);
3270 g_strfreev(path_orig);
3271 rc = GPG_ERR_ENOMEM;
3272 goto fail;
3275 xmlFree(a);
3276 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3278 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3279 g_strfreev(path_orig);
3280 goto fail;
3283 if (!rc) {
3284 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3286 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3287 g_strfreev(path_orig);
3288 goto fail;
3290 else if (!rc) {
3291 xmlNodePtr parent = n->parent;
3293 xmlUnlinkNode(n);
3294 xmlFreeNode(n);
3295 n = parent;
3299 g_strfreev(path);
3300 path = path_orig;
3302 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3303 n = create_element_path(client, &path, &rc);
3305 if (rc)
3306 goto fail;
3309 copy = xmlCopyNodeList(root);
3310 n = xmlAddChildList(n, copy);
3312 if (!n)
3313 rc = EPWMD_LIBXML_ERROR;
3315 else {
3316 /* Check if the content root element can create a DTD root element. */
3317 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3318 rc = GPG_ERR_SYNTAX;
3319 goto fail;
3322 xmlChar *a;
3324 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3325 rc = GPG_ERR_SYNTAX;
3326 goto fail;
3329 gchar *tmp = g_strdup((gchar *)a);
3330 xmlFree(a);
3331 gboolean literal = is_literal_element(&tmp);
3333 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3334 g_free(tmp);
3335 rc = GPG_ERR_INV_VALUE;
3336 goto fail;
3339 if (strv_printf(&path, "%s", tmp) == FALSE) {
3340 g_free(tmp);
3341 rc = GPG_ERR_ENOMEM;
3342 goto fail;
3345 g_free(tmp);
3346 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3348 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3349 rc = EPWMD_LIBXML_ERROR;
3350 goto fail;
3353 /* Overwriting the existing tree. */
3354 if (!rc) {
3355 xmlUnlinkNode(n);
3356 xmlFreeNodeList(n);
3359 rc = 0;
3360 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3361 n = xmlCopyNode(root, 1);
3362 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3365 if (n && !rc)
3366 rc = update_element_mtime(n->parent);
3368 fail:
3369 if (doc)
3370 xmlFreeDoc(doc);
3372 if (path)
3373 g_strfreev(path);
3375 g_strfreev(req);
3376 client->inquire_status = INQUIRE_DONE;
3377 return rc;
3380 static gint import_command(assuan_context_t ctx, gchar *line)
3382 gpg_error_t rc;
3383 struct client_s *client = assuan_get_pointer(ctx);
3385 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3387 if (rc)
3388 return send_error(ctx, rc);
3390 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3391 client->inquire_status = INQUIRE_BUSY;
3392 return 0;
3395 static gpg_error_t do_lock_command(struct client_s *client)
3397 gpg_error_t rc = lock_file_mutex(client);
3399 if (!rc)
3400 client->is_lock_cmd = TRUE;
3402 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3405 static gint lock_command(assuan_context_t ctx, gchar *line)
3407 struct client_s *client = assuan_get_pointer(ctx);
3409 return do_lock_command(client);
3412 static gint unlock_command(assuan_context_t ctx, gchar *line)
3414 struct client_s *client = assuan_get_pointer(ctx);
3416 unlock_file_mutex(client);
3417 return send_error(ctx, 0);
3420 static gint getpid_command(assuan_context_t ctx, gchar *line)
3422 gpg_error_t rc;
3423 gchar buf[32];
3424 pid_t pid = getpid();
3426 print_fmt(buf, sizeof(buf), "%i", pid);
3427 rc = xfer_data(ctx, buf, strlen(buf));
3428 return send_error(ctx, rc);
3431 static gint version_command(assuan_context_t ctx, gchar *line)
3433 gpg_error_t rc;
3434 gchar buf[32];
3436 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3437 rc = xfer_data(ctx, buf, strlen(buf));
3438 return send_error(ctx, rc);
3441 #ifdef WITH_PINENTRY
3442 static void set_option_value(gchar **opt, const gchar *value)
3444 if (opt)
3445 g_free(*opt);
3447 *opt = NULL;
3449 if (value)
3450 *opt = g_strdup(value);
3452 #endif
3454 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3455 const gchar *value)
3457 struct client_s *client = assuan_get_pointer(ctx);
3458 gpg_error_t rc;
3460 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3461 glong l = 0;
3463 if (value) {
3464 l = strtol(value, NULL, 10);
3466 if (l < 0 || l > 2)
3467 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3470 MUTEX_LOCK(&rcfile_mutex);
3471 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3472 MUTEX_UNLOCK(&rcfile_mutex);
3473 goto done;
3475 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3476 glong l = 0;
3478 if (value) {
3479 l = strtol(value, NULL, 10);
3481 if (l < 0 || l > 1)
3482 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3485 client->rc_on_locked = l ? TRUE : FALSE;
3486 goto done;
3488 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3489 rc = parse_open_opt_lock(client, (gpointer)value);
3491 if (rc)
3492 return rc;
3494 client->opts |= OPT_LOCK;
3496 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3497 if (!value) {
3498 client->opts &= ~(OPT_CIPHER);
3499 goto done;
3502 rc = parse_save_opt_cipher(client, (gpointer)value);
3504 if (rc)
3505 return rc;
3507 client->opts |= OPT_CIPHER;
3508 goto done;
3510 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3511 rc = parse_save_opt_iterations(client, (gpointer)value);
3513 if (rc)
3514 return rc;
3516 goto done;
3518 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3519 pth_attr_t attr = pth_attr_of(pth_self());
3520 gchar buf[41];
3522 if (!value) {
3523 pth_attr_destroy(attr);
3524 goto done;
3527 print_fmt(buf, sizeof(buf), "%s", value);
3528 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3529 pth_attr_destroy(attr);
3530 #ifdef WITH_PINENTRY
3531 if (client->pinentry->name)
3532 g_free(client->pinentry->name);
3534 client->pinentry->name = g_strdup(buf);
3536 if (!client->pinentry->name)
3537 return GPG_ERR_ENOMEM;
3538 #endif
3540 goto done;
3542 #ifdef WITH_PINENTRY
3543 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3544 set_option_value(&client->pinentry->lcmessages, value);
3545 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3546 set_option_value(&client->pinentry->lcctype, value);
3547 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3548 set_option_value(&client->pinentry->ttyname, value);
3549 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3550 set_option_value(&client->pinentry->ttytype, value);
3551 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3552 set_option_value(&client->pinentry->display, value);
3553 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3554 set_option_value(&client->pinentry->path, value);
3555 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3556 set_option_value(&client->pinentry->title, value);
3557 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3558 set_option_value(&client->pinentry->prompt, value);
3559 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3560 set_option_value(&client->pinentry->desc, value);
3561 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3562 gchar *p = NULL;
3563 gint n;
3565 if (!value)
3566 goto done;
3568 n = strtol(value, &p, 10);
3570 if (*p || n < 0)
3571 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3573 MUTEX_LOCK(&rcfile_mutex);
3574 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3575 "global", "pinentry_timeout", n);
3576 MUTEX_UNLOCK(&rcfile_mutex);
3577 goto done;
3579 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3580 rc = parse_opt_pinentry(client, (gpointer)value);
3582 if (rc)
3583 return rc;
3585 goto done;
3587 #else
3588 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3589 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3590 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3591 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3592 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3593 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3594 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3595 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3596 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3597 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3598 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3599 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3600 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3601 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3602 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3603 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3604 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3605 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3606 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3607 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3608 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3609 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3610 #endif
3611 else
3612 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3614 done:
3615 return 0;
3618 static gint unset_command(assuan_context_t ctx, gchar *line)
3620 log_write2("ARGS=\"%s\"", line);
3621 return send_error(ctx, set_unset_common(ctx, line, NULL));
3624 static gint set_command(assuan_context_t ctx, gchar *line)
3626 gchar name[64] = {0}, value[256] = {0};
3628 log_write2("ARGS=\"%s\"", line);
3630 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3631 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3633 return send_error(ctx, set_unset_common(ctx, name, value));
3636 static gint rename_command(assuan_context_t ctx, gchar *line)
3638 struct client_s *client = assuan_get_pointer(ctx);
3639 gpg_error_t rc;
3640 gchar **req, **src, *dst;
3641 xmlNodePtr n, ndst;
3643 log_write2("ARGS=\"%s\"", line);
3644 req = split_input_line(line, " ", -1);
3646 if (!req || !req[0] || !req[1]) {
3647 g_strfreev(req);
3648 return send_error(ctx, GPG_ERR_SYNTAX);
3651 dst = req[1];
3652 is_literal_element(&dst);
3654 if (!valid_xml_element((xmlChar *)dst)) {
3655 g_strfreev(req);
3656 return GPG_ERR_INV_VALUE;
3659 if (strchr(req[0], '\t'))
3660 src = split_input_line(req[0], "\t", -1);
3661 else
3662 src = split_input_line(req[0], " ", -1);
3664 if (!src || !*src) {
3665 rc = GPG_ERR_SYNTAX;
3666 goto fail;
3669 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3671 if (src[1] && n)
3672 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3673 NULL, FALSE, 0, NULL, FALSE);
3675 if (!n)
3676 goto fail;
3679 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3681 if (!a) {
3682 rc = GPG_ERR_ENOMEM;
3683 goto fail;
3686 /* To prevent unwanted effects:
3688 * <root name="a"><b/></root>
3690 * RENAME a<TAB>b b
3692 if (xmlStrEqual(a, (xmlChar *)dst)) {
3693 xmlFree(a);
3694 rc = GPG_ERR_AMBIGUOUS_NAME;
3695 goto fail;
3698 xmlFree(a);
3699 gchar **tmp = NULL;
3701 if (src[1]) {
3702 gchar **p;
3704 for (p = src; *p; p++) {
3705 if (!*(p+1))
3706 break;
3708 strv_printf(&tmp, "%s", *p);
3712 strv_printf(&tmp, "!%s", dst);
3713 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3715 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3716 g_strfreev(tmp);
3717 goto fail;
3720 if (tmp[1] && ndst)
3721 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3722 NULL, NULL, FALSE, 0, NULL, FALSE);
3724 g_strfreev(tmp);
3726 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3727 goto fail;
3729 rc = 0;
3731 /* Target may exist:
3733 * <root name="a"/>
3734 * <root name="b" target="a"/>
3736 * RENAME b a
3738 * Would need to do:
3739 * RENAME !b a
3741 if (ndst == n) {
3742 rc = GPG_ERR_AMBIGUOUS_NAME;
3743 goto fail;
3746 if (ndst) {
3747 unlink_node(ndst);
3748 xmlFreeNodeList(ndst);
3751 rc = add_attribute(n, "_name", dst);
3753 fail:
3754 g_strfreev(req);
3755 g_strfreev(src);
3756 return send_error(ctx, rc);
3759 static gint copy_command(assuan_context_t ctx, gchar *line)
3761 struct client_s *client = assuan_get_pointer(ctx);
3762 gpg_error_t rc;
3763 gchar **req, **src = NULL, **dst = NULL;
3764 xmlNodePtr nsrc, ndst, new;
3766 log_write2("ARGS=\"%s\"", line);
3767 req = split_input_line(line, " ", -1);
3769 if (!req || !req[0] || !req[1]) {
3770 g_strfreev(req);
3771 return send_error(ctx, GPG_ERR_SYNTAX);
3774 if (strchr(req[0], '\t'))
3775 src = split_input_line(req[0], "\t", -1);
3776 else
3777 src = split_input_line(req[0], " ", -1);
3779 if (!src || !*src) {
3780 rc = GPG_ERR_SYNTAX;
3781 goto fail;
3784 if (strchr(req[1], '\t'))
3785 dst = split_input_line(req[1], "\t", -1);
3786 else
3787 dst = split_input_line(req[1], " ", -1);
3789 if (!dst || !*dst) {
3790 rc = GPG_ERR_SYNTAX;
3791 goto fail;
3794 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3796 if (nsrc && src[1])
3797 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3798 NULL, NULL, FALSE, 0, NULL, FALSE);
3800 if (!nsrc)
3801 goto fail;
3803 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3805 if (ndst && dst[1])
3806 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3807 NULL, NULL, FALSE, 0, NULL, FALSE);
3809 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3810 goto fail;
3812 new = xmlCopyNodeList(nsrc);
3814 if (!new) {
3815 rc = GPG_ERR_ENOMEM;
3816 goto fail;
3819 if (!ndst)
3820 ndst = create_element_path(client, &dst, &rc);
3822 if (!ndst) {
3823 xmlUnlinkNode(new);
3824 xmlFreeNodeList(new);
3825 goto fail;
3828 /* Merge any attributes from the src node to the initial dst node. */
3829 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3830 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3831 continue;
3833 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3835 if (a)
3836 xmlRemoveProp(a);
3838 xmlChar *tmp = xmlNodeGetContent(attr->children);
3839 xmlNewProp(ndst, attr->name, tmp);
3840 xmlFree(tmp);
3841 rc = add_attribute(ndst, NULL, NULL);
3844 xmlNodePtr n = ndst->children;
3845 xmlUnlinkNode(n);
3846 xmlFreeNodeList(n);
3847 ndst->children = NULL;
3849 if (!new->children) {
3850 xmlUnlinkNode(new);
3851 xmlFreeNodeList(new);
3852 goto fail;
3855 n = xmlCopyNodeList(new->children);
3857 if (!n) {
3858 rc = GPG_ERR_ENOMEM;
3859 goto fail;
3862 xmlUnlinkNode(new);
3863 xmlFreeNodeList(new);
3864 n = xmlAddChildList(ndst, n);
3866 if (!n) {
3867 rc = GPG_ERR_ENOMEM;
3868 goto fail;
3871 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3873 fail:
3874 if (req)
3875 g_strfreev(req);
3877 if (src)
3878 g_strfreev(src);
3880 if (dst)
3881 g_strfreev(dst);
3883 return send_error(ctx, rc);
3886 static gint move_command(assuan_context_t ctx, gchar *line)
3888 struct client_s *client = assuan_get_pointer(ctx);
3889 gpg_error_t rc;
3890 gchar **req, **src = NULL, **dst = NULL;
3891 xmlNodePtr nsrc, ndst = NULL;
3893 log_write2("ARGS=\"%s\"", line);
3894 req = split_input_line(line, " ", -1);
3896 if (!req || !req[0] || !req[1]) {
3897 g_strfreev(req);
3898 return send_error(ctx, GPG_ERR_SYNTAX);
3901 if (strchr(req[0], '\t'))
3902 src = split_input_line(req[0], "\t", -1);
3903 else
3904 src = split_input_line(req[0], " ", -1);
3906 if (!src || !*src) {
3907 rc = GPG_ERR_SYNTAX;
3908 goto fail;
3911 if (strchr(req[1], '\t'))
3912 dst = split_input_line(req[1], "\t", -1);
3913 else
3914 dst = split_input_line(req[1], " ", -1);
3916 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3918 if (nsrc && src[1])
3919 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3920 NULL, NULL, FALSE, 0, NULL, FALSE);
3922 if (!nsrc)
3923 goto fail;
3925 if (dst) {
3926 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3928 if (ndst && dst[1])
3929 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3930 NULL, NULL, FALSE, 0, NULL, FALSE);
3932 else
3933 ndst = xmlDocGetRootElement(client->doc);
3935 for (xmlNodePtr n = ndst; n; n = n->parent) {
3936 if (n == nsrc) {
3937 rc = GPG_ERR_CONFLICT;
3938 goto fail;
3942 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3943 goto fail;
3945 rc = 0;
3947 if (ndst) {
3948 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3949 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3951 xmlFree(a);
3953 if (dup) {
3954 if (dup == nsrc)
3955 goto fail;
3957 if (ndst == xmlDocGetRootElement(client->doc)) {
3958 xmlNodePtr n = nsrc;
3959 gboolean match = FALSE;
3961 while (n->parent && n->parent != ndst)
3962 n = n->parent;
3964 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3965 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3967 if (xmlStrEqual(a, b)) {
3968 match = TRUE;
3969 xmlUnlinkNode(nsrc);
3970 xmlUnlinkNode(n);
3971 xmlFreeNodeList(n);
3974 xmlFree(a);
3975 xmlFree(b);
3977 if (!match) {
3978 xmlUnlinkNode(dup);
3979 xmlFreeNodeList(dup);
3982 else
3983 xmlUnlinkNode(dup);
3987 if (!ndst && dst)
3988 ndst = create_element_path(client, &dst, &rc);
3990 if (!ndst)
3991 goto fail;
3993 update_element_mtime(nsrc->parent);
3994 xmlUnlinkNode(nsrc);
3995 ndst = xmlAddChildList(ndst, nsrc);
3997 if (!ndst)
3998 rc = GPG_ERR_ENOMEM;
4000 update_element_mtime(ndst->parent);
4002 fail:
4003 if (req)
4004 g_strfreev(req);
4006 if (src)
4007 g_strfreev(src);
4009 if (dst)
4010 g_strfreev(dst);
4012 return send_error(ctx, rc);
4015 static int ls_command(assuan_context_t ctx, gchar *line)
4017 log_write2("ARGS=\"%s\"", line);
4018 gpg_error_t rc;
4019 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4020 gchar *dir = expand_homedir(tmp);
4021 DIR *d = opendir(dir);
4023 rc = gpg_error_from_syserror();
4024 g_free(tmp);
4026 if (!d) {
4027 g_free(dir);
4028 return send_error(ctx, rc);
4031 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4032 struct dirent *p = g_malloc(len), *cur = NULL;
4033 gchar *list = NULL;
4035 g_free(dir);
4036 rc = 0;
4038 while (!readdir_r(d, p, &cur) && cur) {
4039 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4040 continue;
4041 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4042 continue;
4044 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4046 if (!tmp) {
4047 if (list)
4048 g_free(list);
4050 rc = GPG_ERR_ENOMEM;
4051 break;
4054 g_free(list);
4055 list = tmp;
4058 closedir(d);
4059 g_free(p);
4061 if (rc)
4062 return send_error(ctx, rc);
4064 if (!list)
4065 return send_error(ctx, GPG_ERR_NO_VALUE);
4067 list[strlen(list)-1] = 0;
4068 rc = xfer_data(ctx, list, strlen(list));
4069 g_free(list);
4070 return send_error(ctx, rc);
4073 static void bye_notify(assuan_context_t ctx)
4075 struct client_s *cl = assuan_get_pointer(ctx);
4077 /* This will let assuan_process_next() return. */
4078 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4079 cl->last_rc = 0; // BYE command result
4082 static void reset_notify(assuan_context_t ctx)
4084 struct client_s *cl = assuan_get_pointer(ctx);
4086 if (cl)
4087 cleanup_client(cl);
4091 * This is called before every Assuan command.
4093 gint command_startup(assuan_context_t ctx, const gchar *name)
4095 struct client_s *cl = assuan_get_pointer(ctx);
4096 gpg_error_t rc;
4098 log_write1("%s", name);
4100 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
4101 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
4102 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
4103 !g_ascii_strcasecmp(name, "GETCONFIG") ||
4104 !g_ascii_strcasecmp(name, "GETPID") ||
4105 !g_ascii_strcasecmp(name, "VERSION") ||
4106 !g_ascii_strcasecmp(name, "SET") ||
4107 !g_ascii_strcasecmp(name, "BYE") ||
4108 !g_ascii_strcasecmp(name, "NOP") ||
4109 !g_ascii_strcasecmp(name, "CANCEL") ||
4110 !g_ascii_strcasecmp(name, "RESET") ||
4111 !g_ascii_strcasecmp(name, "END") ||
4112 !g_ascii_strcasecmp(name, "HELP") ||
4113 !g_ascii_strcasecmp(name, "OPTION") ||
4114 !g_ascii_strcasecmp(name, "INPUT") ||
4115 !g_ascii_strcasecmp(name, "OUTPUT") ||
4116 !g_ascii_strcasecmp(name, "LS") ||
4117 !g_ascii_strcasecmp(name, "UNSET"))
4118 return 0;
4120 #ifdef WITH_PINENTRY
4121 if (!(cl->opts & OPT_PINENTRY))
4122 reset_pin_defaults(cl->pinentry);
4123 #endif
4125 cl->last_rc = rc = file_modified(cl);
4127 if (rc) {
4128 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4129 !g_ascii_strcasecmp(name, "OPEN"))
4130 rc = 0;
4133 return rc;
4137 * This is called after every Assuan command.
4139 void command_finalize(assuan_context_t ctx, gint rc)
4141 struct client_s *client = assuan_get_pointer(ctx);
4143 if (!client->is_lock_cmd)
4144 unlock_file_mutex(client);
4146 log_write1(N_("command completed (rc=%u)"), client->last_rc);
4147 client->opts &= ~(OPT_INQUIRE);
4148 client->opts &= ~(OPT_BASE64);
4151 static gint help_command(assuan_context_t ctx, gchar *line)
4153 gpg_error_t rc;
4154 gint i;
4156 if (!line || !*line) {
4157 gchar *buf = g_strdup(N_("Usage: help [<COMMAND>]\nCOMMANDS:"));
4158 gchar *tmp;
4160 for (i = 0; command_table[i]; i++) {
4161 gchar *p = strrchr(buf, '\n');
4162 gboolean newline = FALSE;
4164 if (p && strlen(p)+strlen(command_table[i]->name) > 79) {
4165 tmp = g_strdup_printf("%s\n", buf);
4166 g_free(buf);
4167 buf = tmp;
4168 newline = TRUE;
4171 tmp = g_strdup_printf("%s%s%s", buf, !newline ? " " : "",
4172 command_table[i]->name);
4173 g_free(buf);
4174 buf = tmp;
4177 tmp = g_strdup_printf("%s\n", buf);
4178 g_free(buf);
4179 buf = tmp;
4180 rc = xfer_data(ctx, buf, strlen(buf));
4181 g_free(buf);
4182 return send_error(ctx, rc);
4185 for (i = 0; command_table[i]; i++) {
4186 if (!g_strcasecmp(line, command_table[i]->name)) {
4187 gchar *tmp = g_strdup_printf(N_("Usage: %s"), command_table[i]->help);
4188 rc = xfer_data(ctx, tmp, strlen(tmp));
4189 g_free(tmp);
4190 return send_error(ctx, rc);
4194 return send_error(ctx, GPG_ERR_UNKNOWN_COMMAND);
4197 void new_command(const gchar *name,
4198 gint (*handler)(assuan_context_t, gchar *), const gchar *help)
4200 gint i = 0;
4202 if (command_table)
4203 for (i = 0; command_table[i]; i++);
4205 command_table = g_realloc(command_table, (i+2)*sizeof(struct command_table_s *));
4206 command_table[i] = g_malloc0(sizeof(struct command_table_s));
4207 command_table[i]->name = name;
4208 command_table[i]->handler = handler;
4209 command_table[i++]->help = help;
4210 command_table[i] = NULL;
4213 void deinit_commands()
4215 gint i;
4217 for (i = 0; command_table[i]; i++)
4218 g_free(command_table[i]);
4220 g_free(command_table);
4223 void init_commands()
4225 /* !BEGIN-HELP-TEXT!
4227 * This comment is used as a marker to generate the offline documentation
4228 * for commands found in doc/COMMANDS.
4230 new_command("HELP", help_command, N_(
4231 "HELP [<COMMAND>]\n"
4232 " Show available commands or command specific help text.\n"
4235 new_command("OPEN", open_command, N_(
4236 "OPEN [--lock] [--inquire | --pinentry=[0|1]] [--base64] <filename> [<key>]\n"
4237 " Opens <filename> using <key>. When the filename is not found on the\n"
4238 " file-system a new document will be created. If the file is found, it is\n"
4239 " looked for in the file cache for an existing key. When found and no key\n"
4240 " was specified, the cached key will be used for decryption (if encrypted).\n"
4241 " When not found, pinentry(1) will be used to retrieve the key (see the\n"
4242 " OPTIONS documentation).\n"
4243 "\n"
4244 " When the --lock option is passed then the file mutex will be locked as if\n"
4245 " the LOCK command had been sent after the file had been opened.\n"
4246 "\n"
4247 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4248 " retrieve the filename and key arguments.\n"
4249 "\n"
4250 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4251 " specifying the --pinentry option with the value 1 or 0 respectively. When\n"
4252 " no value is specified then the configuration file value will be used. If\n"
4253 " the passphrase is invalid then it is up to the client whether to retry or\n"
4254 " not. To decrypt an encrypted file with an empty passphrase and avoid the\n"
4255 " pinentry dialog, use --pinentry=0.\n"
4256 "\n"
4257 " When a \"key_file\" configuration parameter has been set for the current\n"
4258 " file and there is no cache entry, then an --inquire must be used to\n"
4259 " retrieve the key.\n"
4260 "\n"
4261 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4262 " decoded before doing decryption. This allows for binary keys and may also\n"
4263 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4266 new_command("SAVE", save_command, N_(
4267 "SAVE [--reset] [--inquire | --pinentry=[0|1]] [--cipher=[<string>]]\n"
4268 " [--iterations=[N]] [--base64] [<key>]\n"
4269 " Writes the XML document to disk. The file written to is the file that was\n"
4270 " opened using the OPEN command. If <key> is not specified then the\n"
4271 " currently cached key will be used. If the file is a new file or the file\n"
4272 " isn't found in the file cache then <key> will be used. If both <key> is\n"
4273 " not specified and the file is not cached then pinentry(1) will be used to\n"
4274 " retrieve the key (see below) unless the configured number of iterations is\n"
4275 " 0 in which case the file will be saved unencrypted.\n"
4276 "\n"
4277 " Note that when both <key> is specified and the configured number of\n"
4278 " iterations is 0 the iterations for the current filename will be reset to\n"
4279 " 1. This is to be on the safe side and prevent misuse.\n"
4280 "\n"
4281 " The --iterations option can be used to change the number of encryption\n"
4282 " iterations for the opened file. When 0 no encryption will be performed.\n"
4283 " When this option is either not passed or is specified without a value then\n"
4284 " previous setting obtained from the file header will be used.\n"
4285 "\n"
4286 " You can specify an alternate cipher to encrypt with by specifying a cipher\n"
4287 " string with the --cipher option. Omitting the string uses the current\n"
4288 " cipher of the opened file or the default if the file is a new one. The\n"
4289 " default is specified in the configuration file. See pwmd(1) for available\n"
4290 " ciphers.\n"
4291 "\n"
4292 " Using pinentry for passphrase retrieval can be enabled or disabled by\n"
4293 " specifying the --pinentry option with the value 1 or 0, respectively. When\n"
4294 " no value is specified then the configuration file value will be used.\n"
4295 " When enabled and the passphrase confirmation fails, the pinentry process\n"
4296 " is started over again until either the passphrases match or until the\n"
4297 " input is canceled by the user. To save with encryption and with an empty\n"
4298 " passphrase, use --pinentry=0.\n"
4299 "\n"
4300 " When --reset is specified then the cached passphrase for the opened file\n"
4301 " will be cleared before doing the actual SAVE as if the CLEARCACHE command\n"
4302 " had been sent.\n"
4303 "\n"
4304 " The --inquire option disables pinentry usage and uses a server inquire to\n"
4305 " retrieve the key.\n"
4306 "\n"
4307 " When a \"key_file\" configuration parameter has been set for the current\n"
4308 " file and there is no cache entry, then an --inquire must be used to\n"
4309 " retrieve the key.\n"
4310 "\n"
4311 " The --base64 option specifies that the key is Base64 encoded. It will be\n"
4312 " decoded before doing encryption. This allows for binary keys and may also\n"
4313 " be used with --inquire. This option is ignored when a pinentry is used.\n"
4316 new_command("ISCACHED", iscached_command, N_(
4317 "ISCACHED <filename>\n"
4318 " An OK response is returned if the specified file is found in the file\n"
4319 " cache. If not found in the cache but exists on the filesystem,\n"
4320 " GPG_ERR_NOT_FOUND is returned. Otherwise a filesystem error is returned.\n"
4323 new_command("CLEARCACHE", clearcache_command, N_(
4324 "CLEARCACHE [<filename>]\n"
4325 " Clears a file cache entry. This will forget the timeout and key for all or\n"
4326 " the specified file. Always returns an OK response.\n"
4329 new_command("CACHETIMEOUT", cachetimeout_command, N_(
4330 "CACHETIMEOUT <filename> <seconds>\n"
4331 " Specify the number of seconds the specified file will be cached. -1 will\n"
4332 " keep the cache entry forever, 0 will require the key each time the OPEN or\n"
4333 " SAVE commands are used. Also see the \"cache_timeout\" configuration\n"
4334 " parameter. Returns ERR if the filename isn't cached or if the timeout is\n"
4335 " invalid. OK otherwise.\n"
4338 new_command("LIST", list_command, N_(
4339 "LIST [--no-recurse] [--verbose] [[!]element[<TAB>[!]element[...]]]\n"
4340 " If no element path is given then a newline separated list of root elements\n"
4341 " is returned with the data response. If given, then all reachable elements\n"
4342 " for the specified element path are returned unless the --no-recurse option\n"
4343 " is specified. If specified, only the child elements of the element path\n"
4344 " are returned without recursing into grandchildren. Each element in the\n"
4345 " path is prefixed with the literal '!' character when the element contains\n"
4346 " no \"target\" attribute. Refer to THE TARGET ATTRIBUTE for more information.\n"
4347 "\n"
4348 " When the --verbose option is passed then each element path returned in the\n"
4349 " list will have a single space character followed by either a 0 or 1\n"
4350 " appended to it. When 0, the element path has no children, otherwise it\n"
4351 " does have children. When used with the --no-recurse option this may be\n"
4352 " useful to limit the amount of data transferred to the client.\n"
4355 new_command("REALPATH", realpath_command, N_(
4356 "REALPATH [!]element[<TAB>[!]element[...]]\n"
4357 " Resolves all \"target\" attributes of the specified element path and returns\n"
4358 " the result with a data response.\n"
4361 new_command("STORE", store_command, N_(
4362 "STORE [!]element[[<TAB>[!]element[...]]<TAB>[content]]\n"
4363 " Creates a new element tree or modifies the content of an existing element\n"
4364 " path. If only a single element is specified, a new root element is\n"
4365 " created. Otherwise, elements are TAB delimited and the content will be set\n"
4366 " to the last TAB delimited argument. If no content is specified after the\n"
4367 " last TAB then the content for the last specified element will be removed\n"
4368 " or empty when creating a new element.\n"
4369 "\n"
4370 " The only restriction of an element name is that it not contain whitespace\n"
4371 " or begin with the literal element character '!' unless specifying a\n"
4372 " literal element. There is no whitespace between the TAB delimited\n"
4373 " elements. It is recommended that the value or content be base 64 encoded\n"
4374 " when it contains control or TAB characters to prevent XML and pwmd parsing\n"
4375 " errors.\n"
4376 "\n"
4377 " PWMD reads the element path from the client via the Assuan INQUIRE\n"
4378 " protocol response: the STORE command is sent by itself without arguments,\n"
4379 " then the server responds with INQUIRE. The client then sends the element\n"
4380 " path prefixed with a \"D \" data response. The element path may extend\n"
4381 " multiple lines but each must be prefixed with the data \"D \" response. When\n"
4382 " finished, the client sends \"END\" on an empty line. This is needed so an\n"
4383 " element path and value can be more than 1000 bytes long, the Assuan\n"
4384 " protocol line limit.\n"
4387 new_command("RENAME", rename_command, N_(
4388 "RENAME [!]element[<TAB>[!]element[...]] <value>\n"
4389 " Renames the specified element to the new value. If an element of the same\n"
4390 " name as the value exists then it will be overwritten.\n"
4393 new_command("COPY", copy_command, N_(
4394 "COPY [!]element[<TAB>[!]element[...]] [!]element[<TAB>[!]element[...]]\n"
4395 " Copies the entire element tree starting from the child node of the source\n"
4396 " element path, to the destination element path. If the destination element\n"
4397 " path doesn't exist then it is created; otherwise it is overwritten.\n"
4398 "\n"
4399 " Note that attributes from the source element path are merged into the\n"
4400 " destination element path when the destination element path exists. When an\n"
4401 " attribute of the same name exists in both the source and destination\n"
4402 " element paths then the destination attribute will be updated to the source\n"
4403 " attribute value.\n"
4406 new_command("MOVE", move_command, N_(
4407 "MOVE [!]element[<TAB>[!]element[...]] [[!]element[<TAB>[!]element[...]]]\n"
4408 " Moves the source element path to the destination element path. If the\n"
4409 " destination is not specified then it will be moved to the root of the\n"
4410 " document. If the destination is specified and exists then it will be\n"
4411 " overwritten; otherwise it will be created.\n"
4414 new_command("DELETE", delete_command, N_(
4415 "DELETE [!]element[<TAB>[!]element[...]]\n"
4416 " Removes the specified element path from the XML document.\n"
4419 new_command("GET", get_command, N_(
4420 "GET [!]element[<TAB>[!]element[...]]\n"
4421 " Retrieves the content or XML text node of the specified element path. The\n"
4422 " data is returned with a data response.\n"
4425 new_command("ATTR", attr_command, N_(
4426 "ATTR SET|GET|DELETE|LIST [<attribute>] [!]<arg1> [!][arg2]\n"
4427 " ATTR SET attribute [!]element[<TAB>[!]element[...]] [attribute_value]\n"
4428 " Stores or updates an attribute name and optional value of an element\n"
4429 " path.\n"
4430 "\n"
4431 " ATTR DELETE attribute [!]element[<TAB>[!]element[...]]\n"
4432 " Removes an attribute from an element path.\n"
4433 "\n"
4434 " ATTR LIST [!]element[<TAB>[!]element[...]]\n"
4435 " Gets a newline separated list of attributes from an element path.\n"
4436 "\n"
4437 " ATTR GET attribute [!]element[<TAB>[!]element[...]]\n"
4438 " Gets the value of an attribute from an element path.\n"
4439 "\n"
4440 " The \"_name\" attribute (case sensitive) cannot be removed with ATTR DELETE\n"
4441 " if the element path is the root element. Although it can be SET to change\n"
4442 " the element name but only if the destination element name doesn't exist.\n"
4443 " Use the RENAME command for that instead.\n"
4444 "\n"
4445 " There is another special attribute \"_mtime\" which is updated each time an\n"
4446 " element is modified: either by storing content, editing attributes or\n"
4447 " deleting a child element.\n"
4448 "\n"
4449 " Also see THE TARGET ATTRIBUTE.\n"
4452 new_command("XPATH", xpath_command, N_(
4453 "XPATH <expression>[<TAB>[value]]\n"
4454 " Evaluates an XPath expression. If no value argument is specified, it is\n"
4455 " assumed the expression is a request to return a result. Otherwise, the\n"
4456 " result is set to the value argument and the document is updated. If there\n"
4457 " is no value after the <TAB> character, the value is assumed to be empty\n"
4458 " and the document is updated.\n"
4461 new_command("XPATHATTR", xpathattr_command, N_(
4462 "XPATHATTR SET|DELETE <name> <expression>[<TAB>[<value>]]\n"
4463 " Like the XPATH command but operates on element attributes and won't return\n"
4464 " a result. For the SET operation the <value> is optional but the field is\n"
4465 " required in which case the value will be empty.\n"
4468 new_command("IMPORT", import_command, N_(
4469 "IMPORT <content>[<TAB>[!]element[<TAB>[!]element[...]]]\n"
4470 " Like the STORE command (an INQUIRE), but the content argument is raw XML\n"
4471 " data. The content is created as a child of the specified element path. If\n"
4472 " an element of the element path does not exist then it is created. If no\n"
4473 " element path is specified then the content must begin with an pwmd DTD\n"
4474 " root element.\n"
4475 "\n"
4476 " Note that the new content must begin with an XML element node. Also note\n"
4477 " that an existing child node of the same element name as the root node of\n"
4478 " the imported content will be overwritten.\n"
4481 new_command("DUMP", dump_command, N_(
4482 "DUMP\n"
4483 " Shows the in memory XML document with indenting. To dump a specific\n"
4484 " element tree, use the XPATH command.\n"
4487 new_command("LOCK", lock_command, N_(
4488 "LOCK\n"
4489 " Locks the mutex associated with the opened file. This prevents other\n"
4490 " clients from sending commands to the same opened file until the client\n"
4491 " that sent this command either disconnects or sends the UNLOCK command.\n"
4494 new_command("UNLOCK", unlock_command, N_(
4495 "UNLOCK\n"
4496 " Unlocks the file mutex which was locked with the LOCK command.\n"
4499 new_command("GETPID", getpid_command, N_(
4500 "GETPID\n"
4501 " Retrieves the process id of the server.\n"
4504 new_command("GETCONFIG", getconfig_command, N_(
4505 "GETCONFIG [filename] <parameter>\n"
4506 " Returns the value of a pwmd configuration variable with a data response.\n"
4507 " If no file has been opened then the value for the specified file or the\n"
4508 " default from the \"global\" section will be returned. If a file has been\n"
4509 " opened and no filename is specified, the value previously set with the SET\n"
4510 " command, if any, will be returned.\n"
4511 "\n"
4512 " If there is no such configuration parameter defined, GPG_ERR_NO_VALUE is\n"
4513 " returned.\n"
4516 new_command("VERSION", version_command, N_(
4517 "VERSION\n"
4518 " Returns the server version number with a data response.\n"
4521 new_command("SET", set_command, N_(
4522 "SET <NAME>=<VALUE>\n"
4523 " Sets a client option NAME to VALUE. Use the UNSET command to reset an\n"
4524 " option to its default value.\n"
4525 "\n"
4526 " NAME |VALUE |Description\n"
4527 " -----------------|----------|----------------------------------------------\n"
4528 " ENABLE_PINENTRY 0|1 When 0, disable use of pinentry. The default\n"
4529 " is 1.\n"
4530 "\n"
4531 " * Deprecated. Pass --pinentry to the OPEN and\n"
4532 " SAVE commands instead.\n"
4533 "\n"
4534 " PINENTRY_TIMEOUT <integer> The number of seconds before the pinentry\n"
4535 " process will terminate while waiting for a\n"
4536 " passphrase. The default is 20, 0 disables.\n"
4537 "\n"
4538 " PINENTRTY_PATH <string> Full path to the pinentry binary. The default\n"
4539 " is specified at compile time.\n"
4540 "\n"
4541 " TTYNAME <string> Same as the --ttyname option to pinentry(1).\n"
4542 "\n"
4543 " TTYTYPE <string> Same as the --ttytype option to pinentry(1).\n"
4544 "\n"
4545 " DISPLAY <string> Same as the --display option to pinentry(1).\n"
4546 "\n"
4547 " TITLE <string> Sets the title string of the pinentry dialog.\n"
4548 "\n"
4549 " PROMPT <string> Sets the prompt string of the pinentry dialog.\n"
4550 "\n"
4551 " DESC <string> Sets the error or description string of the\n"
4552 " pinentry dialog.\n"
4553 "\n"
4554 " LC_CTYPE <string> Same as the --lc-ctype option to pinentry(1).\n"
4555 "\n"
4556 " LC_MESSAGES <string> Same as the --lc-messages option to\n"
4557 " pinentry(1).\n"
4558 "\n"
4559 " NAME <string> Associates the thread ID of the connection\n"
4560 " with the specified textual representation.\n"
4561 " Useful for debugging log messages.\n"
4562 "\n"
4563 " CIPHER <string> The cipher to use for the next SAVE.\n"
4564 "\n"
4565 " * Deprecated. Use --cipher instead.\n"
4566 "\n"
4567 " ITERATIONS <integer> The number of encryption iterations to do\n"
4568 " when the SAVE command is sent. An opened file\n"
4569 " is needed when setting this option. The\n"
4570 " CONFIG status message is sent after receiving\n"
4571 " this command.\n"
4572 "\n"
4573 " * Deprecated. Use --iterations instead.\n"
4574 "\n"
4575 " LOCK_ON_OPEN 0|1 If enabled then the file mutex will be locked\n"
4576 " after a successful OPEN as if the LOCK\n"
4577 " command had been sent.\n"
4578 "\n"
4579 " * Deprecated. Use --lock instead.\n"
4580 "\n"
4581 " RC_ON_LOCKED 0|1 If enabled then return an error code instead\n"
4582 " of a status message when the file mutex is\n"
4583 " locked by another thread.\n"
4586 new_command("UNSET", unset_command, N_(
4587 "UNSET <NAME>\n"
4588 " Resets option NAME to the value specified in the server configuration\n"
4589 " file. Some options have no default and will be reset to NULL or 0\n"
4590 " depending on the value type. See the SET command for available options.\n"
4593 new_command("LS", ls_command, N_(
4594 "LS\n"
4595 " Lists the contents of the configured data_directory. The result is a\n"
4596 " newline separated list of filenames.\n"
4598 /* !END-HELP-TEXT! */
4601 gpg_error_t register_commands(assuan_context_t ctx)
4603 gint i = 0, rc;
4605 for (; command_table[i]; i++) {
4606 rc = assuan_register_command (ctx, command_table[i]->name,
4607 command_table[i]->handler);
4609 if (rc)
4610 return rc;
4613 rc = assuan_register_bye_notify(ctx, bye_notify);
4615 if (rc)
4616 return rc;
4618 rc = assuan_register_reset_notify(ctx, reset_notify);
4620 if (rc)
4621 return rc;
4623 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4625 if (rc)
4626 return rc;
4628 return assuan_register_post_cmd_notify(ctx, command_finalize);
4631 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4632 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4634 goffset insize, len;
4635 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4636 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
4637 gulong outsize = 0;
4638 gpg_error_t rc;
4639 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4640 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4641 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4643 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4644 insize = crypto->fh->st.st_size - fh_size;
4645 crypto->iv = gcry_malloc(crypto->blocksize);
4647 if (!crypto->iv) {
4648 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4649 return GPG_ERR_ENOMEM;
4652 if (crypto->fh->v1)
4653 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4654 else
4655 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4657 crypto->inbuf = gcry_malloc(insize);
4659 if (!crypto->inbuf) {
4660 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4661 return GPG_ERR_ENOMEM;
4664 crypto->insize = insize;
4665 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4667 if (len != crypto->insize)
4668 return GPG_ERR_INV_LENGTH;
4670 /* No encryption iterations. This is a plain (gzipped) file. */
4671 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4672 (!crypto->fh->v1 && fh_iter <= 0L)) {
4674 * cache_file_count() needs both .used == TRUE and a valid key in
4675 * order for it to count as a used cache entry. Fixes CACHE status
4676 * messages.
4678 memset(crypto->key, '!', hashlen);
4679 goto decompress;
4682 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4683 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4684 return rc;
4687 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4688 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4689 return rc;
4692 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4693 client->filename : "global", "iteration_progress");
4695 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4696 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4698 if (rc)
4699 return rc;
4702 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4704 if (rc)
4705 return rc;
4707 crypto->tkey = gcry_malloc(hashlen);
4709 if (!crypto->tkey) {
4710 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4711 return GPG_ERR_ENOMEM;
4714 memcpy(crypto->tkey, crypto->key, hashlen);
4715 guchar *tkey = crypto->tkey;
4716 tkey[0] ^= 1;
4718 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4719 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4720 return rc;
4723 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4724 if (iter_progress > 0ULL && iter >= iter_progress) {
4725 if (!(iter % iter_progress)) {
4726 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4727 ++n_iter * iter_progress, fh_iter);
4729 if (rc)
4730 return rc;
4734 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4735 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4736 return rc;
4739 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4741 if (rc) {
4742 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4743 return rc;
4746 iter++;
4749 if (iter_progress && fh_iter >= iter_progress) {
4750 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4752 if (rc)
4753 return rc;
4756 decompress:
4757 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4758 len = 0;
4760 if (crypto->fh->ver.fh2.iter > 0ULL) {
4761 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4762 return GPG_ERR_INV_PASSPHRASE;
4764 len = sizeof(crypto_magic);
4767 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4768 (gpointer *)&crypto->outbuf, &outsize);
4770 if (rc)
4771 return rc;
4773 else {
4774 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4775 (gpointer *)&crypto->outbuf, &outsize);
4777 if (rc == GPG_ERR_ENOMEM)
4778 return rc;
4779 else if (rc)
4780 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4782 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4783 gcry_free(crypto->outbuf);
4784 crypto->outbuf = NULL;
4785 return GPG_ERR_INV_PASSPHRASE;
4789 if (ctx) {
4790 client->xml = crypto->outbuf;
4791 client->len = outsize;
4792 crypto->outbuf = NULL;
4794 else if (dst) {
4795 *dst = crypto->outbuf;
4796 *dst_len = outsize;
4797 crypto->outbuf = NULL;
4800 /* The calling function should free the crypto struct. */
4801 return 0;