CLEARCACHE command fix when no filename was specified.
[pwmd.git] / src / commands.c
blob97d206d3b6d27a979c14b50369dc4ccba0ec35cd
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 static guchar crypto_magic[5] = "\177PWMD";
64 static gpg_error_t do_lock_command(struct client_s *client);
66 static void *z_alloc(void *data, unsigned items, unsigned size)
68 return gcry_calloc(items, size);
71 static void z_free(void *data, void *p)
73 gcry_free(p);
76 static gpg_error_t file_modified(struct client_s *client)
78 struct stat st;
79 gpg_error_t rc;
81 if (client->state != STATE_OPEN)
82 return EPWMD_NO_FILE;
84 rc = lock_file_mutex(client);
86 if (rc)
87 return rc;
89 if (lstat(client->filename, &st) == 0 && client->mtime) {
90 if (client->mtime != st.st_mtime)
91 return EPWMD_FILE_MODIFIED;
94 pth_cancel_point();
95 return 0;
98 static gpg_error_t parse_xml(assuan_context_t ctx)
100 struct client_s *client = assuan_get_pointer(ctx);
102 client->doc = xmlReadMemory(client->xml, client->len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
104 if (!client->doc)
105 return EPWMD_LIBXML_ERROR;
107 if (!client->crypto->fh || client->crypto->fh->ver.fh2.version >= 0x212)
108 return 0;
110 return convert_elements(client->doc);
113 void unlock_file_mutex(struct client_s *client)
115 pth_mutex_t *m;
117 if (client->has_lock == FALSE)
118 return;
120 CACHE_LOCK(client->ctx);
122 if (cache_get_mutex(client->md5file, &m) == FALSE) {
123 CACHE_UNLOCK;
124 return;
127 CACHE_UNLOCK;
128 MUTEX_UNLOCK(m);
129 client->has_lock = client->is_lock_cmd = FALSE;
132 gpg_error_t lock_file_mutex(struct client_s *client)
134 pth_mutex_t *m;
135 gpg_error_t rc = 0;
137 if (client->has_lock == TRUE)
138 return 0;
140 CACHE_LOCK(client->ctx);
142 if (cache_get_mutex(client->md5file, &m) == FALSE) {
143 CACHE_UNLOCK;
144 return 0;
147 CACHE_UNLOCK;
149 if (client->rc_on_locked) {
150 if (!pth_mutex_acquire(m, TRUE, NULL))
151 return GPG_ERR_LOCKED;
152 #ifdef MUTEX_DEBUG
153 MUTEX_LOCK_DEBUG(m);
154 #endif
156 else
157 MUTEX_TRYLOCK(client, m, rc);
159 if (!rc)
160 client->has_lock = TRUE;
162 return rc;
165 void free_client(struct client_s *client)
167 if (client->doc)
168 xmlFreeDoc(client->doc);
170 if (client->xml)
171 gcry_free(client->xml);
173 if (client->filename)
174 g_free(client->filename);
176 if (client->crypto)
177 cleanup_crypto(&client->crypto);
179 if (client->xml_error)
180 xmlResetError(client->xml_error);
183 void cleanup_client(struct client_s *client)
185 assuan_context_t ctx = client->ctx;
186 struct client_thread_s *thd = client->thd;
187 gboolean rc_on_locked = client->rc_on_locked;
188 gboolean lock_on_open = client->lock_on_open;
189 #ifdef WITH_PINENTRY
190 struct pinentry_s *pin = client->pinentry;
191 #endif
193 unlock_file_mutex(client);
194 CACHE_LOCK(client->ctx);
195 cache_decr_refcount(client->md5file);
198 * This may be a new file so don't use a cache slot. save_command() will
199 * set this to FALSE on success.
201 if (client->new == TRUE)
202 cache_clear(client->md5file, 1);
204 CACHE_UNLOCK;
205 free_client(client);
206 memset(client, 0, sizeof(struct client_s));
207 client->state = STATE_CONNECTED;
208 client->ctx = ctx;
209 client->thd = thd;
210 client->freed = TRUE;
211 #ifdef WITH_PINENTRY
212 client->pinentry = pin;
213 #endif
214 client->rc_on_locked = rc_on_locked;
215 client->lock_on_open = lock_on_open;
218 static void gz_cleanup(void *arg)
220 struct gz_s **gz = (struct gz_s **)arg;
222 if (!gz)
223 return;
225 if (!(*gz)->done && (*gz)->out)
226 gcry_free((*gz)->out);
228 if ((*gz)->which == STATUS_COMPRESS) {
229 if ((*gz)->z.zalloc)
230 deflateEnd(&(*gz)->z);
232 else {
233 if ((*gz)->z.zalloc)
234 inflateEnd(&(*gz)->z);
237 g_free(*gz);
238 *gz = NULL;
241 gpg_error_t do_decompress(assuan_context_t ctx, gpointer in, gulong insize,
242 gpointer *out, gulong *outsize)
244 struct gz_s *gz;
245 gz_header h;
246 gchar buf[17];
247 gpg_error_t rc;
248 gint zrc;
250 gz = g_malloc0(sizeof(struct gz_s));
252 if (!gz)
253 return GPG_ERR_ENOMEM;
255 pth_cleanup_push(gz_cleanup, &gz);
256 gz->which = STATUS_DECOMPRESS;
257 gz->z.zalloc = z_alloc;
258 gz->z.zfree = z_free;
259 gz->z.next_in = in;
260 gz->z.avail_in = (uInt)insize;
261 gz->z.avail_out = zlib_bufsize;
262 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
264 if (!gz->out) {
265 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
266 pth_cleanup_pop(1);
267 return GPG_ERR_ENOMEM;
270 zrc = inflateInit2(&gz->z, 47);
272 if (zrc != Z_OK) {
273 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
274 pth_cleanup_pop(1);
275 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
278 memset(&h, 0, sizeof(gz_header));
279 h.comment = (guchar *)buf;
280 h.comm_max = sizeof(buf);
281 zrc = inflateGetHeader(&gz->z, &h);
283 if (zrc != Z_OK) {
284 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
285 pth_cleanup_pop(1);
286 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
289 zrc = inflate(&gz->z, Z_BLOCK);
291 if (zrc != Z_OK) {
292 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
293 pth_cleanup_pop(1);
294 return zrc == Z_MEM_ERROR ? GPG_ERR_ENOMEM : GPG_ERR_COMPR_ALGO;
297 if (h.comment)
298 insize = (gulong)strtol((gchar *)h.comment, NULL, 10);
300 do {
301 gpointer p;
303 zrc = inflate(&gz->z, Z_FINISH);
305 switch (zrc) {
306 case Z_OK:
307 break;
308 case Z_BUF_ERROR:
309 if (!gz->z.avail_out) {
310 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
312 if (!p) {
313 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
314 rc = GPG_ERR_ENOMEM;
315 goto fail;
318 gz->out = p;
319 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
320 gz->z.avail_out = zlib_bufsize;
321 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li",
322 gz->z.total_out, insize);
324 if (rc)
325 goto fail;
327 break;
328 case Z_STREAM_END:
329 break;
330 default:
331 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
332 rc = GPG_ERR_COMPR_ALGO;
333 goto fail;
334 break;
336 } while (zrc != Z_STREAM_END);
338 rc = send_status(ctx, STATUS_DECOMPRESS, "%li %li", gz->z.total_out,
339 insize);
341 if (rc)
342 goto fail;
344 *out = gz->out;
345 *outsize = gz->z.total_out;
346 gz->done = TRUE;
347 pth_cleanup_pop(1);
348 return 0;
350 fail:
351 pth_cleanup_pop(1);
352 return rc;
355 file_header_internal_t *read_file_header(const gchar *filename, gboolean v1,
356 gpg_error_t *rc)
358 gint fd;
359 gsize len;
360 file_header_internal_t *fh = g_malloc0(sizeof(file_header_internal_t));
361 gsize fh_size;
362 gpointer p;
364 *rc = 0;
366 if (!fh) {
367 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
368 *rc = GPG_ERR_ENOMEM;
369 return NULL;
372 pth_cleanup_push(g_free, fh);
373 fh_size = v1 ? sizeof(fh->ver.fh1) : sizeof(fh->ver.fh2);
375 if (lstat(filename, &fh->st) == -1) {
376 *rc = gpg_error_from_syserror();
377 pth_cleanup_pop(1);
378 return NULL;
381 if (!S_ISREG(fh->st.st_mode)) {
382 *rc = GPG_ERR_ENOANO;
383 pth_cleanup_pop(1);
384 return NULL;
387 fd = open(filename, O_RDONLY);
389 if (fd == -1) {
390 *rc = gpg_error_from_syserror();
391 pth_cleanup_pop(1);
392 return NULL;
395 pth_cleanup_push(cleanup_fd_cb, &fd);
396 p = v1 ? (void *)&fh->ver.fh1 : (void *)&fh->ver.fh2;
397 len = pth_read(fd, p, fh_size);
399 if (len != fh_size) {
400 *rc = gpg_error_from_syserror();
401 pth_cleanup_pop(1);
402 pth_cleanup_pop(1);
403 return NULL;
406 fh->v1 = v1;
407 fh->fd = fd;
408 pth_cleanup_pop(0);
409 pth_cleanup_pop(0);
410 return fh;
413 static gpg_error_t open_command_finalize(assuan_context_t ctx, guchar *unused,
414 gboolean cached)
416 struct client_s *client = assuan_get_pointer(ctx);
417 gpg_error_t rc;
418 gint timeout;
419 guchar *key = client->crypto->key;
421 /* New file. */
422 if (!client->crypto->fh) {
423 if (key[0])
424 goto update_cache;
426 goto done;
429 rc = init_client_crypto2(client->filename, client->crypto);
431 if (rc) {
432 cleanup_client(client);
433 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
436 rc = try_xml_decrypt(ctx, client->crypto, NULL, NULL);
438 if (rc) {
439 cleanup_client(client);
440 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
443 update_cache:
444 CACHE_LOCK(client->ctx);
446 if (cached == FALSE) {
447 if (cache_update_key(client->md5file, key) == FALSE) {
448 cleanup_client(client);
449 CACHE_UNLOCK;
450 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
453 timeout = get_key_file_integer(client->filename, "cache_timeout");
454 cache_reset_timeout(client->md5file, timeout);
456 else
457 cache_set_timeout(client->md5file, -2);
459 CACHE_UNLOCK;
461 done:
462 rc = parse_xml(ctx);
464 if (client->xml) {
465 gcry_free(client->xml);
466 client->xml = NULL;
469 if (!rc) {
470 if (client->new == FALSE)
471 send_status_all(STATUS_CACHE);
473 client->state = STATE_OPEN;
476 if (!rc && client->new == FALSE &&
477 client->crypto->fh->ver.fh2.iter != (guint64)get_key_file_double(client->filename, "iterations")) {
478 MUTEX_LOCK(&rcfile_mutex);
479 g_key_file_set_double(keyfileh, client->filename, "iterations",
480 client->crypto->fh->ver.fh2.iter);
481 MUTEX_UNLOCK(&rcfile_mutex);
482 send_status_all(STATUS_CONFIG);
485 cleanup_crypto(&client->crypto);
487 if (!rc && client->lock_on_open)
488 return do_lock_command(client);
490 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
493 static void req_cleanup(void *arg)
495 if (!arg)
496 return;
498 g_strfreev((gchar **)arg);
501 static gpg_error_t parse_open_opt_lock(gpointer data, gpointer value)
503 struct client_s *client = data;
504 const gchar *p = value;
506 if (p && *p) {
507 long l = strtol(p, NULL, 10);
509 if (l < 0 || l > 1)
510 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
512 client->lock_on_open = l ? TRUE : FALSE;
514 else if ((!p || !*p) && (client->opts & OPT_LOCK))
515 client->lock_on_open = FALSE;
516 else
517 client->lock_on_open = TRUE;
519 return 0;
522 static gpg_error_t parse_opt_pinentry(gpointer data, gpointer value)
524 #ifdef WITH_PINENTRY
525 struct client_s *client = data;
526 gchar *p = NULL;
527 gchar *str = value;
528 gint n;
530 if (!str || !*str) {
531 client->pinentry->enable = -1;
532 client->opts &= ~(OPT_PINENTRY);
533 return 0;
536 n = strtol(str, &p, 10);
538 if (*p || n < 0 || n > 1)
539 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
541 client->pinentry->enable = n ? TRUE : FALSE;
542 client->opts |= OPT_PINENTRY;
543 return 0;
544 #else
545 return GPG_ERR_NOT_IMPLEMENTED;
546 #endif
549 static gpg_error_t parse_opt_inquire(gpointer data, gpointer value)
551 struct client_s *client = data;
553 (void)value;
554 client->opts |= OPT_INQUIRE;
555 return 0;
558 static gpg_error_t parse_opt_base64(gpointer data, gpointer value)
560 struct client_s *client = data;
562 (void)value;
563 client->opts |= OPT_BASE64;
564 return 0;
567 static gpg_error_t hash_key(struct client_s *client, const gchar *key)
569 guchar *tmp;
570 gsize len;
572 if (client->opts & OPT_BASE64)
573 tmp = g_base64_decode(key, &len);
574 else {
575 tmp = (guchar *)g_strdup(key);
576 len = strlen(key);
579 if (!tmp)
580 return GPG_ERR_ENOMEM;
582 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, tmp, len);
583 g_free(tmp);
584 return 0;
587 static gpg_error_t open_command_common(assuan_context_t ctx, gchar *line)
589 gboolean cached = FALSE;
590 gpg_error_t rc;
591 struct client_s *client = assuan_get_pointer(ctx);
592 gchar **req;
593 gchar *filename = NULL;
594 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
596 if ((req = split_input_line(line, " ", 2)) != NULL)
597 filename = req[0];
599 pth_cleanup_push(req_cleanup, req);
601 if (!filename || !*filename) {
602 pth_cleanup_pop(1);
603 return client->opts & OPT_INQUIRE ? GPG_ERR_SYNTAX : send_error(ctx, GPG_ERR_SYNTAX);
606 log_write2("ARGS=\"%s\" %s", filename, req[1] ? "<passphrase>" : "");
608 if (valid_filename(filename) == FALSE) {
609 pth_cleanup_pop(1);
610 return client->opts & OPT_INQUIRE ? GPG_ERR_INV_VALUE : send_error(ctx, GPG_ERR_INV_VALUE);
613 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
614 CACHE_LOCK(client->ctx);
616 if (cache_has_file(client->md5file) == FALSE) {
617 if (cache_add_file(client->md5file, NULL) == FALSE) {
618 pth_cleanup_pop(1);
619 CACHE_UNLOCK;
620 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
624 CACHE_UNLOCK;
625 rc = lock_file_mutex(client);
627 if (rc) {
628 pth_cleanup_pop(1);
629 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
632 client->freed = FALSE;
633 CACHE_LOCK(client->ctx);
634 cache_incr_refcount(client->md5file);
635 CACHE_UNLOCK;
636 client->crypto = init_client_crypto();
638 if (!client->crypto) {
639 pth_cleanup_pop(1);
640 cleanup_client(client);
641 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
644 client->crypto->key = gcry_malloc(hashlen);
646 if (!client->crypto->key) {
647 pth_cleanup_pop(1);
648 log_write("%s(%i): %s", __FUNCTION__, __LINE__,
649 GPG_ERR_ENOMEM);
650 cleanup_client(client);
651 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
654 memset(client->crypto->key, 0, hashlen);
655 client->crypto->fh = read_file_header(filename, FALSE, &rc);
657 if (!client->crypto->fh) {
658 if (gpg_err_code_to_errno(rc) != ENOENT) {
659 log_write("%s: %s", filename, pwmd_strerror(rc));
660 pth_cleanup_pop(1);
661 cleanup_client(client);
662 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
666 * New files don't need a key.
668 if ((client->xml = new_document()) == NULL) {
669 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
670 pth_cleanup_pop(1);
671 cleanup_client(client);
672 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
675 client->len = xmlStrlen(client->xml);
676 client->new = TRUE;
677 client->filename = g_strdup(filename);
679 if (!client->filename) {
680 pth_cleanup_pop(1);
681 cleanup_client(client);
682 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
683 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
686 if (req[1] && *req[1]) {
687 rc = hash_key(client, req[1]);
689 if (rc) {
690 pth_cleanup_pop(1);
691 cleanup_client(client);
692 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
696 pth_cleanup_pop(1);
697 #ifdef WITH_PINENTRY
698 client->pinentry->filename = g_strdup(client->filename);
700 if (!client->pinentry->filename) {
701 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
702 cleanup_client(client);
703 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
705 #endif
706 return open_command_finalize(ctx, NULL, cached);
708 else {
709 if (!(client->opts & OPT_CIPHER))
710 g_key_file_set_string(keyfileh, filename, "cipher",
711 pwmd_cipher_to_str(client->crypto->fh->ver.fh2.flags));
713 client->mtime = client->crypto->fh->st.st_mtime;
716 client->filename = g_strdup(filename);
718 if (!client->filename) {
719 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
720 pth_cleanup_pop(1);
721 cleanup_client(client);
722 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
725 #ifdef WITH_PINENTRY
726 if (client->pinentry->filename)
727 g_free(client->pinentry->filename);
729 client->pinentry->filename = g_strdup(client->filename);
731 if (!client->pinentry->filename) {
732 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
733 pth_cleanup_pop(1);
734 cleanup_client(client);
735 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
737 #endif
739 if (client->crypto->fh->ver.fh2.iter <= 0ULL)
740 goto done;
742 CACHE_LOCK(client->ctx);
743 cached = cache_get_key(client->md5file, client->crypto->key);
744 CACHE_UNLOCK;
746 if (cached == FALSE) {
747 gchar *tmp = get_key_file_string(filename, "key_file");
749 if (tmp && !(client->opts & OPT_INQUIRE)) {
750 g_free(tmp);
751 pth_cleanup_pop(1);
752 cleanup_client(client);
753 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
756 if (tmp)
757 g_free(tmp);
760 * No key specified and no matching filename found in the cache. Use
761 * pinentry to retrieve the key. Cannot return assuan_process_done()
762 * here otherwise the command will be interrupted. The event loop in
763 * client_thread() will poll the file descriptor waiting for it to
764 * become ready to read a pinentry_key_s which will contain the
765 * entered key or an error code. It will then call
766 * open_command_finalize() to to finish the command.
768 if (!req[1] || !*req[1]) {
769 #ifdef WITH_PINENTRY
770 gboolean b = get_key_file_boolean(filename, "enable_pinentry");
772 /* From set_pinentry_defaults(). */
773 if (client->opts & OPT_INQUIRE ||
774 client->pinentry->enable == FALSE ||
775 (client->pinentry->enable == -1 && b == FALSE)) {
776 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
777 goto done;
780 pth_cleanup_pop(1);
781 rc = lock_pin_mutex(client);
783 if (rc) {
784 unlock_pin_mutex(client->pinentry);
785 cleanup_client(client);
786 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
789 client->pinentry->which = PINENTRY_OPEN;
790 rc = pinentry_fork(ctx);
792 if (rc) {
793 unlock_pin_mutex(client->pinentry);
794 cleanup_client(client);
795 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
798 // Called from pinentry iterate.
799 client->pinentry->cb = open_command_finalize;
800 client->pinentry->status = PINENTRY_INIT;
801 return 0;
802 #else
803 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
804 goto done;
805 #endif
808 rc = hash_key(client, req[1]);
810 if (rc) {
811 pth_cleanup_pop(1);
812 cleanup_client(client);
813 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
816 else if (req && req[1] && *req[1]) {
817 rc = hash_key(client, req[1]);
819 if (rc) {
820 pth_cleanup_pop(1);
821 cleanup_client(client);
822 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
826 done:
827 pth_cleanup_pop(1);
828 return open_command_finalize(ctx, NULL, cached);
831 static gint open_command_inquire_finalize(gpointer data, gint assuan_rc,
832 guchar *line, gsize len)
834 assuan_context_t ctx = data;
835 struct client_s *client = assuan_get_pointer(ctx);
836 gpg_error_t rc = file_modified(client);
838 if (assuan_rc || (rc && rc != EPWMD_NO_FILE)) {
839 if (line)
840 xfree(line);
842 return assuan_rc ? assuan_rc : rc;
845 rc = open_command_common(ctx, (gchar *)line);
847 if (line)
848 xfree(line);
850 client->inquire_status = INQUIRE_DONE;
851 return rc;
854 static gint open_command(assuan_context_t ctx, gchar *line)
856 gpg_error_t rc;
857 struct client_s *client = assuan_get_pointer(ctx);
858 struct argv_s *args[] = {
859 &(struct argv_s) { "lock", OPTION_TYPE_NOARG, parse_open_opt_lock },
860 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
861 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
862 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
863 NULL
866 if (client->state == STATE_OPEN)
867 cleanup_client(client);
869 if (!(client->opts & OPT_LOCK))
870 client->lock_on_open = FALSE;
872 rc = parse_options(&line, args, client);
874 if (rc)
875 return send_error(ctx, rc);
877 if ((client->opts & OPT_INQUIRE)) {
878 rc = assuan_inquire_ext(ctx, "OPEN", 0, open_command_inquire_finalize,
879 ctx);
881 if (rc)
882 return send_error(ctx, rc);
884 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
885 client->inquire_status = INQUIRE_BUSY;
886 return 0;
889 return open_command_common(ctx, line);
892 gpg_error_t do_compress(assuan_context_t ctx, gint level, gpointer data,
893 guint size, gpointer *out, gulong *outsize)
895 struct gz_s *gz;
896 gz_header h;
897 gchar buf[17];
898 gint cmd = Z_NO_FLUSH;
899 gint zrc;
900 gpg_error_t rc;
902 gz = g_malloc0(sizeof(struct gz_s));
904 if (!gz)
905 return GPG_ERR_ENOMEM;
907 pth_cleanup_push(gz_cleanup, &gz);
908 gz->which = STATUS_COMPRESS;
909 gz->z.zalloc = z_alloc;
910 gz->z.zfree = z_free;
911 gz->z.next_in = data;
912 gz->z.avail_in = size < zlib_bufsize ? (uInt)size : (uInt)zlib_bufsize;
913 gz->z.avail_out = (uInt)zlib_bufsize;
914 gz->z.next_out = gz->out = gcry_malloc(zlib_bufsize);
916 if (!gz->out) {
917 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
918 pth_cleanup_pop(1);
919 return GPG_ERR_ENOMEM;
922 zrc = deflateInit2(&gz->z, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
924 if (zrc != Z_OK) {
925 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
926 pth_cleanup_pop(1);
927 return GPG_ERR_COMPR_ALGO;
930 /* Rather than store the size of the uncompressed data in the file header,
931 * store it in the comment field of the gzip header. Don't give anyone too
932 * much information. Not sure why really, but it seems the right way. :)
934 memset(&h, 0, sizeof(gz_header));
935 g_snprintf(buf, sizeof(buf), "%u", size);
936 h.comment = (guchar *)buf;
937 zrc = deflateSetHeader(&gz->z, &h);
939 if (zrc != Z_OK) {
940 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
941 pth_cleanup_pop(1);
942 return GPG_ERR_COMPR_ALGO;
945 do {
946 gpointer p;
948 zrc = deflate(&gz->z, cmd);
950 switch (zrc) {
951 case Z_OK:
952 break;
953 case Z_BUF_ERROR:
954 if (!gz->z.avail_out) {
955 p = gcry_realloc(gz->out, gz->z.total_out + zlib_bufsize);
957 if (!p) {
958 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
959 rc = GPG_ERR_ENOMEM;
960 goto fail;
963 gz->out = p;
964 gz->z.next_out = (guchar *)gz->out + gz->z.total_out;
965 gz->z.avail_out = zlib_bufsize;
968 if (!gz->z.avail_in && gz->z.total_in < size) {
969 if (gz->z.total_in + zlib_bufsize > size)
970 gz->z.avail_in = size - gz->z.total_in;
971 else
972 gz->z.avail_in = zlib_bufsize;
974 rc = send_status(ctx, STATUS_COMPRESS, "%li %u",
975 gz->z.total_in, size);
977 if (rc)
978 goto fail;
981 if (gz->z.total_in >= size)
982 cmd = Z_FINISH;
984 break;
985 case Z_STREAM_END:
986 break;
987 default:
988 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gz->z.msg);
989 rc = GPG_ERR_COMPR_ALGO;
990 goto fail;
992 } while (zrc != Z_STREAM_END);
994 rc = send_status(ctx, STATUS_COMPRESS, "%li %u", gz->z.total_in, size);
996 if (rc)
997 goto fail;
999 *out = gz->out;
1000 *outsize = gz->z.total_out;
1001 gz->done = TRUE;
1002 pth_cleanup_pop(1);
1003 return 0;
1005 fail:
1006 pth_cleanup_pop(1);
1007 return rc;
1010 #define CRYPTO_BLOCKSIZE(c) (c->blocksize * 1024)
1013 * Useful for a large amount of data. Rather than doing all of the data in one
1014 * iteration do it in chunks. This lets the command be cancelable rather than
1015 * waiting for it to complete.
1017 static gpg_error_t iterate_crypto_once(struct client_s *client,
1018 struct crypto_s *crypto, status_msg_t which)
1020 gpg_error_t rc = 0;
1021 goffset len = CRYPTO_BLOCKSIZE(crypto);
1022 gpointer p = gcry_malloc(len);
1023 goffset total = 0;
1024 gpointer inbuf;
1026 if (!p)
1027 return GPG_ERR_ENOMEM;
1029 if (crypto->insize < CRYPTO_BLOCKSIZE(crypto))
1030 len = crypto->insize;
1032 pth_cleanup_push(gcry_free, p);
1034 for (;;) {
1035 inbuf = (guchar *)crypto->inbuf + total;
1036 guchar *tmp;
1038 if (len + total > crypto->insize)
1039 len = crypto->blocksize;
1041 if (which == STATUS_ENCRYPT)
1042 rc = gcry_cipher_encrypt(crypto->gh, p, len, inbuf, len);
1043 else
1044 rc = gcry_cipher_decrypt(crypto->gh, p, len, inbuf, len);
1046 if (rc)
1047 goto done;
1049 tmp = (guchar *)crypto->inbuf + total;
1050 memmove(tmp, p, len);
1051 total += len;
1053 if (total >= crypto->insize)
1054 break;
1056 pth_cancel_point();
1059 done:
1060 pth_cleanup_pop(1);
1061 return rc;
1064 /* The crypto struct must be setup for iterations and .key. */
1065 gpg_error_t do_xml_encrypt(struct client_s *client,
1066 struct crypto_s *crypto, const gchar *filename)
1068 goffset len = crypto->insize;
1069 gpointer inbuf;
1070 gchar *p;
1071 gpg_error_t rc;
1072 guint64 iter_progress = 0ULL, n_iter = 0ULL, xiter = 0ULL;
1073 gchar tmp[FILENAME_MAX];
1074 struct stat st;
1075 mode_t mode = 0;
1076 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1078 if (!crypto->fh->ver.fh2.iter) {
1080 * cache_file_count() needs both .used == TRUE and a valid key in
1081 * order for it to count as a used cache entry. Fixes CACHE status
1082 * messages.
1084 memset(crypto->key, '!', hashlen);
1085 goto write_file;
1089 * Resize the existing xml buffer to the block size required by gcrypt
1090 * rather than duplicating it and wasting memory.
1092 crypto->insize += sizeof(crypto_magic);
1093 len = (crypto->insize / crypto->blocksize) * crypto->blocksize;
1095 if (crypto->insize % crypto->blocksize)
1096 len += crypto->blocksize;
1098 inbuf = gcry_realloc(crypto->inbuf, len);
1100 if (!inbuf) {
1101 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1102 return GPG_ERR_ENOMEM;
1105 guchar *tmpbuf = inbuf;
1106 memmove(&tmpbuf[sizeof(crypto_magic)], tmpbuf, len-sizeof(crypto_magic));
1107 memcpy(tmpbuf, crypto_magic, sizeof(crypto_magic));
1108 crypto->inbuf = tmpbuf;
1109 crypto->insize = len;
1110 gcry_create_nonce(crypto->fh->ver.fh2.iv, crypto->blocksize);
1112 if (crypto->tkey)
1113 gcry_free(crypto->tkey);
1115 crypto->tkey = gcry_malloc(hashlen);
1117 if (!crypto->tkey) {
1118 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1119 return GPG_ERR_ENOMEM;
1122 memcpy(crypto->tkey, crypto->key, hashlen);
1123 guchar *tkey = crypto->tkey;
1124 tkey[0] ^= 1;
1126 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
1127 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1128 return rc;
1131 iter_progress = (guint64)get_key_file_double(
1132 client ? client->filename : "global", "iteration_progress");
1134 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1135 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1136 "0 %llu", crypto->fh->ver.fh2.iter);
1138 if (rc)
1139 return rc;
1142 while (xiter < crypto->fh->ver.fh2.iter-1) {
1143 if (iter_progress > 0ULL && xiter >= iter_progress) {
1144 if (!(xiter % iter_progress)) {
1145 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1146 "%llu %llu", ++n_iter * iter_progress,
1147 crypto->fh->ver.fh2.iter);
1149 if (rc)
1150 return rc;
1154 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1155 crypto->blocksize))) {
1156 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1157 return rc;
1160 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1162 if (rc) {
1163 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1164 return rc;
1167 xiter++;
1170 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->fh->ver.fh2.iv,
1171 crypto->blocksize))) {
1172 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1173 return rc;
1176 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
1177 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
1178 return rc;
1181 rc = iterate_crypto_once(client, crypto, STATUS_ENCRYPT);
1183 if (rc)
1184 return rc;
1186 if (iter_progress && crypto->fh->ver.fh2.iter >= iter_progress) {
1187 rc = send_status(client ? client->ctx : NULL, STATUS_ENCRYPT,
1188 "%llu %llu", crypto->fh->ver.fh2.iter, crypto->fh->ver.fh2.iter);
1190 if (rc)
1191 return rc;
1194 write_file:
1195 tmp[0] = 0;
1197 if (filename) {
1198 if (!client && !g_ascii_strcasecmp(filename, "-")) {
1199 crypto->fh->fd = STDOUT_FILENO;
1200 goto do_write_file;
1203 if (lstat(filename, &st) == 0) {
1204 mode = st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
1206 if (!(mode & S_IWUSR))
1207 return GPG_ERR_EACCES;
1209 else if (errno != ENOENT)
1210 return gpg_error_from_syserror();
1212 g_snprintf(tmp, sizeof(tmp), "%s.XXXXXX", filename);
1213 crypto->fh->fd = mkstemp(tmp);
1215 if (crypto->fh->fd == -1) {
1216 rc = gpg_error_from_syserror();
1217 p = strrchr(tmp, '/');
1218 p++;
1219 log_write("%s: %s", p, pwmd_strerror(rc));
1220 return rc;
1223 pth_cleanup_push(cleanup_unlink_cb, tmp);
1225 else
1227 * xml_import() or convert_file() from command line.
1229 crypto->fh->fd = STDOUT_FILENO;
1231 do_write_file:
1232 crypto->fh->ver.fh2.magic[0] = '\177';
1233 crypto->fh->ver.fh2.magic[1] = 'P';
1234 crypto->fh->ver.fh2.magic[2] = 'W';
1235 crypto->fh->ver.fh2.magic[3] = 'M';
1236 crypto->fh->ver.fh2.magic[4] = 'D';
1237 crypto->fh->ver.fh2.version = VERSION_HEX;
1238 len = pth_write(crypto->fh->fd, &crypto->fh->ver.fh2, sizeof(crypto->fh->ver.fh2));
1240 if (len != sizeof(crypto->fh->ver.fh2)) {
1241 rc = gpg_error_from_syserror();
1243 if (tmp[0])
1244 pth_cleanup_pop(1);
1246 return rc;
1249 len = pth_write(crypto->fh->fd, crypto->inbuf, crypto->insize);
1251 if (len != crypto->insize) {
1252 rc = gpg_error_from_syserror();
1254 if (tmp[0])
1255 pth_cleanup_pop(1);
1257 return rc;
1260 if (fsync(crypto->fh->fd) == -1) {
1261 rc = gpg_error_from_syserror();
1263 if (tmp[0])
1264 pth_cleanup_pop(1);
1266 return rc;
1269 if (tmp[0]) {
1270 #ifdef WITH_LIBACL
1271 acl_t acl;
1272 #endif
1273 if (mode && get_key_file_boolean(filename, "backup") == TRUE) {
1274 gchar tmp2[FILENAME_MAX];
1276 g_snprintf(tmp2, sizeof(tmp2), "%s.backup", filename);
1277 #ifdef WITH_LIBACL
1278 acl = acl_get_file(filename, ACL_TYPE_ACCESS);
1280 if (!acl)
1281 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1282 #endif
1284 if (rename(filename, tmp2) == -1) {
1285 rc = gpg_error_from_syserror();
1286 pth_cleanup_pop(1);
1287 #ifdef WITH_LIBACL
1288 if (acl)
1289 acl_free(acl);
1290 #endif
1291 return rc;
1294 #ifdef WITH_LIBACL
1295 else {
1296 acl = acl_get_file(".", ACL_TYPE_DEFAULT);
1298 if (!acl)
1299 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1301 #endif
1303 if (rename(tmp, filename) == -1) {
1304 rc = gpg_error_from_syserror();
1305 pth_cleanup_pop(1);
1306 #ifdef WITH_LIBACL
1307 if (acl)
1308 acl_free(acl);
1309 #endif
1310 return rc;
1313 pth_cleanup_pop(0);
1315 if (mode)
1316 chmod(filename, mode);
1318 #ifdef WITH_LIBACL
1319 if (acl && acl_set_file(filename, ACL_TYPE_ACCESS, acl))
1320 log_write("ACL: %s: %s", filename, pwmd_strerror(gpg_error_from_syserror()));
1322 if (acl)
1323 acl_free(acl);
1324 #endif
1327 if (client && lstat(filename, &st) == 0)
1328 client->mtime = st.st_mtime;
1330 return 0;
1333 gpg_error_t update_save_flags(const gchar *filename,
1334 struct crypto_s *crypto)
1336 gpg_error_t rc;
1337 guint64 iter;
1339 /* New file? */
1340 if (!crypto->fh) {
1341 crypto->fh = g_malloc0(sizeof(file_header_internal_t));
1343 if (!crypto->fh)
1344 return GPG_ERR_ENOMEM;
1347 rc = init_client_crypto2(filename, crypto);
1349 if (rc)
1350 return rc;
1352 if (filename && !crypto->fh->v1) {
1353 iter = (guint64)get_key_file_double(filename, "iterations");
1354 crypto->fh->ver.fh2.iter = iter < 0L ? 0UL : iter;
1357 return 0;
1360 static gpg_error_t save_command_finalize(assuan_context_t ctx, guchar *key,
1361 gboolean cached)
1363 struct client_s *client = assuan_get_pointer(ctx);
1364 gpointer xmlbuf;
1365 gulong outsize = 0;
1366 guint len;
1367 gint clevel;
1368 gint timeout;
1369 gpointer outbuf;
1370 gpg_error_t rc;
1372 if (client->crypto->key && client->crypto->key != key)
1373 gcry_free(client->crypto->key);
1375 client->crypto->key = key;
1376 rc = update_element_mtime(xmlDocGetRootElement(client->doc));
1378 if (rc) {
1379 cleanup_crypto(&client->crypto);
1380 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1383 xmlDocDumpFormatMemory(client->doc, (xmlChar **)&xmlbuf, (gint *)&len, 0);
1384 pth_cleanup_push(xmlFree, xmlbuf);
1385 clevel = get_key_file_integer(client->filename, "compression_level");
1387 if (clevel < 0)
1388 clevel = 0;
1390 rc = do_compress(ctx, clevel, xmlbuf, len, &outbuf, &outsize);
1392 if (rc) {
1393 pth_cleanup_pop(1);
1394 cleanup_crypto(&client->crypto);
1396 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1398 else {
1399 pth_cleanup_pop(1);
1400 xmlbuf = outbuf;
1401 len = outsize;
1404 client->crypto->inbuf = xmlbuf;
1405 client->crypto->insize = len;
1406 rc = update_save_flags(client->filename, client->crypto);
1408 if (rc) {
1409 cleanup_crypto(&client->crypto);
1410 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1411 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1414 rc = do_xml_encrypt(client, client->crypto, client->filename);
1416 if (rc) {
1417 cleanup_crypto(&client->crypto);
1418 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1421 timeout = get_key_file_integer(client->filename, "cache_timeout");
1422 CACHE_LOCK(client->ctx);
1424 if (cached) {
1425 cache_reset_timeout(client->md5file, timeout);
1426 CACHE_UNLOCK;
1428 if (client->new == TRUE)
1429 send_status_all(STATUS_CACHE);
1431 client->new = FALSE;
1432 cleanup_crypto(&client->crypto);
1433 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1436 if (cache_update_key(client->md5file, client->crypto->key) == FALSE) {
1437 CACHE_UNLOCK;
1438 cleanup_crypto(&client->crypto);
1439 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1442 client->new = FALSE;
1443 cache_reset_timeout(client->md5file, timeout);
1444 CACHE_UNLOCK;
1445 send_status_all(STATUS_CACHE);
1446 cleanup_crypto(&client->crypto);
1447 return client->opts & OPT_INQUIRE ? 0 : send_error(ctx, 0);
1450 static gpg_error_t parse_save_opt_iterations(gpointer data, gpointer v)
1452 struct client_s *client = data;
1453 guint64 n;
1454 gchar *value = v;
1455 gchar *p = NULL;
1457 if (!client->filename)
1458 return EPWMD_NO_FILE;
1460 if (!value || !*value)
1461 return 0;
1463 errno = 0;
1464 n = strtoul(value, &p, 10);
1466 if (errno || (p && *p) || n == G_MAXULONG)
1467 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_ERANGE);
1469 MUTEX_LOCK(&rcfile_mutex);
1470 g_key_file_set_double(keyfileh,
1471 client->filename ? client->filename : "global", "iterations", n);
1472 MUTEX_UNLOCK(&rcfile_mutex);
1474 if (client->filename)
1475 client->opts |= OPT_ITERATIONS;
1477 return 0;
1480 static gpg_error_t parse_save_opt_cipher(gpointer data, gpointer value)
1482 struct client_s *client = data;
1483 const gchar *p = value;
1484 guint64 flags;
1486 if (!client->filename)
1487 return EPWMD_NO_FILE;
1489 if (!p || !*p)
1490 return 0;
1492 flags = pwmd_cipher_str_to_cipher(p);
1494 if (!flags)
1495 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
1497 MUTEX_LOCK(&rcfile_mutex);
1498 g_key_file_set_string(keyfileh, client->filename, "cipher", p);
1499 MUTEX_UNLOCK(&rcfile_mutex);
1501 if (!value)
1502 g_free((gchar *)p);
1504 return 0;
1507 static gpg_error_t parse_save_opt_reset(gpointer data, gpointer value)
1509 struct client_s *client = data;
1511 CACHE_LOCK(client->ctx);
1512 cache_clear(client->md5file, 1);
1513 CACHE_UNLOCK;
1514 return 0;
1517 static gpg_error_t save_command_common(assuan_context_t ctx, gchar *line)
1519 struct client_s *client = assuan_get_pointer(ctx);
1520 gboolean cached = FALSE;
1521 guint hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
1523 CACHE_LOCK(ctx);
1524 cached = cache_iscached(client->md5file);
1525 CACHE_UNLOCK;
1528 * If a cache entry doesn't exist for this file and the file has a
1529 * "key_file" or "key" parameter, then it's an error. The reason is that
1530 * cache expiration would be useless. Unless this is an inquire, then its
1531 * fine.
1533 if (cached == FALSE) {
1534 gchar *tmp = get_key_file_string(client->filename, "key_file");
1536 if (tmp && !(client->opts & OPT_INQUIRE)) {
1537 g_free(tmp);
1538 return send_error(ctx, GPG_ERR_WRONG_KEY_USAGE);
1541 if (tmp)
1542 g_free(tmp);
1545 cached = FALSE;
1547 /* New file? */
1548 if (!client->crypto) {
1549 client->crypto = init_client_crypto();
1551 if (!client->crypto) {
1552 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1553 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1557 client->crypto->key = gcry_malloc(hashlen);
1559 if (!client->crypto->key) {
1560 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1561 cleanup_crypto(&client->crypto);
1562 return client->opts & OPT_INQUIRE ? GPG_ERR_ENOMEM : send_error(ctx, GPG_ERR_ENOMEM);
1565 memset(client->crypto->key, '!', hashlen);
1567 if (get_key_file_double(client->filename, "iterations") <= 0L &&
1568 (!line || !*line))
1569 goto done;
1571 if (!line || !*line) {
1572 /* It doesn't make sense to use an --inquire with an empty
1573 * passphrase. This will prevent a pinentry dialog. */
1574 if (client->opts & OPT_INQUIRE) {
1575 cleanup_crypto(&client->crypto);
1576 return GPG_ERR_WRONG_KEY_USAGE;
1579 client->crypto->tkey = gcry_malloc(hashlen);
1581 if (!client->crypto->tkey) {
1582 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
1583 cleanup_crypto(&client->crypto);
1584 return send_error(ctx, GPG_ERR_ENOMEM);
1587 memset(client->crypto->tkey, '!', hashlen);
1588 CACHE_LOCK(ctx);
1590 if (cache_get_key(client->md5file, client->crypto->key) == FALSE ||
1591 !memcmp(client->crypto->key, client->crypto->tkey, hashlen)) {
1592 CACHE_UNLOCK;
1594 #ifdef WITH_PINENTRY
1595 gpg_error_t rc;
1597 if (client->pinentry->enable == FALSE ||
1598 get_key_file_boolean(client->filename, "enable_pinentry") == FALSE) {
1599 /* Empty keys are allowed. */
1600 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1601 goto done;
1604 lock_pin_mutex(client);
1605 client->pinentry->which = PINENTRY_SAVE;
1606 rc = pinentry_fork(ctx);
1608 if (rc) {
1609 unlock_pin_mutex(client->pinentry);
1610 cleanup_crypto(&client->crypto);
1611 return send_error(ctx, rc);
1614 client->pinentry->cb = save_command_finalize;
1615 client->pinentry->status = PINENTRY_INIT;
1616 return 0;
1617 #else
1618 /* Empty keys are allowed. */
1619 gcry_md_hash_buffer(GCRY_MD_SHA256, client->crypto->key, "", 1);
1620 goto done;
1621 #endif
1623 else {
1624 CACHE_UNLOCK;
1625 cached = TRUE;
1628 else {
1629 gpg_error_t rc;
1631 if (get_key_file_double(client->filename, "iterations") <= 0L) {
1632 guint64 iter = (guint64)get_key_file_double(NULL, "iterations");
1634 if (iter <= 0L)
1635 iter = 1;
1637 MUTEX_LOCK(&rcfile_mutex);
1638 g_key_file_set_double(keyfileh, client->filename, "iterations", iter);
1639 MUTEX_UNLOCK(&rcfile_mutex);
1640 client->opts |= OPT_ITERATIONS;
1641 rc = send_status(ctx, STATUS_CONFIG, NULL);
1643 if (rc) {
1644 cleanup_crypto(&client->crypto);
1645 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1649 rc = hash_key(client, line);
1651 if (rc) {
1652 cleanup_crypto(&client->crypto);
1653 return client->opts & OPT_INQUIRE ? rc : send_error(ctx, rc);
1657 done:
1658 return save_command_finalize(ctx, client->crypto->key, cached);
1661 static gint save_command_inquire_finalize(gpointer data, gint assuan_rc,
1662 guchar *line, gsize len)
1664 assuan_context_t ctx = data;
1665 struct client_s *client = assuan_get_pointer(ctx);
1666 gpg_error_t rc = file_modified(client);
1668 if (assuan_rc || rc) {
1669 if (line)
1670 xfree(line);
1672 return assuan_rc ? assuan_rc : rc;
1675 rc = save_command_common(ctx, (gchar *)line);
1677 if (line)
1678 xfree(line);
1680 client->inquire_status = INQUIRE_DONE;
1681 return rc;
1684 static gint save_command(assuan_context_t ctx, gchar *line)
1686 struct stat st;
1687 struct client_s *client = assuan_get_pointer(ctx);
1688 gpg_error_t rc;
1689 struct argv_s *args[] = {
1690 &(struct argv_s) { "iterations", OPTION_TYPE_OPTARG, parse_save_opt_iterations },
1691 &(struct argv_s) { "cipher", OPTION_TYPE_OPTARG, parse_save_opt_cipher },
1692 &(struct argv_s) { "pinentry", OPTION_TYPE_OPTARG, parse_opt_pinentry },
1693 &(struct argv_s) { "reset", OPTION_TYPE_NOARG, parse_save_opt_reset },
1694 &(struct argv_s) { "inquire", OPTION_TYPE_NOARG, parse_opt_inquire },
1695 &(struct argv_s) { "base64", OPTION_TYPE_NOARG, parse_opt_base64 },
1696 NULL
1699 rc = parse_options(&line, args, client);
1701 if (rc)
1702 return send_error(ctx, rc);
1704 if (lstat(client->filename, &st) == -1 && errno != ENOENT)
1705 return send_error(ctx, gpg_error_from_syserror());
1707 if (errno != ENOENT && !S_ISREG(st.st_mode)) {
1708 log_write("%s: %s", client->filename, pwmd_strerror(GPG_ERR_ENOANO));
1709 return send_error(ctx, GPG_ERR_ENOANO);
1712 if ((client->opts & OPT_INQUIRE)) {
1713 rc = assuan_inquire_ext(ctx, "SAVE", 0, save_command_inquire_finalize,
1714 ctx);
1716 if (rc)
1717 return send_error(ctx, rc);
1719 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1720 client->inquire_status = INQUIRE_BUSY;
1721 return 0;
1724 if (line && *line)
1725 log_write2("ARGS=%s", "<passphrase>");
1727 return save_command_common(ctx, line);
1730 static gint delete_command(assuan_context_t ctx, gchar *line)
1732 struct client_s *client = assuan_get_pointer(ctx);
1733 gchar **req;
1734 gpg_error_t rc;
1735 xmlNodePtr n;
1737 log_write2("ARGS=\"%s\"", line);
1739 if (strchr(line, '\t'))
1740 req = split_input_line(line, "\t", -1);
1741 else
1742 req = split_input_line(line, " ", -1);
1744 if (!req || !*req)
1745 return send_error(ctx, GPG_ERR_SYNTAX);
1747 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1749 if (!n) {
1750 g_strfreev(req);
1751 return send_error(ctx, rc);
1755 * No sub-node defined. Remove the entire node (root element).
1757 if (!req[1]) {
1758 if (n) {
1759 rc = unlink_node(n);
1760 xmlFreeNode(n);
1763 g_strfreev(req);
1764 return send_error(ctx, rc);
1767 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
1768 g_strfreev(req);
1770 if (!n)
1771 return send_error(ctx, rc);
1773 if (n) {
1774 rc = unlink_node(n);
1775 xmlFreeNode(n);
1778 return send_error(ctx, rc);
1782 * Don't return with assuan_process_done() here. This has been called from
1783 * assuan_process_next() and the command should be finished in
1784 * client_thread().
1786 static gint store_command_finalize(gpointer data, gint assuan_rc, guchar *line,
1787 gsize len)
1789 assuan_context_t ctx = data;
1790 struct client_s *client = assuan_get_pointer(ctx);
1791 gchar **req;
1792 xmlNodePtr n;
1793 gpg_error_t rc = file_modified(client);
1795 if (assuan_rc || rc) {
1796 if (line)
1797 xfree(line);
1798 return assuan_rc ? assuan_rc : rc;
1801 req = split_input_line((gchar *)line, "\t", 0);
1802 xfree(line);
1804 if (!req || !*req)
1805 return GPG_ERR_SYNTAX;
1807 again:
1808 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1810 if (rc && rc == GPG_ERR_ELEMENT_NOT_FOUND) {
1811 rc = new_root_element(client->doc, *req);
1813 if (rc) {
1814 g_strfreev(req);
1815 return rc;
1818 goto again;
1821 if (!n) {
1822 g_strfreev(req);
1823 return rc;
1826 if (req[1]) {
1827 if (!n->children)
1828 n = create_elements_cb(n, req+1, &rc, NULL);
1829 else
1830 n = find_elements(client->doc, n->children, req+1, &rc,
1831 NULL, NULL, create_elements_cb, FALSE, 0, NULL, FALSE);
1834 g_strfreev(req);
1835 client->inquire_status = INQUIRE_DONE;
1837 if (!rc)
1838 rc = update_element_mtime(n);
1840 return rc;
1843 static gint store_command(assuan_context_t ctx, gchar *line)
1845 struct client_s *client = assuan_get_pointer(ctx);
1846 gpg_error_t rc;
1848 rc = assuan_inquire_ext(ctx, "STORE", 0, store_command_finalize, ctx);
1850 if (rc)
1851 return send_error(ctx, rc);
1853 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
1854 client->inquire_status = INQUIRE_BUSY;
1855 return 0;
1858 static void *send_data_cb(void *arg)
1860 struct assuan_cmd_s *data = arg;
1861 gint old;
1862 gpg_error_t *rc;
1864 pth_cancel_state(PTH_CANCEL_ENABLE|PTH_CANCEL_ASYNCHRONOUS, &old);
1865 rc = g_malloc(sizeof(gpg_error_t));
1866 *rc = assuan_send_data(data->ctx, data->line, data->line_len);
1867 pth_cancel_state(old, NULL);
1868 pth_exit(rc);
1869 return NULL;
1872 /* For every assuan command that needs to be sent to the client, a timeout is
1873 * needed to determine if the client lost the connection. The timeout is the
1874 * same as the "keepalive" configuration parameter or a default if unset.
1876 gpg_error_t do_assuan_command(assuan_context_t ctx,
1877 void *(*cb)(void *data), void *data)
1879 pth_attr_t attr = pth_attr_new();
1880 pth_t tid;
1881 gint to = get_key_file_integer("global", "keepalive");
1882 pth_event_t ev, tev;
1883 pth_status_t st;
1884 gpg_error_t rc = 0;
1885 void *p;
1887 pth_attr_init(attr);
1888 pth_attr_set(attr, PTH_ATTR_JOINABLE, TRUE);
1889 tid = pth_spawn(attr, cb, data);
1890 rc = gpg_error_from_syserror();
1891 pth_attr_destroy(attr);
1893 if (!tid) {
1894 log_write("%s(%i): pth_spawn(): %s", __FILE__, __LINE__, pwmd_strerror(rc));
1895 return rc;
1898 pth_cleanup_push(cleanup_cancel_cb, tid);
1899 to = to <= 0 ? DEFAULT_KEEPALIVE_TO : to;
1900 ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD, tid);
1901 tev = to ? pth_event(PTH_EVENT_TIME, pth_timeout(to, 0)) : NULL;
1902 ev = pth_event_concat(ev, tev, NULL);
1903 pth_cleanup_push(cleanup_ev_cb, ev);
1904 pth_yield(tid);
1905 pth_wait(ev);
1907 if (tev) {
1908 st = pth_event_status(tev);
1910 if (st == PTH_STATUS_OCCURRED) {
1911 pth_cleanup_pop(1);
1912 pth_cleanup_pop(1);
1913 return GPG_ERR_TIMEOUT;
1917 st = pth_event_status(ev);
1919 if (st == PTH_STATUS_FAILED) {
1920 pth_cancel(tid);
1921 pth_join(tid, &p);
1922 g_free(p);
1923 rc = GPG_ERR_ASS_WRITE_ERROR;
1925 else if (st == PTH_STATUS_OCCURRED) {
1926 pth_join(tid, &p);
1927 rc = *(gpg_error_t *)p;
1928 g_free(p);
1931 pth_cleanup_pop(1);
1932 pth_cleanup_pop(0);
1933 return rc;
1936 static gpg_error_t xfer_data(assuan_context_t ctx, const gchar *line,
1937 gint total)
1939 gint to_send;
1940 gint sent = 0;
1941 gpg_error_t rc;
1942 struct assuan_cmd_s data;
1943 gint progress = get_key_file_integer("global", "xfer_progress");
1944 gint flush = 0;
1946 progress = progress>0 ? (progress/ASSUAN_LINELENGTH)*ASSUAN_LINELENGTH : 0;
1947 to_send = total < ASSUAN_LINELENGTH ? total : ASSUAN_LINELENGTH;
1948 data.ctx = ctx;
1949 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1951 if (rc)
1952 return rc;
1954 again:
1955 do {
1956 if (sent + to_send > total)
1957 to_send = total - sent;
1959 data.line = flush ? NULL : (gchar *)line+sent;
1960 data.line_len = flush ? 0 : to_send;
1961 rc = do_assuan_command(ctx, send_data_cb, &data);
1963 if (!rc) {
1964 sent += flush ? 0 : to_send;
1966 if ((progress && !(sent % progress) && sent != total) ||
1967 (sent == total && flush))
1968 rc = send_status(ctx, STATUS_XFER, "%li %li", sent, total);
1970 if (!flush && !rc && sent == total) {
1971 flush = 1;
1972 goto again;
1975 } while (!rc && sent < total);
1977 return rc;
1980 static gint get_command(assuan_context_t ctx, gchar *line)
1982 struct client_s *client = assuan_get_pointer(ctx);
1983 gchar **req;
1984 gpg_error_t rc;
1985 xmlNodePtr n;
1987 log_write2("ARGS=\"%s\"", line);
1988 req = split_input_line(line, "\t", -1);
1990 if (!req || !*req) {
1991 g_strfreev(req);
1992 return send_error(ctx, GPG_ERR_SYNTAX);
1995 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
1997 if (!n) {
1998 g_strfreev(req);
1999 return send_error(ctx, rc);
2002 if (req[1])
2003 n = find_elements(client->doc, n->children, req+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2005 g_strfreev(req);
2007 if (rc)
2008 return send_error(ctx, rc);
2010 if (!n || !n->children)
2011 return send_error(ctx, GPG_ERR_NO_VALUE);
2013 n = find_text_node(n->children);
2015 if (!n || !n->content || !*n->content)
2016 return send_error(ctx, GPG_ERR_NO_VALUE);
2018 rc = xfer_data(ctx, (gchar *)n->content, xmlStrlen(n->content));
2019 return send_error(ctx, rc);
2022 static xmlNodePtr realpath_elements_cb(xmlNodePtr node, gchar **target,
2023 gpg_error_t *rc, gchar **req_orig, void *data)
2025 gchar *path = *(gchar **)data;
2026 gchar *tmp = NULL, *result;
2028 if (path) {
2029 g_free(path);
2030 *(gchar **)data = NULL;
2033 path = g_strjoinv("\t", target);
2035 if (!path) {
2036 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2037 *rc = GPG_ERR_ENOMEM;
2038 return NULL;
2041 if (req_orig) {
2042 tmp = g_strjoinv("\t", req_orig);
2044 if (!tmp) {
2045 g_free(path);
2046 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2047 *rc = GPG_ERR_ENOMEM;
2048 return NULL;
2052 if (tmp && *tmp)
2053 result = g_strdup_printf("%s\t%s", path, tmp);
2054 else
2055 result = g_strdup(path);
2057 if (!result) {
2058 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2059 *rc = GPG_ERR_ENOMEM;
2060 g_free(path);
2061 g_free(tmp);
2062 return NULL;
2065 g_free(path);
2066 g_free(tmp);
2067 *(gchar **)data = result;
2068 return node;
2071 static void list_command_cleanup1(void *arg);
2072 static gint realpath_command(assuan_context_t ctx, gchar *line)
2074 gpg_error_t rc;
2075 struct client_s *client = assuan_get_pointer(ctx);
2076 gchar **req;
2077 gchar *t;
2078 gint i;
2079 xmlNodePtr n;
2080 GString *string;
2081 gchar *rp = NULL;
2083 log_write2("ARGS=\"%s\"", line);
2085 if (strchr(line, '\t') != NULL) {
2086 if ((req = split_input_line(line, "\t", 0)) == NULL)
2087 return send_error(ctx, GPG_ERR_SYNTAX);
2089 else {
2090 if ((req = split_input_line(line, " ", 0)) == NULL)
2091 return send_error(ctx, GPG_ERR_SYNTAX);
2094 n = find_root_element(client->doc, &req, &rc, NULL, 0, FALSE);
2096 if (!n) {
2097 g_strfreev(req);
2098 return send_error(ctx, rc);
2101 rp = g_strjoinv("\t", req);
2103 if (!rp) {
2104 g_strfreev(req);
2105 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2106 return send_error(ctx, GPG_ERR_ENOMEM);
2109 if (req[1]) {
2110 n = find_elements(client->doc, n->children, req+1, &rc,
2111 NULL, realpath_elements_cb, NULL, FALSE, 0, &rp, FALSE);
2113 if (!n) {
2114 g_free(rp);
2115 g_strfreev(req);
2116 return send_error(ctx, rc);
2120 string = g_string_new(rp);
2121 g_free(rp);
2122 g_strfreev(req);
2124 if (!string) {
2125 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2126 return send_error(ctx, GPG_ERR_ENOMEM);
2129 again:
2130 for (i = 0, t = string->str + i; *t; t++, i++) {
2131 if ((!i && *t != '!') || (*t == '\t' && *(t+1) && *(t+1) != '!')) {
2132 string = g_string_insert_c(string, !i ? i++ : ++i, '!');
2133 goto again;
2137 pth_cleanup_push(list_command_cleanup1, string);
2138 rc = xfer_data(ctx, string->str, string->len);
2139 pth_cleanup_pop(1);
2140 return send_error(ctx, rc);
2143 static void list_command_cleanup1(void *arg)
2145 g_string_free((GString *)arg, TRUE);
2148 static void list_command_cleanup2(void *arg)
2150 struct element_list_s *elements = arg;
2152 if (elements) {
2153 if (elements->list) {
2154 gint total = g_slist_length(elements->list);
2155 gint i;
2157 for (i = 0; i < total; i++) {
2158 gchar *tmp = g_slist_nth_data(elements->list, i);
2159 g_free(tmp);
2162 g_slist_free(elements->list);
2165 if (elements->prefix)
2166 g_free(elements->prefix);
2168 if (elements->req)
2169 g_strfreev(elements->req);
2171 g_free(elements);
2175 static gpg_error_t parse_list_opt_norecurse(gpointer data, gpointer value)
2177 struct element_list_s *elements = data;
2179 elements->recurse = FALSE;
2180 return 0;
2183 static gpg_error_t parse_list_opt_verbose(gpointer data, gpointer value)
2185 struct element_list_s *elements = data;
2187 elements->verbose = TRUE;
2188 return 0;
2191 static gint list_command(assuan_context_t ctx, gchar *line)
2193 struct client_s *client = assuan_get_pointer(ctx);
2194 gpg_error_t rc;
2195 struct element_list_s *elements = NULL;
2196 gchar *tmp;
2197 struct argv_s *args[] = {
2198 &(struct argv_s) { "no-recurse", OPTION_TYPE_NOARG, parse_list_opt_norecurse },
2199 &(struct argv_s) { "verbose", OPTION_TYPE_NOARG, parse_list_opt_verbose },
2200 NULL
2203 if (disable_list_and_dump == TRUE)
2204 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2206 elements = g_malloc0(sizeof(struct element_list_s));
2208 if (!elements) {
2209 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2210 return GPG_ERR_ENOMEM;
2213 elements->recurse = TRUE; // default
2214 pth_cleanup_push(list_command_cleanup2, elements);
2215 rc = parse_options(&line, args, elements);
2217 if (rc)
2218 goto fail;
2220 if (!*line) {
2221 GString *str;
2223 rc = list_root_elements(client->doc, &str, elements->verbose);
2225 if (rc) {
2226 pth_cleanup_pop(1);
2227 return send_error(ctx, rc);
2230 pth_cleanup_push(list_command_cleanup1, str);
2231 rc = xfer_data(ctx, str->str, str->len);
2232 pth_cleanup_pop(1);
2233 pth_cleanup_pop(1);
2234 return send_error(ctx, rc);
2237 elements->req = split_input_line(line, " ", 0);
2239 if (!elements->req)
2240 strv_printf(&elements->req, "%s", line);
2242 rc = create_path_list(client->doc, elements, *elements->req);
2244 if (rc)
2245 goto fail;
2247 if (elements) {
2248 gint total = g_slist_length(elements->list);
2249 gint i;
2250 GString *str;
2252 if (!total) {
2253 rc = GPG_ERR_NO_VALUE;
2254 goto fail;
2257 str = g_string_new(NULL);
2259 if (!str) {
2260 rc = GPG_ERR_ENOMEM;
2261 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2262 goto fail;
2265 for (i = 0; i < total; i++) {
2266 tmp = g_slist_nth_data(elements->list, i);
2267 g_string_append_printf(str, "%s%s", tmp, i+1 == total ? "" : "\n");
2270 pth_cleanup_push(list_command_cleanup1, str);
2271 rc = xfer_data(ctx, str->str, str->len);
2272 pth_cleanup_pop(1);
2274 else
2275 rc = GPG_ERR_NO_VALUE;
2277 fail:
2278 pth_cleanup_pop(1);
2279 return send_error(ctx, rc);
2283 * req[0] - element path
2285 static gpg_error_t attribute_list(assuan_context_t ctx, gchar **req)
2287 struct client_s *client = assuan_get_pointer(ctx);
2288 gchar **attrlist = NULL;
2289 gint i = 0;
2290 gchar **path = NULL;
2291 xmlAttrPtr a;
2292 xmlNodePtr n, an;
2293 gchar *line;
2294 gpg_error_t rc;
2296 if (!req || !req[0])
2297 return GPG_ERR_SYNTAX;
2299 if ((path = split_input_line(req[0], "\t", 0)) == NULL) {
2301 * The first argument may be only a root element.
2303 if ((path = split_input_line(req[0], " ", 0)) == NULL)
2304 return GPG_ERR_SYNTAX;
2307 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2309 if (!n) {
2310 g_strfreev(path);
2311 return rc;
2314 if (path[1]) {
2315 n = find_elements(client->doc, n->children, path+1, &rc,
2316 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2318 if (!n) {
2319 g_strfreev(path);
2320 return rc;
2324 g_strfreev(path);
2326 for (a = n->properties; a; a = a->next) {
2327 gchar **pa;
2329 if ((pa = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
2330 if (attrlist)
2331 g_strfreev(attrlist);
2333 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2334 return GPG_ERR_ENOMEM;
2337 attrlist = pa;
2338 an = a->children;
2339 attrlist[i] = g_strdup_printf("%s %s", (gchar *)a->name,
2340 an && an->content ? (gchar *)an->content : "");
2342 if (!attrlist[i]) {
2343 g_strfreev(attrlist);
2344 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2345 return GPG_ERR_ENOMEM;
2348 attrlist[++i] = NULL;
2351 if (!attrlist)
2352 return GPG_ERR_NO_VALUE;
2354 line = g_strjoinv("\n", attrlist);
2356 if (!line) {
2357 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2358 g_strfreev(attrlist);
2359 return GPG_ERR_ENOMEM;
2362 pth_cleanup_push(g_free, line);
2363 pth_cleanup_push(req_cleanup, attrlist);
2364 rc = xfer_data(ctx, line, strlen(line));
2365 pth_cleanup_pop(1);
2366 pth_cleanup_pop(1);
2367 return rc;
2371 * req[0] - attribute
2372 * req[1] - element path
2374 static gpg_error_t attribute_delete(struct client_s *client, gchar **req)
2376 xmlNodePtr n;
2377 gchar **path = NULL;
2378 gpg_error_t rc;
2380 if (!req || !req[0] || !req[1])
2381 return GPG_ERR_SYNTAX;
2383 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2385 * The first argument may be only a root element.
2387 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2388 return GPG_ERR_SYNTAX;
2392 * Don't remove the "_name" attribute for the root element. To remove an
2393 * root element use DELETE <name>.
2395 if (!path[1] && xmlStrEqual((xmlChar *)req[0], (xmlChar *)"_name")) {
2396 rc = GPG_ERR_SYNTAX;
2397 goto fail;
2400 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2402 if (!n)
2403 goto fail;
2405 if (path[1]) {
2406 n = find_elements(client->doc, n->children, path+1, &rc,
2407 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2409 if (!n)
2410 goto fail;
2413 rc = delete_attribute(n, (xmlChar *)req[0]);
2415 fail:
2416 g_strfreev(path);
2417 return rc;
2420 static xmlNodePtr create_element_path(struct client_s *client, gchar ***path,
2421 gpg_error_t *rc)
2423 gchar **src = *path;
2424 gchar **src_orig = g_strdupv(src);
2425 xmlNodePtr n = NULL;
2427 *rc = 0;
2429 if (!src_orig) {
2430 *rc = GPG_ERR_ENOMEM;
2431 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2432 goto fail;
2435 again:
2436 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2438 if (!n) {
2439 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND) {
2440 *rc = new_root_element(client->doc, src[0]);
2442 if (*rc)
2443 goto fail;
2445 goto again;
2447 else
2448 goto fail;
2451 if (src[1]) {
2452 if (!n->children)
2453 n = create_target_elements_cb(n, src+1, rc, NULL);
2454 else
2455 n = find_elements(client->doc, n->children, src+1, rc,
2456 NULL, NULL, create_target_elements_cb, FALSE, 0, NULL, FALSE);
2458 if (!n)
2459 goto fail;
2462 * Reset the position of the element tree now that the elements
2463 * have been created.
2465 g_strfreev(src);
2466 src = src_orig;
2467 src_orig = NULL;
2468 n = find_root_element(client->doc, &src, rc, NULL, 0, FALSE);
2470 if (!n)
2471 goto fail;
2473 n = find_elements(client->doc, n->children, src+1, rc,
2474 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2476 if (!n)
2477 goto fail;
2480 fail:
2481 if (src_orig)
2482 g_strfreev(src_orig);
2484 *path = src;
2485 return n;
2489 * Creates a "target" attribute. When other commands encounter an element with
2490 * this attribute, the element path is modified to the target value. If the
2491 * source element path doesn't exist when using 'ATTR SET target', it is
2492 * created, but the destination element path must exist.
2494 * req[0] - source element path
2495 * req[1] - destination element path
2497 static gpg_error_t target_attribute(struct client_s *client, gchar **req)
2499 gchar **src, **dst, *line = NULL, **odst = NULL;
2500 gpg_error_t rc;
2501 xmlNodePtr n;
2503 if (!req || !req[0] || !req[1])
2504 return GPG_ERR_SYNTAX;
2506 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
2508 * The first argument may be only a root element.
2510 if ((src = split_input_line(req[0], " ", 0)) == NULL)
2511 return GPG_ERR_SYNTAX;
2514 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
2516 * The first argument may be only a root element.
2518 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
2519 rc = GPG_ERR_SYNTAX;
2520 goto fail;
2524 odst = g_strdupv(dst);
2526 if (!odst) {
2527 rc = GPG_ERR_ENOMEM;
2528 goto fail;
2531 n = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
2534 * Make sure the destination element path exists.
2536 if (!n)
2537 goto fail;
2539 if (dst[1]) {
2540 n = find_elements(client->doc, n->children, dst+1, &rc,
2541 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2543 if (!n)
2544 goto fail;
2547 n = create_element_path(client, &src, &rc);
2549 if (rc)
2550 goto fail;
2552 line = g_strjoinv("\t", odst);
2554 if (!line) {
2555 rc = GPG_ERR_ENOMEM;
2556 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2557 goto fail;
2560 rc = add_attribute(n, "target", line);
2562 fail:
2563 g_free(line);
2564 g_strfreev(src);
2565 g_strfreev(dst);
2566 g_strfreev(odst);
2567 return rc;
2571 * req[0] - name
2572 * req[1] - new name
2574 static gpg_error_t name_attribute(struct client_s *client, gchar **req)
2576 gpg_error_t rc;
2577 gchar **tmp;
2578 xmlNodePtr n;
2580 tmp = g_strdupv(req);
2582 if (!tmp) {
2583 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2584 return GPG_ERR_ENOMEM;
2587 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2588 g_strfreev(tmp);
2590 if (!n)
2591 return rc;
2593 if (g_utf8_collate(req[0], req[1]) == 0)
2594 return 0;
2597 * Will not overwrite an existing root.
2599 tmp = g_strdupv(req+1);
2601 if (!tmp) {
2602 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2603 return GPG_ERR_ENOMEM;
2606 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2607 g_strfreev(tmp);
2609 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
2610 return rc;
2612 if (n)
2613 return GPG_ERR_AMBIGUOUS_NAME;
2615 if (!valid_xml_element((xmlChar *)req[1]))
2616 return GPG_ERR_SYNTAX;
2618 tmp = g_strdupv(req);
2620 if (!tmp) {
2621 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2622 return GPG_ERR_ENOMEM;
2625 n = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
2626 g_strfreev(tmp);
2628 if (!n)
2629 return GPG_ERR_ELEMENT_NOT_FOUND;
2631 return add_attribute(n, "_name", req[1]);
2635 * req[0] - attribute
2636 * req[1] - element path
2638 static gpg_error_t attribute_get(assuan_context_t ctx, gchar **req)
2640 struct client_s *client = assuan_get_pointer(ctx);
2641 xmlNodePtr n;
2642 xmlChar *a;
2643 gchar **path= NULL;
2644 gpg_error_t rc;
2646 if (!req || !req[0] || !req[1])
2647 return GPG_ERR_SYNTAX;
2649 if (strchr(req[1], '\t')) {
2650 if ((path = split_input_line(req[1], "\t", 0)) == NULL)
2651 return GPG_ERR_SYNTAX;
2653 else {
2654 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2655 return GPG_ERR_SYNTAX;
2658 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2660 if (!n)
2661 goto fail;
2663 if (path[1]) {
2664 n = find_elements(client->doc, n->children, path+1, &rc,
2665 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2667 if (!n)
2668 goto fail;
2671 g_strfreev(path);
2673 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL)
2674 return GPG_ERR_NOT_FOUND;
2676 pth_cleanup_push(xmlFree, a);
2678 if (*a)
2679 rc = xfer_data(ctx, (gchar *)a, xmlStrlen(a));
2680 else
2681 rc = GPG_ERR_NO_VALUE;
2683 pth_cleanup_pop(1);
2684 return rc;
2686 fail:
2687 g_strfreev(path);
2688 return rc;
2692 * req[0] - attribute
2693 * req[1] - element path
2694 * req[2] - value
2696 static gpg_error_t attribute_set(struct client_s *client, gchar **req)
2698 gchar **path = NULL;
2699 gpg_error_t rc;
2700 xmlNodePtr n;
2702 if (!req || !req[0] || !req[1])
2703 return GPG_ERR_SYNTAX;
2706 * Reserved attribute names.
2708 if (!strcmp(req[0], "_name")) {
2710 * Only reserved for the root element. Not the rest of the
2711 * document.
2713 if (strchr(req[1], '\t') == NULL)
2714 return name_attribute(client, req + 1);
2716 else if (!strcmp(req[0], "target"))
2717 return target_attribute(client, req + 1);
2719 if ((path = split_input_line(req[1], "\t", 0)) == NULL) {
2721 * The first argument may be only a root element.
2723 if ((path = split_input_line(req[1], " ", 0)) == NULL)
2724 return GPG_ERR_SYNTAX;
2727 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
2729 if (!n)
2730 goto fail;
2732 if (path[1]) {
2733 n = find_elements(client->doc, n->children, path+1, &rc,
2734 NULL, NULL, NULL, FALSE, 0, NULL, FALSE);
2736 if (!n)
2737 goto fail;
2740 rc = add_attribute(n, req[0], req[2]);
2742 fail:
2743 g_strfreev(path);
2744 return rc;
2748 * req[0] - command
2749 * req[1] - attribute name or element path if command is LIST
2750 * req[2] - element path
2751 * req[2] - element path or value
2753 static gint attr_command(assuan_context_t ctx, gchar *line)
2755 struct client_s *client = assuan_get_pointer(ctx);
2756 gchar **req;
2757 gpg_error_t rc = 0;
2759 log_write2("ARGS=\"%s\"", line);
2760 req = split_input_line(line, " ", 4);
2762 if (!req || !req[0] || !req[1]) {
2763 g_strfreev(req);
2764 return send_error(ctx, GPG_ERR_SYNTAX);
2767 pth_cleanup_push(req_cleanup, req);
2769 if (g_ascii_strcasecmp(req[0], "SET") == 0)
2770 rc = attribute_set(client, req+1);
2771 else if (g_ascii_strcasecmp(req[0], "GET") == 0)
2772 rc = attribute_get(ctx, req+1);
2773 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
2774 rc = attribute_delete(client, req+1);
2775 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
2776 rc = attribute_list(ctx, req+1);
2777 else
2778 rc = GPG_ERR_SYNTAX;
2780 pth_cleanup_pop(1);
2781 return send_error(ctx, rc);
2784 static gint iscached_command(assuan_context_t ctx, gchar *line)
2786 gchar **req = split_input_line(line, " ", 0);
2787 guchar md5file[16];
2788 gchar *path, *tmp;
2790 if (!req || !*req) {
2791 g_strfreev(req);
2792 return send_error(ctx, GPG_ERR_SYNTAX);
2795 log_write2("ARGS=\"%s\"", line);
2797 if (!valid_filename(req[0])) {
2798 g_strfreev(req);
2799 return GPG_ERR_INV_VALUE;
2802 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2803 CACHE_LOCK(ctx);
2805 if (cache_iscached(md5file)) {
2806 g_strfreev(req);
2807 CACHE_UNLOCK;
2808 return send_error(ctx, 0);
2811 CACHE_UNLOCK;
2812 tmp = get_key_file_string("global", "data_directory");
2814 if (!tmp) {
2815 g_strfreev(req);
2816 return GPG_ERR_ENOMEM;
2819 path = expand_homedir(tmp);
2821 if (!path) {
2822 g_strfreev(req);
2823 g_free(tmp);
2824 return GPG_ERR_ENOMEM;
2827 g_free(tmp);
2828 tmp = path;
2829 path = g_strdup_printf("%s/%s", tmp, req[0]);
2830 g_free(tmp);
2832 if (!path) {
2833 g_strfreev(req);
2834 return GPG_ERR_ENOMEM;
2837 if (access(path, R_OK) == -1) {
2838 gpg_error_t rc = gpg_error_from_syserror();
2840 g_free(path);
2841 g_strfreev(req);
2842 return send_error(ctx, rc);
2845 g_free(path);
2846 return send_error(ctx, GPG_ERR_NOT_FOUND);
2849 static gint clearcache_command(assuan_context_t ctx, gchar *line)
2851 gchar **req = split_input_line(line, " ", 0);
2852 guchar md5file[16];
2854 log_write2("ARGS=\"%s\"", line);
2855 CACHE_LOCK(ctx);
2857 if (!req || !*req) {
2858 g_strfreev(req);
2859 cache_clear(NULL, 2);
2860 CACHE_UNLOCK;
2861 return send_error(ctx, 0);
2864 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2865 g_strfreev(req);
2867 if (cache_clear(md5file, 1) == FALSE) {
2868 CACHE_UNLOCK;
2869 return send_error(ctx, GPG_ERR_NOT_FOUND);
2872 CACHE_UNLOCK;
2873 return send_error(ctx, 0);
2876 static gint cachetimeout_command(assuan_context_t ctx, gchar *line)
2878 guchar md5file[16];
2879 glong timeout;
2880 gchar **req = split_input_line(line, " ", 0);
2881 gchar *p;
2883 if (!req || !*req || !req[1]) {
2884 g_strfreev(req);
2885 return send_error(ctx, GPG_ERR_SYNTAX);
2888 errno = 0;
2889 timeout = strtol(req[1], &p, 10);
2891 if (errno != 0 || *p != 0 || timeout < -1) {
2892 g_strfreev(req);
2893 return send_error(ctx, GPG_ERR_SYNTAX);
2896 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[0], strlen(req[0]));
2897 CACHE_LOCK(client->ctx);
2899 if (cache_set_timeout(md5file, timeout) == FALSE) {
2900 CACHE_UNLOCK;
2901 return send_error(ctx, GPG_ERR_NOT_FOUND);
2904 CACHE_UNLOCK;
2905 return send_error(ctx, 0);
2908 static gint dump_command(assuan_context_t ctx, gchar *line)
2910 xmlChar *xml;
2911 gint len;
2912 struct client_s *client = assuan_get_pointer(ctx);
2913 gpg_error_t rc;
2915 if (disable_list_and_dump == TRUE)
2916 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2918 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
2920 if (!xml) {
2921 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2922 return send_error(ctx, GPG_ERR_ENOMEM);
2925 pth_cleanup_push(xmlFree, xml);
2926 rc = xfer_data(ctx, (gchar *)xml, len);
2927 pth_cleanup_pop(1);
2928 return send_error(ctx, rc);
2931 static gint getconfig_command(assuan_context_t ctx, gchar *line)
2933 struct client_s *client = assuan_get_pointer(ctx);
2934 gpg_error_t rc = 0;
2935 gchar filename[255]={0}, param[747]={0};
2936 gchar *p, *tmp, *fp = client->filename, *paramp = line;
2938 log_write2("ARGS=\"%s\"", line);
2940 if (strchr(line, ' ')) {
2941 sscanf(line, " %254[^ ] %746c", filename, param);
2942 paramp = param;
2943 fp = filename;
2946 if (fp && !valid_filename(fp))
2947 return send_error(ctx, GPG_ERR_INV_VALUE);
2949 paramp = g_ascii_strdown(paramp, -1);
2951 if (!paramp) {
2952 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
2953 return send_error(ctx, GPG_ERR_ENOMEM);
2956 if (fp && !g_ascii_strcasecmp(paramp, "iterations")) {
2957 if (!(client->opts & OPT_ITERATIONS) || fp != client->filename) {
2958 file_header_internal_t *fh = read_file_header(fp, FALSE, &rc);
2960 if (!fh && rc != GPG_ERR_ENOENT)
2961 return send_error(ctx, rc);
2963 if (!rc) {
2964 g_free(paramp);
2965 p = g_strdup_printf("%lu", (unsigned long)fh->ver.fh2.iter);
2966 close_file_header(fh);
2968 if (!p) {
2969 log_write("%s(%i): %s", __FILE__, __LINE__,
2970 pwmd_strerror(GPG_ERR_ENOMEM));
2971 return send_error(ctx, GPG_ERR_ENOMEM);
2974 goto done;
2978 else if (!g_ascii_strcasecmp(paramp, "enable_pinentry")) {
2979 #ifdef WITH_PINENTRY
2980 gboolean n;
2982 if (fp == client->filename && (client->opts & OPT_PINENTRY))
2983 n = client->pinentry->enable;
2984 else
2985 n = get_key_file_boolean(fp, "enable_pinentry");
2987 p = g_strdup_printf("%s", n ? "true" : "false");
2989 if (!p) {
2990 log_write("%s(%i): %s", __FILE__, __LINE__,
2991 pwmd_strerror(GPG_ERR_ENOMEM));
2992 return send_error(ctx, GPG_ERR_ENOMEM);
2995 goto done;
2996 #else
2997 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
2998 #endif
3000 else if (!g_ascii_strcasecmp(paramp, "pinentry_timeout")) {
3001 #ifdef WITH_PINENTRY
3002 p = g_strdup_printf("%i", get_key_file_integer(fp, "pinentry_timeout"));
3004 if (!p) {
3005 log_write("%s(%i): %s", __FILE__, __LINE__,
3006 pwmd_strerror(GPG_ERR_ENOMEM));
3007 return send_error(ctx, GPG_ERR_ENOMEM);
3010 goto done;
3011 #else
3012 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3013 #endif
3016 p = get_key_file_string(fp ? fp : "global", paramp);
3017 g_free(paramp);
3019 if (!p)
3020 return send_error(ctx, GPG_ERR_NO_VALUE);
3022 tmp = expand_homedir(p);
3023 g_free(p);
3025 if (!tmp) {
3026 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3027 return send_error(ctx, GPG_ERR_ENOMEM);
3030 p = tmp;
3031 done:
3032 pth_cleanup_push(g_free, p);
3033 rc = xfer_data(ctx, p, strlen(p));
3034 pth_cleanup_pop(1);
3035 return send_error(ctx, rc);
3038 struct xpath_s {
3039 xmlXPathContextPtr xp;
3040 xmlXPathObjectPtr result;
3041 xmlBufferPtr buf;
3042 gchar **req;
3045 static void xpath_command_cleanup(void *arg)
3047 struct xpath_s *xpath = arg;
3049 req_cleanup(xpath->req);
3051 if (xpath->buf)
3052 xmlBufferFree(xpath->buf);
3054 if (xpath->result)
3055 xmlXPathFreeObject(xpath->result);
3057 if (xpath->xp)
3058 xmlXPathFreeContext(xpath->xp);
3061 static gint xpath_command(assuan_context_t ctx, gchar *line)
3063 struct client_s *client = assuan_get_pointer(ctx);
3064 gpg_error_t rc;
3065 struct xpath_s xpath;
3067 log_write2("ARGS=\"%s\"", line);
3069 if (disable_list_and_dump == TRUE)
3070 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3072 if (!line || !*line)
3073 return send_error(ctx, GPG_ERR_SYNTAX);
3075 memset(&xpath, 0, sizeof(struct xpath_s));
3077 if ((xpath.req = split_input_line(line, "\t", 2)) == NULL) {
3078 if (strv_printf(&xpath.req, "%s", line) == FALSE)
3079 return send_error(ctx, GPG_ERR_ENOMEM);
3082 xpath.xp = xmlXPathNewContext(client->doc);
3084 if (!xpath.xp) {
3085 xpath_command_cleanup(&xpath);
3086 return send_error(ctx, EPWMD_LIBXML_ERROR);
3089 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3091 if (!xpath.result) {
3092 xpath_command_cleanup(&xpath);
3093 return send_error(ctx, EPWMD_LIBXML_ERROR);
3096 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3097 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3098 goto fail;
3101 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3102 (xmlChar *)xpath.req[1], &xpath.buf, 0, NULL);
3104 if (rc)
3105 goto fail;
3106 else if (!xpath.req[1] && !xmlBufferLength(xpath.buf)) {
3107 rc = GPG_ERR_NO_VALUE;
3108 goto fail;
3110 else if (xpath.req[1])
3111 goto fail;
3113 pth_cleanup_push(xpath_command_cleanup, &xpath);
3114 rc = xfer_data(ctx, (gchar *)xmlBufferContent(xpath.buf),
3115 xmlBufferLength(xpath.buf));
3116 pth_cleanup_pop(0);
3118 fail:
3119 xpath_command_cleanup(&xpath);
3120 return send_error(ctx, rc);
3123 /* XPATHATTR SET|DELETE <name> <expression>[<TAB>[value]] */
3124 static gint xpathattr_command(assuan_context_t ctx, gchar *line)
3126 struct client_s *client = assuan_get_pointer(ctx);
3127 gpg_error_t rc;
3128 struct xpath_s xpath;
3129 gchar **req = NULL;
3130 gboolean cmd = FALSE; //SET
3132 log_write2("ARGS=\"%s\"", line);
3134 if (disable_list_and_dump == TRUE)
3135 return send_error(ctx, GPG_ERR_NOT_IMPLEMENTED);
3137 if (!line || !*line)
3138 return send_error(ctx, GPG_ERR_SYNTAX);
3140 memset(&xpath, 0, sizeof(struct xpath_s));
3142 if ((req = split_input_line(line, " ", 3)) == NULL)
3143 return send_error(ctx, GPG_ERR_ENOMEM);
3145 if (!req[0]) {
3146 rc = GPG_ERR_SYNTAX;
3147 goto fail;
3150 if (!g_ascii_strcasecmp(req[0], "SET"))
3151 cmd = FALSE;
3152 else if (!g_ascii_strcasecmp(req[0], "DELETE"))
3153 cmd = TRUE;
3154 else {
3155 rc = GPG_ERR_SYNTAX;
3156 goto fail;
3159 if (!req[1] || !req[2]) {
3160 rc = GPG_ERR_SYNTAX;
3161 goto fail;
3164 if ((xpath.req = split_input_line(req[2], "\t", 3)) == NULL) {
3165 rc = GPG_ERR_ENOMEM;
3166 goto fail;
3169 if (!xpath.req[0] || (!xpath.req[1] && !cmd) || (xpath.req[1] && cmd)) {
3170 rc = GPG_ERR_SYNTAX;
3171 goto fail;
3174 xpath.xp = xmlXPathNewContext(client->doc);
3176 if (!xpath.xp) {
3177 rc = EPWMD_LIBXML_ERROR;
3178 goto fail;
3181 xpath.result = xmlXPathEvalExpression((xmlChar *)xpath.req[0], xpath.xp);
3183 if (!xpath.result) {
3184 rc = EPWMD_LIBXML_ERROR;
3185 goto fail;
3188 if (xmlXPathNodeSetIsEmpty(xpath.result->nodesetval)) {
3189 rc = GPG_ERR_ELEMENT_NOT_FOUND;
3190 goto fail;
3193 rc = recurse_xpath_nodeset(client->doc, xpath.result->nodesetval,
3194 (xmlChar *)xpath.req[1], &xpath.buf, cmd, (xmlChar *)req[1]);
3196 fail:
3197 g_strfreev(req);
3198 xpath_command_cleanup(&xpath);
3199 return send_error(ctx, rc);
3202 static gint import_command_finalize(gpointer data, gint assuan_rc, guchar *line,
3203 gsize len)
3205 struct client_s *client = assuan_get_pointer((assuan_context_t)data);
3206 gpg_error_t rc = file_modified(client);
3207 gchar **req, **path = NULL, **path_orig = NULL, *content;
3208 xmlDocPtr doc = NULL;
3209 xmlNodePtr n, root, copy;
3211 if (assuan_rc || rc) {
3212 if (line)
3213 xfree(line);
3214 return assuan_rc ? assuan_rc : rc;
3217 req = split_input_line((gchar *)line, "\t", 2);
3218 xfree(line);
3220 if (!req || !*req)
3221 return GPG_ERR_SYNTAX;
3223 content = req[0];
3224 path = split_input_line(req[1], "\t", 0);
3226 if (!content || !*content) {
3227 rc = GPG_ERR_SYNTAX;
3228 goto fail;
3231 doc = xmlReadDoc((xmlChar *)content, NULL, "UTF-8", XML_PARSE_NOBLANKS);
3233 if (!doc) {
3234 rc = EPWMD_LIBXML_ERROR;
3235 goto fail;
3238 root = xmlDocGetRootElement(doc);
3239 rc = validate_import(root);
3241 if (rc)
3242 goto fail;
3244 if (path) {
3245 path_orig = g_strdupv(path);
3247 if (!path_orig) {
3248 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
3249 rc = GPG_ERR_ENOMEM;
3250 goto fail;
3253 xmlChar *a = xmlGetProp(root, (xmlChar *)"_name");
3255 if (!a) {
3256 g_strfreev(path_orig);
3257 rc = GPG_ERR_ENOMEM;
3258 goto fail;
3261 if (strv_printf(&path, "%s", (gchar *)a) == FALSE) {
3262 xmlFree(a);
3263 g_strfreev(path_orig);
3264 rc = GPG_ERR_ENOMEM;
3265 goto fail;
3268 xmlFree(a);
3269 n = find_root_element(client->doc, &path, &rc, NULL, 0, FALSE);
3271 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3272 g_strfreev(path_orig);
3273 goto fail;
3276 if (!rc) {
3277 n = find_elements(client->doc, n->children, path+1, &rc, NULL, NULL, NULL, FALSE, 0, NULL, TRUE);
3279 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3280 g_strfreev(path_orig);
3281 goto fail;
3283 else if (!rc) {
3284 xmlNodePtr parent = n->parent;
3286 xmlUnlinkNode(n);
3287 xmlFreeNode(n);
3288 n = parent;
3292 g_strfreev(path);
3293 path = path_orig;
3295 if (rc == GPG_ERR_ELEMENT_NOT_FOUND) {
3296 n = create_element_path(client, &path, &rc);
3298 if (rc)
3299 goto fail;
3302 copy = xmlCopyNodeList(root);
3303 n = xmlAddChildList(n, copy);
3305 if (!n)
3306 rc = EPWMD_LIBXML_ERROR;
3308 else {
3309 /* Check if the content root element can create a DTD root element. */
3310 if (!xmlStrEqual((xmlChar *)"element", root->name)) {
3311 rc = GPG_ERR_SYNTAX;
3312 goto fail;
3315 xmlChar *a;
3317 if ((a = xmlGetProp(root, (xmlChar *)"_name")) == NULL) {
3318 rc = GPG_ERR_SYNTAX;
3319 goto fail;
3322 gchar *tmp = g_strdup((gchar *)a);
3323 xmlFree(a);
3324 gboolean literal = is_literal_element(&tmp);
3326 if (!valid_xml_element((xmlChar *)tmp) || literal) {
3327 g_free(tmp);
3328 rc = GPG_ERR_INV_VALUE;
3329 goto fail;
3332 if (strv_printf(&path, "%s", tmp) == FALSE) {
3333 g_free(tmp);
3334 rc = GPG_ERR_ENOMEM;
3335 goto fail;
3338 g_free(tmp);
3339 n = find_root_element(client->doc, &path, &rc, NULL, 0, TRUE);
3341 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3342 rc = EPWMD_LIBXML_ERROR;
3343 goto fail;
3346 /* Overwriting the existing tree. */
3347 if (!rc) {
3348 xmlUnlinkNode(n);
3349 xmlFreeNodeList(n);
3352 rc = 0;
3353 xmlSetProp(root, (xmlChar *)"_name", (xmlChar *)path[0]);
3354 n = xmlCopyNode(root, 1);
3355 n = xmlAddChildList(xmlDocGetRootElement(client->doc), n);
3358 if (n && !rc)
3359 rc = update_element_mtime(n->parent);
3361 fail:
3362 if (doc)
3363 xmlFreeDoc(doc);
3365 if (path)
3366 g_strfreev(path);
3368 g_strfreev(req);
3369 client->inquire_status = INQUIRE_DONE;
3370 return rc;
3373 static gint import_command(assuan_context_t ctx, gchar *line)
3375 gpg_error_t rc;
3376 struct client_s *client = assuan_get_pointer(ctx);
3378 rc = assuan_inquire_ext(ctx, "IMPORT", 0, import_command_finalize, ctx);
3380 if (rc)
3381 return send_error(ctx, rc);
3383 /* Don't return with assuan_process_done() here. This is an INQUIRE. */
3384 client->inquire_status = INQUIRE_BUSY;
3385 return 0;
3388 static gpg_error_t do_lock_command(struct client_s *client)
3390 gpg_error_t rc = lock_file_mutex(client);
3392 if (!rc)
3393 client->is_lock_cmd = TRUE;
3395 return client->opts & OPT_INQUIRE ? rc : send_error(client->ctx, rc);
3398 static gint lock_command(assuan_context_t ctx, gchar *line)
3400 struct client_s *client = assuan_get_pointer(ctx);
3402 return do_lock_command(client);
3405 static gint unlock_command(assuan_context_t ctx, gchar *line)
3407 struct client_s *client = assuan_get_pointer(ctx);
3409 unlock_file_mutex(client);
3410 return send_error(ctx, 0);
3413 static gint getpid_command(assuan_context_t ctx, gchar *line)
3415 gpg_error_t rc;
3416 gchar buf[32];
3417 pid_t pid = getpid();
3419 print_fmt(buf, sizeof(buf), "%i", pid);
3420 rc = xfer_data(ctx, buf, strlen(buf));
3421 return send_error(ctx, rc);
3424 static gint version_command(assuan_context_t ctx, gchar *line)
3426 gpg_error_t rc;
3427 gchar buf[32];
3429 print_fmt(buf, sizeof(buf), "0x%X", VERSION_HEX);
3430 rc = xfer_data(ctx, buf, strlen(buf));
3431 return send_error(ctx, rc);
3434 #ifdef WITH_PINENTRY
3435 static void set_option_value(gchar **opt, const gchar *value)
3437 if (opt)
3438 g_free(*opt);
3440 *opt = NULL;
3442 if (value)
3443 *opt = g_strdup(value);
3445 #endif
3447 static gint set_unset_common(assuan_context_t ctx, const gchar *name,
3448 const gchar *value)
3450 struct client_s *client = assuan_get_pointer(ctx);
3451 gpg_error_t rc;
3453 if (g_ascii_strcasecmp(name, (gchar *)"log_level") == 0) {
3454 glong l = 0;
3456 if (value) {
3457 l = strtol(value, NULL, 10);
3459 if (l < 0 || l > 2)
3460 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3463 MUTEX_LOCK(&rcfile_mutex);
3464 g_key_file_set_integer(keyfileh, "global", "log_level", (gint)l);
3465 MUTEX_UNLOCK(&rcfile_mutex);
3466 goto done;
3468 else if (g_ascii_strcasecmp(name, (gchar *)"rc_on_locked") == 0) {
3469 glong l = 0;
3471 if (value) {
3472 l = strtol(value, NULL, 10);
3474 if (l < 0 || l > 1)
3475 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3478 client->rc_on_locked = l ? TRUE : FALSE;
3479 goto done;
3481 else if (g_ascii_strcasecmp(name, (gchar *)"lock_on_open") == 0) {
3482 rc = parse_open_opt_lock(client, (gpointer)value);
3484 if (rc)
3485 return rc;
3487 client->opts |= OPT_LOCK;
3489 else if (g_ascii_strcasecmp(name, (gchar *)"cipher") == 0) {
3490 if (!value) {
3491 client->opts &= ~(OPT_CIPHER);
3492 goto done;
3495 rc = parse_save_opt_cipher(client, (gpointer)value);
3497 if (rc)
3498 return rc;
3500 client->opts |= OPT_CIPHER;
3501 goto done;
3503 else if (g_ascii_strcasecmp(name, (gchar *)"iterations") == 0) {
3504 rc = parse_save_opt_iterations(client, (gpointer)value);
3506 if (rc)
3507 return rc;
3509 goto done;
3511 else if (g_ascii_strcasecmp(name, (gchar *)"NAME") == 0) {
3512 pth_attr_t attr = pth_attr_of(pth_self());
3513 gchar buf[41];
3515 if (!value) {
3516 pth_attr_destroy(attr);
3517 goto done;
3520 print_fmt(buf, sizeof(buf), "%s", value);
3521 pth_attr_set(attr, PTH_ATTR_NAME, buf);
3522 pth_attr_destroy(attr);
3523 #ifdef WITH_PINENTRY
3524 if (client->pinentry->name)
3525 g_free(client->pinentry->name);
3527 client->pinentry->name = g_strdup(buf);
3529 if (!client->pinentry->name)
3530 return GPG_ERR_ENOMEM;
3531 #endif
3533 goto done;
3535 #ifdef WITH_PINENTRY
3536 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3537 set_option_value(&client->pinentry->lcmessages, value);
3538 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3539 set_option_value(&client->pinentry->lcctype, value);
3540 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3541 set_option_value(&client->pinentry->ttyname, value);
3542 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3543 set_option_value(&client->pinentry->ttytype, value);
3544 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3545 set_option_value(&client->pinentry->display, value);
3546 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3547 set_option_value(&client->pinentry->path, value);
3548 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3549 set_option_value(&client->pinentry->title, value);
3550 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3551 set_option_value(&client->pinentry->prompt, value);
3552 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3553 set_option_value(&client->pinentry->desc, value);
3554 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0) {
3555 gchar *p = NULL;
3556 gint n;
3558 if (!value)
3559 goto done;
3561 n = strtol(value, &p, 10);
3563 if (*p || n < 0)
3564 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_INV_VALUE);
3566 MUTEX_LOCK(&rcfile_mutex);
3567 g_key_file_set_integer(keyfileh, client->filename ? client->filename :
3568 "global", "pinentry_timeout", n);
3569 MUTEX_UNLOCK(&rcfile_mutex);
3570 goto done;
3572 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0) {
3573 rc = parse_opt_pinentry(client, (gpointer)value);
3575 if (rc)
3576 return rc;
3578 goto done;
3580 #else
3581 else if (g_ascii_strcasecmp(name, (gchar *)"lc_messages") == 0)
3582 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3583 else if (g_ascii_strcasecmp(name, (gchar *)"lc_ctype") == 0)
3584 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3585 else if (g_ascii_strcasecmp(name, (gchar *)"ttyname") == 0)
3586 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3587 else if (g_ascii_strcasecmp(name, (gchar *)"ttytype") == 0)
3588 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3589 else if (g_ascii_strcasecmp(name, (gchar *)"display") == 0)
3590 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3591 else if (g_ascii_strcasecmp(name, (gchar *)"pinentry_path") == 0)
3592 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3593 else if (g_ascii_strcasecmp(name, (gchar *)"title") == 0)
3594 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3595 else if (g_ascii_strcasecmp(name, (gchar *)"prompt") == 0)
3596 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3597 else if (g_ascii_strcasecmp(name, (gchar *)"desc") == 0)
3598 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3599 else if (g_ascii_strcasecmp(name, "pinentry_timeout") == 0)
3600 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3601 else if (g_ascii_strcasecmp(name, "enable_pinentry") == 0)
3602 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_NOT_IMPLEMENTED);
3603 #endif
3604 else
3605 return gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_UNKNOWN_OPTION);
3607 done:
3608 return 0;
3611 static gint unset_command(assuan_context_t ctx, gchar *line)
3613 log_write2("ARGS=\"%s\"", line);
3614 return send_error(ctx, set_unset_common(ctx, line, NULL));
3617 static gint set_command(assuan_context_t ctx, gchar *line)
3619 gchar name[64] = {0}, value[256] = {0};
3621 log_write2("ARGS=\"%s\"", line);
3623 if (sscanf(line, " %63[_a-zA-Z] = %255c", name, value) != 2)
3624 return send_error(ctx, gpg_err_make(PWMD_ERR_SOURCE, GPG_ERR_SYNTAX));
3626 return send_error(ctx, set_unset_common(ctx, name, value));
3629 static gint rename_command(assuan_context_t ctx, gchar *line)
3631 struct client_s *client = assuan_get_pointer(ctx);
3632 gpg_error_t rc;
3633 gchar **req, **src, *dst;
3634 xmlNodePtr n, ndst;
3636 log_write2("ARGS=\"%s\"", line);
3637 req = split_input_line(line, " ", -1);
3639 if (!req || !req[0] || !req[1]) {
3640 g_strfreev(req);
3641 return send_error(ctx, GPG_ERR_SYNTAX);
3644 dst = req[1];
3645 is_literal_element(&dst);
3647 if (!valid_xml_element((xmlChar *)dst)) {
3648 g_strfreev(req);
3649 return GPG_ERR_INV_VALUE;
3652 if (strchr(req[0], '\t'))
3653 src = split_input_line(req[0], "\t", -1);
3654 else
3655 src = split_input_line(req[0], " ", -1);
3657 if (!src || !*src) {
3658 rc = GPG_ERR_SYNTAX;
3659 goto fail;
3662 n = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3664 if (src[1] && n)
3665 n = find_elements(client->doc, n->children, src+1, &rc, NULL, NULL,
3666 NULL, FALSE, 0, NULL, FALSE);
3668 if (!n)
3669 goto fail;
3672 xmlChar *a = xmlGetProp(n, (xmlChar *)"_name");
3674 if (!a) {
3675 rc = GPG_ERR_ENOMEM;
3676 goto fail;
3679 /* To prevent unwanted effects:
3681 * <root name="a"><b/></root>
3683 * RENAME a<TAB>b b
3685 if (xmlStrEqual(a, (xmlChar *)dst)) {
3686 xmlFree(a);
3687 rc = GPG_ERR_AMBIGUOUS_NAME;
3688 goto fail;
3691 xmlFree(a);
3692 gchar **tmp = NULL;
3694 if (src[1]) {
3695 gchar **p;
3697 for (p = src; *p; p++) {
3698 if (!*(p+1))
3699 break;
3701 strv_printf(&tmp, "%s", *p);
3705 strv_printf(&tmp, "!%s", dst);
3706 ndst = find_root_element(client->doc, &tmp, &rc, NULL, 0, FALSE);
3708 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND) {
3709 g_strfreev(tmp);
3710 goto fail;
3713 if (tmp[1] && ndst)
3714 ndst = find_elements(client->doc, ndst->children, tmp+1, &rc, NULL,
3715 NULL, NULL, FALSE, 0, NULL, FALSE);
3717 g_strfreev(tmp);
3719 if (!ndst && rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3720 goto fail;
3722 rc = 0;
3724 /* Target may exist:
3726 * <root name="a"/>
3727 * <root name="b" target="a"/>
3729 * RENAME b a
3731 * Would need to do:
3732 * RENAME !b a
3734 if (ndst == n) {
3735 rc = GPG_ERR_AMBIGUOUS_NAME;
3736 goto fail;
3739 if (ndst) {
3740 unlink_node(ndst);
3741 xmlFreeNodeList(ndst);
3744 rc = add_attribute(n, "_name", dst);
3746 fail:
3747 g_strfreev(req);
3748 g_strfreev(src);
3749 return send_error(ctx, rc);
3752 static gint copy_command(assuan_context_t ctx, gchar *line)
3754 struct client_s *client = assuan_get_pointer(ctx);
3755 gpg_error_t rc;
3756 gchar **req, **src = NULL, **dst = NULL;
3757 xmlNodePtr nsrc, ndst, new;
3759 log_write2("ARGS=\"%s\"", line);
3760 req = split_input_line(line, " ", -1);
3762 if (!req || !req[0] || !req[1]) {
3763 g_strfreev(req);
3764 return send_error(ctx, GPG_ERR_SYNTAX);
3767 if (strchr(req[0], '\t'))
3768 src = split_input_line(req[0], "\t", -1);
3769 else
3770 src = split_input_line(req[0], " ", -1);
3772 if (!src || !*src) {
3773 rc = GPG_ERR_SYNTAX;
3774 goto fail;
3777 if (strchr(req[1], '\t'))
3778 dst = split_input_line(req[1], "\t", -1);
3779 else
3780 dst = split_input_line(req[1], " ", -1);
3782 if (!dst || !*dst) {
3783 rc = GPG_ERR_SYNTAX;
3784 goto fail;
3787 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3789 if (nsrc && src[1])
3790 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3791 NULL, NULL, FALSE, 0, NULL, FALSE);
3793 if (!nsrc)
3794 goto fail;
3796 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3798 if (ndst && dst[1])
3799 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3800 NULL, NULL, FALSE, 0, NULL, FALSE);
3802 if (!ndst && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3803 goto fail;
3805 new = xmlCopyNodeList(nsrc);
3807 if (!new) {
3808 rc = GPG_ERR_ENOMEM;
3809 goto fail;
3812 if (!ndst)
3813 ndst = create_element_path(client, &dst, &rc);
3815 if (!ndst) {
3816 xmlUnlinkNode(new);
3817 xmlFreeNodeList(new);
3818 goto fail;
3821 /* Merge any attributes from the src node to the initial dst node. */
3822 for (xmlAttrPtr attr = new->properties; attr; attr = attr->next) {
3823 if (xmlStrEqual(attr->name, (xmlChar *)"_name"))
3824 continue;
3826 xmlAttrPtr a = xmlHasProp(ndst, attr->name);
3828 if (a)
3829 xmlRemoveProp(a);
3831 xmlChar *tmp = xmlNodeGetContent(attr->children);
3832 xmlNewProp(ndst, attr->name, tmp);
3833 xmlFree(tmp);
3834 rc = add_attribute(ndst, NULL, NULL);
3837 xmlNodePtr n = ndst->children;
3838 xmlUnlinkNode(n);
3839 xmlFreeNodeList(n);
3840 ndst->children = NULL;
3842 if (!new->children) {
3843 xmlUnlinkNode(new);
3844 xmlFreeNodeList(new);
3845 goto fail;
3848 n = xmlCopyNodeList(new->children);
3850 if (!n) {
3851 rc = GPG_ERR_ENOMEM;
3852 goto fail;
3855 xmlUnlinkNode(new);
3856 xmlFreeNodeList(new);
3857 n = xmlAddChildList(ndst, n);
3859 if (!n) {
3860 rc = GPG_ERR_ENOMEM;
3861 goto fail;
3864 rc = update_element_mtime(xmlDocGetRootElement(client->doc) == ndst->parent ? ndst : ndst->parent);
3866 fail:
3867 if (req)
3868 g_strfreev(req);
3870 if (src)
3871 g_strfreev(src);
3873 if (dst)
3874 g_strfreev(dst);
3876 return send_error(ctx, rc);
3879 static gint move_command(assuan_context_t ctx, gchar *line)
3881 struct client_s *client = assuan_get_pointer(ctx);
3882 gpg_error_t rc;
3883 gchar **req, **src = NULL, **dst = NULL;
3884 xmlNodePtr nsrc, ndst = NULL;
3886 log_write2("ARGS=\"%s\"", line);
3887 req = split_input_line(line, " ", -1);
3889 if (!req || !req[0] || !req[1]) {
3890 g_strfreev(req);
3891 return send_error(ctx, GPG_ERR_SYNTAX);
3894 if (strchr(req[0], '\t'))
3895 src = split_input_line(req[0], "\t", -1);
3896 else
3897 src = split_input_line(req[0], " ", -1);
3899 if (!src || !*src) {
3900 rc = GPG_ERR_SYNTAX;
3901 goto fail;
3904 if (strchr(req[1], '\t'))
3905 dst = split_input_line(req[1], "\t", -1);
3906 else
3907 dst = split_input_line(req[1], " ", -1);
3909 nsrc = find_root_element(client->doc, &src, &rc, NULL, 0, FALSE);
3911 if (nsrc && src[1])
3912 nsrc = find_elements(client->doc, nsrc->children, src+1, &rc, NULL,
3913 NULL, NULL, FALSE, 0, NULL, FALSE);
3915 if (!nsrc)
3916 goto fail;
3918 if (dst) {
3919 ndst = find_root_element(client->doc, &dst, &rc, NULL, 0, FALSE);
3921 if (ndst && dst[1])
3922 ndst = find_elements(client->doc, ndst->children, dst+1, &rc, NULL,
3923 NULL, NULL, FALSE, 0, NULL, FALSE);
3925 else
3926 ndst = xmlDocGetRootElement(client->doc);
3928 for (xmlNodePtr n = ndst; n; n = n->parent) {
3929 if (n == nsrc) {
3930 rc = GPG_ERR_CONFLICT;
3931 goto fail;
3935 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
3936 goto fail;
3938 rc = 0;
3940 if (ndst) {
3941 xmlChar *a = node_has_attribute(nsrc, (xmlChar *)"_name");
3942 xmlNodePtr dup = find_element(ndst->children, (gchar *)a, NULL);
3944 xmlFree(a);
3946 if (dup) {
3947 if (dup == nsrc)
3948 goto fail;
3950 if (ndst == xmlDocGetRootElement(client->doc)) {
3951 xmlNodePtr n = nsrc;
3952 gboolean match = FALSE;
3954 while (n->parent && n->parent != ndst)
3955 n = n->parent;
3957 xmlChar *a = node_has_attribute(n, (xmlChar *)"_name");
3958 xmlChar *b = node_has_attribute(nsrc, (xmlChar *)"_name");
3960 if (xmlStrEqual(a, b)) {
3961 match = TRUE;
3962 xmlUnlinkNode(nsrc);
3963 xmlUnlinkNode(n);
3964 xmlFreeNodeList(n);
3967 xmlFree(a);
3968 xmlFree(b);
3970 if (!match) {
3971 xmlUnlinkNode(dup);
3972 xmlFreeNodeList(dup);
3975 else
3976 xmlUnlinkNode(dup);
3980 if (!ndst && dst)
3981 ndst = create_element_path(client, &dst, &rc);
3983 if (!ndst)
3984 goto fail;
3986 update_element_mtime(nsrc->parent);
3987 xmlUnlinkNode(nsrc);
3988 ndst = xmlAddChildList(ndst, nsrc);
3990 if (!ndst)
3991 rc = GPG_ERR_ENOMEM;
3993 update_element_mtime(ndst->parent);
3995 fail:
3996 if (req)
3997 g_strfreev(req);
3999 if (src)
4000 g_strfreev(src);
4002 if (dst)
4003 g_strfreev(dst);
4005 return send_error(ctx, rc);
4008 static int ls_command(assuan_context_t ctx, gchar *line)
4010 log_write2("ARGS=\"%s\"", line);
4011 gpg_error_t rc;
4012 gchar *tmp = g_key_file_get_string(keyfileh, "global", "data_directory", NULL);
4013 gchar *dir = expand_homedir(tmp);
4014 DIR *d = opendir(dir);
4016 rc = gpg_error_from_syserror();
4017 g_free(tmp);
4019 if (!d) {
4020 g_free(dir);
4021 return send_error(ctx, rc);
4024 size_t len = offsetof(struct dirent, d_name)+pathconf(dir, _PC_NAME_MAX)+1;
4025 struct dirent *p = g_malloc(len), *cur = NULL;
4026 gchar *list = NULL;
4028 g_free(dir);
4029 rc = 0;
4031 while (!readdir_r(d, p, &cur) && cur) {
4032 if (cur->d_name[0] == '.' && cur->d_name[1] == '\0')
4033 continue;
4034 else if (cur->d_name[0] == '.' && cur->d_name[1] == '.' && cur->d_name[2] == '\0')
4035 continue;
4037 tmp = g_strdup_printf("%s%s\n", list ? list : "", cur->d_name);
4039 if (!tmp) {
4040 if (list)
4041 g_free(list);
4043 rc = GPG_ERR_ENOMEM;
4044 break;
4047 g_free(list);
4048 list = tmp;
4051 closedir(d);
4052 g_free(p);
4054 if (rc)
4055 return send_error(ctx, rc);
4057 if (!list)
4058 return send_error(ctx, GPG_ERR_NO_VALUE);
4060 list[strlen(list)-1] = 0;
4061 rc = xfer_data(ctx, list, strlen(list));
4062 g_free(list);
4063 return send_error(ctx, rc);
4066 static void bye_notify(assuan_context_t ctx)
4068 struct client_s *cl = assuan_get_pointer(ctx);
4070 /* This will let assuan_process_next() return. */
4071 fcntl(cl->thd->fd, F_SETFL, O_NONBLOCK);
4074 static void reset_notify(assuan_context_t ctx)
4076 struct client_s *cl = assuan_get_pointer(ctx);
4078 if (cl)
4079 cleanup_client(cl);
4083 * This is called before every Assuan command.
4085 gint command_startup(assuan_context_t ctx, const gchar *name)
4087 struct client_s *cl = assuan_get_pointer(ctx);
4088 gpg_error_t rc;
4090 log_write1("%s", name);
4092 if (!g_ascii_strcasecmp(name, "ISCACHED") ||
4093 !g_ascii_strcasecmp(name, "CLEARCACHE") ||
4094 !g_ascii_strcasecmp(name, "CACHETIMEOUT") ||
4095 !g_ascii_strcasecmp(name, "GETCONFIG") ||
4096 !g_ascii_strcasecmp(name, "GETPID") ||
4097 !g_ascii_strcasecmp(name, "VERSION") ||
4098 !g_ascii_strcasecmp(name, "SET") ||
4099 !g_ascii_strcasecmp(name, "BYE") ||
4100 !g_ascii_strcasecmp(name, "NOP") ||
4101 !g_ascii_strcasecmp(name, "CANCEL") ||
4102 !g_ascii_strcasecmp(name, "RESET") ||
4103 !g_ascii_strcasecmp(name, "END") ||
4104 !g_ascii_strcasecmp(name, "HELP") ||
4105 !g_ascii_strcasecmp(name, "OPTION") ||
4106 !g_ascii_strcasecmp(name, "INPUT") ||
4107 !g_ascii_strcasecmp(name, "OUTPUT") ||
4108 !g_ascii_strcasecmp(name, "LS") ||
4109 !g_ascii_strcasecmp(name, "UNSET"))
4110 return 0;
4112 #ifdef WITH_PINENTRY
4113 if (!(cl->opts & OPT_PINENTRY))
4114 reset_pin_defaults(cl->pinentry);
4115 #endif
4117 cl->last_rc = rc = file_modified(cl);
4119 if (rc) {
4120 if ((rc == EPWMD_NO_FILE || rc == EPWMD_FILE_MODIFIED) &&
4121 !g_ascii_strcasecmp(name, "OPEN"))
4122 rc = 0;
4125 return rc;
4129 * This is called after every Assuan command.
4131 void command_finalize(assuan_context_t ctx, gint rc)
4133 struct client_s *client = assuan_get_pointer(ctx);
4135 if (!client->is_lock_cmd)
4136 unlock_file_mutex(client);
4138 log_write1(N_("command completed (rc=%u)"), client->last_rc);
4139 client->opts &= ~(OPT_INQUIRE);
4140 client->opts &= ~(OPT_BASE64);
4143 gpg_error_t register_commands(assuan_context_t ctx)
4145 static struct {
4146 const gchar *name;
4147 gint (*handler)(assuan_context_t, gchar *line);
4148 } table[] = {
4149 { "OPEN", open_command },
4150 { "SAVE", save_command },
4151 { "LIST", list_command },
4152 { "REALPATH", realpath_command },
4153 { "STORE", store_command },
4154 { "DELETE", delete_command },
4155 { "GET", get_command },
4156 { "ATTR", attr_command },
4157 { "ISCACHED", iscached_command },
4158 { "CLEARCACHE", clearcache_command },
4159 { "CACHETIMEOUT", cachetimeout_command },
4160 { "GETCONFIG", getconfig_command },
4161 { "DUMP", dump_command },
4162 { "XPATH", xpath_command },
4163 { "XPATHATTR", xpathattr_command },
4164 { "IMPORT", import_command },
4165 { "LOCK", lock_command },
4166 { "UNLOCK", unlock_command },
4167 { "GETPID", getpid_command },
4168 { "VERSION", version_command },
4169 { "SET", set_command },
4170 { "UNSET", unset_command },
4171 { "RENAME", rename_command },
4172 { "COPY", copy_command },
4173 { "LS", ls_command },
4174 { "MOVE", move_command },
4175 { "INPUT", NULL },
4176 { "OUTPUT", NULL },
4177 { NULL, NULL }
4179 gint i, rc;
4181 for (i=0; table[i].name; i++) {
4182 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
4184 if (rc)
4185 return rc;
4188 rc = assuan_register_bye_notify(ctx, bye_notify);
4190 if (rc)
4191 return rc;
4193 rc = assuan_register_reset_notify(ctx, reset_notify);
4195 if (rc)
4196 return rc;
4198 rc = assuan_register_pre_cmd_notify(ctx, command_startup);
4200 if (rc)
4201 return rc;
4203 return assuan_register_post_cmd_notify(ctx, command_finalize);
4206 gpg_error_t try_xml_decrypt(assuan_context_t ctx,
4207 struct crypto_s *crypto, gpointer *dst, goffset *dst_len)
4209 goffset insize, len;
4210 struct client_s *client = ctx ? assuan_get_pointer(ctx) : NULL;
4211 guint64 iter = 0ULL, n_iter = 0ULL, iter_progress = 0ULL;
4212 gulong outsize = 0;
4213 gpg_error_t rc;
4214 gsize fh_size = crypto->fh->v1 ? sizeof(crypto->fh->ver.fh1) : sizeof(crypto->fh->ver.fh2);
4215 guint64 fh_iter = crypto->fh->v1 ? crypto->fh->ver.fh1.iter : crypto->fh->ver.fh2.iter;
4216 gsize hashlen = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
4218 lseek(crypto->fh->fd, fh_size, SEEK_SET);
4219 insize = crypto->fh->st.st_size - fh_size;
4220 crypto->iv = gcry_malloc(crypto->blocksize);
4222 if (!crypto->iv) {
4223 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4224 return GPG_ERR_ENOMEM;
4227 if (crypto->fh->v1)
4228 memcpy(crypto->iv, crypto->fh->ver.fh1.iv, crypto->blocksize);
4229 else
4230 memcpy(crypto->iv, crypto->fh->ver.fh2.iv, crypto->blocksize);
4232 crypto->inbuf = gcry_malloc(insize);
4234 if (!crypto->inbuf) {
4235 log_write("%s(%i): %s", __FILE__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4236 return GPG_ERR_ENOMEM;
4239 crypto->insize = insize;
4240 len = pth_read(crypto->fh->fd, crypto->inbuf, crypto->insize);
4242 if (len != crypto->insize)
4243 return GPG_ERR_INV_LENGTH;
4245 /* No encryption iterations. This is a plain (gzipped) file. */
4246 if ((crypto->fh->v1 && (long)fh_iter < 0L) ||
4247 (!crypto->fh->v1 && fh_iter <= 0L)) {
4249 * cache_file_count() needs both .used == TRUE and a valid key in
4250 * order for it to count as a used cache entry. Fixes CACHE status
4251 * messages.
4253 memset(crypto->key, '!', hashlen);
4254 goto decompress;
4257 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4258 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4259 return rc;
4262 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->key, crypto->keysize))) {
4263 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4264 return rc;
4267 iter_progress = (guint64)get_key_file_double(client && client->filename ?
4268 client->filename : "global", "iteration_progress");
4270 if (iter_progress > 0ULL && fh_iter >= iter_progress) {
4271 rc = send_status(ctx, STATUS_DECRYPT, "0 %llu", fh_iter);
4273 if (rc)
4274 return rc;
4277 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4279 if (rc)
4280 return rc;
4282 crypto->tkey = gcry_malloc(hashlen);
4284 if (!crypto->tkey) {
4285 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(GPG_ERR_ENOMEM));
4286 return GPG_ERR_ENOMEM;
4289 memcpy(crypto->tkey, crypto->key, hashlen);
4290 guchar *tkey = crypto->tkey;
4291 tkey[0] ^= 1;
4293 if ((rc = gcry_cipher_setkey(crypto->gh, crypto->tkey, crypto->keysize))) {
4294 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4295 return rc;
4298 while (iter < (crypto->fh->v1 ? fh_iter : fh_iter-1)) {
4299 if (iter_progress > 0ULL && iter >= iter_progress) {
4300 if (!(iter % iter_progress)) {
4301 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu",
4302 ++n_iter * iter_progress, fh_iter);
4304 if (rc)
4305 return rc;
4309 if ((rc = gcry_cipher_setiv(crypto->gh, crypto->iv, crypto->blocksize))) {
4310 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4311 return rc;
4314 rc = iterate_crypto_once(client, crypto, STATUS_DECRYPT);
4316 if (rc) {
4317 log_write("%s(%i): %s", __FUNCTION__, __LINE__, pwmd_strerror(rc));
4318 return rc;
4321 iter++;
4324 if (iter_progress && fh_iter >= iter_progress) {
4325 rc = send_status(ctx, STATUS_DECRYPT, "%llu %llu", fh_iter, fh_iter);
4327 if (rc)
4328 return rc;
4331 decompress:
4332 if (!crypto->fh->v1 && crypto->fh->ver.fh2.version >= 0x218) {
4333 len = 0;
4335 if (crypto->fh->ver.fh2.iter > 0ULL) {
4336 if (memcmp(crypto->inbuf, crypto_magic, sizeof(crypto_magic)))
4337 return GPG_ERR_INV_PASSPHRASE;
4339 len = sizeof(crypto_magic);
4342 rc = do_decompress(ctx, (guchar *)crypto->inbuf+len, crypto->insize-len,
4343 (gpointer *)&crypto->outbuf, &outsize);
4345 if (rc)
4346 return rc;
4348 else {
4349 rc = do_decompress(ctx, crypto->inbuf, crypto->insize,
4350 (gpointer *)&crypto->outbuf, &outsize);
4352 if (rc == GPG_ERR_ENOMEM)
4353 return rc;
4354 else if (rc)
4355 return GPG_ERR_INV_PASSPHRASE; // Not a valid gzip header. Must be a bad key.
4357 if (g_strncasecmp(crypto->outbuf, "<?xml ", 6) != 0) {
4358 gcry_free(crypto->outbuf);
4359 crypto->outbuf = NULL;
4360 return GPG_ERR_INV_PASSPHRASE;
4364 if (ctx) {
4365 client->xml = crypto->outbuf;
4366 client->len = outsize;
4367 crypto->outbuf = NULL;
4369 else if (dst) {
4370 *dst = crypto->outbuf;
4371 *dst_len = outsize;
4372 crypto->outbuf = NULL;
4375 /* The calling function should free the crypto struct. */
4376 return 0;